diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/_images/complex-hfsm.png b/_images/complex-hfsm.png new file mode 100644 index 000000000..f79292d94 Binary files /dev/null and b/_images/complex-hfsm.png differ diff --git a/_sources/adc/adc_example.md.txt b/_sources/adc/adc_example.md.txt new file mode 100644 index 000000000..3c9bb4149 --- /dev/null +++ b/_sources/adc/adc_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/adc/example/README.md +``` diff --git a/_sources/adc/adc_types.rst.txt b/_sources/adc/adc_types.rst.txt new file mode 100644 index 000000000..702d547fb --- /dev/null +++ b/_sources/adc/adc_types.rst.txt @@ -0,0 +1,12 @@ +ADC Types +********* + +Simple container for data associated with an ADC channel configuration, +including the unit, the channel, and the attenuation desired. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/adc_types.inc diff --git a/_sources/adc/ads1x15.rst.txt b/_sources/adc/ads1x15.rst.txt new file mode 100644 index 000000000..0dbbfe5be --- /dev/null +++ b/_sources/adc/ads1x15.rst.txt @@ -0,0 +1,18 @@ +ADS1x15 I2C ADC +*************** + +The `ADS1x15` provides a class for communicating with the ADS1x15 (ADS1015 and +ADS1115) family of I2C ADC chips with configurable gain and sampling rate. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + ads1x15_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ads1x15.inc diff --git a/_sources/adc/ads1x15_example.md.txt b/_sources/adc/ads1x15_example.md.txt new file mode 100644 index 000000000..abd31ff74 --- /dev/null +++ b/_sources/adc/ads1x15_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/ads1x15/example/README.md +``` diff --git a/_sources/adc/ads7138.rst.txt b/_sources/adc/ads7138.rst.txt new file mode 100644 index 000000000..32c659b2b --- /dev/null +++ b/_sources/adc/ads7138.rst.txt @@ -0,0 +1,23 @@ +ADS7138 I2C ADC +*************** + +The `Ads7138` class implements support for the Texas Instruments ADS7138 12-bit +8-channel ADC. The ADS7138 is a 12-bit, 8-channel, low-power, successive +approximation register (SAR) analog-to-digital converter (ADC) which can +configure any of its 8 channels as single-ended analog inputs, digital inputs, +or digital outputs. It has an operating mode that allows the user to configure +the device for a single conversion, or to automatically convert on a +continuous basis. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + ads7138_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ads7138.inc diff --git a/_sources/adc/ads7138_example.md.txt b/_sources/adc/ads7138_example.md.txt new file mode 100644 index 000000000..63c3e3e83 --- /dev/null +++ b/_sources/adc/ads7138_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/ads7138/example/README.md +``` diff --git a/_sources/adc/continuous_adc.rst.txt b/_sources/adc/continuous_adc.rst.txt new file mode 100644 index 000000000..75a77fdeb --- /dev/null +++ b/_sources/adc/continuous_adc.rst.txt @@ -0,0 +1,23 @@ +Continuous ADC +************** + +The `ContinuousAdc` provides a mechanism for high-frequency, continuous, +deterministic sampling of analog voltages for multiple channels (potentially +across multiple ADC units, depending on the ESP32 chip used). It does this be +enabling the continuous ADC DMA mode and then running its own task which +retrieves the data and filters it. When the user calls `get_mv(adc_channel_t)`, +it simply returns the most recent filtered value for that channel, if it was +configured. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + adc_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/continuous_adc.inc diff --git a/_sources/adc/index.rst.txt b/_sources/adc/index.rst.txt new file mode 100644 index 000000000..3f87b1933 --- /dev/null +++ b/_sources/adc/index.rst.txt @@ -0,0 +1,14 @@ +ADC APIs +******** + +.. toctree:: + :maxdepth: 1 + + ads1x15 + ads7138 + oneshot_adc + continuous_adc + tla2528 + adc_types + +Code examples for the ADC API are provided in the respective component folders. diff --git a/_sources/adc/oneshot_adc.rst.txt b/_sources/adc/oneshot_adc.rst.txt new file mode 100644 index 000000000..ce73b5ba7 --- /dev/null +++ b/_sources/adc/oneshot_adc.rst.txt @@ -0,0 +1,22 @@ +Oneshot ADC +*********** + +The `OneshotAdc` allows the user a simple, low-resource way to sporadically (and +with moderate frequency needs) measure an analog voltage for multiple channels +on a single ADC UNIT. It does not start or manage any tasks and does not perform +any filtering on the data. Each time the user calls `read_raw(adc_channel_t)` or +`read_mv(adc_channel_t)`, it block and trigger an analog read for the associated +channel (if it was configured to do so). + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + adc_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/oneshot_adc.inc diff --git a/_sources/adc/tla2528.rst.txt b/_sources/adc/tla2528.rst.txt new file mode 100644 index 000000000..a25ac921d --- /dev/null +++ b/_sources/adc/tla2528.rst.txt @@ -0,0 +1,23 @@ +TLA2528 I2C ADC +*************** + +The `Tla2528` class implements support for the Texas Instruments TLA2528 12-bit +8-channel ADC. The TLA2528 is a 12-bit, 8-channel, low-power, successive +approximation register (SAR) analog-to-digital converter (ADC) which can +configure any of its 8 channels as single-ended analog inputs, digital inputs, +or digital outputs. It has an operating mode that allows the user to configure +the device for a single conversion, or to automatically convert on a +sequenced basis. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + tla2528_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/tla2528.inc diff --git a/_sources/adc/tla2528_example.md.txt b/_sources/adc/tla2528_example.md.txt new file mode 100644 index 000000000..b6742a535 --- /dev/null +++ b/_sources/adc/tla2528_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/tla2528/example/README.md +``` diff --git a/_sources/base_component.rst.txt b/_sources/base_component.rst.txt new file mode 100644 index 000000000..7de4a262c --- /dev/null +++ b/_sources/base_component.rst.txt @@ -0,0 +1,16 @@ +Base Compoenent +*************** + +The `espp::BaseComponent` provides a simple base class for all components in the +ESP-CPP package. It provides a simple interface for the component to be +initialized and to be updated. + +It is not required to use the `BaseComponent` class, but it is recommended to +use as it provides a standardized API for logging and log management. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/base_component.inc diff --git a/_sources/base_peripheral.rst.txt b/_sources/base_peripheral.rst.txt new file mode 100644 index 000000000..cf48e7675 --- /dev/null +++ b/_sources/base_peripheral.rst.txt @@ -0,0 +1,20 @@ +Base Peripheral +*************** + +The `espp::BasePeripheral` class is a base class for all peripherals. It +provides a common interface for all peripherals and is used to access the +peripheral's registers. It is primarily designed to be used as a base class for +peripheral classes that communicate using I2C (address-based) or SPI (CS-based) +protocols. + +The base class provides an interface for specifying different communications +functions that the peripheral may use, as well as providing some base +implementations for common functionality such as reading / writing u8 and u16 +values from / to a register. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/base_peripheral.inc diff --git a/_sources/battery/index.rst.txt b/_sources/battery/index.rst.txt new file mode 100644 index 000000000..d72e3a5b8 --- /dev/null +++ b/_sources/battery/index.rst.txt @@ -0,0 +1,11 @@ +Battery APIs +************ + +.. toctree:: + :maxdepth: 1 + + max1704x + +These components provide a common interface to battery devices. They provide +functions for monitoring the battery level and charging status, and for +configuring the battery charging parameters. diff --git a/_sources/battery/max1704x.rst.txt b/_sources/battery/max1704x.rst.txt new file mode 100644 index 000000000..7c510b7d2 --- /dev/null +++ b/_sources/battery/max1704x.rst.txt @@ -0,0 +1,38 @@ +MAX1704X +******** + +The MAX17048/MAX17049 ICs are tiny, micropower current fuel gauges for +lithium-ion (Li+) batteries in handheld and portable equipment. The MAX17048 +operates with a single lithium cell and the MAX17049 with two lithium cells in +series. + +The ICs use the sophisticated Li+ battery-modeling algorithm ModelGauge™ to +track the battery relative state-of-charge (SOC) continuously over widely varying +charge and discharge conditions. The ModelGauge algorithm eliminates +current-sense resistor and battery-learn cycles required in traditional fuel +gauges. Temperature compensation is implemented using the system +microcontroller. + +The ICs automatically detect when the battery enters a low-current state and +enters low-power 3µA hibernate mode, while still providing accurate fuel +gauging. The ICs automatically exit hibernate mode when the system returns to +active state. + +On battery insertion, the ICs debounce initial voltage measurements to improve +the initial SOC estimate, thus allowing them to be located on system side. SOC, +voltage, and rate information is accessed using the I2C interface. The ICs are +available in a tiny 0.9mm x 1.7mm, 8-bump wafer-level package (WLP), or a 2mm x +2mm, 8-pin TDFN package. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + max1704x_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/max1704x.inc diff --git a/_sources/battery/max1704x_example.md.txt b/_sources/battery/max1704x_example.md.txt new file mode 100644 index 000000000..09480cddd --- /dev/null +++ b/_sources/battery/max1704x_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/max1704x/example/README.md +``` diff --git a/_sources/bldc/bldc_driver.rst.txt b/_sources/bldc/bldc_driver.rst.txt new file mode 100644 index 000000000..8ea158696 --- /dev/null +++ b/_sources/bldc/bldc_driver.rst.txt @@ -0,0 +1,13 @@ +BLDC Driver +*********** + +The `BldcDriver` component wraps around the `ESP MCPWM Peripheral +`_ +to provide full 6 PWM control over a 3 phase brushless dc motor. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/bldc_driver.inc diff --git a/_sources/bldc/bldc_motor.rst.txt b/_sources/bldc/bldc_motor.rst.txt new file mode 100644 index 000000000..2947159ef --- /dev/null +++ b/_sources/bldc/bldc_motor.rst.txt @@ -0,0 +1,35 @@ +BLDC Motor +********** + +The `BldcMotor` implements the Field-Oriented Control (FOC) algorithm with +support for multiple transforms to drive voltage (such as Sinusoidal and Space +Vector). It supports the following motion control configurations (which can be +changed dynamically): + +* Closed-loop angle +* Closed-loop velocity +* Open-loop angle +* Open-loop velocity + +Note: currently the code has some support for Torque control, but that requires +current sense - for which I don't yet have the hardware to support the +development of. + +The `BldcMotor` should be configured with a `BldcDriver` and optional `Sensor` +(for angle & speed of the motor), and optional `CurrentSensor` (for measuring +the phase currents of the motor and providing torque control). + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + bldc_motor_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/bldc_motor.inc +.. include-build-file:: inc/bldc_types.inc +.. include-build-file:: inc/sensor_direction.inc diff --git a/_sources/bldc/bldc_motor_example.md.txt b/_sources/bldc/bldc_motor_example.md.txt new file mode 100644 index 000000000..1e3bc53cc --- /dev/null +++ b/_sources/bldc/bldc_motor_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/bldc_motor/example/README.md +``` diff --git a/_sources/bldc/index.rst.txt b/_sources/bldc/index.rst.txt new file mode 100644 index 000000000..852734e43 --- /dev/null +++ b/_sources/bldc/index.rst.txt @@ -0,0 +1,15 @@ +BLDC APIs +********* + +.. toctree:: + :maxdepth: 1 + + bldc_driver + bldc_motor + +These components provide interfaces by which the user can control brushless DC +(BLDC) motors. The driver component(s) implement the low-level voltage / pwm +output to the motor directly, where the motor component(s) implement the +open-loop or closed-loop control algorithms - using the driver. + +Code examples for the BLDC API are provided in the `bldc_motor` example folder. diff --git a/_sources/ble/battery_service.rst.txt b/_sources/ble/battery_service.rst.txt new file mode 100644 index 000000000..3388d289d --- /dev/null +++ b/_sources/ble/battery_service.rst.txt @@ -0,0 +1,12 @@ +Battery Service +*************** + +The `BatteryService` implements the standard BLE battery service, providing +battery state information from a BLE peripheral to a BLE central. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/battery_service.inc diff --git a/_sources/ble/ble_gatt_server.rst.txt b/_sources/ble/ble_gatt_server.rst.txt new file mode 100644 index 000000000..dcb425ae3 --- /dev/null +++ b/_sources/ble/ble_gatt_server.rst.txt @@ -0,0 +1,22 @@ +BLE GATT Server +*************** + +The `BleGattServer` implements the standard BLE GATT server which has various +APIs for controlling the server and adding services. It automatically builds and +adds standard battery service and device information service. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + ble_gatt_server_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ble_appearances.inc +.. include-build-file:: inc/ble_gatt_server.inc +.. include-build-file:: inc/ble_gatt_server_callbacks.inc +.. include-build-file:: inc/ble_gatt_server_menu.inc diff --git a/_sources/ble/ble_gatt_server_example.md.txt b/_sources/ble/ble_gatt_server_example.md.txt new file mode 100644 index 000000000..415b816af --- /dev/null +++ b/_sources/ble/ble_gatt_server_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/ble_gatt_server/example/README.md +``` diff --git a/_sources/ble/device_info_service.rst.txt b/_sources/ble/device_info_service.rst.txt new file mode 100644 index 000000000..943632f69 --- /dev/null +++ b/_sources/ble/device_info_service.rst.txt @@ -0,0 +1,12 @@ +Device Info Service +******************* + +The `DeviceInfoService` implements the standard BLE device information service, +providing device information from a BLE peripheral to a BLE central. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/device_info_service.inc diff --git a/_sources/ble/gfps_service.rst.txt b/_sources/ble/gfps_service.rst.txt new file mode 100644 index 000000000..4c8b61021 --- /dev/null +++ b/_sources/ble/gfps_service.rst.txt @@ -0,0 +1,23 @@ +Google Fast Pair Service (GFPS) Service +*************************************** + +The `GfpsService` implements the Google Fast Pair Service, allowing first-party +fast-pair experience on Android devices using the google nearby framework. This +also supports app matching / launching, as well as Google's `Find My Device` +service. Finally, GFPS supports sharing device pairing info across that +account's google devices and personalizing the name of the device. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + gfps_service_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/gfps_service.inc +.. include-build-file:: inc/gfps_characteristic_callbacks.inc +.. include-build-file:: inc/gfps.inc diff --git a/_sources/ble/gfps_service_example.md.txt b/_sources/ble/gfps_service_example.md.txt new file mode 100644 index 000000000..e72290c09 --- /dev/null +++ b/_sources/ble/gfps_service_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/gfps_service/example/README.md +``` diff --git a/_sources/ble/hid_service.rst.txt b/_sources/ble/hid_service.rst.txt new file mode 100644 index 000000000..f58b25a3d --- /dev/null +++ b/_sources/ble/hid_service.rst.txt @@ -0,0 +1,19 @@ +HID Service +*********** + +The `HidService` implements the standard BLE HID service, providing dynamic and +configurable HID input, output, and feature reports from a BLE peripheral to a +BLE central. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + hid_service_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/hid_service.inc diff --git a/_sources/ble/hid_service_example.md.txt b/_sources/ble/hid_service_example.md.txt new file mode 100644 index 000000000..fafbae7f2 --- /dev/null +++ b/_sources/ble/hid_service_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/hid_service/example/README.md +``` diff --git a/_sources/ble/index.rst.txt b/_sources/ble/index.rst.txt new file mode 100644 index 000000000..4493b5409 --- /dev/null +++ b/_sources/ble/index.rst.txt @@ -0,0 +1,17 @@ +BLE APIs +******** + +.. toctree:: + :maxdepth: 1 + + battery_service + ble_gatt_server + ble_gatt_server_example + device_info_service + gfps_service + gfps_service_example + hid_service + hid_service_example + +These components provide some interfaces for implementing a BLE peripheral - +namely a BLE GATT Server hosting various services. diff --git a/_sources/button.rst.txt b/_sources/button.rst.txt new file mode 100644 index 000000000..56bb8441c --- /dev/null +++ b/_sources/button.rst.txt @@ -0,0 +1,28 @@ +Button APIs +*********** + +The `Button` class provides a simple way to read the state of a button. There +are two ways to configure the functionality of the button. + +The first uses `Button::Config` to configure the button to call a function when +the button is pressed or released and uses the `Interrupt` class' task and ISR +for signaling. At any time, a user may also call the `is_pressed` method to read +the current state of the button's input pin. + +The second uses `Button::SimpleConfig` to simply configure the button as an +input with configurable pull-up or pull-down resistors and a configurable active +state (high or low). In this configuration, the input is read manually any time +the user calls the `is_pressed` method. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + button_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/button.inc diff --git a/_sources/button_example.md.txt b/_sources/button_example.md.txt new file mode 100644 index 000000000..c0f57aae1 --- /dev/null +++ b/_sources/button_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/button/example/README.md +``` diff --git a/_sources/cli.rst.txt b/_sources/cli.rst.txt new file mode 100644 index 000000000..1bf11610f --- /dev/null +++ b/_sources/cli.rst.txt @@ -0,0 +1,46 @@ +Command Line Interface (CLI) APIs +********************************* + +The `cli.hpp` header provides a convenience include / wrapper around +`daniele77/cli `_. It also exposes `cli`'s +include folder, so including `"cli.hpp"` is completely equivalent to including +`` - but you can additionally include other files from +``. It also provides a few conveniences: + +1. a `espp::Cli` class which inherits from `cli::CliSession` and has a + near-identical implementation as `cli`'s `CliFileSesson`, with the exception + that it explicitly reads character by character instead of line by line and + prints out the characters as they are being input, and +2. a static `espp::Cli::configure_stdin_stdout()` function which sets up the esp + UART to enable blocking `std::cin` read, which is needed for `std::cin` to + work (and therefore - currently - for `cli` to work). This function is + automatically called by the `espp::Cli` constructor, but it can also be + called manually without needing to create a `espp::Cli` object if you wish to + simply use the `std::cin` and related functions. +3. a `espp::LineInput` class which provides support for an interactive input + system which can optionally have history with navigation. It allows for + getting the user input as an arbitrary input string while enabling some + keyboard movement and editing commands. The `espp::Cli` uses the + `espp::LineInput` class internally to handle the input aspects of the Cli, + but the `espp::LineInput` class can be re-used anywhere you want to get one + or more lines of user input in a reusable way. Note that if you use it in + another class / outside the `espp::Cli` class, you will need to call the + `espp::Cli::configure_stdin_stdout()` as mentioned above. + +Please see the documentation for the `cli submodule +`_ if you have any questions about usage +beyond the examples provided here. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + cli_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/cli.inc +.. include-build-file:: inc/line_input.inc diff --git a/_sources/cli_example.md.txt b/_sources/cli_example.md.txt new file mode 100644 index 000000000..a588ce06c --- /dev/null +++ b/_sources/cli_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/cli/example/README.md +``` diff --git a/_sources/color.rst.txt b/_sources/color.rst.txt new file mode 100644 index 000000000..f0c7e888d --- /dev/null +++ b/_sources/color.rst.txt @@ -0,0 +1,25 @@ +Color APIs +********** + +The `color.hpp` header provides two classes for performing color management, +interpolation, and conversion - `espp::Rgb` and `espp::Hsv` which can be +converted between each other. The RGB color space provides support for additive +blending (which includes averaging, as opposed to light-model-based mixing) and +is therefore suited for producing gradients. + +Please see `Computer Graphics and Geometric Modeling: Implementation and +Algorithms `_, specifically section +8.6 for more information. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + color_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/color.inc diff --git a/_sources/color_example.md.txt b/_sources/color_example.md.txt new file mode 100644 index 000000000..7c199b0be --- /dev/null +++ b/_sources/color_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/color/example/README.md +``` diff --git a/_sources/controller.rst.txt b/_sources/controller.rst.txt new file mode 100644 index 000000000..86acb554f --- /dev/null +++ b/_sources/controller.rst.txt @@ -0,0 +1,22 @@ +Controller APIs +*************** + +The `Controller` class provides a convenience for reading multiple GPIOs at once +and mapping their state to common controller buttons. It can optionally be +configured to support joystick select, as well as to convert analog joystick +values into digital directional values (up/down/left/right). It can also be used +for just a subset of the buttons, should you wish to do so, by providing the +GPIO configuration for the unused buttons to be -1. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + controller_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/controller.inc diff --git a/_sources/controller_example.md.txt b/_sources/controller_example.md.txt new file mode 100644 index 000000000..fbcf05a6d --- /dev/null +++ b/_sources/controller_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/controller/example/README.md +``` diff --git a/_sources/csv.rst.txt b/_sources/csv.rst.txt new file mode 100644 index 000000000..801ba81c3 --- /dev/null +++ b/_sources/csv.rst.txt @@ -0,0 +1,21 @@ +CSV APIs +******** + +The `csv.hpp` header provides a convenience include / wrapper around +`p-ranav/csv2 `_ +ESP peripheral api as it would be configured for an incremental encoder with +quadrature output (see `Wikipedia +`_). The AbiEncoder can be +configured to be either `LINEAR` or `ROTATIONAL`, and provides access to the +current `count` of the encoder (including the overflow underflow conditions). + +Code examples for the ABI Encoder are provided in the `encoder` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + encoder_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/abi_encoder.inc diff --git a/_sources/encoder/as5600.rst.txt b/_sources/encoder/as5600.rst.txt new file mode 100644 index 000000000..c1ee4bcae --- /dev/null +++ b/_sources/encoder/as5600.rst.txt @@ -0,0 +1,36 @@ +AS5600 Magnetic Encoder +*********************** + +The `AS5600` magnetic encoder component provides the user a convenient way to +measure + +* Raw count +* Raw radians +* Raw degrees +* Accumulated count (since the component was created) +* Accumulated radians (since the component was created) +* Accumulated degrees (since the component was created) +* Speed (rotations per minute / RPM) + +It does so by spawning a task which periodically reads the magnetic encoder, +updates the accumulator, and computes the velocity. The component can be +configured to optionally filter the velocity. + +The periodicity / update rate of the encoder can be configured at time of +creation. + +The encoder is designed to fulfill the needs of the `BldcMotor` API, to provide +closed-loop motor control. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + as5600_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/as5600.inc diff --git a/_sources/encoder/as5600_example.md.txt b/_sources/encoder/as5600_example.md.txt new file mode 100644 index 000000000..6bae5bf76 --- /dev/null +++ b/_sources/encoder/as5600_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/as5600/example/README.md +``` diff --git a/_sources/encoder/encoder_example.md.txt b/_sources/encoder/encoder_example.md.txt new file mode 100644 index 000000000..7671fd626 --- /dev/null +++ b/_sources/encoder/encoder_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/encoder/example/README.md +``` diff --git a/_sources/encoder/encoder_types.rst.txt b/_sources/encoder/encoder_types.rst.txt new file mode 100644 index 000000000..71ea0a3b4 --- /dev/null +++ b/_sources/encoder/encoder_types.rst.txt @@ -0,0 +1,12 @@ +Encoder Types +************* + +Type definitions for the different kinds of encoders supported. Used as template +specialization parameters when constructing encoders. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/encoder_types.inc diff --git a/_sources/encoder/index.rst.txt b/_sources/encoder/index.rst.txt new file mode 100644 index 000000000..9b752924a --- /dev/null +++ b/_sources/encoder/index.rst.txt @@ -0,0 +1,14 @@ +Encoder APIs +************ + +.. toctree:: + :maxdepth: 1 + + abi_encoder + encoder_types + as5600 + mt6701 + +There are several different types of encoders provided, some within the encoder +component directly, as well as some that are standalone components for +interacting with encoder chips over a serial interface such as I2C. diff --git a/_sources/encoder/mt6701.rst.txt b/_sources/encoder/mt6701.rst.txt new file mode 100644 index 000000000..d0be1ab10 --- /dev/null +++ b/_sources/encoder/mt6701.rst.txt @@ -0,0 +1,36 @@ +MT6701 Magnetic Encoder +*********************** + +The `MT6701` magnetic encoder component provides the user a convenient way to +measure + +* Raw count +* Raw radians +* Raw degrees +* Accumulated count (since the component was created) +* Accumulated radians (since the component was created) +* Accumulated degrees (since the component was created) +* Speed (rotations per minute / RPM) + +It does so by spawning a task which periodically reads the magnetic encoder, +updates the accumulator, and computes the velocity. The component can be +configured to optionally filter the velocity. + +The periodicity / update rate of the encoder can be configured at time of +creation. + +The encoder is designed to fulfill the needs of the `BldcMotor` API, to provide +closed-loop motor control. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + mt6701_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/mt6701.inc diff --git a/_sources/encoder/mt6701_example.md.txt b/_sources/encoder/mt6701_example.md.txt new file mode 100644 index 000000000..75a082bbd --- /dev/null +++ b/_sources/encoder/mt6701_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/mt6701/example/README.md +``` diff --git a/_sources/esp32_timer_cam.rst.txt b/_sources/esp32_timer_cam.rst.txt new file mode 100644 index 000000000..1421a1c9b --- /dev/null +++ b/_sources/esp32_timer_cam.rst.txt @@ -0,0 +1,25 @@ +ESP32 TimerCam +************** + +Esp32-Timer-Cam +--------------- + +The ESP32 TimerCam is a little usb-c webcamera using the ESP32. It has a little +blue LED, a real-time clock (RTC), and supports battery operation with battery +voltage monitoring as well. + +The `espp::EspTimerCam` component provides a singleton hardware abstraction for +initializing the I2C, LED, RTC, and ADC subsystems. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + esp32_timer_cam_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/esp32-timer-cam.inc diff --git a/_sources/esp32_timer_cam_example.md.txt b/_sources/esp32_timer_cam_example.md.txt new file mode 100644 index 000000000..0d9148418 --- /dev/null +++ b/_sources/esp32_timer_cam_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/esp32-timer-cam/example/README.md +``` diff --git a/_sources/esp_box.rst.txt b/_sources/esp_box.rst.txt new file mode 100644 index 000000000..871026e18 --- /dev/null +++ b/_sources/esp_box.rst.txt @@ -0,0 +1,26 @@ +ESP BOX +******* + +Esp-Box +------- + +The ESP32-S3-BOX and ESP32-S3-BOX-3 are development boards for the ESP32-S3 +module. They feature a nice touchscreen display, a speaker, microphones, and +expansion headers. + +The `espp::EspBox` component provides a singleton hardware abstraction for +initializing the touch, display, and audio subsystems, as well as automatically +determining which version of the Box it's running on. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + esp_box_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/esp-box.inc diff --git a/_sources/esp_box_example.md.txt b/_sources/esp_box_example.md.txt new file mode 100644 index 000000000..0b940eaf4 --- /dev/null +++ b/_sources/esp_box_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/esp-box/example/README.md +``` diff --git a/_sources/event_manager.rst.txt b/_sources/event_manager.rst.txt new file mode 100644 index 000000000..a560b4025 --- /dev/null +++ b/_sources/event_manager.rst.txt @@ -0,0 +1,27 @@ +Event Manager APIs +****************** + +The `EventManager` class enables anonymous publish/subscribe interactions +between different software components and contexts in the system. It provides a +singleton class which manages the registry of publishers and subscribers in the +system and provides loose coupling between them. To subscribe to events/data, a +component must register itself with the manager by calling `add_subscriber()` - +which will register a callback function associated with that component for the +event/topic provided. All callback functions for a given topic/event are called +from the same thread/context - a thread that is started and managed by the +EventManager. As noted in a few places, it is recommended to use a +(de-)serialization library such as espp::serialization / alpaca for transforming +data structures to/from `std::vector` for publishing/subscribing. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + event_manager_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/event_manager.inc diff --git a/_sources/event_manager_example.md.txt b/_sources/event_manager_example.md.txt new file mode 100644 index 000000000..edd4a0e93 --- /dev/null +++ b/_sources/event_manager_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/event_manager/example/README.md +``` diff --git a/_sources/file_system.rst.txt b/_sources/file_system.rst.txt new file mode 100644 index 000000000..69fc0c995 --- /dev/null +++ b/_sources/file_system.rst.txt @@ -0,0 +1,25 @@ +File System APIs +**************** + +The `FileSystem` class provides a simple interface for interacting with the +filesystem. It provides a singleton class which manages the filesystem and also +includes the relevant POSIX, newlib, and C++ standard library headers providing +access to the filesystem. It is a wrapper around the `LittleFS` library and +can be configured using menuconfig to use a custom partition label. + +It also provides some utility functions for interacting with the filesystem +and performing operations such as getting the total, used, and free space on +the filesystem, and listing files in a directory. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + file_system_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/file_system.inc diff --git a/_sources/file_system_example.md.txt b/_sources/file_system_example.md.txt new file mode 100644 index 000000000..0089b2a8d --- /dev/null +++ b/_sources/file_system_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/file_system/example/README.md +``` diff --git a/_sources/filters/biquad.rst.txt b/_sources/filters/biquad.rst.txt new file mode 100644 index 000000000..0f63f14c3 --- /dev/null +++ b/_sources/filters/biquad.rst.txt @@ -0,0 +1,13 @@ +Biquad Filter +************* + +The `BiquadFilter` class provides an implementation of a `Digital Biequad Filter +`_ with implementations for +both the `Direct Form 1` and `Direct Form 2`. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/biquad_filter.inc diff --git a/_sources/filters/butterworth.rst.txt b/_sources/filters/butterworth.rst.txt new file mode 100644 index 000000000..01f9e7a5d --- /dev/null +++ b/_sources/filters/butterworth.rst.txt @@ -0,0 +1,13 @@ +Butterworth Filter +****************** + +The `ButterworthFilter` class provides an implementation of a `Digital +Butterworth Filter `_, +implemented as biquad sections (second order sections). + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/butterworth_filter.inc diff --git a/_sources/filters/filters_example.md.txt b/_sources/filters/filters_example.md.txt new file mode 100644 index 000000000..dd2f9cd11 --- /dev/null +++ b/_sources/filters/filters_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/filters/example/README.md +``` diff --git a/_sources/filters/index.rst.txt b/_sources/filters/index.rst.txt new file mode 100644 index 000000000..4a8260999 --- /dev/null +++ b/_sources/filters/index.rst.txt @@ -0,0 +1,16 @@ +Filter APIs +*********** + +.. toctree:: + :maxdepth: 1 + + filters_example + biquad + butterworth + lowpass + simple_lowpass + sos + transfer_function + +There are several different types of filters provided, as well as some base +classes from which to build more generic filters. diff --git a/_sources/filters/lowpass.rst.txt b/_sources/filters/lowpass.rst.txt new file mode 100644 index 000000000..b864b9bf3 --- /dev/null +++ b/_sources/filters/lowpass.rst.txt @@ -0,0 +1,14 @@ +Lowpass Filter +************** + +The `LowpassFilter` class provides an implementation of a digial lowpass +infinite impulse response (IIR) filter, which leverages the hardware +acceleration provided by `esp-dsp `_ and +which leverages the vector instructions on the espressif processors. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/lowpass_filter.inc diff --git a/_sources/filters/simple_lowpass.rst.txt b/_sources/filters/simple_lowpass.rst.txt new file mode 100644 index 000000000..8190eb621 --- /dev/null +++ b/_sources/filters/simple_lowpass.rst.txt @@ -0,0 +1,12 @@ +Simple Lowpass Filter +********************* + +The `SimpleLowpassFilter` class provides an implementation of a simple moving +average filter with a configurable time constant. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/simple_lowpass_filter.inc diff --git a/_sources/filters/sos.rst.txt b/_sources/filters/sos.rst.txt new file mode 100644 index 000000000..1e1685a7d --- /dev/null +++ b/_sources/filters/sos.rst.txt @@ -0,0 +1,15 @@ +Second Order Sections (SoS) Filter +********************************** + +The `SosFilter` class provides an implementation of a Second Order Sections +(SoS) filter. For more information please see `series second-order sections +`_ +as well as `Digital Biquad Filter +`_. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/sos_filter.inc diff --git a/_sources/filters/transfer_function.rst.txt b/_sources/filters/transfer_function.rst.txt new file mode 100644 index 000000000..e38940336 --- /dev/null +++ b/_sources/filters/transfer_function.rst.txt @@ -0,0 +1,12 @@ +Transfer Function API +********************* + +The `TransferFunction` struct provides a simple container for storing the A and +B coefficients for an N-th order transfer function. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/transfer_function.inc diff --git a/_sources/ftp/ftp_server.rst.txt b/_sources/ftp/ftp_server.rst.txt new file mode 100644 index 000000000..9278620a7 --- /dev/null +++ b/_sources/ftp/ftp_server.rst.txt @@ -0,0 +1,26 @@ +FTP Server +********** + +The `FtpServer` class implements a simple FTP server. It accepts new connections +and spawns a new `FtpClientSession` for each one. Each session is handled in its +own thread. + +The `FtpClientSession` class implements the FTP protocol. It is responsible for +handling the commands and sending the responses. + +Note that the FTP server does not implement any authentication mechanism. It +accepts any username and password. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + ftp_server_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ftp_server.inc +.. include-build-file:: inc/ftp_client_session.inc diff --git a/_sources/ftp/ftp_server_example.md.txt b/_sources/ftp/ftp_server_example.md.txt new file mode 100644 index 000000000..101459039 --- /dev/null +++ b/_sources/ftp/ftp_server_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/ftp/example/README.md +``` diff --git a/_sources/ftp/index.rst.txt b/_sources/ftp/index.rst.txt new file mode 100644 index 000000000..390613334 --- /dev/null +++ b/_sources/ftp/index.rst.txt @@ -0,0 +1,11 @@ +FTP APIs +******** + +.. toctree:: + :maxdepth: 1 + + ftp_server + +FTP can be used to transfer files between computers. ESPP currently provides an +implementation of the FTP server side. The FTP client side is not yet +implemented. diff --git a/_sources/haptics/bldc_haptics.rst.txt b/_sources/haptics/bldc_haptics.rst.txt new file mode 100644 index 000000000..c87d44c2b --- /dev/null +++ b/_sources/haptics/bldc_haptics.rst.txt @@ -0,0 +1,40 @@ +BLDC Haptics +************ + +The `BldcHaptics` class is a high-level interface for controlling a BLDC motor +with a haptic feedback loop. It is designed to be used to provide haptic +feedback as part of a rotary input device (the BLDC motor). The component +provides a `DetentConfig` interface for configuring the input / haptic feedback +profile for the motor dynamically with configuration of: + + - Range of motion (min/max position + width of each position) + - Width of each position in the range (which will be used to calculate the + actual range of motion based on the number of positions) + - Strength of the haptic feedback at each position (detent) + - Strength of the haptic feedback at the edges of the range of motion + - Specific positions to provide haptic feedback at (detents) + - Snap point (percentage of position width which will trigger a snap to the + nearest position) + + +The component also provides a `HapticConfig` interface for configuring the +haptic feedback loop with configuration of: + + - Strength of the haptic feedback + - Frequency of the haptic feedback [currently not implemented] + - Duration of the haptic feedback [currently not implemented] + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + bldc_haptics_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/detent_config.inc +.. include-build-file:: inc/haptic_config.inc +.. include-build-file:: inc/bldc_haptics.inc diff --git a/_sources/haptics/bldc_haptics_example.md.txt b/_sources/haptics/bldc_haptics_example.md.txt new file mode 100644 index 000000000..bde6ba81d --- /dev/null +++ b/_sources/haptics/bldc_haptics_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/bldc_haptics/example/README.md +``` diff --git a/_sources/haptics/drv2605.rst.txt b/_sources/haptics/drv2605.rst.txt new file mode 100644 index 000000000..489acf605 --- /dev/null +++ b/_sources/haptics/drv2605.rst.txt @@ -0,0 +1,23 @@ +DRV2605 Haptic Motor Driver +*************************** + +The `DRV2605` haptic motor driver component allows the user to configure and +play custom or preconfigured haptic feedback sequences via a serial interface +such as I2C. It supports directly driving ECM (eccentric rotating mass) and LRA +(linear resonant actuator) type haptic motors. It also supports fully custom +waveforms (e.g. via using the audio, pwm / analog functions) as well as a preset +library of 123 different haptic waveforms which can be played in sequences of up +to 8 waveforms. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + drv2605_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/drv2605.inc diff --git a/_sources/haptics/drv2605_example.md.txt b/_sources/haptics/drv2605_example.md.txt new file mode 100644 index 000000000..8492f27b0 --- /dev/null +++ b/_sources/haptics/drv2605_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/drv2605/example/README.md +``` diff --git a/_sources/haptics/index.rst.txt b/_sources/haptics/index.rst.txt new file mode 100644 index 000000000..d3a00145d --- /dev/null +++ b/_sources/haptics/index.rst.txt @@ -0,0 +1,13 @@ +Haptics APIs +************ + +.. toctree:: + :maxdepth: 1 + + bldc_haptics + drv2605 + +There are multiple components which provide haptic feedback functionality, +ranging from haptics driven using BLDC motors to specific peripheral drivers +designed for directly driving ERM (eccentric rotating mass) and LRA (linear +resonant actuator) haptic motors. diff --git a/_sources/hid/hid-rp.rst.txt b/_sources/hid/hid-rp.rst.txt new file mode 100644 index 000000000..284673dae --- /dev/null +++ b/_sources/hid/hid-rp.rst.txt @@ -0,0 +1,20 @@ +HID-RP +****** + +The `hid-rp` component provides a wrapper around +https://github.com/intergatedcircuits/hid-rp and also provides an example +implementation of a configurable HID Gamepad using hid-rp. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + hid-rp_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/hid-rp.inc +.. include-build-file:: inc/hid-rp-gamepad.inc diff --git a/_sources/hid/hid-rp_example.md.txt b/_sources/hid/hid-rp_example.md.txt new file mode 100644 index 000000000..d807dd7bf --- /dev/null +++ b/_sources/hid/hid-rp_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/hid-rp/example/README.md +``` diff --git a/_sources/hid/index.rst.txt b/_sources/hid/index.rst.txt new file mode 100644 index 000000000..ab5a326c9 --- /dev/null +++ b/_sources/hid/index.rst.txt @@ -0,0 +1,10 @@ +HID APIs +******** + +.. toctree:: + :maxdepth: 1 + + hid-rp + +These components provide interfaces for creating and managing HID reports, +report maps, etc. diff --git a/_sources/i2c.rst.txt b/_sources/i2c.rst.txt new file mode 100644 index 000000000..075ce0cf8 --- /dev/null +++ b/_sources/i2c.rst.txt @@ -0,0 +1,22 @@ +I2C +*** + +The `I2C` class provides a simple interface to the I2C bus. It is a wrapper +around the esp-idf I2C driver. + +A helper `I2cMenu` is also provided which can be used to interactively test +I2C buses - scanning the bus, probing devices, reading and writing to devices. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + i2c_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/i2c.inc +.. include-build-file:: inc/i2c_menu.inc diff --git a/_sources/i2c_example.md.txt b/_sources/i2c_example.md.txt new file mode 100644 index 000000000..90e62eba6 --- /dev/null +++ b/_sources/i2c_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/i2c/example/README.md +``` diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..73f2832f4 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,64 @@ +ESPP Documentation +========================= + +This is the documentation for the ESP-IDF C++ library esp-cpp/espp. + + +This is the documentation for esp-idf c++ components, ESPP (`espp `_). ESPP provides additional c++ components and abstractions for building applications from reusable components. + + +.. toctree:: + :maxdepth: 2 + + adc/index + base_component + base_peripheral + battery/index + bldc/index + ble/index + button + controller + cli + color + csv + display/index + encoder/index + esp32_timer_cam + esp_box + event_manager + file_system + filters/index + ftp/index + haptics/index + hid/index + i2c + interrupt + input/index + io_expander/index + joystick + led + led_strip + logger + monitor + motorgo_mini + math/index + matouch_rotary_display + network/index + nfc/index + nvs + pid + qwiicnes + rmt + rtc/index + rtsp + seeed_studio_round_display + serialization + state_machine + t_deck + t_dongle_s3 + tabulate + task + thermistor + timer + wifi/index + wrover_kit diff --git a/_sources/input/chsc6x.rst.txt b/_sources/input/chsc6x.rst.txt new file mode 100644 index 000000000..00aab8b02 --- /dev/null +++ b/_sources/input/chsc6x.rst.txt @@ -0,0 +1,17 @@ +CHSC6X Touch Controller +********************** + +The `Chsc6x` class provides an interface to the CHSC6X touch controller. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + chsc6x_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/chsc6x.inc diff --git a/_sources/input/chsc6x_example.md.txt b/_sources/input/chsc6x_example.md.txt new file mode 100644 index 000000000..d948489bc --- /dev/null +++ b/_sources/input/chsc6x_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/chsc6x/example/README.md +``` diff --git a/_sources/input/cst816.rst.txt b/_sources/input/cst816.rst.txt new file mode 100644 index 000000000..8e2eb99fd --- /dev/null +++ b/_sources/input/cst816.rst.txt @@ -0,0 +1,17 @@ +CST816 Touch Controller +********************** + +The `Cst816` class provides an interface to the CST816 touch controller. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + cst816_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/cst816.inc diff --git a/_sources/input/cst816_example.md.txt b/_sources/input/cst816_example.md.txt new file mode 100644 index 000000000..ed3c82d22 --- /dev/null +++ b/_sources/input/cst816_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/cst816/example/README.md +``` diff --git a/_sources/input/encoder_input.rst.txt b/_sources/input/encoder_input.rst.txt new file mode 100644 index 000000000..32ff83709 --- /dev/null +++ b/_sources/input/encoder_input.rst.txt @@ -0,0 +1,13 @@ +Encoder Input +************* + +Encoder input provides a light and configurable wrapper around lvgl input +device driver - specifically designed for encoders, which have a single +incremental input and a single button. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/encoder_input.inc diff --git a/_sources/input/ft5x06.rst.txt b/_sources/input/ft5x06.rst.txt new file mode 100644 index 000000000..875656a33 --- /dev/null +++ b/_sources/input/ft5x06.rst.txt @@ -0,0 +1,17 @@ +FT5x06 Touch Controller +*********************** + +The FT5x06 is a capacitive touch controller that supports up to 5 touch points. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + ft5x06_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ft5x06.inc diff --git a/_sources/input/ft5x06_example.md.txt b/_sources/input/ft5x06_example.md.txt new file mode 100644 index 000000000..3d83069fd --- /dev/null +++ b/_sources/input/ft5x06_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/ft5x06/example/README.md +``` diff --git a/_sources/input/gt911.rst.txt b/_sources/input/gt911.rst.txt new file mode 100644 index 000000000..38fc945fd --- /dev/null +++ b/_sources/input/gt911.rst.txt @@ -0,0 +1,17 @@ +GT911 Touch Controller +********************** + +The `Gt911` class provides an interface to the GT911 touch controller. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + gt911_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/gt911.inc diff --git a/_sources/input/gt911_example.md.txt b/_sources/input/gt911_example.md.txt new file mode 100644 index 000000000..c50343d47 --- /dev/null +++ b/_sources/input/gt911_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/gt911/example/README.md +``` diff --git a/_sources/input/index.rst.txt b/_sources/input/index.rst.txt new file mode 100644 index 000000000..acbeefa9b --- /dev/null +++ b/_sources/input/index.rst.txt @@ -0,0 +1,16 @@ +Input APIs +********** + +.. toctree:: + :maxdepth: 1 + + chsc6x + cst816 + ft5x06 + gt911 + tt21100 + t_keyboard + encoder_input + keypad_input + pointer_input + touchpad_input diff --git a/_sources/input/keypad_input.rst.txt b/_sources/input/keypad_input.rst.txt new file mode 100644 index 000000000..614b3ebd2 --- /dev/null +++ b/_sources/input/keypad_input.rst.txt @@ -0,0 +1,15 @@ +Keypad Input +************ + +Keypad input provides a light and configurable wrapper around lvgl input device +driver - specifically designed for use with a keypad, which is typically a +matrix of buttons, typically containing buttons such as LEFT, RIGHT, UP, DOWN, +ENTER, ESCAPE, etc. + + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/keypad_input.inc diff --git a/_sources/input/pointer_input.rst.txt b/_sources/input/pointer_input.rst.txt new file mode 100644 index 000000000..a85ea4407 --- /dev/null +++ b/_sources/input/pointer_input.rst.txt @@ -0,0 +1,12 @@ +Pointer Input +************* + +Pointer input provides a light and configurable wrapper around lvgl input device +driver - specifically designed for mice, with configurable cursor icons. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/pointer_input.inc diff --git a/_sources/input/t_keyboard.rst.txt b/_sources/input/t_keyboard.rst.txt new file mode 100644 index 000000000..f5ff9b2b8 --- /dev/null +++ b/_sources/input/t_keyboard.rst.txt @@ -0,0 +1,18 @@ +LilyGo T-Keyboard +***************** + +The `TKeyboard` component provides a simple interface to the T-Keyboard +keypad. It allows you to read which key is currently pressed. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + t_keyboard_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/t_keyboard.inc diff --git a/_sources/input/t_keyboard_example.md.txt b/_sources/input/t_keyboard_example.md.txt new file mode 100644 index 000000000..1cb897217 --- /dev/null +++ b/_sources/input/t_keyboard_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/t_keyboard/example/README.md +``` diff --git a/_sources/input/touchpad_input.rst.txt b/_sources/input/touchpad_input.rst.txt new file mode 100644 index 000000000..e4d6ec74e --- /dev/null +++ b/_sources/input/touchpad_input.rst.txt @@ -0,0 +1,13 @@ +Touchpad Input +************** + +Touchpad input provides a light and configurable wrapper around lvgl input +device driver - specifically designed for touch panels, with an optional home +button (part of the touch panel). + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/touchpad_input.inc diff --git a/_sources/input/tt21100.rst.txt b/_sources/input/tt21100.rst.txt new file mode 100644 index 000000000..363539f36 --- /dev/null +++ b/_sources/input/tt21100.rst.txt @@ -0,0 +1,19 @@ +TT21100 Touch Controller +************************ + +The `TT21100` is a touch controller that supports up to 10 touch points. It +supports both mutual and self capacitance sensing. It can be used with `TT21100` +touchpad sensor. This touch controller can be found in the ESP32-S3-BOX. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + tt21100_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/tt21100.inc diff --git a/_sources/input/tt21100_example.md.txt b/_sources/input/tt21100_example.md.txt new file mode 100644 index 000000000..703c640df --- /dev/null +++ b/_sources/input/tt21100_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/tt21100/example/README.md +``` diff --git a/_sources/interrupt.rst.txt b/_sources/interrupt.rst.txt new file mode 100644 index 000000000..8bec103c1 --- /dev/null +++ b/_sources/interrupt.rst.txt @@ -0,0 +1,28 @@ +Interrupt APIs +************** + +The `Interrupt` class provides APIs to register interrupt handlers for GPIO and +configure the interrupts. Interrupts can be configured to trigger on rising +edge, falling edge, high level, low level, or any change in the input signal. A +single interrupt object can manage multiple GPIO pins with separate callbacks +for each GPIO, or separte `Interrupt` objects can be created (though that uses +more memory and CPU as each `Interrupt` will has its own queue, ISR handler, and +task. + +Finally, the `Interrupt` class is also designed to be subclassed if desired to +provide additional functionality, or it can of course be included as a member +within another class. The Button class provides a very simple implementation of +a subclass of `Interrupt`. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + interrupt_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/interrupt.inc diff --git a/_sources/interrupt_example.md.txt b/_sources/interrupt_example.md.txt new file mode 100644 index 000000000..f38d96b41 --- /dev/null +++ b/_sources/interrupt_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/interrupt/example/README.md +``` diff --git a/_sources/io_expander/aw9523.rst.txt b/_sources/io_expander/aw9523.rst.txt new file mode 100644 index 000000000..828e8a5ad --- /dev/null +++ b/_sources/io_expander/aw9523.rst.txt @@ -0,0 +1,20 @@ +AW9523 I/O Expander +********************* + +The `AW9523` I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as I2C. It also supports +dimming control for LEDs attached to the expander's port pins, when those pins +are configured into a special LED mode. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + aw9523_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/aw9523.inc diff --git a/_sources/io_expander/aw9523_example.md.txt b/_sources/io_expander/aw9523_example.md.txt new file mode 100644 index 000000000..ef6baa301 --- /dev/null +++ b/_sources/io_expander/aw9523_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/aw9523/example/README.md +``` diff --git a/_sources/io_expander/index.rst.txt b/_sources/io_expander/index.rst.txt new file mode 100644 index 000000000..3f38fff71 --- /dev/null +++ b/_sources/io_expander/index.rst.txt @@ -0,0 +1,13 @@ +IO Expander APIs +**************** + +.. toctree:: + :maxdepth: 1 + + aw9523 + kts1622 + mcp23x17 + +There are several different types of I/O expanders provided which are standalone +components for interacting with I/O expander chips over a serial interface such +as I2C. diff --git a/_sources/io_expander/kts1622.rst.txt b/_sources/io_expander/kts1622.rst.txt new file mode 100644 index 000000000..0b425cd31 --- /dev/null +++ b/_sources/io_expander/kts1622.rst.txt @@ -0,0 +1,18 @@ +KTS1622 I/O Expander +********************* + +The `KTS1622` I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as I2C. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + kts1622_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/kts1622.inc diff --git a/_sources/io_expander/kts1622_example.md.txt b/_sources/io_expander/kts1622_example.md.txt new file mode 100644 index 000000000..815d0153a --- /dev/null +++ b/_sources/io_expander/kts1622_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/kts1622/example/README.md +``` diff --git a/_sources/io_expander/mcp23x17.rst.txt b/_sources/io_expander/mcp23x17.rst.txt new file mode 100644 index 000000000..d154c3d34 --- /dev/null +++ b/_sources/io_expander/mcp23x17.rst.txt @@ -0,0 +1,18 @@ +MCP23x17 I/O Expander +********************* + +The `MCP23x17` I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as SPI or I2C. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + mcp23x17_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/mcp23x17.inc diff --git a/_sources/io_expander/mcp23x17_example.md.txt b/_sources/io_expander/mcp23x17_example.md.txt new file mode 100644 index 000000000..bf30873e7 --- /dev/null +++ b/_sources/io_expander/mcp23x17_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/mcp23x17/example/README.md +``` diff --git a/_sources/joystick.rst.txt b/_sources/joystick.rst.txt new file mode 100644 index 000000000..44017fc40 --- /dev/null +++ b/_sources/joystick.rst.txt @@ -0,0 +1,25 @@ +Joystick APIs +************* + +Joystick +-------- + +The `Joystick` class provides a wrapper around a 2-axis analog joystick, with an +associated reader function for grabbing the raw values. When the joystick +`update()` is called, the raw values are mapped into the range [-1,1] for each +axis according to the configuration provided. + +Code examples for the task API are provided in the `joystick` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + joystick_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/joystick.inc diff --git a/_sources/joystick_example.md.txt b/_sources/joystick_example.md.txt new file mode 100644 index 000000000..636e52217 --- /dev/null +++ b/_sources/joystick_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/joystick/example/README.md +``` diff --git a/_sources/led.rst.txt b/_sources/led.rst.txt new file mode 100644 index 000000000..ebd051a76 --- /dev/null +++ b/_sources/led.rst.txt @@ -0,0 +1,25 @@ +LED APIs +******** + +LED +--- + +The LED provides a convenient and thread-safe wrapper around the `ESP-IDF LEDC +perhipheral +`_. + +It allows for both instant and hardware-based timed changing (fading) of duty cycle (in +floating point percent [0,100]). + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + led_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/led.inc diff --git a/_sources/led_example.md.txt b/_sources/led_example.md.txt new file mode 100644 index 000000000..5c481c568 --- /dev/null +++ b/_sources/led_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/led/example/README.md +``` diff --git a/_sources/led_strip.rst.txt b/_sources/led_strip.rst.txt new file mode 100644 index 000000000..d6155506c --- /dev/null +++ b/_sources/led_strip.rst.txt @@ -0,0 +1,21 @@ +LED Strip APIs +************** + +The `LedStrip` component provides APIs to control LED strips. It supports +various LED strip types, such as WS2812, WS2811, WS2813, SK6812, APA102, etc. +You can use it directly with an SPI driver to talk to APA102 LED strips, or you +can use it with a RMT driver (such as the `Rmt` component) to talk to WS2812, +WS2811, WS2813, SK6812, etc. LED strips. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + led_strip_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/led_strip.inc diff --git a/_sources/led_strip_example.md.txt b/_sources/led_strip_example.md.txt new file mode 100644 index 000000000..8fd574318 --- /dev/null +++ b/_sources/led_strip_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/led_strip/example/README.md +``` diff --git a/_sources/logger.rst.txt b/_sources/logger.rst.txt new file mode 100644 index 000000000..b6900dcb0 --- /dev/null +++ b/_sources/logger.rst.txt @@ -0,0 +1,30 @@ +Logging APIs +************ + +Format +------ + +Format is a simple component which exposes `libfmt` for use within esp-idf as a +single include. + +Logger +------ + +The logger provides a cross-platform wrapper around `libfmt` for providing +configurable log output with different levels that can be turned on / off at +runtime. + +Code examples for the logging API are provided in the `logger` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + logger_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/logger.inc diff --git a/_sources/logger_example.md.txt b/_sources/logger_example.md.txt new file mode 100644 index 000000000..5ff232aa4 --- /dev/null +++ b/_sources/logger_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/logger/example/README.md +``` diff --git a/_sources/math/bezier.rst.txt b/_sources/math/bezier.rst.txt new file mode 100644 index 000000000..e9409c689 --- /dev/null +++ b/_sources/math/bezier.rst.txt @@ -0,0 +1,13 @@ +Bezier +****** + +The `bezier` header provides a templated implementation of cubic bezier curves +and rational cubic bezier curves. Intended use for these templated functions is +on raw floating point values or on the associated Vector2d class. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/bezier.inc diff --git a/_sources/math/fast_math.rst.txt b/_sources/math/fast_math.rst.txt new file mode 100644 index 000000000..241e3dfa0 --- /dev/null +++ b/_sources/math/fast_math.rst.txt @@ -0,0 +1,27 @@ +Fast Math +********* + +The `Fast Math` header provides a set of static functions which implement +optimized approximations of the following functions: + +* fast_sqrt +* fast_ln +* fast_sin +* fast_cos + +along with some utility functions: + +* square (x^2) +* cube (x^3) +* sgn (sign of a number) +* round (round floating point value to nearest integer value) +* lerp (linear interpolate between two points) +* inv_lerp (inverse linear interpolate between two points) +* piecewise_linear (compute the piecewise linear interpolation between a set of points) + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/fast_math.inc diff --git a/_sources/math/gaussian.rst.txt b/_sources/math/gaussian.rst.txt new file mode 100644 index 000000000..75d51f8c2 --- /dev/null +++ b/_sources/math/gaussian.rst.txt @@ -0,0 +1,18 @@ +Gaussian +******** + +The `gaussian` class provides an implementation of the gaussian function: + +.. math:: + + y(t)= \alpha e^{ -\frac{ (t-\beta)^2 }{ 2\gamma^2 } } + +The class allows for dynamically changing the :math:`\alpha`, :math:`\beta`, and +:math:`\gamma` parameters. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/gaussian.inc diff --git a/_sources/math/index.rst.txt b/_sources/math/index.rst.txt new file mode 100644 index 000000000..c7f15c9d7 --- /dev/null +++ b/_sources/math/index.rst.txt @@ -0,0 +1,12 @@ +Math APIs +********* + +.. toctree:: + :maxdepth: 1 + + math_example + bezier + fast_math + gaussian + range_mapper + vector2d diff --git a/_sources/math/math_example.md.txt b/_sources/math/math_example.md.txt new file mode 100644 index 000000000..88f2c2469 --- /dev/null +++ b/_sources/math/math_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/math/example/README.md +``` diff --git a/_sources/math/range_mapper.rst.txt b/_sources/math/range_mapper.rst.txt new file mode 100644 index 000000000..a48966605 --- /dev/null +++ b/_sources/math/range_mapper.rst.txt @@ -0,0 +1,12 @@ +Range Mapper +************ + +The `RangeMapper` provides a class which allows you to map from a configurable +input range to a standardized output range of [-1,1]. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/range_mapper.inc diff --git a/_sources/math/vector2d.rst.txt b/_sources/math/vector2d.rst.txt new file mode 100644 index 000000000..90faf469f --- /dev/null +++ b/_sources/math/vector2d.rst.txt @@ -0,0 +1,12 @@ +Vector2d +******** + +The `Vector2d` provides a container for a 2-dimensional vector with associated +math operations implemented. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/vector2d.inc diff --git a/_sources/matouch_rotary_display.rst.txt b/_sources/matouch_rotary_display.rst.txt new file mode 100644 index 000000000..758f1ab9a --- /dev/null +++ b/_sources/matouch_rotary_display.rst.txt @@ -0,0 +1,26 @@ +MaTouch Rotary Display +********************** + +Matouch-Rotary-Display +---------------------- + +The Matouch Rotary Display is a development board for the ESP32-S3 module. It +features a nice touchscreen display, a rotary encoder, a push button behind the +screen, and some expansion headers along with other peripherals like a micro-SD +card. + +The `espp::MatouchRotaryDisplay` component provides a singleton hardware +abstraction for initializing the touch, display, and button. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + matouch_rotary_display_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/matouch-rotary-display.inc diff --git a/_sources/matouch_rotary_display_example.md.txt b/_sources/matouch_rotary_display_example.md.txt new file mode 100644 index 000000000..425eca6c3 --- /dev/null +++ b/_sources/matouch_rotary_display_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/matouch-rotary-display/example/README.md +``` diff --git a/_sources/monitor.rst.txt b/_sources/monitor.rst.txt new file mode 100644 index 000000000..418113a5e --- /dev/null +++ b/_sources/monitor.rst.txt @@ -0,0 +1,28 @@ +Monitoring APIs +*************** + +Task Monitor +------------ + +The task monitor provides the ability to use the FreeRTOS trace facility to +output information about the CPU utilization (%), stack high water mark (bytes), +and priority of all the tasks running on the system. + +There is an associated `task-monitor `_ +python gui which can parse the output of this component and render it as a chart +or into a table for visualization. + +Code examples for the monitor API are provided in the `monitor` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + monitor_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/task_monitor.inc diff --git a/_sources/monitor_example.md.txt b/_sources/monitor_example.md.txt new file mode 100644 index 000000000..20ad0c00c --- /dev/null +++ b/_sources/monitor_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/monitor/example/README.md +``` diff --git a/_sources/motorgo_mini.rst.txt b/_sources/motorgo_mini.rst.txt new file mode 100644 index 000000000..49a4474f1 --- /dev/null +++ b/_sources/motorgo_mini.rst.txt @@ -0,0 +1,27 @@ +MotorGo Mini +************ + +MotorGo Mini +------------ + +The MotorGo Mini is a small, low-cost, low-power motor controller that can be +used to control a two motors. + +https://motorgo.net + +It's pretty sweet and the component provides the implementation of the two +channel FOC motor controller, along with other peripheral classes such as the +ADC, LEDs, and I2C. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + motorgo_mini_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/motorgo-mini.inc diff --git a/_sources/motorgo_mini_example.md.txt b/_sources/motorgo_mini_example.md.txt new file mode 100644 index 000000000..0d4543114 --- /dev/null +++ b/_sources/motorgo_mini_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/motorgo-mini/example/README.md +``` diff --git a/_sources/network/index.rst.txt b/_sources/network/index.rst.txt new file mode 100644 index 000000000..9d6b8fdce --- /dev/null +++ b/_sources/network/index.rst.txt @@ -0,0 +1,18 @@ +Network APIs +************ + +.. toctree:: + :maxdepth: 1 + + socket_example + socket + udp_socket + tcp_socket + +The network APIs provide a useful abstraction over POSIX sockets enabling easily +starting client/server sockets and allowing their use with std::function +callbacks for servers. + +Currently, UDP and TCP sockets are supported. + +Code examples for the network API are provided in the `socket` example folder.. diff --git a/_sources/network/socket.rst.txt b/_sources/network/socket.rst.txt new file mode 100644 index 000000000..06e5823e8 --- /dev/null +++ b/_sources/network/socket.rst.txt @@ -0,0 +1,14 @@ +Sockets +******* + +The socket provides the base abstraction around the socket file descriptor and +includes some initialization, cleanup, and conversion utilities. + +The socket class is subclassed into UdpSocket and TcpSocket. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/socket.inc diff --git a/_sources/network/socket_example.md.txt b/_sources/network/socket_example.md.txt new file mode 100644 index 000000000..06819abc6 --- /dev/null +++ b/_sources/network/socket_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/socket/example/README.md +``` diff --git a/_sources/network/tcp_socket.rst.txt b/_sources/network/tcp_socket.rst.txt new file mode 100644 index 000000000..5c1fc1a64 --- /dev/null +++ b/_sources/network/tcp_socket.rst.txt @@ -0,0 +1,15 @@ +TCP Sockets +*********** + +TCP sockets provide reliable, ordered communication over IP network sockets and +have built-in protocols for handling packet acknowledgement as well as +transmission speed / bandwidth adjustment. + +TCP sockets cannot be used with multicast (many to one, one to many). + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/tcp_socket.inc diff --git a/_sources/network/udp_socket.rst.txt b/_sources/network/udp_socket.rst.txt new file mode 100644 index 000000000..a33fc1019 --- /dev/null +++ b/_sources/network/udp_socket.rst.txt @@ -0,0 +1,14 @@ +UDP Sockets +*********** + +UDP sockets provide unreliable, unordered communication over IP network sockets. + +UDP sockets can be used in unicast (point to point), multicast (one to many and +many to one), and broadcast (one to all). + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/udp_socket.inc diff --git a/_sources/nfc/index.rst.txt b/_sources/nfc/index.rst.txt new file mode 100644 index 000000000..eb757d0ae --- /dev/null +++ b/_sources/nfc/index.rst.txt @@ -0,0 +1,8 @@ +NFC APIs +******** + +.. toctree:: + :maxdepth: 1 + + ndef + st25dv diff --git a/_sources/nfc/ndef.rst.txt b/_sources/nfc/ndef.rst.txt new file mode 100644 index 000000000..6cd1ce564 --- /dev/null +++ b/_sources/nfc/ndef.rst.txt @@ -0,0 +1,12 @@ +NDEF +**** + +The `NDEF` component provides a utility class for dealing with NFC Data Exchange +Format (NDEF) records, which are used by NFC Tags. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/ndef.inc diff --git a/_sources/nfc/st25dv.rst.txt b/_sources/nfc/st25dv.rst.txt new file mode 100644 index 000000000..5e530fcfb --- /dev/null +++ b/_sources/nfc/st25dv.rst.txt @@ -0,0 +1,22 @@ +ST25DV +****** + +The `St25dv` provides a utility class for NFC communications using the ST25DV +Dynamic NFC / RFID tag. The tag includes 4Kb, 16Kb, or 64Kb EEPROM along with +support for fast transfer mode - which enables bi-directional communications +with other NFC/RFID enabled devices such as phones. This chip stores in its +EEPROM NFC T5T tag records - which include a CC header (that this class +maintains) followed by serialized NDEF records. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + st25dv_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/st25dv.inc diff --git a/_sources/nfc/st25dv_example.md.txt b/_sources/nfc/st25dv_example.md.txt new file mode 100644 index 000000000..b1fb24bf6 --- /dev/null +++ b/_sources/nfc/st25dv_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/st25dv/example/README.md +``` diff --git a/_sources/nvs.rst.txt b/_sources/nvs.rst.txt new file mode 100644 index 000000000..a85b74206 --- /dev/null +++ b/_sources/nvs.rst.txt @@ -0,0 +1,30 @@ +NVS APIs +******** + +NVS +--- + +The `NVS` component provides a simple class representing an NVS controller. + +NVSHandle +--------- + +The `NVSHandle` class manages individual NVS storage handles, allowing for scoped +control over specific NVS namespaces. It simplifies operations like reading, +writing, and committing key-value pairs within these namespaces. + +Code examples for the NVS and NVSHandle API are provided in the `nvs` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + nvs_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/nvs.inc +.. include-build-file:: inc/nvs_handle_espp.inc diff --git a/_sources/nvs_example.md.txt b/_sources/nvs_example.md.txt new file mode 100644 index 000000000..07021b45b --- /dev/null +++ b/_sources/nvs_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/nvs/example/README.md +``` diff --git a/_sources/pid.rst.txt b/_sources/pid.rst.txt new file mode 100644 index 000000000..1c668317d --- /dev/null +++ b/_sources/pid.rst.txt @@ -0,0 +1,24 @@ +PID APIs +******** + +PID +--- + +The `PID` component provides a simple, thread-safe class representing a PID +controller. It tracks how frequently its `update()` method is called and can +have its gains change dynamically. + +Code examples for the task API are provided in the `pid` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + pid_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/pid.inc diff --git a/_sources/pid_example.md.txt b/_sources/pid_example.md.txt new file mode 100644 index 000000000..8392f2df6 --- /dev/null +++ b/_sources/pid_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/pid/example/README.md +``` diff --git a/_sources/qwiicnes.rst.txt b/_sources/qwiicnes.rst.txt new file mode 100644 index 000000000..f6df88dd1 --- /dev/null +++ b/_sources/qwiicnes.rst.txt @@ -0,0 +1,17 @@ +QwiicNES +******** + +The `Qwiicnes` component provides a driver for the `SparkFun Qwiic NES Controller `_. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + qwiicnes_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/qwiicnes.inc diff --git a/_sources/qwiicnes_example.md.txt b/_sources/qwiicnes_example.md.txt new file mode 100644 index 000000000..b75b54b33 --- /dev/null +++ b/_sources/qwiicnes_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/qwiicnes/example/README.md +``` diff --git a/_sources/rmt.rst.txt b/_sources/rmt.rst.txt new file mode 100644 index 000000000..f3eaff280 --- /dev/null +++ b/_sources/rmt.rst.txt @@ -0,0 +1,31 @@ +Remote Control Transceiver (RMT) +******************************** + +The `Rmt` class provides a wrapper around the ESP32 RMT peripheral. It allows +you to send infrared signals with the ESP32. See the esp-idf documentation for +more information about the RMT peripheral. +(https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html) + +The `RmtEncoder` class provides a wrapper around the ESP32 rmt encoder +functionality. It allows you to encode infrared signals with the ESP32. See the +esp-idf documentation for more information about the RMT encoder +(https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html#rmt-encoder) + +The main functionality of the `Rmt` / `RmtEncoder` classes beyond what is +provided by the esp-idf is to allow the use of the RMT peripheral with c++ +functions (such as with bound functions, functionals, etc.). It also provides a +simpler wrapper / interface to the user. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + rmt_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/rmt.inc +.. include-build-file:: inc/rmt_encoder.inc diff --git a/_sources/rmt_example.md.txt b/_sources/rmt_example.md.txt new file mode 100644 index 000000000..7cde5d37e --- /dev/null +++ b/_sources/rmt_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/rmt/example/README.md +``` diff --git a/_sources/rtc/bm8563.rst.txt b/_sources/rtc/bm8563.rst.txt new file mode 100644 index 000000000..6cf498dda --- /dev/null +++ b/_sources/rtc/bm8563.rst.txt @@ -0,0 +1,17 @@ +BM8563 +****** + +The `Bm8563` component provides a driver for the Bm8563 RTC chip. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + bm8563_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/bm8563.inc diff --git a/_sources/rtc/bm8563_example.md.txt b/_sources/rtc/bm8563_example.md.txt new file mode 100644 index 000000000..8ee79db62 --- /dev/null +++ b/_sources/rtc/bm8563_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/bm8563/example/README.md +``` diff --git a/_sources/rtc/index.rst.txt b/_sources/rtc/index.rst.txt new file mode 100644 index 000000000..21c22ca5f --- /dev/null +++ b/_sources/rtc/index.rst.txt @@ -0,0 +1,7 @@ +RTC APIs +******** + +.. toctree:: + :maxdepth: 1 + + bm8563 diff --git a/_sources/rtsp.rst.txt b/_sources/rtsp.rst.txt new file mode 100644 index 000000000..d769bc8d0 --- /dev/null +++ b/_sources/rtsp.rst.txt @@ -0,0 +1,55 @@ +RTSP APIs +********* + +RTSP Client +----------- + +The `RtspClient` class provides an interface to an RTSP server. It is used to +send RTSP requests and receive RTSP responses. It also provides an interface +to the RTP and RTCP sessions that are created as a result of the RTSP +interactions. + +The `RtspClient` currently only supports MJPEG streams, since the ESP32 does +not have a hardware decoder for H.264 or H.265. + +Additionally the client currently only supports UDP transport for RTP and RTCP +packets. TCP transport is not supported. + +The user can register a callback function to be notified when new, complete JPEG +frames are received. The callback function is called with a pointer to the JPEG +frame. + + +RTSP Server +----------- + +The `RtspServer` class provides an implementation of an RTSP server. It is used +to receive RTSP requests and send RTSP responses. It is designed to allow the +user to send JPEG frames to the server, which will then send them to the client +over RTP/UDP. + +The server currently only supports MJPEG streams, since the ESP32 does not have +a hardware encoder for H.264 or H.265. + +Additionally, the server currently only supports UDP transport for RTP and RTCP +packets. TCP transport is not supported. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + rtsp_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/rtsp_client.inc +.. include-build-file:: inc/rtsp_server.inc +.. include-build-file:: inc/rtsp_session.inc +.. include-build-file:: inc/rtp_packet.inc +.. include-build-file:: inc/rtp_jpeg_packet.inc +.. include-build-file:: inc/rtcp_packet.inc +.. include-build-file:: inc/jpeg_header.inc +.. include-build-file:: inc/jpeg_frame.inc diff --git a/_sources/rtsp_example.md.txt b/_sources/rtsp_example.md.txt new file mode 100644 index 000000000..3af905368 --- /dev/null +++ b/_sources/rtsp_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/rtsp/example/README.md +``` diff --git a/_sources/seeed_studio_round_display.rst.txt b/_sources/seeed_studio_round_display.rst.txt new file mode 100644 index 000000000..775523a44 --- /dev/null +++ b/_sources/seeed_studio_round_display.rst.txt @@ -0,0 +1,26 @@ +Seeed Studio Round Display +************************** + +SsRoundDisplay +-------------- + +The Seeed Studio Round Display is a development board containing a 240x240 round +display with touchscreen, RTC, battery charger, and uSD card slot. It support +connection to a QtyPy or a XIAO module. + +The `espp::SsRoundDisplay` component provides a singleton hardware abstraction +for initializing the display and touchscreen components for the Seeed Studio +Round Display. + +.. ------------------------------ Example ------------------------------------- + +.. toctree:: + + seeed_studio_round_display_example.md + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/seeed-studio-round-display.inc diff --git a/_sources/seeed_studio_round_display_example.md.txt b/_sources/seeed_studio_round_display_example.md.txt new file mode 100644 index 000000000..7e4b2b028 --- /dev/null +++ b/_sources/seeed_studio_round_display_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/seeed-studio-round-display/example/README.md +``` diff --git a/_sources/serialization.rst.txt b/_sources/serialization.rst.txt new file mode 100644 index 000000000..e1609afe9 --- /dev/null +++ b/_sources/serialization.rst.txt @@ -0,0 +1,34 @@ +Serialization APIs +****************** + +.. _alpaca-section: + +Alpaca +------ + +The serialization library is a light wrapper around the third-party `alpaca +`_ serialization library. + +Serialization +------------- + +The `Serialization` component provides a simple wrapper with reasonable default +options around the :ref:`alpaca-section` libarary. The default +serialization/deserialization options are configured such that messages / types +can be distinguished from each other. + +Code examples for the serialization API are provided in the `serialization` +example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + serialization_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/serialization.inc diff --git a/_sources/serialization_example.md.txt b/_sources/serialization_example.md.txt new file mode 100644 index 000000000..81382ee05 --- /dev/null +++ b/_sources/serialization_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/serialization/example/README.md +``` diff --git a/_sources/state_machine.rst.txt b/_sources/state_machine.rst.txt new file mode 100644 index 000000000..f1d9403bd --- /dev/null +++ b/_sources/state_machine.rst.txt @@ -0,0 +1,32 @@ +State Machine APIs +****************** + +The `state_machine` component is a light wrapper around the `webgme-hfsm +`_ static generated code. It is +designed to be used as the component that one or more specific hfsms (manually written or +generated from webgme-hfsm) can depend on. + +Code examples for the state_machine API are provided in the `state_machine` +example folder. + +The example runs the generated code for the following example hsfm (which is +provided and for which the code was generated from webgme-hfsm): + +.. image:: images/complex-hfsm.png + :alt: "Complex" example HFSM showing the many of the UML formalisms supported. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + state_machine_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/state_machine.inc +.. include-build-file:: inc/state_base.inc +.. include-build-file:: inc/shallow_history_state.inc +.. include-build-file:: inc/deep_history_state.inc diff --git a/_sources/state_machine_example.md.txt b/_sources/state_machine_example.md.txt new file mode 100644 index 000000000..cf8ccd385 --- /dev/null +++ b/_sources/state_machine_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/state_machine/example/README.md +``` diff --git a/_sources/t_deck.rst.txt b/_sources/t_deck.rst.txt new file mode 100644 index 000000000..5fc481422 --- /dev/null +++ b/_sources/t_deck.rst.txt @@ -0,0 +1,24 @@ +LilyGo T-Deck +************* + +T-Deck +------ + +The LilyGo T-Deck is a development board for the ESP32-S3 module. It features a +nice touchscreen display and expansion headers. + +The `espp::TDeck` component provides a singleton hardware abstraction for +initializing the touch and display subsystems. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + t_deck_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/t-deck.inc diff --git a/_sources/t_deck_example.md.txt b/_sources/t_deck_example.md.txt new file mode 100644 index 000000000..aca4e8317 --- /dev/null +++ b/_sources/t_deck_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/t-deck/example/README.md +``` diff --git a/_sources/t_dongle_s3.rst.txt b/_sources/t_dongle_s3.rst.txt new file mode 100644 index 000000000..1d0fca943 --- /dev/null +++ b/_sources/t_dongle_s3.rst.txt @@ -0,0 +1,25 @@ +LilyGo T-Dongle S3 +****************** + +T-Dongle S3 +----------- + +The LilyGo T-Dongle S3 is a development board for the ESP32-S3 module. It +features a USB-A connector which doubles as a micro-SD card reader, a color LCD, +an RGB LED, and a button. + +The `espp::TDongleS3` component provides a singleton hardware abstraction for +initializing the display and LED subsystems. + +.. ------------------------------ Example ------------------------------------- + +.. toctree:: + + t_dongle_s3_example.md + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/t-dongle-s3.inc diff --git a/_sources/t_dongle_s3_example.md.txt b/_sources/t_dongle_s3_example.md.txt new file mode 100644 index 000000000..92f169ab4 --- /dev/null +++ b/_sources/t_dongle_s3_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/t-dongle-s3/example/README.md +``` diff --git a/_sources/tabulate.rst.txt b/_sources/tabulate.rst.txt new file mode 100644 index 000000000..496f9d422 --- /dev/null +++ b/_sources/tabulate.rst.txt @@ -0,0 +1,22 @@ +Tabulate APIs +************* + +The `tabulate.hpp` header provides a convenience include / wrapper around +`p-ranav/tabulate `_. It also exposes +`tabulate`'s include folder, so including `tabulate.hpp` is completely +equivalent to including both `tabulate/table.hpp`. Please see the documentation +for tabulate if you have any questions about usage beyond the examples provided +here. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + tabulate_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/tabulate.inc diff --git a/_sources/tabulate_example.md.txt b/_sources/tabulate_example.md.txt new file mode 100644 index 000000000..e5910eabc --- /dev/null +++ b/_sources/tabulate_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/tabulate/example/README.md +``` diff --git a/_sources/task.rst.txt b/_sources/task.rst.txt new file mode 100644 index 000000000..e6cc7aa2f --- /dev/null +++ b/_sources/task.rst.txt @@ -0,0 +1,26 @@ +Task APIs +********* + +Task +---- + +The `Task` component provides a cross-platform API around `std::thread` with +some additional configuration of stack size, priority, and core affinity for +FreeRTOS / ESP, as well as providing a callback API which enables interruptible +sleeps and termination of the task. + +Code examples for the task API are provided in the `task` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + task_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/task.inc +.. include-build-file:: inc/run_on_core.inc diff --git a/_sources/task_example.md.txt b/_sources/task_example.md.txt new file mode 100644 index 000000000..efd860490 --- /dev/null +++ b/_sources/task_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/task/example/README.md +``` diff --git a/_sources/thermistor.rst.txt b/_sources/thermistor.rst.txt new file mode 100644 index 000000000..3b961097d --- /dev/null +++ b/_sources/thermistor.rst.txt @@ -0,0 +1,47 @@ +Thermistor APIs +*************** + +The Thermistor APIs provide a set of functions to read the temperature from a +thermistor. The thermistor stores the relevant information (from the datasheet) +such as the B value, the nominal resistance, circuit configuration (upper or +lower part of the voltage divider), the fixed resistor value, and the supply +voltage. + +It uses these data to compute the measured resistance of the thermistor, from +which the temperature can then be calculated using the Steinhart-Hart equation. +See the `Wikipedia article +`_ for more +information. + +Using the Steinhart-Hart equation, the temperature can be calculated using the +following formula: + +.. math:: + T = \frac{1}{\frac{1}{T_0} + \frac{1}{B} \\ln \frac{R}{R_0}} + +where: + +- :math:`T` is the temperature in Kelvin +- :math:`T_0` is the nominal temperature in Kelvin (e.g. 298.15 K, 25 °C) +- :math:`B` is the B (beta) value of the thermistor (e.g. 3950 K) +- :math:`R` is the resistance of the thermistor, measured in Ohm +- :math:`R_0` is the nominal resistance of the thermistor (e.g. 10000 Ohm at 25 °C) + + +Note: the `thermistor` component assumes that the thermistor is used within a +voltage divider circuit, with a fixed resistor. The component can be configured +so that either the thermistor or the fixed resistor is the upper part of the +voltage divider. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + thermistor_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/thermistor.inc diff --git a/_sources/thermistor_example.md.txt b/_sources/thermistor_example.md.txt new file mode 100644 index 000000000..b36e26d93 --- /dev/null +++ b/_sources/thermistor_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/thermistor/example/README.md +``` diff --git a/_sources/timer.rst.txt b/_sources/timer.rst.txt new file mode 100644 index 000000000..3d2bf7bc5 --- /dev/null +++ b/_sources/timer.rst.txt @@ -0,0 +1,49 @@ +Timer APIs +********** + +Timer +----- + +The `Timer` component provides a cross-platform API for executing callback +functions with a specified period. The timer can be started, stopped, and +restarted, and the timer can have an optional initial delay before the first +callback is executed. The timer can be configured to run once or repeatedly. + +The timer API is implemented using the `Task` component, and the timer callback +is executed in the context of the timer task. + +Code examples for the task API are provided in the `timer` example folder. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + timer_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/timer.inc + +High Resolution Timer +--------------------- + +The `HighResolutionTimer` component provides an esp-idf specific API to create +managed high resolution timer objects using the esp_timer API. The timer can be +started, stopped, and restarted, and it can be configured as a one-shot timer +or a periodic timer. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + timer_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/high_resolution_timer.inc diff --git a/_sources/timer_example.md.txt b/_sources/timer_example.md.txt new file mode 100644 index 000000000..391ff2473 --- /dev/null +++ b/_sources/timer_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/timer/example/README.md +``` diff --git a/_sources/wifi/index.rst.txt b/_sources/wifi/index.rst.txt new file mode 100644 index 000000000..c2a56b48f --- /dev/null +++ b/_sources/wifi/index.rst.txt @@ -0,0 +1,11 @@ +WiFi APIs +********* + +.. toctree:: + :maxdepth: 1 + + wifi_sta + wifi_ap + wifi_example + +Code examples for the wifi API are provided in the `wifi` example folder. diff --git a/_sources/wifi/wifi_ap.rst.txt b/_sources/wifi/wifi_ap.rst.txt new file mode 100644 index 000000000..3f1b13a01 --- /dev/null +++ b/_sources/wifi/wifi_ap.rst.txt @@ -0,0 +1,12 @@ +WiFi Access Point (AP) +********************** + +The WiFi access point enables the ESP to host its own WiFi network to which +other devices can connect. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/wifi_ap.inc diff --git a/_sources/wifi/wifi_example.md.txt b/_sources/wifi/wifi_example.md.txt new file mode 100644 index 000000000..9d76cef70 --- /dev/null +++ b/_sources/wifi/wifi_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../../components/wifi/example/README.md +``` diff --git a/_sources/wifi/wifi_sta.rst.txt b/_sources/wifi/wifi_sta.rst.txt new file mode 100644 index 000000000..a260a4070 --- /dev/null +++ b/_sources/wifi/wifi_sta.rst.txt @@ -0,0 +1,12 @@ +WiFi Station (STA) +****************** + +The WiFi station enables the ESP to scan for and connect to an exising WiFi +access point. + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/wifi_sta.inc diff --git a/_sources/wrover_kit.rst.txt b/_sources/wrover_kit.rst.txt new file mode 100644 index 000000000..af6b32840 --- /dev/null +++ b/_sources/wrover_kit.rst.txt @@ -0,0 +1,24 @@ +ESP32-WROVER-KIT +**************** + +Wrover-Kit +---------- + +The ESP32-WROVER-KIT is a development board for the ESP32-WROVER module. It +features a nice display and a lot of expansion headers. + +The `espp::WroverKit` component provides a singleton hardware abstraction for +initializing the display subsystems. + +.. ------------------------------- Example ------------------------------------- + +.. toctree:: + + wrover_kit_example + +.. ---------------------------- API Reference ---------------------------------- + +API Reference +------------- + +.. include-build-file:: inc/wrover-kit.inc diff --git a/_sources/wrover_kit_example.md.txt b/_sources/wrover_kit_example.md.txt new file mode 100644 index 000000000..dc26d033e --- /dev/null +++ b/_sources/wrover_kit_example.md.txt @@ -0,0 +1,2 @@ +```{include} ../../components/wrover-kit/example/README.md +``` diff --git a/_static/DejaVuSans.ttf b/_static/DejaVuSans.ttf new file mode 100644 index 000000000..19ed0b468 Binary files /dev/null and b/_static/DejaVuSans.ttf differ diff --git a/_static/NotoSansSC-Regular.otf b/_static/NotoSansSC-Regular.otf new file mode 100644 index 000000000..7cd0b77ae Binary files /dev/null and b/_static/NotoSansSC-Regular.otf differ diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..bf18350b6 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,906 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 000000000..92fad4b5c --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 000000000..54b3c4638 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 000000000..40eafe5fc --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 000000000..40ac33108 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,220 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const codeCells = document.querySelectorAll('div.highlight pre') + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + return formatCopyText(target.innerText, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 000000000..b9168c556 --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,58 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 000000000..e380325bc --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 000000000..ba75bdc2e --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.selectors{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;font-size:110%;line-height:1.6em;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}footer .footer li{display:inline-block}footer .footer li.footer-aside{float:right;display:inline-block}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..e1bfd708b --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,358 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + this.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + var url = new URL(window.location); + url.searchParams.delete('highlight'); + window.history.replaceState({}, '', url); + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar : function() { + $('input[name=q]').first().focus(); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + return; + + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON') { + if (event.altKey || event.ctrlKey || event.metaKey) + return; + + if (!event.shiftKey) { + switch (event.key) { + case 'ArrowLeft': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 'ArrowRight': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + case 'Escape': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.hideSearchWords(); + return false; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case '/': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.focusSearchBar(); + return false; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..6fdbd7dc1 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: 'main', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/espressif-logo.svg b/_static/espressif-logo.svg new file mode 100644 index 000000000..1725310bf --- /dev/null +++ b/_static/espressif-logo.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/espressif2.pdf b/_static/espressif2.pdf new file mode 100644 index 000000000..05d20ec86 Binary files /dev/null and b/_static/espressif2.pdf differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery-3.5.1.js b/_static/jquery-3.5.1.js new file mode 100644 index 000000000..50937333b --- /dev/null +++ b/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ADC Example

+

This example shows the use of the espp::OneshotAdc and the espp::ContinuousAdc components.

+

It uses the following components:

+
    +
  • adc

  • +
  • logger

  • +
  • task

  • +
+

These adc components can be used to read analog values using the ESP’s built-in +ADC hardware, supporting DMA and filtering as well.

+
+

How to use example

+

You can build and run this example on any esp dev board, such as the QtPy ESP32 +series, the TinyPICO / TinyS3 boards, the WROVER-DevKit, and the ESP32-S3-BOX. +Make sure to set the idf target when building the example.

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+
+
+
+

Example Output

+

CleanShot 2023-06-21 at 09 08 47

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/adc_types.html b/adc/adc_types.html new file mode 100644 index 000000000..15826e993 --- /dev/null +++ b/adc/adc_types.html @@ -0,0 +1,222 @@ + + + + + + + ADC Types - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ADC Types

+

Simple container for data associated with an ADC channel configuration, +including the unit, the channel, and the attenuation desired.

+
+

API Reference

+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/ads1x15.html b/adc/ads1x15.html new file mode 100644 index 000000000..b2c984c8d --- /dev/null +++ b/adc/ads1x15.html @@ -0,0 +1,946 @@ + + + + + + + ADS1x15 I2C ADC - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ADS1x15 I2C ADC

+

The ADS1x15 provides a class for communicating with the ADS1x15 (ADS1015 and +ADS1115) family of I2C ADC chips with configurable gain and sampling rate.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Ads1x15 : public espp::BasePeripheral<>
+

Class for reading values from the ADS1x15 family of ADC chips.

+
+

ADS1X15 Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_1,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO, // pin 3 on the joybonnet
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO, // pin 5 on the joybonnet
+    });
+    // make the actual ads class
+    espp::Ads1x15 ads(espp::Ads1x15::Ads1015Config{
+        .device_address = espp::Ads1x15::DEFAULT_ADDRESS,
+        .write = [&i2c](uint8_t addr, const uint8_t *data,
+                        size_t len) { return i2c.write(addr, data, len); },
+        .read = [&i2c](uint8_t addr, uint8_t *data,
+                       size_t len) { return i2c.read(addr, data, len); },
+    });
+    // make the task which will get the raw data from the I2C ADC
+    auto ads_read_task_fn = [&ads](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - start).count();
+      std::error_code ec;
+      auto x_mv = ads.sample_mv(1, ec); // channel 1
+      if (ec) {
+        logger.error("error reading channel 1: {}", ec.message());
+        return false;
+      }
+      auto y_mv = ads.sample_mv(0, ec); // channel 0
+      if (ec) {
+        logger.error("error reading channel 0: {}", ec.message());
+        return false;
+      }
+      logger.info("{:.3f}, {:.3f}, {:.3f}", elapsed, x_mv, y_mv);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        using namespace std::chrono_literals;
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 200ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto ads_task = espp::Task::make_unique({.callback = ads_read_task_fn,
+                                             .task_config =
+                                                 {
+                                                     .name = "ADS",
+                                                     .stack_size_bytes{4 * 1024},
+                                                 },
+                                             .log_level = espp::Logger::Verbosity::INFO});
+    ads_task->start();
+
+
+
+
+

Public Types

+
+
+enum class Gain
+

Gain values for the ADC conversion.

+

Values:

+
+
+enumerator TWOTHIRDS
+

+/-6.144V range = Gain 2/3

+
+ +
+
+enumerator ONE
+

+/-4.096V range = Gain 1

+
+ +
+
+enumerator TWO
+

+/-2.048V range = Gain 2 (default)

+
+ +
+
+enumerator FOUR
+

+/-1.024V range = Gain 4

+
+ +
+
+enumerator EIGHT
+

+/-0.512V range = Gain 8

+
+ +
+
+enumerator SIXTEEN
+

+/-0.256V range = Gain 16

+
+ +
+ +
+
+enum class Ads1015Rate : uint16_t
+

Sampling rates for the ADS1015 chips.

+

Values:

+
+
+enumerator SPS128
+

128 samples per second

+
+ +
+
+enumerator SPS250
+

250 samples per second

+
+ +
+
+enumerator SPS490
+

490 samples per second

+
+ +
+
+enumerator SPS920
+

920 samples per second

+
+ +
+
+enumerator SPS1600
+

1600 samples per second (default)

+
+ +
+
+enumerator SPS2400
+

2400 samples per second

+
+ +
+
+enumerator SPS3300
+

3300 samples per second

+
+ +
+ +
+
+enum class Ads1115Rate : uint16_t
+

Sampling rates for the ADS1115 chips.

+

Values:

+
+
+enumerator SPS8
+

8 samples per second

+
+ +
+
+enumerator SPS16
+

16 samples per second

+
+ +
+
+enumerator SPS32
+

32 samples per second

+
+ +
+
+enumerator SPS64
+

64 samples per second

+
+ +
+
+enumerator SPS128
+

128 samples per second (default)

+
+ +
+
+enumerator SPS250
+

250 samples per second

+
+ +
+
+enumerator SPS475
+

475 samples per second

+
+ +
+
+enumerator SPS860
+

860 samples per second

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Ads1x15(const Ads1015Config &config)
+

Construct Ads1x15 specficially for ADS1015.

+
+
Parameters
+

config – Configuration structure.

+
+
+
+ +
+
+inline explicit Ads1x15(const Ads1115Config &config)
+

Construct Ads1x15 specficially for ADS1115.

+
+
Parameters
+

config – Configuration structure.

+
+
+
+ +
+
+inline float sample_mv(int channel, std::error_code &ec)
+

Communicate with the ADC to sample the channel and return the sampled value.

+
+
Parameters
+
    +
  • channel – Which channel of the ADC to sample

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
Returns
+

The voltage (in mV) sampled on the channel.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x48)
+

I2C address of the ADS1x15 chips.

+
+ +
+
+
+struct Ads1015Config
+

Configuration for ADS1015 ADC.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the ADC.

+
+ +
+
+BasePeripheral::read_fn read
+

Function to read from the ADC.

+
+ +
+
+Gain gain = {Gain::TWOTHIRDS}
+

Gain for the ADC.

+
+ +
+
+Ads1015Rate sample_rate = {Ads1015Rate::SPS1600}
+

Sample rate for the ADC.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+
+struct Ads1115Config
+

Configuration for ADS1115 ADC.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the ADC.

+
+ +
+
+BasePeripheral::read_fn read
+

Function to read from the ADC.

+
+ +
+
+Gain gain = {Gain::TWOTHIRDS}
+

Gain for the ADC.

+
+ +
+
+Ads1115Rate sample_rate = {Ads1115Rate::SPS128}
+

Sample rate for the ADC.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/ads1x15_example.html b/adc/ads1x15_example.html new file mode 100644 index 000000000..e748e4eeb --- /dev/null +++ b/adc/ads1x15_example.html @@ -0,0 +1,235 @@ + + + + + + + Ads1x15 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Ads1x15 Example

+

This example shows the use of the Ads1x15 component to communicate with an +ADS1015 I2C analog to digital converter using the I2C peripheral of the ESP32.

+

It uses the task component to periodically read two channels of analog data +from the ADS1015 and print them in CSV format using the format component.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

example_output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/ads7138.html b/adc/ads7138.html new file mode 100644 index 000000000..4d01409ea --- /dev/null +++ b/adc/ads7138.html @@ -0,0 +1,1544 @@ + + + + + + + ADS7138 I2C ADC - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ADS7138 I2C ADC

+

The Ads7138 class implements support for the Texas Instruments ADS7138 12-bit +8-channel ADC. The ADS7138 is a 12-bit, 8-channel, low-power, successive +approximation register (SAR) analog-to-digital converter (ADC) which can +configure any of its 8 channels as single-ended analog inputs, digital inputs, +or digital outputs. It has an operating mode that allows the user to configure +the device for a single conversion, or to automatically convert on a +continuous basis.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Ads7138 : public espp::BasePeripheral<>
+

Class for reading values from the ADS7138 family of ADC chips.

+

The ADS7138 is a 16-bit, 8-channel ADC with 8 digital I/O pins. It supports a variety of sampling modes, including autonomous sampling, manual sampling, and auto sequence sampling. It also supports oversampling ratios of 2, 4, 8, 16, 32, 64, and 128. It additionally allows the user to configure the analog or digital inputs to trigger an alert when the value goes above or below a threshold (enter or leave a region of voltage).

+

+
+

ADS7138 Example

+
    static constexpr gpio_num_t ALERT_PIN = (gpio_num_t)CONFIG_EXAMPLE_ALERT_GPIO;
+    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_1,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+
+    // make the actual ads class
+    static int select_bit_mask = (1 << 5);
+    espp::Ads7138 ads(espp::Ads7138::Config{
+        .device_address = espp::Ads7138::DEFAULT_ADDRESS,
+        .mode = espp::Ads7138::Mode::AUTONOMOUS,
+        .analog_inputs = {espp::Ads7138::Channel::CH1, espp::Ads7138::Channel::CH3},
+        .digital_inputs = {espp::Ads7138::Channel::CH5},
+        .digital_outputs =
+            {espp::Ads7138::Channel::CH7}, // On the BP-ADS7128, CH7 is the LED (active low)
+        // unordered map of channel to digital output value
+        .digital_output_values = {{espp::Ads7138::Channel::CH7, 1}}, // start the LED off
+        // enable oversampling / averaging
+        .oversampling_ratio = espp::Ads7138::OversamplingRatio::OSR_32,
+        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3),
+        .log_level = espp::Logger::Verbosity::WARN,
+    });
+
+    // create the gpio event queue
+    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
+    // setup gpio interrupts for mute button
+    gpio_config_t io_conf;
+    memset(&io_conf, 0, sizeof(io_conf));
+    // interrupt on falling edge since the ALERT pin is pulled up
+    io_conf.intr_type = GPIO_INTR_NEGEDGE;
+    io_conf.pin_bit_mask = (1 << static_cast<int>(ALERT_PIN));
+    io_conf.mode = GPIO_MODE_INPUT;
+    io_conf.pull_up_en = GPIO_PULLUP_ENABLE; // it's pulled up on the BP-ADS7128 as well
+    gpio_config(&io_conf);
+
+    // install gpio isr service
+    gpio_install_isr_service(0);
+    gpio_isr_handler_add(ALERT_PIN, gpio_isr_handler, (void *)ALERT_PIN);
+
+    // start the gpio task
+    auto alert_task = espp::Task::make_unique({
+        .callback = [&ads](auto &m, auto &cv) -> bool {
+          static uint32_t io_num;
+          // block until we get a message from the interrupt handler
+          if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
+            // see if it's the mute button
+            if (io_num == (int)ALERT_PIN) {
+              // we got an interrupt from the ALERT pin, so read the event data
+              uint8_t event_flags = 0;
+              uint8_t event_high_flags = 0;
+              uint8_t event_low_flags = 0;
+              std::error_code ec;
+              ads.get_event_data(&event_flags, &event_high_flags, &event_low_flags,
+                                 ec); // NOTE: this clears the event flags / ALERT
+              if (ec) {
+                logger.error("error getting event data: {}", ec.message());
+                return false;
+              }
+
+              // See if there was an alert on the digital input (Sel, channel 5)
+              if (event_flags & select_bit_mask) {
+                // See if there was actually a low event on the digital input (Sel, channel 5)
+                if (event_low_flags & select_bit_mask) {
+                  logger.info("ALERT: Select pressed!");
+                }
+              }
+            }
+          }
+          // don't want to stop the task
+          return false;
+        },
+        .task_config =
+            {
+                .name = "alert",
+                .stack_size_bytes = 4 * 1024,
+            },
+    });
+    alert_task->start();
+
+    std::error_code ec;
+    // configure the alert pin
+    ads.configure_alert(espp::Ads7138::OutputMode::PUSH_PULL, espp::Ads7138::AlertLogic::ACTIVE_LOW,
+                        ec);
+    if (ec) {
+      logger.error("error configuring alert: {}", ec.message());
+    }
+
+    // set the digital output drive mode to open-drain
+    ads.set_digital_output_mode(espp::Ads7138::Channel::CH7, espp::Ads7138::OutputMode::OPEN_DRAIN,
+                                ec);
+    if (ec) {
+      logger.error("error setting digital output mode: {}", ec.message());
+    }
+
+    // set an alert on the digital input (Sel) so that we can get notified when the button is
+    // pressed (goes low)
+    ads.set_digital_alert(espp::Ads7138::Channel::CH5, espp::Ads7138::DigitalEvent::LOW, ec);
+    if (ec) {
+      logger.error("error setting digital alert: {}", ec.message());
+    }
+
+    // make the task which will get the raw data from the I2C ADC
+    fmt::print("%time (s), x (mV), y (mV), select pressed\n");
+    auto ads_read_task_fn = [&ads](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - start).count();
+
+      std::error_code ec;
+      // get the analog input data
+      auto all_mv = ads.get_all_mv(ec);
+      if (ec) {
+        logger.error("error getting analog data: {}", ec.message());
+        return false;
+      }
+      auto x_mv = all_mv[0]; // the first channel is channel 1 (X axis)
+      auto y_mv = all_mv[1]; // the second channel is channel 3 (Y axis)
+
+      // alternatively we could get the analog data in a map
+      auto mapped_mv = ads.get_all_mv_map(ec);
+      if (ec) {
+        logger.error("error getting analog data: {}", ec.message());
+        return false;
+      }
+
+      x_mv = mapped_mv[espp::Ads7138::Channel::CH1];
+      y_mv = mapped_mv[espp::Ads7138::Channel::CH3];
+
+      // NOTE: we could get all digital inputs as a bitmask using
+      // get_digital_input_values(), but we'll just get the one we want.
+      // If we wanted to get all of them, we could do:
+      // auto input_values = ads.get_digital_input_values();
+      auto select_value = ads.get_digital_input_value(espp::Ads7138::Channel::CH5,
+                                                      ec); // the button is on channel 5
+      if (ec) {
+        logger.error("error getting digital input value: {}", ec.message());
+        return false;
+      }
+
+      auto select_pressed = select_value == 0; // joystick button is active low
+
+      // use fmt to print so it doesn't have the prefix and can be used more
+      // easily as CSV (for plotting using uart_serial_plotter)
+      fmt::print("{:.3f}, {:.3f}, {:.3f}, {}\n", elapsed, x_mv, y_mv, select_pressed ? 1 : 0);
+      if (select_pressed) {
+        ads.set_digital_output_value(espp::Ads7138::Channel::CH7, 0, ec); // turn on the LED
+      } else {
+        ads.set_digital_output_value(espp::Ads7138::Channel::CH7, 1, ec); // turn off the LED
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        using namespace std::chrono_literals;
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_until(lk, now + 10ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+
+    auto ads_task = espp::Task::make_unique({.callback = ads_read_task_fn,
+                                             .task_config =
+                                                 {
+                                                     .name = "ADS",
+                                                     .stack_size_bytes{8 * 1024},
+                                                 },
+                                             .log_level = espp::Logger::Verbosity::INFO});
+    ads_task->start();
+
+
+
+
+

Public Types

+
+
+enum class OversamplingRatio : uint8_t
+

Possible oversampling ratios, see data sheet Table 15 (p. 34)

+

Values:

+
+
+enumerator NONE
+

No oversampling.

+
+ +
+
+enumerator OSR_2
+

2x oversampling

+
+ +
+
+enumerator OSR_4
+

4x oversampling

+
+ +
+
+enumerator OSR_8
+

8x oversampling

+
+ +
+
+enumerator OSR_16
+

16x oversampling

+
+ +
+
+enumerator OSR_32
+

32x oversampling

+
+ +
+
+enumerator OSR_64
+

64x oversampling

+
+ +
+
+enumerator OSR_128
+

128x oversampling

+
+ +
+ +
+
+enum class Channel : uint8_t
+

Possible channel numbers.

+

The ADS7138 has 8 channels, see data sheet Table 1 (p. 4)

+
+

Note

+

The channel numbers are 0-indexed.

+
+
+

Note

+

The channel may be configured as digital input, digital output, or analog input.

+
+

Values:

+
+
+enumerator CH0
+

Channel 0.

+
+ +
+
+enumerator CH1
+

Channel 1.

+
+ +
+
+enumerator CH2
+

Channel 2.

+
+ +
+
+enumerator CH3
+

Channel 3.

+
+ +
+
+enumerator CH4
+

Channel 4.

+
+ +
+
+enumerator CH5
+

Channel 5.

+
+ +
+
+enumerator CH6
+

Channel 6.

+
+ +
+
+enumerator CH7
+

Channel 7.

+
+ +
+ +
+
+enum class Mode : uint8_t
+

Possible modes for analog input conversion.

+

The ADS7128 device has the following sampling modes:

    +
  • Manual Mode: Allows the external host processor to directly request and control when the data are sampled. The host provides I2C frames to control conversions and the captured data are returned overthe I2C bus after each conversion.

  • +
  • Auto-Sequence Mode: The host can configure the device to scan through the enabled analog input channels. The host must provide continuous clocks (SCL) to the device to scan through the channels and to read the data from the device. The mux automatically switches through the predetermined channel sequence, and the data conversion results are sent through the data bus.

  • +
  • Autonomous Mode: After receiving the first start of conversion pulse from the host, the ADS7128 device then generates the subsequent start of conversion signals autonomously. The device features an internal oscillator to generate the start of ADC conversion pulses without the host controlling the conversions. Output data are not returned over the digital bus; only a signal on the ALERT is generated when an input signal crosses the programmable thresholds.

  • +
+

+

Values:

+
+
+enumerator MANUAL
+

Manual mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is controlled by register write to MANUAL_CHID field of the CHANNEL_SEL register.

+
+ +
+
+enumerator AUTO_SEQ
+

Auto sequence mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is incremented after each conversion.

+
+ +
+
+enumerator AUTONOMOUS
+

Autonomous mode (conversion is controlled by the ADC internally) and the MUX is incremented after each conversion.

+
+ +
+ +
+
+enum class AnalogEvent
+

Event for triggering alerts on analog inputs.

+

Values:

+
+
+enumerator OUTSIDE
+

Trigger when ADC value goes outside the low/high thresholds.

+
+ +
+
+enumerator INSIDE
+

Trigger when ADC value goes inside the low/high thresholds.

+
+ +
+ +
+
+enum class DigitalEvent
+

Event for triggering alerts on digital inputs.

+

Values:

+
+
+enumerator HIGH
+

Trigger on logic 1.

+
+ +
+
+enumerator LOW
+

Trigger on logic 0.

+
+ +
+ +
+
+enum class OutputMode : uint8_t
+

Output mode for digital output channels and ALERT pin.

+

Values:

+
+
+enumerator OPEN_DRAIN
+

Open drain output mode.

+
+ +
+
+enumerator PUSH_PULL
+

Push-pull output mode.

+
+ +
+ +
+
+enum class DataFormat : uint8_t
+

Enum for the data format that can be read from the ADC.

+

Values:

+
+
+enumerator RAW
+

Raw data format, 12 bit ADC data.

+
+ +
+
+enumerator AVERAGED
+

Averaged data format, 16 bit ADC data.

+
+ +
+ +
+
+enum class Append : uint8_t
+

Enum for the different configurations of bits that can be appended to the data when reading from the ADC.

+

Values:

+
+
+enumerator NONE
+

No append.

+
+ +
+
+enumerator CHANNEL_ID
+

Append Channel ID.

+
+ +
+
+enumerator STATUS
+

Append status flags.

+
+ +
+ +
+
+enum class AlertLogic : uint8_t
+

Alert logic for ALERT pin.

+

Values:

+
+
+enumerator ACTIVE_LOW
+

ALERT pin is active low.

+
+ +
+
+enumerator ACTIVE_HIGH
+

ALERT pin is active high.

+
+ +
+
+enumerator PULSED_LOW
+

ALERT pin is pulsed low per alert flag.

+
+ +
+
+enumerator PULSED_HIGH
+

ALERT pin is pulsed high per alert flag.

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Ads7138(const Config &config)
+

Construct Ads7138.

+
+
Parameters
+

config – Configuration structure.

+
+
+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the ADC This function uses the configuration structure passed to the constructor to configure the ADC.

+
+

Note

+

This function must be called before any other functions as it configures the ADC pins and sets the mode.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline float get_mv(Channel channel, std::error_code &ec)
+

Communicate with the ADC to get the analog value for the channel and return it.

+
+

Note

+

The channel must have been configured as an analog input.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the value from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the value from the ADC’s buffer (blocking until conversion is complete).

+
+
+

Note

+

This function will return 0 and log an error if the channel is not configured as an analog input.

+
+
+
Parameters
+
    +
  • channel – Which channel of the ADC to read

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The voltage (in mV) read from the channel.

+
+
+
+ +
+
+inline std::vector<float> get_all_mv(std::error_code &ec)
+

Communicate with the ADC to get the analog value for all channels and return them.

+
+

Note

+

The channels must have been configured as analog inputs.

+
+
+

Note

+

The vector will be in the order of the channels configured in the constructor.

+
+
+

Note

+

The vector will be the same length as the number of channels configured in the constructor.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

A vector of the voltages (in mV) read from each channel.

+
+
+
+ +
+
+inline std::unordered_map<Channel, float> get_all_mv_map(std::error_code &ec)
+

Communicate with the ADC to get the analog value for all channels and return them.

+
+

Note

+

These are the channels that were configured as analog inputs.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

An unordered map of the voltages (in mV) read from each channel.

+
+
+
+ +
+
+inline void configure_alert(OutputMode output_mode, AlertLogic alert_logic, std::error_code &ec)
+

Configure the ALERT pin.

+
+
Parameters
+
    +
  • output_mode – Output mode ALERT pin

  • +
  • alert_logic – Alert logic for ALERT pin

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_analog_alert(Channel channel, float high_threshold_mv, float low_threshold_mv, AnalogEvent event, int event_count, std::error_code &ec)
+

Configure the analog channel to generate an alert when the voltage crosses a low or high threshold.

+
+

Note

+

The channel must have been configured as an analog input.

+
+
+
Parameters
+
    +
  • channel – Analog channel to configure

  • +
  • high_threshold_mv – High threshold (in mV) to generate an alert

  • +
  • low_threshold_mv – Low threshold (in mV) to generate an alert

  • +
  • event – Event type which will generate an alert

  • +
  • event_count – Number of events to generate an alert (1-15). Checks n+1 consecutive samples above or below threshold before setting event flag.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_digital_alert(Channel channel, DigitalEvent event, std::error_code &ec)
+

Configure the digital input channel to generate an alert when the input goes high or low.

+
+
Parameters
+
    +
  • channel – Digital input channel to configure

  • +
  • event – Event type which will generate an alert

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void get_event_data(uint8_t *event_flags, uint8_t *event_high_flags, uint8_t *event_low_flags, std::error_code &ec)
+

Get all the event data registers.

+
+

Note

+

The event flags are cleared after reading.

+
+
+
Parameters
+
    +
  • event_flags[inout] Event flag register

  • +
  • event_high_flags[inout] Event high flag register

  • +
  • event_low_flags[inout] Event low flag register

  • +
  • ec[inout] Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline uint8_t get_event_flags(std::error_code &ec)
+

Get the event flag register.

+
+

Note

+

The event flags are NOT cleared after reading.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The event flag register

+
+
+
+ +
+
+inline uint8_t get_event_high_flag(std::error_code &ec)
+

Get the event high flag register.

+
+

Note

+

The event high flags are NOT cleared after reading.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The event high flag register

+
+
+
+ +
+
+inline uint8_t get_event_low_flag(std::error_code &ec)
+

Get the event low flag register.

+
+

Note

+

The event low flags are NOT cleared after reading.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The event low flag register

+
+
+
+ +
+
+inline void clear_event_high_flag(uint8_t flags, std::error_code &ec)
+

Clear the event flag register.

+
+
Parameters
+
    +
  • flags – Flags to clear

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_event_low_flag(uint8_t flags, std::error_code &ec)
+

Clear the event flag register.

+
+
Parameters
+
    +
  • flags – Flags to clear

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_digital_output_mode(Channel channel, OutputMode output_mode, std::error_code &ec)
+

Configure the digital output mode for the given channel.

+
+

Note

+

The channel must have been configured as a digital output.

+
+
+
Parameters
+
    +
  • channel – Channel to configure

  • +
  • output_mode – Output mode for the channel

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_digital_output_value(Channel channel, bool value, std::error_code &ec)
+

Set the digital output value for the given channel.

+
+

Note

+

The channel must have been configured as a digital output.

+
+
+
Parameters
+
    +
  • channel – Which channel to set the digital output value for.

  • +
  • value – The value to set the digital output to.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline bool get_digital_input_value(Channel channel, std::error_code &ec)
+

Get the digital input value for the given channel.

+
+

Note

+

The channel must have been configured as a digital input.

+
+
+
Parameters
+
    +
  • channel – Which channel to get the digital input value for.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The value of the digital input.

+
+
+
+ +
+
+inline uint8_t get_digital_input_values(std::error_code &ec)
+

Get the digital input values for all channels.

+
+

Note

+

The returned value is a bitfield, with each bit corresponding to a channel. The LSB corresponds to channel 0, the MSB to channel 7.

+
+
+

Note

+

Only channels configured as digital inputs are returned.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The values of the digital inputs.

+
+
+
+ +
+
+inline void reset(std::error_code &ec)
+

Perform a software reset of the device.

+
+

Note

+

This will reset all registers to their default values (converting all channels to analog inputs and disabling all events).

+
+
+

Note

+

If the write is successful, the function will wait for the reset to complete before returning

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x10)
+

Default I2C address of the device (when both R1 and R2 are DNP) (see data sheet Table 2, p. 16)

+
+ +
+
+
+struct Config
+

Configuration structure.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device.

+
+ +
+
+float avdd_volts = 3.3f
+

AVDD voltage in Volts. Used for calculating analog input voltage.

+
+ +
+
+Mode mode = Mode::AUTONOMOUS
+

Mode for analog input conversion.

+
+ +
+
+std::vector<Channel> analog_inputs = {}
+

List of analog input channels to sample.

+
+ +
+
+std::vector<Channel> digital_inputs = {}
+

List of digital input channels to sample.

+
+ +
+
+std::vector<Channel> digital_outputs = {}
+

List of digital output channels to sample.

+
+ +
+
+std::unordered_map<Channel, OutputMode> digital_output_modes = {}
+

Optional output mode for digital output channels. If not specified, the default value is open-drain.

+
+ +
+
+std::unordered_map<Channel, bool> digital_output_values = {}
+

Optional initial values for digital output channels. If not specified, the default value is false in open-drain mode.

+
+ +
+
+OversamplingRatio oversampling_ratio = OversamplingRatio::NONE
+

Oversampling ratio to use.

+
+ +
+
+bool statistics_enabled = true
+

Enable statistics collection (min, max, recent)

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the ADC.

+
+ +
+
+BasePeripheral::read_fn read
+

Function to read from the ADC.

+
+ +
+
+bool auto_init = true
+

Automatically initialize the ADC on construction. If false, initialize() must be called before any other functions.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/ads7138_example.html b/adc/ads7138_example.html new file mode 100644 index 000000000..bbca0a86f --- /dev/null +++ b/adc/ads7138_example.html @@ -0,0 +1,336 @@ + + + + + + + Ads7138 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Ads7138 Example

+

This example shows the use of the Ads7138 component to communicate with an +ADS7138 I2C analog to digital converter using the I2C peripheral of the ESP32.

+

It uses the task component to periodically read two channels of analog data +and one channel of digital input from the ADS7138, set one channel of digital +output, and print the data in CSV format using the format component.

+

This example is designed to be run on a QtPy ESP32S3, with the BP-ADS7128 +boosterpack plugged in. We connect the I2C pins on the QtPy Qwiic header (3.3V, +GPIO41 SDA and GPIO40 SCL, and GND) to J1 of the BP-ADS7128: 3.3V (pin 1), SCL +(pin 9), SDA (pin 10), and GND (pin 22). We also connect the 5V pin on the QtPy +header to the 5V pin on the BP-ADS7128 (pin 21 of J1). We then run this example, +and we should see the raw ADC values printed to the console. Finally we connect +a jumper wire between the ALERT pin of the BP-ADS7128 (pin 13 of J3) and the A0 +pin of the QtPy (GPIO18). We should see the ALERT pin go low when the joystick +button is pressed. We use a GPIO interrupt handler + task to detect the falling +edge of the ALERT pin, and print a message to the console.

+

Table of connections between QtPy and BP-ADS7128:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

QtPy

BP-ADS7138

3.3V (Qwiic)

3.3V (J1 pin 1)

GND (Qwiic)

GND (J1 pin 22)

I2C SDA (Qwiic)

SDA (J1 pin 10)

I2C SCL (Qwiic)

SCL (J1 pin 9)

5V

5V (J1 pin 21)

A0 (GPIO18)

ALERT (J3 pin 13)

+

Connected to the BP-ADS7128, we have a Adafruit Thumb Joystick. The X axis +of the joystick is connected to channel 1 of the BP-ADS7128, and the Y axis +of the joystick is connected to channel 3 of the BP-ADS7128. The joystick +also has a button, which is connected to channel 5 of the BP-ADS7128. We +should see the raw ADC values of the joystick printed to the console, and +when we press the button on the joystick, we should see the digital value +change from 1 to 0.

+

Table of connections between BP-ADS7128 and Adafruit Thumb Joystick:

+ + + + + + + + + + + + + + + + + + + + + + + +

BP-ADS7128

Joystick

CH1 (J5 pin 2)

X axis (Xout)

GND (J5 pin 4)

GND

CH3 (J5 pin 6)

Y axis (Yout)

CH5 (J5 pin 8)

Button (Sel)

3.3V (J1 pin 1)

VCC

+

NOTE: The analog inputs on J5 of the BP-ADS7128 are connected via a 10k +resistor in series to the actual analog input of the ADS7128. This is to +protect the ADS7128 from overvoltage. Therefore you may want to add a pull-up +resistor to the digital input (Sel) of the joystick, so that when the button +is not pressed, the digital input is pulled high. Otherwise, the digital +input will be floating, and the ADS7128 will read a random value.

+

On the BP-ADS7128, we also have an LED connected to channel 7. This LED is +active low, so when we set the digital output to 1, the LED should turn off, +and when we set the digital output to 0, the LED should turn on. We can +change the digital output value by pressing the button on the joystick.

+

image

+
+

How to use example

+
+

Hardware Required

+

To run this example, you need:

+ +
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2023-06-07 at 11 54 43 +CleanShot 2023-06-06 at 13 46 56 +CleanShot 2023-06-06 at 13 51 55

+
+

Example videos

+

https://github.com/esp-cpp/espp/assets/213467/f1c5e0df-35ca-4c15-b8cb-d1455f7dbd67

+

https://github.com/esp-cpp/espp/assets/213467/6c56c2cf-8789-4452-beca-ffdaf68f13cb

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/continuous_adc.html b/adc/continuous_adc.html new file mode 100644 index 000000000..79d630ebb --- /dev/null +++ b/adc/continuous_adc.html @@ -0,0 +1,549 @@ + + + + + + + Continuous ADC - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Continuous ADC

+

The ContinuousAdc provides a mechanism for high-frequency, continuous, +deterministic sampling of analog voltages for multiple channels (potentially +across multiple ADC units, depending on the ESP32 chip used). It does this be +enabling the continuous ADC DMA mode and then running its own task which +retrieves the data and filters it. When the user calls get_mv(adc_channel_t), +it simply returns the most recent filtered value for that channel, if it was +configured.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class ContinuousAdc : public espp::BaseComponent
+

ContinuousAdc provides a wrapper around the ESP-IDF continuous adc subsystem, enabling high-frequency, filtered measurements of analog values. The get_mv() function will always return the most up to date value, without needing to perform additional reads (therefore it is non-blocking).

+
+

Continuous ADC Example

+
    std::vector<espp::AdcConfig> channels{
+        {.unit = ADC_UNIT_1, .channel = ADC_CHANNEL_6, .attenuation = ADC_ATTEN_DB_12},
+        {.unit = ADC_UNIT_1, .channel = ADC_CHANNEL_7, .attenuation = ADC_ATTEN_DB_12}};
+    // this initailizes the DMA and filter task for the continuous adc
+    espp::ContinuousAdc adc(
+        {.sample_rate_hz = 20 * 1000,
+         .channels = channels,
+         .convert_mode =
+             ADC_CONV_SINGLE_UNIT_1, // or BOTH_UNIT, ALTER_UNIT, SINGLE_UNIT_1, SINGLE_UNIT_2
+         .window_size_bytes = 1024,
+         .log_level = espp::Logger::Verbosity::WARN});
+    adc.start();
+    auto task_fn = [&adc, &channels](std::mutex &m, std::condition_variable &cv) {
+      for (auto &conf : channels) {
+        auto maybe_mv = adc.get_mv(conf);
+        if (maybe_mv.has_value()) {
+          fmt::print("{}: {} mV\n", conf, maybe_mv.value());
+        } else {
+          fmt::print("{}: no value!\n", conf);
+        }
+        auto maybe_rate = adc.get_rate(conf);
+        if (maybe_rate.has_value()) {
+          fmt::print("{}: {} Hz\n", conf, maybe_rate.value());
+        } else {
+          fmt::print("{}: no rate!\n", conf);
+        }
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Read ADC"},
+                            .log_level = espp::Logger::Verbosity::INFO});
+    task.start();
+
+    // test stopping and starting the adc
+    std::this_thread::sleep_for(3s);
+    logger.info("Stopping ADC");
+    adc.stop();
+    std::this_thread::sleep_for(3s);
+    logger.info("Starting ADC");
+    adc.start();
+
+
+
+
+

Note

+

The available modes, frequencies, and throughput is dependent on whether you run on ESP32, ESP32s2, or ESP32s3.

+
+
+

Public Functions

+
+
+inline explicit ContinuousAdc(const Config &config)
+

Initialize and start the continuous adc reader.

+
+
Parameters
+

configConfig used to initialize the reader.

+
+
+
+ +
+
+inline ~ContinuousAdc()
+

Stop, deinit, and destroy the adc reader.

+
+ +
+
+inline void start()
+

Start the continuous adc reader.

+
+ +
+
+inline void stop()
+

Stop the continuous adc reader.

+
+ +
+
+inline std::optional<float> get_mv(const AdcConfig &config)
+

Get the most up to date filtered voltage (in mV) from the provided channel.

+
+
Parameters
+

config – The config used to initialize the channel (includes unit and channel)

+
+
Returns
+

std::optional<float> voltage in mV for the provided channel (if it was configured and the adc is running).

+
+
+
+ +
+
+inline std::optional<float> get_rate(const AdcConfig &config)
+

Get the most up to date sampling rate (in Hz) from the provided channel.

+
+
Parameters
+

config – The config used to initialize the channel (includes unit and channel)

+
+
Returns
+

std::optional<float> Rate in Hz for the provided channel (if it was configured and the adc is running).

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configure the sample rate (globally applied to each channel), select the number of channels, and the conversion mode (for S2 S3)

+
+

Public Members

+
+
+size_t sample_rate_hz
+

Samples per second to read from each channel.

+
+ +
+
+std::vector<AdcConfig> channels
+

Channels to read from, with associated attenuations.

+
+ +
+
+adc_digi_convert_mode_t convert_mode
+

Conversion mode (unit 1, unit 2, alternating, or both). May depend on ESP32 chip.

+
+ +
+
+size_t task_priority = {5}
+

Priority to run the adc data reading / filtering task.

+
+ +
+
+size_t window_size_bytes = {256}
+

Amount of bytes to allocate for the DMA buffer when reading results. Larger values lead to more filtering.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the adc logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/index.html b/adc/index.html new file mode 100644 index 000000000..7ab64ca96 --- /dev/null +++ b/adc/index.html @@ -0,0 +1,215 @@ + + + + + + + ADC APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/adc/oneshot_adc.html b/adc/oneshot_adc.html new file mode 100644 index 000000000..fc2390467 --- /dev/null +++ b/adc/oneshot_adc.html @@ -0,0 +1,526 @@ + + + + + + + Oneshot ADC - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Oneshot ADC

+

The OneshotAdc allows the user a simple, low-resource way to sporadically (and +with moderate frequency needs) measure an analog voltage for multiple channels +on a single ADC UNIT. It does not start or manage any tasks and does not perform +any filtering on the data. Each time the user calls read_raw(adc_channel_t) or +read_mv(adc_channel_t), it block and trigger an analog read for the associated +channel (if it was configured to do so).

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class OneshotAdc : public espp::BaseComponent
+

OneshotAdc provides a wrapper around the ESP-IDF oneshot adc subsystem, enabling simple, direct (blocking / slow) measurements of analog values. The read_mv() function will always take a new measurement (therefore it is blocking).

+
+

Oneshot ADC Example

+
    std::vector<espp::AdcConfig> channels{
+        {.unit = ADC_UNIT_1, .channel = ADC_CHANNEL_6, .attenuation = ADC_ATTEN_DB_12},
+        {.unit = ADC_UNIT_1, .channel = ADC_CHANNEL_7, .attenuation = ADC_ATTEN_DB_12}};
+    espp::OneshotAdc adc({
+        .unit = ADC_UNIT_1,
+        .channels = channels,
+    });
+    auto task_fn = [&adc, &channels](std::mutex &m, std::condition_variable &cv) {
+      static bool use_individual_functions = false;
+      if (use_individual_functions) {
+        // this iteration, we'll use the read_mv function for each channel
+        for (auto &conf : channels) {
+          auto maybe_mv = adc.read_mv(conf);
+          if (maybe_mv.has_value()) {
+            fmt::print("{}: {} mV\n", conf, maybe_mv.value());
+          } else {
+            fmt::print("{}: no value!\n", conf);
+          }
+        }
+      } else {
+        // this iteration, we'll use the read_all_mv function to read all
+        // configured channels
+        auto voltages = adc.read_all_mv();
+        for (const auto &mv : voltages) {
+          fmt::print("{} mV\n", mv);
+        }
+      }
+      use_individual_functions = !use_individual_functions;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Oneshot ADC"},
+                            .log_level = espp::Logger::Verbosity::INFO});
+    task.start();
+
+
+
+
+

Public Functions

+
+
+inline explicit OneshotAdc(const Config &config)
+

Initialize the oneshot adc reader.

+
+
Parameters
+

configConfig used to initialize the reader.

+
+
+
+ +
+
+inline ~OneshotAdc()
+

Delete and destroy the adc reader.

+
+ +
+
+inline std::vector<int> read_all_mv()
+

Take a new ADC reading for all configured channels and convert it to voltage (mV) if the unit was properly calibrated. If it was not properly calibrated, then it will return the same value as read_raw().

+
+
Returns
+

std::vector<float> Voltage in mV for all configured channels (if they were configured).

+
+
+
+ +
+
+inline std::optional<int> read_raw(const AdcConfig &config)
+

Take a new ADC reading for the provided config.

+
+
Parameters
+

config – The channel configuration to take a reading from.

+
+
Returns
+

std::optional<float> raw value for the provided channel config (if it was configured).

+
+
+
+ +
+
+inline std::optional<int> read_mv(const AdcConfig &config)
+

Take a new ADC reading for the provided config and convert it to voltage (mV) if the unit was properly calibrated. If it was not properly calibrated, then it will return the same value as read_raw().

+
+
Parameters
+

config – The channel configuration to take a reading from.

+
+
Returns
+

std::optional<float> Voltage in mV for the provided channel config (if it was configured).

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configure the unit for which to read adc values from the provided channels.

+
+

Note

+

The unit must be the same as what is provided in each element of channels.

+
+
+

Public Members

+
+
+adc_unit_t unit
+

Unit this oneshot reader will be associated with.

+
+

Note

+

all channels must use this unit.

+
+
+ +
+
+std::vector<AdcConfig> channels
+

Channels to read from, with associated attenuations.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the adc logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/tla2528.html b/adc/tla2528.html new file mode 100644 index 000000000..caf6c57b9 --- /dev/null +++ b/adc/tla2528.html @@ -0,0 +1,1245 @@ + + + + + + + TLA2528 I2C ADC - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

TLA2528 I2C ADC

+

The Tla2528 class implements support for the Texas Instruments TLA2528 12-bit +8-channel ADC. The TLA2528 is a 12-bit, 8-channel, low-power, successive +approximation register (SAR) analog-to-digital converter (ADC) which can +configure any of its 8 channels as single-ended analog inputs, digital inputs, +or digital outputs. It has an operating mode that allows the user to configure +the device for a single conversion, or to automatically convert on a +sequenced basis.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Tla2528 : public espp::BasePeripheral<>
+

Class for reading values from the TLA2528 family of ADC chips.

+

The TLA2528 is a 16-bit, 8-channel ADC with 8 digital I/O pins. It supports a variety of sampling modes, including manual sampling, and auto sequence sampling. It also supports oversampling ratios of 2, 4, 8, 16, 32, 64, and 128. It additionally allows the user to configure the analog or digital inputs to trigger an alert when the value goes above or below a threshold (enter or leave a region of voltage).

+

+
+

TLA2528 Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+
+    static std::vector<espp::Tla2528::Channel> channels = {
+        espp::Tla2528::Channel::CH0, espp::Tla2528::Channel::CH1, espp::Tla2528::Channel::CH2,
+        espp::Tla2528::Channel::CH3, espp::Tla2528::Channel::CH4, espp::Tla2528::Channel::CH5,
+        espp::Tla2528::Channel::CH6, espp::Tla2528::Channel::CH7};
+
+    // make the actual tla class
+    espp::Tla2528 tla(espp::Tla2528::Config{
+        // Address pin is connected via 11k to ADC_DECAP, so the default address
+        // of 0x10 becomes 0x16
+        .device_address = espp::Tla2528::DEFAULT_ADDRESS | 0x06,
+        .mode = espp::Tla2528::Mode::AUTO_SEQ,
+        .analog_inputs = channels,
+        .digital_inputs = {},
+        .digital_outputs = {},
+        // enable oversampling / averaging
+        .oversampling_ratio = espp::Tla2528::OversamplingRatio::NONE,
+        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3),
+        .log_level = espp::Logger::Verbosity::WARN,
+    });
+
+    // make the task which will get the raw data from the I2C ADC
+    fmt::print("%time (s), ntc (mV), x (mV), y (mV)\n");
+    auto tla_read_task_fn = [&tla](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - start).count();
+
+      // get the analog input data individually; NOTE: this only works if you have configured the
+      // TLA2528 to use MANUAL mode
+      // auto ch0_mv = tla.get_mv(channels[0]);
+      // auto ch1_mv = tla.get_mv(channels[1]);
+      // auto ch2_mv = tla.get_mv(channels[2]);
+
+      // Could also read them all at once; NOTE: this only works if you have configured the
+      // TLA2528 to use AUTO_SEQ mode (which is more efficient)
+      // auto all_mv = tla.get_all_mv();
+      // auto ch0_mv = all_mv[0];
+      // auto ch1_mv = all_mv[1];
+      // auto ch2_mv = all_mv[2];
+
+      // Could also use the mapped version; NOTE: this only works if you have configured the
+      // TLA2528 to use AUTO_SEQ mode (which is more efficient)
+      std::error_code ec;
+      auto all_mv_map = tla.get_all_mv_map(ec);
+      if (ec) {
+        logger.error("error reading TLA2528: {}", ec.message());
+        return false;
+      }
+
+      // use fmt to print so it doesn't have the prefix and can be used more
+      // easily as CSV (for plotting using uart_serial_plotter)
+      fmt::print("{:.3f}", elapsed);
+      for (auto &[ch, mv] : all_mv_map) {
+        fmt::print(", {:.1f}", mv);
+      }
+      fmt::print("\n");
+
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        using namespace std::chrono_literals;
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_until(lk, now + 10ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+
+    auto tla_task = espp::Task::make_unique({.callback = tla_read_task_fn,
+                                             .task_config =
+                                                 {
+                                                     .name = "TLA",
+                                                     .stack_size_bytes{8 * 1024},
+                                                 },
+                                             .log_level = espp::Logger::Verbosity::INFO});
+    tla_task->start();
+
+
+
+
+

Public Types

+
+
+enum class OversamplingRatio : uint8_t
+

Possible oversampling ratios, see data sheet Table 15 (p. 34)

+

Values:

+
+
+enumerator NONE
+

No oversampling.

+
+ +
+
+enumerator OSR_2
+

2x oversampling

+
+ +
+
+enumerator OSR_4
+

4x oversampling

+
+ +
+
+enumerator OSR_8
+

8x oversampling

+
+ +
+
+enumerator OSR_16
+

16x oversampling

+
+ +
+
+enumerator OSR_32
+

32x oversampling

+
+ +
+
+enumerator OSR_64
+

64x oversampling

+
+ +
+
+enumerator OSR_128
+

128x oversampling

+
+ +
+ +
+
+enum class Channel : uint8_t
+

Possible channel numbers.

+

The TLA2528 has 8 channels, see data sheet Table 1 (p. 4)

+
+

Note

+

The channel numbers are 0-indexed.

+
+
+

Note

+

The channel may be configured as digital input, digital output, or analog input.

+
+

Values:

+
+
+enumerator CH0
+

Channel 0.

+
+ +
+
+enumerator CH1
+

Channel 1.

+
+ +
+
+enumerator CH2
+

Channel 2.

+
+ +
+
+enumerator CH3
+

Channel 3.

+
+ +
+
+enumerator CH4
+

Channel 4.

+
+ +
+
+enumerator CH5
+

Channel 5.

+
+ +
+
+enumerator CH6
+

Channel 6.

+
+ +
+
+enumerator CH7
+

Channel 7.

+
+ +
+ +
+
+enum class Mode : uint8_t
+

Possible modes for analog input conversion.

+

The ADS7128 device has the following sampling modes:

    +
  • Manual Mode: Allows the external host processor to directly request and control when the data are sampled. The host provides I2C frames to control conversions and the captured data are returned overthe I2C bus after each conversion.

  • +
  • Auto-Sequence Mode: The host can configure the device to scan through the enabled analog input channels. The host must provide continuous clocks (SCL) to the device to scan through the channels and to read the data from the device. The mux automatically switches through the predetermined channel sequence, and the data conversion results are sent through the data bus.

  • +
+

+

Values:

+
+
+enumerator MANUAL
+

Manual mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is controlled by register write to MANUAL_CHID field of the CHANNEL_SEL register.

+
+ +
+
+enumerator AUTO_SEQ
+

Auto sequence mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is incremented after each conversion.

+
+ +
+ +
+
+enum class OutputMode : uint8_t
+

Output mode for digital output channels and ALERT pin.

+

Values:

+
+
+enumerator OPEN_DRAIN
+

Open drain output mode.

+
+ +
+
+enumerator PUSH_PULL
+

Push-pull output mode.

+
+ +
+ +
+
+enum class DataFormat : uint8_t
+

Enum for the data format that can be read from the ADC.

+

Values:

+
+
+enumerator RAW
+

Raw data format, 12 bit ADC data.

+
+ +
+
+enumerator AVERAGED
+

Averaged data format, 16 bit ADC data.

+
+ +
+ +
+
+enum class Append : uint8_t
+

Enum for the different configurations of bits that can be appended to the data when reading from the ADC.

+

Values:

+
+
+enumerator NONE
+

No append.

+
+ +
+
+enumerator CHANNEL_ID
+

Append Channel ID.

+
+ +
+ +
+
+enum class AlertLogic : uint8_t
+

Alert logic for ALERT pin.

+

Values:

+
+
+enumerator ACTIVE_LOW
+

ALERT pin is active low.

+
+ +
+
+enumerator ACTIVE_HIGH
+

ALERT pin is active high.

+
+ +
+
+enumerator PULSED_LOW
+

ALERT pin is pulsed low per alert flag.

+
+ +
+
+enumerator PULSED_HIGH
+

ALERT pin is pulsed high per alert flag.

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Tla2528(const Config &config)
+

Construct Tla2528.

+
+
Parameters
+

config – Configuration structure.

+
+
+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the ADC This function uses the configuration structure passed to the constructor to configure the ADC.

+
+

Note

+

This function must be called before any other functions as it configures the ADC pins and sets the mode.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline float get_mv(Channel channel, std::error_code &ec)
+

Communicate with the ADC to get the analog value for the channel and return it.

+
+

Note

+

The channel must have been configured as an analog input.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the value from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the value from the ADC’s buffer (blocking until conversion is complete).

+
+
+

Note

+

This function will return 0 and log an error if the channel is not configured as an analog input.

+
+
+
Parameters
+
    +
  • channel – Which channel of the ADC to read

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The voltage (in mV) read from the channel.

+
+
+
+ +
+
+inline std::vector<float> get_all_mv(std::error_code &ec)
+

Communicate with the ADC to get the analog value for all channels and return them.

+
+

Note

+

The channels must have been configured as analog inputs.

+
+
+

Note

+

The vector will be in the order of the channels configured in the constructor.

+
+
+

Note

+

The vector will be the same length as the number of channels configured in the constructor.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

A vector of the voltages (in mV) read from each channel.

+
+
+
+ +
+
+inline std::unordered_map<Channel, float> get_all_mv_map(std::error_code &ec)
+

Communicate with the ADC to get the analog value for all channels and return them.

+
+

Note

+

These are the channels that were configured as analog inputs.

+
+
+

Note

+

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

An unordered map of the voltages (in mV) read from each channel.

+
+
+
+ +
+
+inline void set_digital_output_mode(Channel channel, OutputMode output_mode, std::error_code &ec)
+

Configure the digital output mode for the given channel.

+
+

Note

+

The channel must have been configured as a digital output.

+
+
+
Parameters
+
    +
  • channel – Channel to configure

  • +
  • output_mode – Output mode for the channel

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_digital_output_value(Channel channel, bool value, std::error_code &ec)
+

Set the digital output value for the given channel.

+
+

Note

+

The channel must have been configured as a digital output.

+
+
+
Parameters
+
    +
  • channel – Which channel to set the digital output value for.

  • +
  • value – The value to set the digital output to.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline bool get_digital_input_value(Channel channel, std::error_code &ec)
+

Get the digital input value for the given channel.

+
+

Note

+

The channel must have been configured as a digital input.

+
+
+
Parameters
+
    +
  • channel – Which channel to get the digital input value for.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The value of the digital input.

+
+
+
+ +
+
+inline uint8_t get_digital_input_values(std::error_code &ec)
+

Get the digital input values for all channels.

+
+

Note

+

The returned value is a bitfield, with each bit corresponding to a channel. The LSB corresponds to channel 0, the MSB to channel 7.

+
+
+

Note

+

Only channels configured as digital inputs are returned.

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The values of the digital inputs.

+
+
+
+ +
+
+inline void reset(std::error_code &ec)
+

Perform a software reset of the device.

+
+

Note

+

This will reset all registers to their default values (converting all channels to analog inputs and disabling all events).

+
+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x10)
+

Default I2C address of the device (when both R1 and R2 are DNP) (see data sheet Table 2, p. 16)

+
+ +
+
+
+struct Config
+

Configuration structure.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device.

+
+ +
+
+float avdd_volts = 3.3f
+

AVDD voltage in Volts. Used for calculating analog input voltage.

+
+ +
+
+Mode mode = Mode::MANUAL
+

Mode for analog input conversion.

+
+ +
+
+std::vector<Channel> analog_inputs = {}
+

List of analog input channels to sample.

+
+ +
+
+std::vector<Channel> digital_inputs = {}
+

List of digital input channels to sample.

+
+ +
+
+std::vector<Channel> digital_outputs = {}
+

List of digital output channels to sample.

+
+ +
+
+std::unordered_map<Channel, OutputMode> digital_output_modes = {}
+

Optional output mode for digital output channels. If not specified, the default value is open-drain.

+
+ +
+
+std::unordered_map<Channel, bool> digital_output_values = {}
+

Optional initial values for digital output channels. If not specified, the default value is false in open-drain mode.

+
+ +
+
+OversamplingRatio oversampling_ratio = OversamplingRatio::NONE
+

Oversampling ratio to use.

+
+ +
+
+Append append = Append::NONE
+

What data to append to samples when reading analog inputs.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the ADC.

+
+ +
+
+BasePeripheral::read_fn read
+

Function to read from the ADC.

+
+ +
+
+bool auto_init = true
+

Automatically initialize the ADC on construction. If false, initialize() must be called before any other functions.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/adc/tla2528_example.html b/adc/tla2528_example.html new file mode 100644 index 000000000..399aee3c9 --- /dev/null +++ b/adc/tla2528_example.html @@ -0,0 +1,249 @@ + + + + + + + Tla2528 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Tla2528 Example

+

This example shows the use of the Tla2528 component to communicate with an +TLA2528 I2C analog to digital converter using the I2C peripheral of the ESP32.

+

It uses the task component to periodically read two channels of analog data +and one channel of digital input from the TLA2528, set one channel of digital +output, and print the data in CSV format using the format component.

+

Note: RAW mode (no oversampling / OversamplingRatio::NONE) has been tested +and shown to be working. Averaging / oversampling mode does not currently work.

+
+

How to use example

+
+

Hardware Required

+

To run this example, you need:

+ +
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2023-10-23 at 12 32 53

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/base_component.html b/base_component.html new file mode 100644 index 000000000..175c4592d --- /dev/null +++ b/base_component.html @@ -0,0 +1,367 @@ + + + + + + + Base Compoenent - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Base Compoenent

+

The espp::BaseComponent provides a simple base class for all components in the +ESP-CPP package. It provides a simple interface for the component to be +initialized and to be updated.

+

It is not required to use the BaseComponent class, but it is recommended to +use as it provides a standardized API for logging and log management.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class BaseComponent
+

Base class for all components Provides a logger and some basic logging configuration

+

Subclassed by espp::BasePeripheral< std::uint8_t >, espp::BasePeripheral< std::uint16_t >, espp::BasePeripheral< uint8_t, Mt6701Interface::I2C==Mt6701Interface::I2C >, espp::BasePeripheral< uint16_t >, espp::BasePeripheral< uint8_t, Interface==Mt6701Interface::I2C >, espp::BldcMotor< espp::BldcDriver, Encoder >, espp::AbiEncoder< T >, espp::BasePeripheral< RegisterAddressType, UseAddress >, espp::BatteryService, espp::BldcDriver, espp::BldcHaptics< M >, espp::BldcMotor< D, S, CS >, espp::BleGattServer, espp::ContinuousAdc, espp::Controller, espp::DeviceInfoService, espp::Display< Pixel >, espp::EncoderInput, espp::EspBox, espp::EspTimerCam, espp::EventManager, espp::FileSystem, espp::FtpClientSession, espp::FtpServer, espp::GfpsService, espp::HidService, espp::HighResolutionTimer, espp::I2c, espp::Interrupt, espp::Joystick, espp::KeypadInput, espp::Led, espp::LedStrip, espp::MatouchRotaryDisplay, espp::MotorGoMini, espp::Nvs, espp::NvsHandle, espp::OneshotAdc, espp::Pid, espp::PointerInput, espp::Rmt, espp::RtspClient, espp::RtspServer, espp::RtspSession, espp::Socket, espp::SsRoundDisplay, espp::TDeck, espp::TDongleS3, espp::Task, espp::TaskMonitor, espp::Thermistor, espp::Timer, espp::TouchpadInput, espp::WifiAp, espp::WifiSta, espp::WroverKit

+
+

Public Functions

+
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/base_peripheral.html b/base_peripheral.html new file mode 100644 index 000000000..22c7867d5 --- /dev/null +++ b/base_peripheral.html @@ -0,0 +1,646 @@ + + + + + + + Base Peripheral - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Base Peripheral

+

The espp::BasePeripheral class is a base class for all peripherals. It +provides a common interface for all peripherals and is used to access the +peripheral’s registers. It is primarily designed to be used as a base class for +peripheral classes that communicate using I2C (address-based) or SPI (CS-based) +protocols.

+

The base class provides an interface for specifying different communications +functions that the peripheral may use, as well as providing some base +implementations for common functionality such as reading / writing u8 and u16 +values from / to a register.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<std::integral RegisterAddressType = std::uint8_t, bool UseAddress = true>
class BasePeripheral : public espp::BaseComponent
+

Base class for all peripherals This class provides a common interface for all peripherals

+

It provides a way to probe the peripheral, write data to the peripheral, read data from the peripheral, and write then read data from the peripheral.

+

The peripheral is protected by a mutex to ensure that only one operation can be performed at a time.

+

Subclassed by espp::Ads1x15, espp::Ads7138, espp::As5600, espp::Aw9523, espp::Bm8563, espp::Chsc6x, espp::Drv2605, espp::Ft5x06, espp::Kts1622, espp::Max1704x, espp::Mcp23x17, espp::Mt6701< Interface >, espp::QwiicNes, espp::TKeyboard, espp::Tla2528, espp::Tt21100

+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the peripheral.

+
+

Public Members

+
+
+uint8_t address{0}
+

The address of the peripheral. Note that this is only used if UseAddress is true.

+
+ +
+
+probe_fn probe = {nullptr}
+

Function to probe the peripheral. Note that this is only used if UseAddress is true

+
+ +
+
+write_fn write = {nullptr}
+

Function to write data to the peripheral.

+
+ +
+
+read_fn read = {nullptr}
+

Function to read data from the peripheral.

+
+ +
+
+read_register_fn read_register{nullptr}
+

Function to read data at a specific address from the peripheral.

+
+ +
+
+write_then_read_fn write_then_read{nullptr}
+

Function to write then read data from the peripheral.

+
+ +
+
+std::chrono::milliseconds separate_write_then_read_delay{0}
+

The delay between the write and read operations in write_then_read in milliseconds if the write_then_read function is not set to a custom function and the write and read functions are separate

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/battery/index.html b/battery/index.html new file mode 100644 index 000000000..471dabf53 --- /dev/null +++ b/battery/index.html @@ -0,0 +1,207 @@ + + + + + + + Battery APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Battery APIs

+
+ +
+

These components provide a common interface to battery devices. They provide +functions for monitoring the battery level and charging status, and for +configuring the battery charging parameters.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/battery/max1704x.html b/battery/max1704x.html new file mode 100644 index 000000000..7357dea95 --- /dev/null +++ b/battery/max1704x.html @@ -0,0 +1,841 @@ + + + + + + + MAX1704X - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MAX1704X

+

The MAX17048/MAX17049 ICs are tiny, micropower current fuel gauges for +lithium-ion (Li+) batteries in handheld and portable equipment. The MAX17048 +operates with a single lithium cell and the MAX17049 with two lithium cells in +series.

+

The ICs use the sophisticated Li+ battery-modeling algorithm ModelGauge™ to +track the battery relative state-of-charge (SOC) continuously over widely varying +charge and discharge conditions. The ModelGauge algorithm eliminates +current-sense resistor and battery-learn cycles required in traditional fuel +gauges. Temperature compensation is implemented using the system +microcontroller.

+

The ICs automatically detect when the battery enters a low-current state and +enters low-power 3µA hibernate mode, while still providing accurate fuel +gauging. The ICs automatically exit hibernate mode when the system returns to +active state.

+

On battery insertion, the ICs debounce initial voltage measurements to improve +the initial SOC estimate, thus allowing them to be located on system side. SOC, +voltage, and rate information is accessed using the I2C interface. The ICs are +available in a tiny 0.9mm x 1.7mm, 8-bump wafer-level package (WLP), or a 2mm x +2mm, 8-pin TDFN package.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Max1704x : public espp::BasePeripheral<>
+

Class to interface with the MAX1704x battery fuel gauge.

+

This class is used to interface with the MAX1704x battery fuel gauge. It is used to get the battery voltage, state of charge, and charge/discharge rate.

+

+
+

MAX1704X Example

+
  espp::Logger logger({.tag = "Max1704x example", .level = espp::Logger::Verbosity::INFO});
+  // make the I2C that we'll use to communicate
+  logger.info("initializing i2c driver...");
+  espp::I2c i2c({
+      .port = I2C_NUM_0,
+      .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+      .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+  });
+  // now make the max1704x which handles GPIO
+  espp::Max1704x max1704x({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                              std::placeholders::_2, std::placeholders::_3),
+                           .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                             std::placeholders::_2, std::placeholders::_3),
+                           .log_level = espp::Logger::Verbosity::WARN});
+  std::error_code ec;
+
+  // and finally, make the task to periodically poll the max1704x and print
+  // the state. NOTE: the Max1704x does not internally manage its own state
+  // update, so whatever rate we use here is the rate at which the state will
+  // update.
+  auto task_fn = [&](std::mutex &m, std::condition_variable &cv) {
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 50ms);
+    }
+    static auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    auto seconds = std::chrono::duration<float>(now - start).count();
+    std::error_code ec;
+    auto voltage = max1704x.get_battery_voltage(ec);
+    if (ec) {
+      return false;
+    }
+    auto soc = max1704x.get_battery_percentage(ec);
+    if (ec) {
+      return false;
+    }
+    auto charge_rate = max1704x.get_battery_charge_rate(ec);
+    if (ec) {
+      return false;
+    }
+    fmt::print("{:0.2f}, {:0.2f}, {:0.2f}, {:0.2f}\n", seconds, voltage, soc, charge_rate);
+    // don't want to stop the task
+    return false;
+  };
+  auto task = espp::Task({.callback = task_fn,
+                          .task_config =
+                              {
+                                  .name = "Max1704x Task",
+                                  .stack_size_bytes = 5 * 1024,
+                              },
+                          .log_level = espp::Logger::Verbosity::WARN});
+  fmt::print("%time(s), voltage (V), SoC (%), Charge Rate (%/hr)\n");
+  task.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Max1704x(const Config &config)
+

Construct a new Max1704x object.

+
+
Parameters
+

config – Configuration for the MAX1704x.

+
+
+
+ +
+
+inline void initalize(std::error_code &ec)
+

Initialize the MAX1704x.

+
+ +
+
+inline uint16_t get_version(std::error_code &ec)
+

Get the IC version.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The IC version.

+
+
+
+ +
+
+inline uint8_t get_chip_id(std::error_code &ec)
+

Get the Chip ID.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The chip ID.

+
+
+
+ +
+
+inline float get_battery_voltage(std::error_code &ec)
+

Get the battery voltage.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The battery voltage in V.

+
+
+
+ +
+
+inline float get_battery_percentage(std::error_code &ec)
+

Get the battery state of charge.

+

This is the percentage of battery charge remaining.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The battery state of charge in %.

+
+
+
+ +
+
+inline float get_battery_charge_rate(std::error_code &ec)
+

Get the battery charge or discharge rate.

+

This is the rate at which the battery is charging or discharging. A positive value indicates charging. A negative value indicates discharging. Units are in % per hour.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The battery charge or discharge rate in %/hr.

+
+
+
+ +
+
+inline AlertStatus get_alert_status(std::error_code &ec)
+

Get the alert status.

+

This is the current alert status of the battery.

+
+
Parameters
+

ec – Error code set if an error occurs.

+
+
Returns
+

The battery alert status as an AlertStatus.

+
+
+
+ +
+
+inline void clear_alert_status(uint8_t flags_to_clear, std::error_code &ec)
+

Clear the alert status.

+

This clears the alert status of the battery.

+
+
Parameters
+
    +
  • flags_to_clear – The flags to clear.

  • +
  • ec – Error code set if an error occurs.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x36
+

Default address of the MAX1704x.

+
+ +
+
+
+struct Config
+

Configuration for the MAX1704x.

+
+

Public Members

+
+
+uint8_t device_address = {DEFAULT_ADDRESS}
+

Address of the MAX1704x.

+
+ +
+
+bool auto_init = {true}
+

Whether to automatically initialize the MAX1704x.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log level for the MAX1704x.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/battery/max1704x_example.html b/battery/max1704x_example.html new file mode 100644 index 000000000..c18e6db37 --- /dev/null +++ b/battery/max1704x_example.html @@ -0,0 +1,239 @@ + + + + + + + MAX1704X Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MAX1704X Example

+

This example shows how to use the MAX1704X driver to control

+
+

How to use example

+
+

Hardware Required

+

This example requires a connection (via I2C) to a dev board which has a MAX1704X +battery gauge chip. The example was tested with a QtPy ESP32s3 dev board and a +MAX1704X breakout board from Adafruit, but can be configured (using +menuconfig) to run on any ESP board by configuring the I2C pins and selecting +CUSTOM hardware.

+ +
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-01-09 at 08 24 25

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/bldc/bldc_driver.html b/bldc/bldc_driver.html new file mode 100644 index 000000000..ef9bda1b7 --- /dev/null +++ b/bldc/bldc_driver.html @@ -0,0 +1,597 @@ + + + + + + + BLDC Driver - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLDC Driver

+

The BldcDriver component wraps around the ESP MCPWM Peripheral +to provide full 6 PWM control over a 3 phase brushless dc motor.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class BldcDriver : public espp::BaseComponent
+

Interface for controlling the 6 PWMs (high/low sides for phases A,B,C) of a brushless dc motor (BLDC motor). Wraps around the ESP32 https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/mcpwm.html peripheral.

+
+

Public Functions

+
+
+inline explicit BldcDriver(const Config &config)
+

Initialize the bldc driver.

+
+

Note

+

Enables the driver.

+
+
+
Parameters
+

configConfig used to initialize the driver.

+
+
+
+ +
+
+inline ~BldcDriver()
+

Disable the BldcDriver and destroy it.

+
+ +
+
+inline void enable()
+

Enable the driver, set the enable pin high (if we were provided an enable pin), and remove any force level on the pins if there was a force level.

+
+ +
+
+inline void disable()
+

Disable the driver, set the enable pin low (if we were provided an enable pin), add a force level to each pin to force the gates all low.

+
+ +
+
+inline bool is_enabled() const
+

Check if the driver is enabled.

+
+
Returns
+

True if the driver is enabled, false otherwise.

+
+
+
+ +
+
+inline bool is_faulted()
+

Check if the driver is faulted.

+
+

Note

+

If no fault pin was provided, this will always return false.

+
+
+
Returns
+

True if the driver is faulted, false otherwise.

+
+
+
+ +
+
+inline void set_phase_state(int state_a, int state_b, int state_c)
+

This function does nothing, merely exists for later if we choose to implement it as part of the FOC control algorithm.

+
+

Note

+

The integers provided are -1 (low), 0 (high impedance), and 1 (active) for the 3 possible states.

+
+
+
Parameters
+
    +
  • state_a – Desired state for phase A.

  • +
  • state_b – Desired state for phase B.

  • +
  • state_c – Desired state for phase C.

  • +
+
+
+
+ +
+
+inline void set_voltage(float ua, float ub, float uc)
+

Set the phase voltages (in volts) to the driver.

+
+

Note

+

Uses the previously configured power supply voltage and limit voltage (if any was provided) to convert to the appropriate pwm.

+
+
+
Parameters
+
    +
  • ua – Desired voltage [0.0f, power_supply_voltage] for phase A.

  • +
  • ub – Desired voltage [0.0f, power_supply_voltage] for phase B.

  • +
  • uc – Desired voltage [0.0f, power_supply_voltage] for phase C.

  • +
+
+
+
+ +
+
+inline void set_pwm(float duty_a, float duty_b, float duty_c)
+

Directly set the duty cycle in range [0.0, 1.0] for each phase.

+
+
Parameters
+
    +
  • duty_a – Duty cycle [0.0, 1.0] for phase A.

  • +
  • duty_b – Duty cycle [0.0, 1.0] for phase B.

  • +
  • duty_c – Duty cycle [0.0, 1.0] for phase C.

  • +
+
+
+
+ +
+
+inline void configure_power(float power_supply_voltage, float voltage_limit = -1.0f)
+

Update the power supply configuration and optional motor voltage limit.

+
+
Parameters
+
    +
  • power_supply_voltage – New max voltage (volts) from the power supply.

  • +
  • voltage_limit – New limit voltage (volts) to allow to the motor.

  • +
+
+
+
+ +
+
+inline float get_voltage_limit() const
+

Get the current motor voltage limit (if any).

+
+
Returns
+

Voltage limit the driver will allow to the motor.

+
+
+
+ +
+
+inline float get_power_supply_limit() const
+

Get the configured power supply voltage.

+
+
Returns
+

Maximum voltage the driver can supply to the motor.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configure the driver for 6-channel control of a BLDC.

+
+

Public Members

+
+
+int gpio_a_h
+

Phase A high side gpio.

+
+ +
+
+int gpio_a_l
+

Phase A low side gpio.

+
+ +
+
+int gpio_b_h
+

Phase B high side gpio.

+
+ +
+
+int gpio_b_l
+

Phase B low side gpio.

+
+ +
+
+int gpio_c_h
+

Phase C high side gpio.

+
+ +
+
+int gpio_c_l
+

Phase C low side gpio.

+
+ +
+
+int gpio_enable = {-1}
+

Enable pin for the BLDC driver (if any).

+
+ +
+
+int gpio_fault = {-1}
+

Fault pin for the BLDC driver (if any).

+
+ +
+
+float power_supply_voltage
+

Voltage of the power supply.

+
+ +
+
+float limit_voltage = {-1}
+

What voltage the motor should be limited to. Less than 0 means no limit. Will be clamped to power supply voltage.

+
+ +
+
+uint64_t dead_zone_ns{100}
+

Dead zone in nanoseconds. Will be applied to both sides of the waveform.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the bldc driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/bldc/bldc_motor.html b/bldc/bldc_motor.html new file mode 100644 index 000000000..c72697fce --- /dev/null +++ b/bldc/bldc_motor.html @@ -0,0 +1,817 @@ + + + + + + + BLDC Motor - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLDC Motor

+

The BldcMotor implements the Field-Oriented Control (FOC) algorithm with +support for multiple transforms to drive voltage (such as Sinusoidal and Space +Vector). It supports the following motion control configurations (which can be +changed dynamically):

+
    +
  • Closed-loop angle

  • +
  • Closed-loop velocity

  • +
  • Open-loop angle

  • +
  • Open-loop velocity

  • +
+

Note: currently the code has some support for Torque control, but that requires +current sense - for which I don’t yet have the hardware to support the +development of.

+

The BldcMotor should be configured with a BldcDriver and optional Sensor +(for angle & speed of the motor), and optional CurrentSensor (for measuring +the phase currents of the motor and providing torque control).

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<DriverConcept D, SensorConcept S, CurrentSensorConcept CS = DummyCurrentSense>
class BldcMotor : public espp::BaseComponent
+

Motor control class for a Brushless DC (BLDC) motor, implementing the field-oriented control (FOC) algorithm. Must be provided a driver object / type, and optionally a position/velocity sensor object/type and optionally a current sensor object / type.

+
+

Example Usage

+
    // now make the mt6701 which decodes the data
+    using Encoder = espp::Mt6701<>;
+    std::shared_ptr<Encoder> mt6701 = std::make_shared<Encoder>(
+        Encoder::Config{.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                           std::placeholders::_2, std::placeholders::_3),
+                        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                          std::placeholders::_2, std::placeholders::_3),
+                        .velocity_filter = nullptr, // no filtering
+                        .update_period = std::chrono::duration<float>(core_update_period),
+                        .log_level = espp::Logger::Verbosity::WARN});
+
+    // now make the bldc driver
+    std::shared_ptr<espp::BldcDriver> driver =
+        std::make_shared<espp::BldcDriver>(espp::BldcDriver::Config{
+            // this pinout is configured for the TinyS3 connected to the
+            // TMC6300-BOB in the BLDC Motor Test Stand
+            .gpio_a_h = 1,
+            .gpio_a_l = 2,
+            .gpio_b_h = 3,
+            .gpio_b_l = 4,
+            .gpio_c_h = 5,
+            .gpio_c_l = 21,
+            .gpio_enable = 34, // connected to the VIO/~Stdby pin of TMC6300-BOB
+            .gpio_fault = 36,  // connected to the nFAULT pin of TMC6300-BOB
+            .power_supply_voltage = 5.0f,
+            .limit_voltage = 5.0f,
+            .log_level = espp::Logger::Verbosity::WARN});
+
+    // now make the bldc motor
+    using BldcMotor = espp::BldcMotor<espp::BldcDriver, Encoder>;
+    auto motor = BldcMotor(BldcMotor::Config{
+        // measured by setting it into ANGLE_OPENLOOP and then counting how many
+        // spots you feel when rotating it.
+        .num_pole_pairs = 7,
+        .phase_resistance =
+            5.0f, // tested by running velocity_openloop and seeing if the veloicty is ~correct
+        .kv_rating =
+            320, // tested by running velocity_openloop and seeing if the velocity is ~correct
+        .current_limit = 1.0f,        // Amps
+        .zero_electric_offset = 0.0f, // set to zero to always calibrate, since this is a test
+        .sensor_direction = espp::detail::SensorDirection::UNKNOWN, // set to unknown to always
+                                                                    // calibrate, since this is a
+                                                                    // test
+        .foc_type = espp::detail::FocType::SPACE_VECTOR_PWM,
+        .driver = driver,
+        .sensor = mt6701,
+        .velocity_pid_config =
+            {
+                .kp = 0.010f,
+                .ki = 1.000f,
+                .kd = 0.000f,
+                .integrator_min = -1.0f, // same scale as output_min (so same scale as current)
+                .integrator_max = 1.0f,  // same scale as output_max (so same scale as current)
+                .output_min = -1.0, // velocity pid works on current (if we have phase resistance)
+                .output_max = 1.0,  // velocity pid works on current (if we have phase resistance)
+            },
+        .angle_pid_config =
+            {
+                .kp = 7.000f,
+                .ki = 0.300f,
+                .kd = 0.010f,
+                .integrator_min = -10.0f, // same scale as output_min (so same scale as velocity)
+                .integrator_max = 10.0f,  // same scale as output_max (so same scale as velocity)
+                .output_min = -20.0,      // angle pid works on velocity (rad/s)
+                .output_max = 20.0,       // angle pid works on velocity (rad/s)
+            },
+        .log_level = espp::Logger::Verbosity::DEBUG});
+
+    static const auto motion_control_type = espp::detail::MotionControlType::VELOCITY;
+    // static const auto motion_control_type = espp::detail::MotionControlType::ANGLE;
+    // static const auto motion_control_type = espp::detail::MotionControlType::VELOCITY_OPENLOOP;
+    // static const auto motion_control_type = espp::detail::MotionControlType::ANGLE_OPENLOOP;
+
+    // Set the motion control type and create a target for the motor (will be
+    // updated in the target update task below)
+    motor.set_motion_control_type(motion_control_type);
+    std::atomic<float> target = 0;
+
+    // enable the motor
+    motor.enable();
+
+    auto motor_task_fn = [&motor, &target]() -> bool {
+      if (motion_control_type == espp::detail::MotionControlType::VELOCITY ||
+          motion_control_type == espp::detail::MotionControlType::VELOCITY_OPENLOOP) {
+        // if it's a velocity setpoint, convert it from RPM to rad/s
+        motor.move(target * espp::RPM_TO_RADS);
+      } else {
+        motor.move(target);
+      }
+      // command the motor
+      motor.loop_foc();
+      // don't want to stop the task
+      return false;
+    };
+    auto motor_timer = espp::HighResolutionTimer({.name = "Motor Timer",
+                                                  .callback = motor_task_fn,
+                                                  .log_level = espp::Logger::Verbosity::WARN});
+    motor_timer.periodic(core_update_period_us);
+
+
+
+
+

Note

+

This is a port (with some modifications) of the excellent work by SimpleFOC - https://simplefoc.com

+
+
+

Public Types

+
+
+typedef std::function<float(float raw)> filter_fn
+

Filter the raw input sample and return it.

+
+
Param raw
+

Most recent raw sample measured.

+
+
Return
+

Filtered output from the input.

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit BldcMotor(const Config &config)
+

Create and initialize the BLDC motor, running through any necessary sensor calibration.

+
+ +
+
+inline ~BldcMotor()
+

Destroy the motor, making sure to disable it first to ensure power is cutoff.

+
+ +
+
+inline bool is_enabled() const
+

Check if the motor is enabled.

+
+
Returns
+

True if the motor is enabled, false otherwise.

+
+
+
+ +
+
+inline void enable()
+

Enable the controller and driver output.

+
+ +
+
+inline void disable()
+

Disable the controller and driver output.

+
+ +
+
+inline void initialize(float zero_electric_offset = 0, detail::SensorDirection sensor_direction = detail::SensorDirection::UNKNOWN)
+

Initialize the motor, running through any necessary sensor calibration.

+
+

Note

+

This function will enable the motor, run through the necessary calibration steps, and then disable the motor.

+
+
+

Note

+

This function is automatically called in the constructor if auto_init is set to true. Otherwise, it must be called manually before the motor can be used.

+
+
+
Parameters
+
    +
  • zero_electric_offset – The zero electrical offset for the motor.

  • +
  • sensor_direction – The direction of the sensor.

  • +
+
+
+
+ +
+
+inline void set_motion_control_type(detail::MotionControlType motion_control_type)
+

Update the motoion control scheme the motor control loop uses.

+
+
Parameters
+

motion_control_type – New motion control to use.

+
+
+
+ +
+
+inline void set_phase_voltage(float uq, float ud, float el_angle)
+

Method using FOC to set Uq to the motor at the optimal angle. Heart of the FOC algorithm.

+
+
Parameters
+
    +
  • uq – Current voltage in q axis to set to the motor

  • +
  • ud – Current voltage in d axis to set to the motor

  • +
  • el_angle – current electrical angle of the motor

  • +
+
+
+
+ +
+
+inline float get_shaft_angle()
+

Return the shaft angle, in radians.

+
+
Returns
+

Motor shaft angle in radians.

+
+
+
+ +
+
+inline float get_shaft_velocity()
+

Return the shaft velocity, in radians per second (rad/s).

+
+
Returns
+

Motor shaft velocity (rad/s).

+
+
+
+ +
+
+inline float get_electrical_angle()
+

Get the electrical angle of the motor - using the mechanical angle, the number of pole pairs, and the zero electrical angle.

+
+
Returns
+

The electrical angle of the motor (in radians)

+
+
+
+ +
+
+inline void loop_foc()
+

Main FOC loop for implementing the torque control, based on the configured detail::TorqueControlType.

+
+

Note

+

Only detail::TorqueControlType::VOLTAGE is supported right now, because the other types require current sense.

+
+
+ +
+
+inline void move(float new_target)
+

Main motion control loop implementing the closed-loop and open-loop angle & velocity control.

+
+

Note

+

Units are based on the detail::MotionControlType; radians if it’s detail::MotionControlType::ANGLE or detail::MotionControlType::ANGLE_OPENLOOP, radians/second if it’s detail::MotionControlType::VELOCITY or detail::MotionControlType::VELOCITY_OPENLOOP, Nm if it’s detail::MotionControlType::TORQUE.

+
+
+
Parameters
+

new_target – The new target for the configured detail::MotionControlType.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

BLDC Motor / FOC configuration structure.

+
+

Public Members

+
+
+size_t num_pole_pairs
+

Number of pole pairs in the motor.

+
+ +
+
+float phase_resistance
+

Motor phase resistance (ohms).

+
+ +
+
+float kv_rating
+

Motor KV rating (1/K_bemf) - rpm/V

+
+ +
+
+float phase_inductance = {0}
+

Motor phase inductance (Henries).

+
+ +
+
+float current_limit = {1.0f}
+

Current limit (Amps) for the controller.

+
+ +
+
+float velocity_limit = {1000.0f}
+

Velocity limit (RPM) for the controller.

+
+ +
+
+detail::FocType foc_type = {detail::FocType::SPACE_VECTOR_PWM}
+

How the voltage for the phases should be calculated.

+
+ +
+
+detail::TorqueControlType torque_controller = {detail::TorqueControlType::VOLTAGE}
+

Torque controller type.

+
+ +
+
+std::shared_ptr<D> driver
+

Driver for low-level setting of phase PWMs.

+
+ +
+
+std::shared_ptr<S> sensor
+

Sensor for measuring position / speed.

+
+ +
+
+bool run_sensor_update{false}
+

Runs the sensor::update() in the loop_foc() function. If false, the sensor must be updated elsewhere (e.g. within a sensor task).

+
+ +
+
+std::shared_ptr<CS> current_sense{nullptr}
+

Sensor for measuring current through the motor.

+
+ +
+
+Pid::Config current_pid_config  {.kp = 0,.ki = 0,.kd = 0,.integrator_min = 0,.integrator_max = 0,.output_min = 0,.output_max = 0}
+

PID configuration for current (amps) pid controller.

+
+ +
+
+Pid::Config velocity_pid_config  {.kp = 0,.ki = 0,.kd = 0,.integrator_min = 0,.integrator_max = 0,.output_min = 0,.output_max =0}
+

PID configuration for velocity pid controller.

+
+ +
+
+Pid::Config angle_pid_config  {.kp = 0,.ki = 0,.kd = 0,.integrator_min = 0,.integrator_max = 0,.output_min = 0,.output_max =0}
+

PID configuration for angle pid controller.

+
+ +
+
+filter_fn q_current_filter = {nullptr}
+

Optional filter added to the sensed q current.

+
+ +
+
+filter_fn d_current_filter = {nullptr}
+

Optional filter added to the sensed d current.

+
+ +
+
+filter_fn velocity_filter = {nullptr}
+

Optional filter added to the sensed velocity.

+
+ +
+
+filter_fn angle_filter = {nullptr}
+

Optional filter added to the sensed angle.

+
+ +
+
+bool auto_init = {true}
+

Automatically initialize the motor. Ensure all necessary objects and communications have been initialized before this object has been constructed, or this will fail.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the Motor.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/bldc/bldc_motor_example.html b/bldc/bldc_motor_example.html new file mode 100644 index 000000000..8f6674e8c --- /dev/null +++ b/bldc/bldc_motor_example.html @@ -0,0 +1,294 @@ + + + + + + + BldcMotor Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BldcMotor Example

+

This example shows the use of the BldcMotor component to drive a BLDC motor +(such as a tiny gimbal motor) using Field-Oriented Control (FOC) in both +open-loop and closed-loop control schemes for both position and velocity +control.

+
+

How to use example

+
+

Hardware Required

+

This example requires a lot of hardware such as:

+
    +
  • Magnetic encoder chip (this example uses Mt6701)

  • +
  • BLDC Motor Driver chip (this example was tested with the TMC6300 BOB dev board)

  • +
  • Some mounting hardware to mount the motor, magnet, encoder, etc.

  • +
+

:warning:

+
+

NOTE: you MUST make sure that you run the example with the +zero_electrical_offset value set to 0 (or not provided) at least once +otherwise the sample will not work and could potentially damage your motor.

+
+

Currently, this is designed to be run on a TinyS3 connected to the motor +driver and encoder via breadboard with the motor powered via a benchtop power +supply at 5V.

+
+
+

Configure the project

+
idf.py menuconfig
+
+
+
    +
  • If there is any project configuration that the user must set for this example, mention this here.

  • +
+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+
+

Screenshots (if appropriate, e.g. schematic, board, console logs, lab pictures):

+

image +image

+
+
+

Video

+

https://github.com/esp-cpp/espp/assets/213467/9a48a29f-9901-44d2-a68e-b27c9220cc24

+
+
+
+

Troubleshooting

+

Make sure to run the example once with zero_electrical_offset set to 0 so that +the motor will go through a calibration / zero offset routine. At the end of +this startup routine it will print the measured zero electrical offset that you +can then provide within the code, at which point it will not need to run the +calibration routine.

+

You must run this calibration any time you change your hardware configuration +(such as by remounting your motor, magnet, encoder chip).

+
+
+

Example Breakdown

+

This example is relatively complex, but builds bldc motor control using the +following components:

+
    +
  • espp::Mt6701

  • +
  • espp::BldcDriver

  • +
  • espp::BldcMotor

  • +
  • ESP-IDF’s i2c peripheral driver

  • +
  • espp::Task for updating the target

  • +
  • espp::Task for logging state

  • +
+

You combine the Mt6701 and BldcDriver together when creating the BldcMotor +and then simply use the API provided by the BldcMotor to set targets for +control (position or velocity) and to get the state of the motor.

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/bldc/index.html b/bldc/index.html new file mode 100644 index 000000000..6d0964572 --- /dev/null +++ b/bldc/index.html @@ -0,0 +1,211 @@ + + + + + + + BLDC APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLDC APIs

+ +

These components provide interfaces by which the user can control brushless DC +(BLDC) motors. The driver component(s) implement the low-level voltage / pwm +output to the motor directly, where the motor component(s) implement the +open-loop or closed-loop control algorithms - using the driver.

+

Code examples for the BLDC API are provided in the bldc_motor example folder.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/battery_service.html b/ble/battery_service.html new file mode 100644 index 000000000..bc28fa975 --- /dev/null +++ b/ble/battery_service.html @@ -0,0 +1,473 @@ + + + + + + + Battery Service - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Battery Service

+

The BatteryService implements the standard BLE battery service, providing +battery state information from a BLE peripheral to a BLE central.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class BatteryService : public espp::BaseComponent
+

Battery Service This class is responsible for creating and managing the Battery Service.

+

The service is created with the following characteristics:

    +
  • Battery Level (read, notify, unencrypted)

  • +
+

+

The Battery Level characteristic is a standard characteristic defined by the Bluetooth SIG. It is used to report the current battery level of the device.

+
+

Public Functions

+
+
+inline explicit BatteryService(espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor

+
+
Parameters
+

log_level – The log level for the component

+
+
+
+ +
+
+inline void init(NimBLEServer *server)
+

Initialize the Battery Service

+
+
Parameters
+

server – The BLE server to add the service to

+
+
+
+ +
+
+inline void deinit()
+

Deinitialize the Battery Service

+
+

Note

+

This should only be called after NimBLEDevice::deinit(true) has been called, since that will free the memory used by the service

+
+
+ +
+
+inline void start()
+

Start the service

+
+

Note

+

This must be called after the service has been initialized

+
+
+ +
+
+inline NimBLEService *get_service()
+

Get the service

+
+
Returns
+

The Battery Service

+
+
+
+ +
+
+inline NimBLEUUID uuid()
+

Get the UUID of the service

+
+
Returns
+

The UUID of the service

+
+
+
+ +
+
+inline void set_battery_level(uint8_t level)
+

Set the battery level

+
+

Note

+

The level is clamped to the range [0, 100]

+
+
+

Note

+

This must be called after the service has been initialized

+
+
+
Parameters
+

level – The battery level

+
+
+
+ +
+
+inline uint8_t get_battery_level()
+

Get the battery level

+
+
Returns
+

The battery level

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/ble_gatt_server.html b/ble/ble_gatt_server.html new file mode 100644 index 000000000..7c82fb0d5 --- /dev/null +++ b/ble/ble_gatt_server.html @@ -0,0 +1,1710 @@ + + + + + + + BLE GATT Server - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLE GATT Server

+

The BleGattServer implements the standard BLE GATT server which has various +APIs for controlling the server and adding services. It automatically builds and +adds standard battery service and device information service.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class BleGattServer : public espp::BaseComponent
+

BLE GATT Server This class is responsible for creating and managing the BLE GATT server. It is responsible for handling the connection and disconnection of clients. It is also responsible for handling the pairing process. It also manages the different services that are part of the GATT server.

+
+

BLE GATT Server Example

+
    // NOTE: esp-nimble-cpp already depends on nvs_flash and initializes
+    //       nvs_flash in the NimBLEDevice::init(), so we don't have to do that
+    //       to store bonding info
+
+    // create the GATT server
+    espp::BleGattServer ble_gatt_server;
+    std::string device_name = "Espp BLE GATT Server";
+    ble_gatt_server.set_log_level(espp::Logger::Verbosity::INFO);
+    ble_gatt_server.set_callbacks({
+        .connect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device connected"); },
+        .disconnect_callback = [&](auto &conn_info,
+                                   auto reason) { logger.info("Device disconnected: {}", reason); },
+        .authentication_complete_callback =
+            [&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
+        // NOTE: this is optional, if you don't provide this callback, it will
+        // perform the exactly function as below:
+        .get_passkey_callback =
+            [&]() {
+              logger.info("Getting passkey");
+              return NimBLEDevice::getSecurityPasskey();
+            },
+        // NOTE: this is optional, if you don't provide this callback, it will
+        // perform the exactly function as below:
+        .confirm_passkey_callback =
+            [&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
+              logger.info("Confirming passkey: {}", passkey);
+              NimBLEDevice::injectConfirmPasskey(conn_info,
+                                                 passkey == NimBLEDevice::getSecurityPasskey());
+            },
+    });
+    ble_gatt_server.init(device_name);
+#if !CONFIG_BT_NIMBLE_EXT_ADV
+    // extended advertisement does not support automatically advertising on
+    // disconnect
+    ble_gatt_server.set_advertise_on_disconnect(true);
+#endif
+
+    // let's configure the security
+    bool bonding = true;
+    bool mitm = false;
+    bool secure_connections = true;
+    ble_gatt_server.set_security(bonding, mitm, secure_connections);
+    // and some i/o and key config
+    NimBLEDevice::setSecurityPasskey(123456);
+    ble_gatt_server.set_io_capabilities(BLE_HS_IO_NO_INPUT_OUTPUT);
+    ble_gatt_server.set_init_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+    ble_gatt_server.set_resp_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+
+    // you can create a service and add it to the server using
+    // ble_gatt_server.server().addService()
+
+    // now start the services
+    ble_gatt_server.start_services(); // starts the device info service and battery service
+    // NOTE: we could also directly start them ourselves if we wanted to
+    //      control the order of starting the services
+    // e.g.:
+    // ble_gatt_server.battery_service().start();
+    // ble_gatt_server.device_info_service().start();
+
+    // now start the gatt server
+    ble_gatt_server.start();
+
+    // let's set some of the service data
+    auto &battery_service = ble_gatt_server.battery_service();
+    battery_service.set_battery_level(99);
+
+    auto &device_info_service = ble_gatt_server.device_info_service();
+    uint8_t vendor_source = 0x01;
+    uint16_t vid = 0xCafe;
+    uint16_t pid = 0xFace;
+    uint16_t product_version = 0x0100;
+    device_info_service.set_pnp_id(vendor_source, vid, pid, product_version);
+    device_info_service.set_manufacturer_name("ESP-CPP");
+    device_info_service.set_model_number("esp-ble-01");
+    device_info_service.set_serial_number("1234567890");
+    device_info_service.set_software_version("1.0.0");
+    device_info_service.set_firmware_version("1.0.0");
+    device_info_service.set_hardware_version("1.0.0");
+
+    // set the advertising data
+    espp::BleGattServer::AdvertisedData adv_data;
+    // uint8_t flags = BLE_HS_ADV_F_DISC_LTD;
+    uint8_t flags = BLE_HS_ADV_F_DISC_GEN;
+    adv_data.setFlags(flags);
+    adv_data.setName(device_name);
+    adv_data.setAppearance((uint16_t)espp::BleAppearance::GENERIC_COMPUTER);
+    adv_data.addTxPower();
+    ble_gatt_server.set_advertisement_data(adv_data);
+
+#if CONFIG_COMPILER_CXX_EXCEPTIONS
+    // let's test and use the BLE menu (CLI)
+    // turn off some of the logs so that it doesn't clutter up the CLI
+    ble_gatt_server.set_log_level(espp::Logger::Verbosity::WARN);
+    // and make the CLI
+    auto ble_menu = espp::BleGattServerMenu(ble_gatt_server);
+    cli::SetColor();
+    cli::Cli cli(ble_menu.get());
+    cli.ExitAction([](auto &out) { out << "Goodbye and thanks for all the fish.\n"; });
+
+    espp::Cli input(cli);
+    input.SetInputHistorySize(10);
+    input.Start(); // this will not return until the user enters the `exit` command.
+#endif
+
+    logger.info("Menu has finished, starting advertising");
+    // The menu has finished, so let's go into a loop to keep the device running
+    // now lets start advertising
+    ble_gatt_server.start_advertising();
+
+    logger.info("Waiting for connection...");
+    // now lets update the battery level every second for a little while
+    uint8_t battery_level = 99;
+    bool was_connected = false;
+    bool can_exit = false;
+    int num_seconds_to_wait = 30;
+    while (true) {
+      auto start = std::chrono::steady_clock::now();
+
+      // if we are now connected, but were not, then get the services
+      if (ble_gatt_server.is_connected() && !was_connected) {
+        was_connected = true;
+        can_exit = true;
+        auto connected_device_infos = ble_gatt_server.get_connected_device_infos();
+        logger.info("Connected devices: {}", connected_device_infos.size());
+        std::vector<std::string> connected_device_names;
+        std::transform(connected_device_infos.begin(), connected_device_infos.end(),
+                       std::back_inserter(connected_device_names),
+                       [&](auto &info) { return ble_gatt_server.get_connected_device_name(info); });
+        logger.info("            Names: {}", connected_device_names);
+      } else if (!ble_gatt_server.is_connected()) {
+        was_connected = false;
+        if (can_exit) {
+          logger.info("No longer connected, exiting");
+          break;
+        }
+      }
+
+      if (!ble_gatt_server.is_connected()) {
+        logger.move_up();
+        logger.clear_line();
+        logger.info("Waiting for connection... {}s", --num_seconds_to_wait);
+        if (num_seconds_to_wait == 0) {
+          logger.info("No connection, exiting");
+          break;
+        }
+        // sleep
+        std::this_thread::sleep_until(start + 1s);
+        continue;
+      }
+
+      // update the battery level
+      battery_service.set_battery_level(battery_level);
+      battery_level = (battery_level % 100) + 1;
+
+      // sleep
+      std::this_thread::sleep_until(start + 1s);
+    }
+
+    // we are done, so stop the server and deinit the BLE stack. NOTE: this will
+    // automatically be called by ~BleGattServer(), but we call it here to show
+    // manual control and to test calling it multiple times since the destructor
+    // will be called immediately after this block ends
+    ble_gatt_server.deinit();
+
+
+
+
+

Public Types

+
+
+enum class DisconnectReason : uint8_t
+

Disconnect reasons for the GATT server. This enum represents the different reasons for disconnection that will be passed to the disconnect callback.

+

This enum is a simplification of the NimBLE disconnect reasons, and is meant to provide a more user-friendly way to handle disconnections. For more information about the possible reasons for disconnection, see https://mynewt.apache.org/latest/network/ble_hs/ble_hs_return_codes.html.

+

Values:

+
+
+enumerator UNKNOWN
+

Unknown reason for disconnection.

+
+ +
+
+enumerator TIMEOUT
+

Disconnected due to timeout.

+
+ +
+
+enumerator CONNECTION_TERMINATED
+

Disconnected due to the connection being terminated.

+
+ +
+
+enumerator REMOTE_USER_TERMINATED
+

Disconnected due to the remote user terminating the connection.

+
+ +
+
+enumerator REMOTE_DEVICE_TERMINATED
+

Disconnected due to the remote device terminating the connection (low resources or power off)

+
+ +
+
+enumerator LOCAL_USER_TERMINATED
+

Disconnected due to the local user terminating the connection.

+
+ +
+
+enumerator AUTHENTICATION_FAILURE
+

Disconnected due to an authentication failure.

+
+ +
+ +
+
+typedef std::function<void(NimBLEConnInfo&)> connect_callback_t
+

Callback for when a device connects to the GATT server.

+
+
Param conn_info
+

The connection information for the device.

+
+
+
+ +
+
+typedef std::function<void(NimBLEConnInfo&, DisconnectReason reason)> disconnect_callback_t
+

Callback for when a device disconnects from the GATT server.

+
+
Param conn_info
+

The connection information for the device.

+
+
Param reason
+

The reason for the disconnection.

+
+
+
+ +
+
+typedef std::function<void(const NimBLEConnInfo&)> authentication_complete_callback_t
+

Callback for when a device completes authentication.

+
+
Param conn_info
+

The connection information for the device.

+
+
+
+ +
+
+typedef std::function<uint32_t(void)> get_passkey_callback_t
+

Callback to retrieve the passkey for the device.

+
+
Return
+

The passkey for the device.

+
+
+
+ +
+
+typedef std::function<void(const NimBLEConnInfo &conn_info, uint32_t)> confirm_passkey_callback_t
+

Callback for confirming the passkey.

+
+
Param conn_info
+

The connection information for the device.

+
+
Param passkey
+

The passkey for the device.

+
+
+
+ +
+
+typedef std::function<void(NimBLEExtAdvertising*, int, uint8_t)> advertisement_stopped_callback_t
+

Callback for when advertising is stopped. This callback is called when advertising is stopped.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Param advertising
+

Pointer to the advertising object.

+
+
Param reason
+

The reason for stopping advertising.

+
+
Param instance
+

The advertising instance that was stopped.

+
+
+
+ +
+
+typedef std::function<void(NimBLEExtAdvertising*, uint8_t, NimBLEAddress)> scan_request_callback_t
+

Callback for when a scan request is received. This callback is called when a scan request is received.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Param advertising
+

Pointer to the advertising object.

+
+
Param instance
+

The advertising instance that received the scan request.

+
+
Param address
+

The address of the device that sent the scan request.

+
+
+
+ +
+
+typedef std::function<void(NimBLEAdvertising*)> advertisement_complete_callback_t
+

Callback for when advertising is complete. This callback is called when advertising is complete.

+
+

Note

+

This is called when advertising is complete, not when the device is actually advertising. It will not be called if the advertisement duration is 0 (i.e. no timeout).

+
+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is not enabled.

+
+
+
Param advertising
+

Pointer to the advertising object.

+
+
+
+ +
+
+

Public Functions

+
+
+inline BleGattServer()
+

Constructor for the GATT server.

+
+ +
+
+inline explicit BleGattServer(const Config &config)
+

Constructor

+
+
Parameters
+

config – The configuration for the GATT server.

+
+
+
+ +
+
+inline ~BleGattServer()
+

Destructor.

+
+ +
+
+inline bool is_connected() const
+

Get whether the GATT server is connected to any clients.

+
+
Returns
+

Whether the GATT server is connected to any clients.

+
+
+
+ +
+
+inline void set_callbacks(const Callbacks &callbacks)
+

Set the callbacks for the GATT server.

+
+
Parameters
+

callbacks – The callbacks for the GATT server.

+
+
+
+ +
+
+inline bool init(const std::string &device_name)
+

Initialize the GATT server This method creates the GATT server and sets the callbacks to this class. It also initializes the device info and battery services.

+
+

Note

+

This method must be called before creating any other services or characteristics.

+
+
+

Note

+

This method must be called before starting the server.

+
+
+
Parameters
+

device_name – The name of the device.

+
+
Returns
+

Whether the GATT server was initialized successfully.

+
+
+
+ +
+
+inline void deinit()
+

Deinitialize the GATT server This method deletes the server and all associated objects. It also invalidates any references/pointers to the server.

+
+

Note

+

After calling this method, any references/pointers to the server and any created services/characteristics will be invalid.

+
+
+

Note

+

This method should only be called after NimBLEDevice::deinit(true) has been called, since that will free the memory used by the server.

+
+
+

Note

+

This method will also deinitialize the device info and battery services.

+
+
+ +
+
+inline void start_services()
+

Start the services This method starts the device info and battery services.

+
+ +
+
+inline bool start()
+

Start the server This method starts the GATT server. This method must be called after the server has been initialized, and after any services / characteristics have been added to the server.

+
+
Returns
+

Whether the server was started successfully.

+
+
+
+ +
+
+inline void set_advertise_on_disconnect(bool advertise_on_disconnect)
+

Set whether to advertise on disconnect

+
+

Note

+

This method is only available when CONFIG_BT_NIMBLE_EXT_ADV is not enabled, ane legacy advertising is used. Otherwise, you will have to manually start advertising after disconnecting.

+
+
+
Parameters
+

advertise_on_disconnect – Whether to advertise on disconnect

+
+
+
+ +
+
+void set_advertisement_data(const AdvertisedData &advertising_data, uint8_t instance = 0)
+

Set the advertisement data for the device.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Parameters
+
    +
  • advertising_data – The advertising data for the device.

  • +
  • instance – The advertising instance to set the data for.

  • +
+
+
+
+ +
+
+void set_scan_response_data(const AdvertisedData &scan_response_data, uint8_t instance = 0)
+

Set the scan response data for the device.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Parameters
+
    +
  • scan_response_data – The scan response data for the device.

  • +
  • instance – The advertising instance to set the data for.

  • +
+
+
+
+ +
+
+void set_advertisement_data(const AdvertisedData &advertising_data)
+

Set the advertisement data for the device.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is disabled.

+
+
+
Parameters
+

advertising_data – The advertising data for the device.

+
+
+
+ +
+
+void set_scan_response_data(const AdvertisedData &scan_response_data)
+

Set the scan response data for the device.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is disabled.

+
+
+
Parameters
+

scan_response_data – The scan response data for the device.

+
+
+
+ +
+
+inline void stop_advertising()
+

Stop advertising This method stops advertising.

+
+ +
+
+void stop_advertising(uint8_t instance)
+

Stop advertising This method stops advertising.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Parameters
+

instance – The advertising instance to stop.

+
+
+
+ +
+
+bool start_advertising(uint32_t duration_ms = 0, uint8_t instance = 0)
+

Start Advertising using the previously set advertising data This method simply starts advertising using the previously set advertising data.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+
Parameters
+
    +
  • duration_ms – The duration of the advertising in milliseconds. If 0, the advertising will not timeout. If non-zero, the advertising will stop after the specified duration.

  • +
  • instance – The advertising instance to start.

  • +
+
+
Returns
+

Whether advertising was started successfully.

+
+
+
+ +
+
+bool start_advertising(const AdvertisingParameters &params)
+

Start Advertising using the previously set advertising data This method simply starts advertising using the previously set advertising data.

+
+

Note

+

This method is only used when CONFIG_BT_NIMBLE_EXT_ADV is not enabled, ane legacy advertising is used. Otherwise, use the NimBLEExtAdvertisement class for advertising and setting the advertising parameters.

+
+
+
Parameters
+

params – The advertising parameters for the device.

+
+
Returns
+

Whether advertising was started successfully.

+
+
+
+ +
+
+bool start_advertising(uint32_t duration_ms = 0, NimBLEAddress *directed_address = nullptr)
+

Start Advertising using the previously set advertising data This method simply starts advertising using the previously set advertising data.

+
+

Note

+

This method is only used when CONFIG_BT_NIMBLE_EXT_ADV is not enabled, ane legacy advertising is used.

+
+
+
Parameters
+
    +
  • duration_ms – The duration of the advertising in milliseconds. If 0, the advertising will not timeout. If non-zero, the advertising will stop after the specified duration.

  • +
  • directed_address – The address to direct advertising to, if any.

  • +
+
+
Returns
+

Whether advertising was started successfully.

+
+
+
+ +
+
+inline NimBLEServer *server() const
+

Get the GATT server.

+
+
Returns
+

The GATT server.

+
+
+
+ +
+
+inline DeviceInfoService &device_info_service()
+

Get the device info service.

+
+ +
+
+inline BatteryService &battery_service()
+

Get the battery service.

+
+ +
+
+inline void set_device_name(const std::string &device_name)
+

Set the name of the device.

+
+
Parameters
+

device_name – The name of the device.

+
+
+
+ +
+
+inline void set_passkey(uint32_t passkey)
+

Set the passkey for the device.

+
+
Parameters
+

passkey – The passkey for the device.

+
+
+
+ +
+
+inline void set_security(bool bonding, bool mitm, bool secure)
+

Set the security settings for the device.

+
+
Parameters
+
    +
  • bonding – Whether to use bonding.

  • +
  • mitm – Man-in-the-middle protection.

  • +
  • secure – Whether to use secure connections.

  • +
+
+
+
+ +
+
+inline void set_io_capabilities(uint8_t io_capabilities)
+

Set the IO capabilities for the device.

+

See also

+

BLE_HS_IO_NO_INPUT_OUTPUT

+
+
+

See also

+

BLE_HS_IO_DISPLAY_ONLY

+
+
+

See also

+

BLE_HS_IO_DISPLAY_YESNO

+
+
+

See also

+

BLE_HS_IO_KEYBOARD_ONLY

+
+
+

See also

+

BLE_HS_IO_NO_INPUT_OUTPUT

+
+
+

See also

+

BLE_HS_IO_KEYBOARD_DISPLAY

+
+

+
+
Parameters
+

io_capabilities – The IO capabilities for the device.

+
+
+
+ +
+
+inline void set_init_key_distribution(uint8_t key_distribution)
+

Set the initial key distribution for the device.

+

See also

+

BLE_SM_PAIR_KEY_DIST_ENC

+
+
+

See also

+

BLE_SM_PAIR_KEY_DIST_ID

+
+

+
+
Parameters
+

key_distribution – The initial key distribution for the device.

+
+
+
+ +
+
+inline void set_resp_key_distribution(uint8_t key_distribution)
+

Set the response key distribution for the device.

+

See also

+

BLE_SM_PAIR_KEY_DIST_ENC

+
+
+

See also

+

BLE_SM_PAIR_KEY_DIST_ID

+
+

+
+
Parameters
+

key_distribution – The response key distribution for the device.

+
+
+
+ +
+
+inline std::vector<NimBLEAddress> get_paired_devices()
+

Get the paired devices

+
+
Returns
+

The paired devices as a vector of Addresses.

+
+
+
+ +
+
+inline std::vector<NimBLEAddress> get_connected_device_addresses()
+

Get the connected device addresses

+
+
Returns
+

The addresses for the connected devices as a vector.

+
+
+
+ +
+
+inline std::vector<NimBLEConnInfo> get_connected_device_infos()
+

Get the NimBLEConnInfo objects for the connected devices

+
+
Returns
+

The connected devices info as a vector of NimBLEConnInfo.

+
+
+
+ +
+
+inline std::string get_connected_device_name(NimBLEConnInfo &conn_info)
+

Get the connected device name

+
+
Parameters
+

conn_info – The connection information for the device.

+
+
Returns
+

The connected device name.

+
+
+
+ +
+
+inline std::vector<std::string> get_connected_device_names()
+

Get the connected device names

+
+

Note

+

This method will connect to each device to get the device name. This may take some time if there are many devices connected.

+
+
+
Returns
+

The connected device names as a vector of strings.

+
+
+
+ +
+
+inline int get_connected_device_rssi(NimBLEConnInfo &conn_info)
+

Get the RSSI of the connected device

+
+
Parameters
+

conn_info – The connection information for the device.

+
+
Returns
+

The RSSI of the connected device.

+
+
+
+ +
+
+inline std::vector<int> get_connected_devices_rssi_values()
+

Get the RSSI of the connected devices

+
+

Note

+

This method will connect to each device to get the RSSI. This may take some time if there are many devices connected.

+
+
+
Returns
+

The RSSI of the connected devices as a vector.

+
+
+
+ +
+
+inline std::vector<NimBLEAddress> disconnect_all()
+

Disconnect from all devices This method disconnects from all devices that are currently connected.

+
+
Returns
+

The Addresses of the devices that were disconnected from.

+
+
+
+ +
+
+inline std::vector<NimBLEAddress> unpair_all()
+

Unpair all devices This method unpairs all devices that are currently paired.

+
+
Returns
+

The Addresses of the devices that were unpaired.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline constexpr uint16_t interval_ms_to_units(uint16_t interval_ms)
+

Convert an interval in milliseconds to units of 0.625 ms.

+
+
Parameters
+

interval_ms – The interval in milliseconds.

+
+
Returns
+

The interval in units of 0.625 ms.

+
+
+
+ +
+
+static inline constexpr uint16_t interval_units_to_ms(uint16_t interval_units)
+

Convert an interval in units of 0.625 ms to milliseconds.

+
+
Parameters
+

interval_units – The interval in units of 0.625 ms.

+
+
Returns
+

The interval in milliseconds.

+
+
+
+ +
+
+
+struct AdvertisingParameters
+

Advertising parameters for the device. This struct contains the advertising parameters for the device.

+

+

See also

+

start_advertising

+
+

+
+

Note

+

This struct is only available when CONFIG_BT_NIMBLE_EXT_ADV is not enabled, ane legacy advertising is used. Otherwise, use the NimBLEExtAdvertisement class.

+
+
+

Public Members

+
+
+bool connectable = true
+

Whether the device should be connectable.

+
+ +
+
+uint16_t min_interval_ms = 20
+

Minimum advertising interval. NOTE: this is in milliseconds, but will be converted to units of 0.625 ms. If the value is not a multiple of 0.625 ms, it will be rounded to the nearest multiple and a log message will be printed.

+
+ +
+
+uint16_t max_interval_ms = 40
+

Maximum advertising interval. NOTE: this is in milliseconds, but will be converted to units of 0.625 ms. If the value is not a multiple of 0.625 ms, it will be rounded to the nearest multiple and a log message will be printed.

+
+ +
+
+bool include_tx_power = false
+

Whether to include the TX power level.

+
+ +
+
+bool scan_response = false
+

Whether the device should include scan response data.

+
+ +
+
+bool scan_request_whitelist = false
+

Whether the device should use the white list when scanning

+
+ +
+
+bool connect_whitelist = false
+

Whether the device should use the white list when connecting

+
+ +
+
+uint32_t duration_ms = 0
+

Advertising duration (in ms, 0 for no timeout)

+
+ +
+
+NimBLEAddress *directed_address = nullptr
+

Address to direct advertising to, if any.

+
+ +
+
+ +
+
+struct Callbacks
+

Callbacks for the GATT server.

+
+

Public Members

+
+
+connect_callback_t connect_callback = nullptr
+

Callback for when a device connects to the GATT server.

+
+ +
+
+disconnect_callback_t disconnect_callback = nullptr
+

Callback for when a device disconnects from the GATT server.

+
+ +
+
+authentication_complete_callback_t authentication_complete_callback = nullptr
+

Callback for when a device completes authentication.

+
+ +
+
+get_passkey_callback_t get_passkey_callback = nullptr
+

Callback for getting the passkey.

+
+

Note

+

If not provided, will simply return NimBLEDevice::getSecurityPasskey().

+
+
+ +
+
+confirm_passkey_callback_t confirm_passkey_callback = nullptr
+

Callback for confirming the passkey.

+
+

Note

+

Within this function or some point after this call, the user should call NimBLEDevice::injectConfirmPIN(conn_info, true/false) to confirm or reject the passkey.

+
+
+

Note

+

If not provided, will simply call NimBLEDevice::injectConfirmPIN(conn_info, passkey == NimBLEDevice::getSecurityPasskey()).

+
+
+ +
+
+advertisement_complete_callback_t advertisement_complete_callback = nullptr
+

Callback for when advertising is complete.

+
+

Note

+

This is called when advertising is complete, not when the device is actually advertising. It will not be called if the advertisement duration is 0 (i.e. no timeout)

+
+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is not enabled.

+
+
+ +
+
+advertisement_stopped_callback_t advertisement_stopped_callback = nullptr
+

Callback for when advertising is stopped.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+ +
+
+scan_request_callback_t scan_request_callback = nullptr
+

Callback for when a scan request is received.

+
+

Note

+

This is only available when CONFIG_BT_NIMBLE_EXT_ADV is enabled.

+
+
+ +
+
+ +
+
+struct Config
+

Configuration for the GATT server.

+
+

Public Members

+
+
+Callbacks callbacks
+

The callbacks for the GATT server.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The verbosity of the logger_.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class BleGattServerCallbacks : public NimBLEServerCallbacks
+

Class for handling GATT server callbacks, as required by NimBLE

+
+

Note

+

This class is not intended to be used directly by the user

+
+
+ +
+
+class BleGattServerAdvertisingCallbacks : public NimBLEExtAdvertisingCallbacks
+

Class for handling GATT server advertising callbacks, as required by NimBLE

+
+

Note

+

This class is not intended to be used directly by the user

+
+
+

Note

+

This class is only available if CONFIG_BT_NIMBLE_EXT_ADV is enabled

+
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class BleGattServerMenu
+

A CLI menu for interacting with BleGattServer.

+

This class provides a CLI menu for interacting with a BleGattServer. It provides options for setting the log verbosity, viewing the paired devices, viewing the connected devices, disconnecting devices, and more.

+
+

Example

+
    // NOTE: esp-nimble-cpp already depends on nvs_flash and initializes
+    //       nvs_flash in the NimBLEDevice::init(), so we don't have to do that
+    //       to store bonding info
+
+    // create the GATT server
+    espp::BleGattServer ble_gatt_server;
+    std::string device_name = "Espp BLE GATT Server";
+    ble_gatt_server.set_log_level(espp::Logger::Verbosity::INFO);
+    ble_gatt_server.set_callbacks({
+        .connect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device connected"); },
+        .disconnect_callback = [&](auto &conn_info,
+                                   auto reason) { logger.info("Device disconnected: {}", reason); },
+        .authentication_complete_callback =
+            [&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
+        // NOTE: this is optional, if you don't provide this callback, it will
+        // perform the exactly function as below:
+        .get_passkey_callback =
+            [&]() {
+              logger.info("Getting passkey");
+              return NimBLEDevice::getSecurityPasskey();
+            },
+        // NOTE: this is optional, if you don't provide this callback, it will
+        // perform the exactly function as below:
+        .confirm_passkey_callback =
+            [&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
+              logger.info("Confirming passkey: {}", passkey);
+              NimBLEDevice::injectConfirmPasskey(conn_info,
+                                                 passkey == NimBLEDevice::getSecurityPasskey());
+            },
+    });
+    ble_gatt_server.init(device_name);
+#if !CONFIG_BT_NIMBLE_EXT_ADV
+    // extended advertisement does not support automatically advertising on
+    // disconnect
+    ble_gatt_server.set_advertise_on_disconnect(true);
+#endif
+
+    // let's configure the security
+    bool bonding = true;
+    bool mitm = false;
+    bool secure_connections = true;
+    ble_gatt_server.set_security(bonding, mitm, secure_connections);
+    // and some i/o and key config
+    NimBLEDevice::setSecurityPasskey(123456);
+    ble_gatt_server.set_io_capabilities(BLE_HS_IO_NO_INPUT_OUTPUT);
+    ble_gatt_server.set_init_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+    ble_gatt_server.set_resp_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+
+    // you can create a service and add it to the server using
+    // ble_gatt_server.server().addService()
+
+    // now start the services
+    ble_gatt_server.start_services(); // starts the device info service and battery service
+    // NOTE: we could also directly start them ourselves if we wanted to
+    //      control the order of starting the services
+    // e.g.:
+    // ble_gatt_server.battery_service().start();
+    // ble_gatt_server.device_info_service().start();
+
+    // now start the gatt server
+    ble_gatt_server.start();
+
+    // let's set some of the service data
+    auto &battery_service = ble_gatt_server.battery_service();
+    battery_service.set_battery_level(99);
+
+    auto &device_info_service = ble_gatt_server.device_info_service();
+    uint8_t vendor_source = 0x01;
+    uint16_t vid = 0xCafe;
+    uint16_t pid = 0xFace;
+    uint16_t product_version = 0x0100;
+    device_info_service.set_pnp_id(vendor_source, vid, pid, product_version);
+    device_info_service.set_manufacturer_name("ESP-CPP");
+    device_info_service.set_model_number("esp-ble-01");
+    device_info_service.set_serial_number("1234567890");
+    device_info_service.set_software_version("1.0.0");
+    device_info_service.set_firmware_version("1.0.0");
+    device_info_service.set_hardware_version("1.0.0");
+
+    // set the advertising data
+    espp::BleGattServer::AdvertisedData adv_data;
+    // uint8_t flags = BLE_HS_ADV_F_DISC_LTD;
+    uint8_t flags = BLE_HS_ADV_F_DISC_GEN;
+    adv_data.setFlags(flags);
+    adv_data.setName(device_name);
+    adv_data.setAppearance((uint16_t)espp::BleAppearance::GENERIC_COMPUTER);
+    adv_data.addTxPower();
+    ble_gatt_server.set_advertisement_data(adv_data);
+
+#if CONFIG_COMPILER_CXX_EXCEPTIONS
+    // let's test and use the BLE menu (CLI)
+    // turn off some of the logs so that it doesn't clutter up the CLI
+    ble_gatt_server.set_log_level(espp::Logger::Verbosity::WARN);
+    // and make the CLI
+    auto ble_menu = espp::BleGattServerMenu(ble_gatt_server);
+    cli::SetColor();
+    cli::Cli cli(ble_menu.get());
+    cli.ExitAction([](auto &out) { out << "Goodbye and thanks for all the fish.\n"; });
+
+    espp::Cli input(cli);
+    input.SetInputHistorySize(10);
+    input.Start(); // this will not return until the user enters the `exit` command.
+#endif
+
+    logger.info("Menu has finished, starting advertising");
+    // The menu has finished, so let's go into a loop to keep the device running
+    // now lets start advertising
+    ble_gatt_server.start_advertising();
+
+    logger.info("Waiting for connection...");
+    // now lets update the battery level every second for a little while
+    uint8_t battery_level = 99;
+    bool was_connected = false;
+    bool can_exit = false;
+    int num_seconds_to_wait = 30;
+    while (true) {
+      auto start = std::chrono::steady_clock::now();
+
+      // if we are now connected, but were not, then get the services
+      if (ble_gatt_server.is_connected() && !was_connected) {
+        was_connected = true;
+        can_exit = true;
+        auto connected_device_infos = ble_gatt_server.get_connected_device_infos();
+        logger.info("Connected devices: {}", connected_device_infos.size());
+        std::vector<std::string> connected_device_names;
+        std::transform(connected_device_infos.begin(), connected_device_infos.end(),
+                       std::back_inserter(connected_device_names),
+                       [&](auto &info) { return ble_gatt_server.get_connected_device_name(info); });
+        logger.info("            Names: {}", connected_device_names);
+      } else if (!ble_gatt_server.is_connected()) {
+        was_connected = false;
+        if (can_exit) {
+          logger.info("No longer connected, exiting");
+          break;
+        }
+      }
+
+      if (!ble_gatt_server.is_connected()) {
+        logger.move_up();
+        logger.clear_line();
+        logger.info("Waiting for connection... {}s", --num_seconds_to_wait);
+        if (num_seconds_to_wait == 0) {
+          logger.info("No connection, exiting");
+          break;
+        }
+        // sleep
+        std::this_thread::sleep_until(start + 1s);
+        continue;
+      }
+
+      // update the battery level
+      battery_service.set_battery_level(battery_level);
+      battery_level = (battery_level % 100) + 1;
+
+      // sleep
+      std::this_thread::sleep_until(start + 1s);
+    }
+
+    // we are done, so stop the server and deinit the BLE stack. NOTE: this will
+    // automatically be called by ~BleGattServer(), but we call it here to show
+    // manual control and to test calling it multiple times since the destructor
+    // will be called immediately after this block ends
+    ble_gatt_server.deinit();
+
+
+
+
+

Public Functions

+
+
+inline explicit BleGattServerMenu(std::reference_wrapper<espp::BleGattServer> server)
+

Construct a new I2cMenu object.

+
+
Parameters
+

i2c – A reference to the I2c bus to interact with.

+
+
+
+ +
+
+inline std::unique_ptr<cli::Menu> get(std::string_view name = "ble", std::string_view description = "BLE GATT Server menu")
+

Get the BleGattServer menu.

+
+
Parameters
+
    +
  • name – The name of the menu.

  • +
  • description – The description of the menu.

  • +
+
+
Returns
+

A unique pointer to the BleGattServer menu that you can use to add to a CLI.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/ble_gatt_server_example.html b/ble/ble_gatt_server_example.html new file mode 100644 index 000000000..b3091c014 --- /dev/null +++ b/ble/ble_gatt_server_example.html @@ -0,0 +1,241 @@ + + + + + + + BLE GATT Server Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLE GATT Server Example

+

This example shows how to use the espp::BleGattServer class to create and manage +a BLE GATT server.

+
+

How to use example

+
+

Hardware Required

+

This example should run on any ESP32s3 development board as it requires no +peripheral connections.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-02-28 at 10 29 10

+

image

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/device_info_service.html b/ble/device_info_service.html new file mode 100644 index 000000000..8609a0fa1 --- /dev/null +++ b/ble/device_info_service.html @@ -0,0 +1,649 @@ + + + + + + + Device Info Service - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Device Info Service

+

The DeviceInfoService implements the standard BLE device information service, +providing device information from a BLE peripheral to a BLE central.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class DeviceInfoService : public espp::BaseComponent
+

Device Information Service This class is responsible for creating and managing the Device Information Service.

+

The service is created with the following characteristics:

    +
  • Manufacturer Name (read)

  • +
  • Model Number (read)

  • +
  • Serial Number (read)

  • +
  • Software Version (read)

  • +
  • Firmware Version (read)

  • +
  • Hardware Version (read)

  • +
  • PnP ID (read)

  • +
+

+

The Device Information Service is a standard Bluetooth service that provides information about the device. This information can be used by a client to identify the device and determine its capabilities. The Device Information Service is defined by the Bluetooth SIG and is intended to be used with any device.

+
+

Public Functions

+
+
+inline explicit DeviceInfoService(espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor

+
+
Parameters
+

log_level – The log level for the component

+
+
+
+ +
+
+inline void init(NimBLEServer *server)
+

Initialize the Device Information Service

+
+
Parameters
+

server – The BLE server to add the service to

+
+
+
+ +
+
+inline void deinit()
+

Deinitialize the Device Information Service

+
+

Note

+

This should only be called after NimBLEDevice::deinit(true) has been called, since that will free the memory used by the service

+
+
+ +
+
+inline void start()
+

Start the service

+
+

Note

+

This must be called after the service has been initialized

+
+
+ +
+
+inline NimBLEService *get_service()
+

Get the service object

+
+
Returns
+

The service object

+
+
+
+ +
+
+inline NimBLEUUID uuid()
+

Get the UUID of the service

+
+
Returns
+

The service UUID

+
+
+
+ +
+
+inline void set_device_info(const DeviceInfo &info)
+

Set the device information

+
+

Note

+

This will set all the characteristics of the service to the values provided in the DeviceInfo struct

+
+
+

Note

+

This must be called after the service has been initialized

+
+
+
Parameters
+

info – The device information

+
+
+
+ +
+
+inline void set_pnp_id(const PnpId &pnp_id)
+

Set the PnP ID

+
+
Parameters
+

pnp_id – The PnP ID

+
+
+
+ +
+
+inline void set_pnp_id(uint8_t vendor_id_source, uint16_t vendor_id, uint16_t product_id, uint16_t product_version)
+

Set the PnP ID

+
+

Note

+

The PnP ID is a standard Bluetooth characteristic that provides information about the device’s Plug and Play ID. This information can be used by a client to identify the device and determine its capabilities.

+
+
+
Parameters
+
    +
  • vendor_id_source – The vendor ID source (0x01 for Bluetooth SIG, 0x02 for USB)

  • +
  • vendor_id – The vendor ID

  • +
  • product_id – The product ID

  • +
  • product_version – The product version

  • +
+
+
+
+ +
+
+inline void set_manufacturer_name(const std::string &name)
+

Set the manufacturer name

+
+
Parameters
+

name – The manufacturer name

+
+
+
+ +
+
+inline void set_model_number(const std::string &number)
+

Set the model number

+
+
Parameters
+

number – The model number

+
+
+
+ +
+
+inline void set_serial_number(const std::string &number)
+

Set the serial number

+
+
Parameters
+

number – The serial number

+
+
+
+ +
+
+inline void set_software_version(const std::string &version)
+

Set the software version

+
+
Parameters
+

version – The software version

+
+
+
+ +
+
+inline void set_firmware_version(const std::string &version)
+

Set the firmware version

+
+
Parameters
+

version – The firmware version

+
+
+
+ +
+
+inline void set_hardware_version(const std::string &version)
+

Set the hardware version

+
+
Parameters
+

version – The hardware version

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct DeviceInfo
+

Device Information.

+
+

Public Members

+
+
+std::string manufacturer_name
+

Manufacturer name.

+
+ +
+
+std::string model_number
+

Model number.

+
+ +
+
+std::string serial_number
+

Serial number.

+
+ +
+
+std::string software_version
+

Software version.

+
+ +
+
+std::string firmware_version
+

Firmware version.

+
+ +
+
+std::string hardware_version
+

Hardware version.

+
+ +
+
+PnpId pnp_id
+

Plug and Play ID.

+
+ +
+
+ +
+
+struct PnpId
+

Plug and Play ID.

+
+

Public Members

+
+
+uint8_t vendor_id_source = 0x01
+

0x01 for Bluetooth SIG, 0x02 for USB

+
+ +
+
+uint16_t vendor_id
+

Vendor ID.

+
+ +
+
+uint16_t product_id
+

Product ID.

+
+ +
+
+uint16_t product_version
+

Product version.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/gfps_service.html b/ble/gfps_service.html new file mode 100644 index 000000000..553172cea --- /dev/null +++ b/ble/gfps_service.html @@ -0,0 +1,1078 @@ + + + + + + + Google Fast Pair Service (GFPS) Service - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Google Fast Pair Service (GFPS) Service

+

The GfpsService implements the Google Fast Pair Service, allowing first-party +fast-pair experience on Android devices using the google nearby framework. This +also supports app matching / launching, as well as Google’s Find My Device +service. Finally, GFPS supports sharing device pairing info across that +account’s google devices and personalizing the name of the device.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class GfpsService : public espp::BaseComponent
+

Google Fast Pair Service This class is responsible for creating and managing the Google Fast Pair Service.

+

The service is created with the following characteristics:

    +
  • Model ID (read, unencrypted)

  • +
  • KB Pairing (write and notify, unencrypted)

  • +
  • Passkey (write and notify, unencrypted)

  • +
  • Account Key (write, unencrypted)

  • +
+

+

Google fast pair service also requires the fast pair provider (device) to support the Device Information Service (DIS, 0x180A) including the Firmware Revision characteristic (0x2A26).

+

For more information see https://developers.google.com/nearby/fast-pair/specifications/characteristics

+

If you need the DeviceInfoService and BatteryService, you can access them through espp::BleGattServer.

+

+

See also

+

BleGattServer

+
+

+
+

GFPS Service Example

+
  // NOTE: esp-nimble-cpp already depends on nvs_flash and initializes
+  //       nvs_flash in the NimBLEDevice::init(), so we don't have to do that
+  //       to store bonding info
+
+  // create the GATT server
+  espp::BleGattServer ble_gatt_server;
+  std::string device_name = "ESP++ GFPS";
+  ble_gatt_server.set_log_level(espp::Logger::Verbosity::INFO);
+  ble_gatt_server.set_callbacks({
+      .connect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device connected"); },
+      .disconnect_callback = [&](auto &conn_info,
+                                 auto reason) { logger.info("Device disconnected: {}", reason); },
+      .authentication_complete_callback =
+          [&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
+      .get_passkey_callback = [&]() { return NimBLEDevice::getSecurityPasskey(); },
+      .confirm_passkey_callback =
+          [&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
+            // set the passkey here, so that GFPS can later compare against it
+            // and inject confirmation/rejection
+            NimBLEDevice::setSecurityPasskey(passkey);
+          },
+  });
+  ble_gatt_server.init(device_name);
+#if CONFIG_BT_NIMBLE_EXT_ADV
+#error                                                                                             \
+    "This example does not support extended advertising, as GFPS does not recognize ext advertisements"
+#endif
+#if !CONFIG_BT_NIMBLE_EXT_ADV
+  ble_gatt_server.set_advertise_on_disconnect(true);
+#endif
+
+  // NOTE: we don't have to set security, since GFPS internally will set it to
+  // what is required by the spec.
+
+  // let's create a GFPS service
+  espp::GfpsService gfps_service;
+  gfps_service.set_log_level(espp::Logger::Verbosity::DEBUG);
+  gfps_service.init(ble_gatt_server.server());
+
+  // now that we've made the input characteristic, we can start the service
+  gfps_service.start();
+  ble_gatt_server.start_services(); // starts the device info service and battery service
+  // NOTE: we could also directly start them ourselves if we wanted to
+  //      control the order of starting the services
+  // e.g.:
+  // ble_gatt_server.battery_service().start();
+  // ble_gatt_server.device_info_service().start();
+
+  // now start the gatt server
+  ble_gatt_server.start();
+
+  // let's set some of the service data
+  auto &battery_service = ble_gatt_server.battery_service();
+  battery_service.set_battery_level(99);
+
+  auto &device_info_service = ble_gatt_server.device_info_service();
+  uint8_t vendor_source = 0x02; // USB
+  uint16_t vid = 0xCafe;
+  uint16_t pid = 0xBabe;
+  uint16_t product_version = 0x0100;
+  device_info_service.set_pnp_id(vendor_source, vid, pid, product_version);
+  device_info_service.set_manufacturer_name("ESP-CPP");
+  // NOTE: this is NOT required to be the same as the GFPS SKU Name
+  device_info_service.set_model_number("espp-gfps-01");
+  device_info_service.set_serial_number("1234567890");
+  device_info_service.set_software_version("1.0.0");
+  device_info_service.set_firmware_version("1.0.0");
+  device_info_service.set_hardware_version("1.0.0");
+
+  // now lets start advertising
+  espp::BleGattServer::AdvertisedData adv_data;
+  // uint8_t flags = BLE_HS_ADV_F_DISC_LTD;
+  uint8_t flags = BLE_HS_ADV_F_DISC_GEN;
+  adv_data.setFlags(flags);
+  adv_data.setName(device_name);
+  adv_data.setAppearance((uint16_t)espp::BleAppearance::GENERIC_DISPLAY);
+  adv_data.setServiceData(gfps_service.uuid(), gfps_service.get_service_data());
+  adv_data.addTxPower();
+  ble_gatt_server.set_advertisement_data(adv_data);
+  ble_gatt_server.start_advertising();
+
+  // now lets update the battery level every second
+  uint8_t battery_level = 99;
+  while (true) {
+    auto start = std::chrono::steady_clock::now();
+
+    // update the battery level
+    battery_service.set_battery_level(battery_level);
+    battery_level = (battery_level % 100) + 1;
+
+    // sleep
+    std::this_thread::sleep_until(start + 1s);
+  }
+
+
+
+
+

Public Functions

+
+
+inline explicit GfpsService(espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor

+
+
Parameters
+

log_level – The log level for the service

+
+
+
+ +
+
+inline explicit GfpsService(NimBLEServer *server, espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor

+
+

Note

+

This constructor will initialize the service with the given server

+
+
+

Note

+

This constructor will also initialize the nearby framework

+
+
+
Parameters
+
    +
  • server – The BLE server to attach the service to

  • +
  • log_level – The log level for the service

  • +
+
+
+
+ +
+
+inline void set_passkey(uint32_t passkey)
+

Set the passkey

+
+

Note

+

This function will set the passkey for the service

+
+
+

Note

+

This function should be called in the ESP_GAP_BLE_NC_REQ_EVT GAP event handler

+
+
+
Parameters
+

passkey – The passkey to set

+
+
+
+ +
+
+inline uint32_t get_passkey() const
+

Get the passkey

+
+
Returns
+

The passkey for the service

+
+
+
+ +
+
+inline void on_pairing_request(NimBLEConnInfo &conn_info)
+

On pairing request This function is called when a pairing request is received

+
+

Note

+

This function will call the GFPS/nearby on_pairing_request function

+
+
+

Note

+

This function should be called in the ESP_GAP_BLE_SEC_REQ_EVT GAP event handler

+
+
+
Parameters
+

conn_info – The connection information for the device

+
+
+
+ +
+
+inline NimBLEService *service() const
+

Get the Service

+
+
Returns
+

The BLE service for the Google Fast Pair Service

+
+
+
+ +
+
+inline NimBLEUUID uuid() const
+

Get the Service UUID

+
+
Returns
+

The UUID for the Google Fast Pair Service

+
+
+
+ +
+
+inline std::string get_service_data() const
+

Get the Service Data

+
+

Note

+

The service data is the 3 byte model ID

+
+
+

Note

+

This is the service data that is advertised

+
+
+
Returns
+

The service data for the Google Fast Pair Service

+
+
+
+ +
+
+inline bool notify(nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Notify the characteristic

+
+

Note

+

This function will notify the given characteristic with the given value

+
+
+
Parameters
+
    +
  • characteristic – The characteristic to notify

  • +
  • value – The value to notify

  • +
  • length – The length of the value

  • +
+
+
Returns
+

True if the notification was successful, false otherwise

+
+
+
+ +
+
+inline void init(NimBLEServer *server)
+

Initialize the service

+
+

Note

+

This function will initialize the service with the given server

+
+
+

Note

+

This function will also initialize the nearby framework

+
+
+
Parameters
+

server – The BLE server to attach the service to

+
+
+
+ +
+
+inline void deinit()
+

Deinitialize the service

+
+

Note

+

This function will deinitialize the service

+
+
+

Note

+

This function will also deinitialize the nearby framework

+
+
+

Note

+

This function should only be called after NimBLEDevice::deinit(true) has been called, since that will free the memory used by the service and the nearby framework

+
+
+ +
+
+inline void start()
+

Start the service

+
+

Note

+

This function will start the service

+
+
+

Note

+

This function will also set the advertisement mode for the nearby framework

+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class GfpsCharacteristicCallback
+

Callback base class for the Google Fast Pair Service This class provides the base functionality for the Google Fast Pair Service characteristic callbacks.

+

Subclassed by espp::GfpsAccountKeyCharacteristicCallbacks, espp::GfpsKbPairingCharacteristicCallbacks, espp::GfpsModelIdCharacteristicCallbacks, espp::GfpsPasskeyCharacteristicCallbacks

+
+

Public Functions

+
+
+inline std::vector<uint8_t> on_gfps_read(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic)
+

Called when a Google Fast Pair Service characteristic is read

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to read

  • +
+
+
Returns
+

The value of the characteristic or an empty vector if the read failed

+
+
+
+ +
+
+inline void on_gfps_write(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Called when a Google Fast Pair Service characteristic is written

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to write

  • +
  • value – The value to write

  • +
  • length – The length of the value

  • +
+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity log_level)
+

Set the log level for the class

+
+
Parameters
+

log_level – The log level

+
+
+
+ +
+
+ +
+
+class GfpsModelIdCharacteristicCallbacks : public NimBLECharacteristicCallbacks, public espp::GfpsCharacteristicCallback
+
+

Public Functions

+
+
+inline void onRead(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Model ID Characteristic is read

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being read

  • +
  • conn_info – The ConnInfo object for the connection associated with the read

  • +
+
+
+
+ +
+
+inline std::vector<uint8_t> on_gfps_read(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic)
+

Called when a Google Fast Pair Service characteristic is read

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to read

  • +
+
+
Returns
+

The value of the characteristic or an empty vector if the read failed

+
+
+
+ +
+
+inline void on_gfps_write(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Called when a Google Fast Pair Service characteristic is written

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to write

  • +
  • value – The value to write

  • +
  • length – The length of the value

  • +
+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity log_level)
+

Set the log level for the class

+
+
Parameters
+

log_level – The log level

+
+
+
+ +
+
+ +
+
+class GfpsKbPairingCharacteristicCallbacks : public NimBLECharacteristicCallbacks, public espp::GfpsCharacteristicCallback
+
+

Public Functions

+
+
+inline void onWrite(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Key-Based Pairing Characteristic is written

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being written

  • +
  • conn_info – The ConnInfo object for the connection associated with the write

  • +
+
+
+
+ +
+
+inline void onRead(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Key-Based Pairing Characteristic is read

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being read

  • +
  • conn_info – The ConnInfo object for the connection associated with the read

  • +
+
+
+
+ +
+
+inline std::vector<uint8_t> on_gfps_read(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic)
+

Called when a Google Fast Pair Service characteristic is read

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to read

  • +
+
+
Returns
+

The value of the characteristic or an empty vector if the read failed

+
+
+
+ +
+
+inline void on_gfps_write(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Called when a Google Fast Pair Service characteristic is written

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to write

  • +
  • value – The value to write

  • +
  • length – The length of the value

  • +
+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity log_level)
+

Set the log level for the class

+
+
Parameters
+

log_level – The log level

+
+
+
+ +
+
+ +
+
+class GfpsPasskeyCharacteristicCallbacks : public NimBLECharacteristicCallbacks, public espp::GfpsCharacteristicCallback
+
+

Public Functions

+
+
+inline void onWrite(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Passkey Pairing Characteristic is written

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being written

  • +
  • conn_info – The ConnInfo object for the connection associated with the write

  • +
+
+
+
+ +
+
+inline void onRead(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Passkey Characteristic is read

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being read

  • +
  • conn_info – The ConnInfo object for the connection associated with the read

  • +
+
+
+
+ +
+
+inline std::vector<uint8_t> on_gfps_read(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic)
+

Called when a Google Fast Pair Service characteristic is read

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to read

  • +
+
+
Returns
+

The value of the characteristic or an empty vector if the read failed

+
+
+
+ +
+
+inline void on_gfps_write(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Called when a Google Fast Pair Service characteristic is written

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to write

  • +
  • value – The value to write

  • +
  • length – The length of the value

  • +
+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity log_level)
+

Set the log level for the class

+
+
Parameters
+

log_level – The log level

+
+
+
+ +
+
+ +
+
+class GfpsAccountKeyCharacteristicCallbacks : public NimBLECharacteristicCallbacks, public espp::GfpsCharacteristicCallback
+
+

Public Functions

+
+
+inline void onWrite(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Account Key Characteristic is written

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being written

  • +
  • conn_info – The ConnInfo object for the connection associated with the write

  • +
+
+
+
+ +
+
+inline void onRead(NimBLECharacteristic *characteristic, NimBLEConnInfo &conn_info) override
+

Called when the Account Key Characteristic is read

+
+
Parameters
+
    +
  • characteristic – The characteristic that is being read

  • +
  • conn_info – The ConnInfo object for the connection associated with the read

  • +
+
+
+
+ +
+
+inline std::vector<uint8_t> on_gfps_read(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic)
+

Called when a Google Fast Pair Service characteristic is read

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to read

  • +
+
+
Returns
+

The value of the characteristic or an empty vector if the read failed

+
+
+
+ +
+
+inline void on_gfps_write(NimBLEConnInfo &conn_info, nearby_fp_Characteristic characteristic, const uint8_t *value, size_t length)
+

Called when a Google Fast Pair Service characteristic is written

+
+
Parameters
+
    +
  • conn_info – The connection information for the device

  • +
  • characteristic – The characteristic to write

  • +
  • value – The value to write

  • +
  • length – The length of the value

  • +
+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity log_level)
+

Set the log level for the class

+
+
Parameters
+

log_level – The log level

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/gfps_service_example.html b/ble/gfps_service_example.html new file mode 100644 index 000000000..4069f4a35 --- /dev/null +++ b/ble/gfps_service_example.html @@ -0,0 +1,245 @@ + + + + + + + Google Fast Pair Service (GFPS) Service Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Google Fast Pair Service (GFPS) Service Example

+

This example shows how to use the espp::GfpsService class together with the +espp::BleGattServer class to create and manage a BLE GATT server that provides +support for Google Fast Pair Service (GFPS) using the +nearby/embedded framework.

+

NOTE: this example uses a pre-registered device. If you want to register your +own device(s), you must do that on the nearby/devices +dashboard.

+
+

How to use example

+
+

Hardware Required

+

This example should run on any ESP32s3 development board as it requires no +peripheral connections.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-03-07 at 17 40 22

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/hid_service.html b/ble/hid_service.html new file mode 100644 index 000000000..e6f6f15d1 --- /dev/null +++ b/ble/hid_service.html @@ -0,0 +1,862 @@ + + + + + + + HID Service - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HID Service

+

The HidService implements the standard BLE HID service, providing dynamic and +configurable HID input, output, and feature reports from a BLE peripheral to a +BLE central.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class HidService : public espp::BaseComponent
+

HID Service This class is responsible for creating and managing the HID service. It is responsible for creating and managing the required characteristics per the HID specification. It allows arbitrary input/output/feature HID reports.

+

NOTE: this is a simplified version of NimBLEHIDDevice, which does not include the DeviceInfoService and BatteryService internally, as espp::BleGattServer already provides the DeviceInfoService and BatteryService.

+

If you need the DeviceInfoService and BatteryService, you can access them through espp::BleGattServer.

+

+

See also

+

BleGattServer

+
+

+
+

HID Service Example

+
  // NOTE: esp-nimble-cpp already depends on nvs_flash and initializes
+  //       nvs_flash in the NimBLEDevice::init(), so we don't have to do that
+  //       to store bonding info
+
+  // create the GATT server
+  espp::BleGattServer ble_gatt_server;
+  std::string device_name = "ESP++ HID";
+  ble_gatt_server.set_log_level(espp::Logger::Verbosity::INFO);
+  ble_gatt_server.set_callbacks({
+      .connect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device connected"); },
+      .disconnect_callback = [&](auto &conn_info,
+                                 auto reason) { logger.info("Device disconnected: {}", reason); },
+      .authentication_complete_callback =
+          [&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
+      // NOTE: this is optional, if you don't provide this callback, it will
+      // perform the exactly function as below:
+      .get_passkey_callback =
+          [&]() {
+            logger.info("Getting passkey");
+            return NimBLEDevice::getSecurityPasskey();
+          },
+      // NOTE: this is optional, if you don't provide this callback, it will
+      // perform the exactly function as below:
+      .confirm_passkey_callback =
+          [&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
+            logger.info("Confirming passkey: {}", passkey);
+            NimBLEDevice::injectConfirmPasskey(conn_info,
+                                               passkey == NimBLEDevice::getSecurityPasskey());
+          },
+  });
+  ble_gatt_server.init(device_name);
+#if CONFIG_BT_NIMBLE_EXT_ADV
+#error                                                                                             \
+    "This example does not support extended advertising, as iOS does not seem to show ext advertisements in their bluetooth settings menu (even if you turn on legacy advertising)"
+#endif
+#if !CONFIG_BT_NIMBLE_EXT_ADV
+  ble_gatt_server.set_advertise_on_disconnect(true);
+#endif
+
+  // for HID we need to set some security
+  bool bonding = true;
+  bool mitm = false;
+  bool secure_connections = true;
+  ble_gatt_server.set_security(bonding, mitm, secure_connections);
+  // and some i/o and key config
+  ble_gatt_server.set_io_capabilities(BLE_HS_IO_NO_INPUT_OUTPUT);
+  ble_gatt_server.set_init_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+  ble_gatt_server.set_resp_key_distribution(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+
+  // let's create a HID service
+  espp::HidService hid_service;
+  hid_service.init(ble_gatt_server.server());
+
+  // configure it some
+  uint8_t country_code = 0x00;
+  uint8_t hid_info_flags = 0x01;
+  hid_service.set_info(country_code, hid_info_flags);
+
+  static constexpr uint8_t input_report_id = 1;
+  static constexpr uint8_t battery_report_id = 4;
+  static constexpr size_t num_buttons = 15;
+  static constexpr int joystick_min = 0;
+  static constexpr int joystick_max = 65534;
+  static constexpr int trigger_min = 0;
+  static constexpr int trigger_max = 1023;
+
+  using GamepadInput =
+      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
+                               joystick_max, trigger_min, trigger_max, input_report_id>;
+  GamepadInput gamepad_input_report;
+
+  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
+  BatteryReport battery_input_report;
+
+  static constexpr uint8_t output_report_id = 2;
+  static constexpr size_t num_leds = 4;
+  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, output_report_id>;
+  GamepadLeds gamepad_leds_report;
+
+  using namespace hid::page;
+  using namespace hid::rdf;
+  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
+                                   collection::application(gamepad_input_report.get_descriptor(),
+                                                           battery_input_report.get_descriptor(),
+                                                           gamepad_leds_report.get_descriptor()));
+
+  // Generate the report descriptor for the gamepad
+  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());
+
+  logger.info("Report Descriptor:");
+  logger.info("  Size: {}", descriptor.size());
+  logger.info("  Data: {::#02x}", descriptor);
+
+  // set the report map (vector of bytes)
+  hid_service.set_report_map(descriptor);
+
+  // use the HID service to make an input report characteristic
+  [[maybe_unused]] auto input_report = hid_service.input_report(input_report_id);
+  [[maybe_unused]] auto battery_report = hid_service.input_report(battery_report_id);
+
+  // use the HID service to make an output report characteristic
+  [[maybe_unused]] auto output_report = hid_service.output_report(output_report_id);
+
+  // now that we've made the input characteristic, we can start the service
+  hid_service.start();
+  // starts the device info service and battery service, see
+  // hid_service_example for more info
+  ble_gatt_server.start_services();
+
+  // now start the gatt server
+  ble_gatt_server.start();
+
+  // let's set some of the service data
+  auto &battery_service = ble_gatt_server.battery_service();
+  battery_service.set_battery_level(99);
+
+  auto &device_info_service = ble_gatt_server.device_info_service();
+  uint8_t vendor_source = 0x02; // USB
+  uint16_t vid = 0x045E;        // Microsoft
+  uint16_t pid = 0x02FD;        // Xbox One Controller
+  uint16_t product_version = 0x0100;
+  device_info_service.set_pnp_id(vendor_source, vid, pid, product_version);
+  device_info_service.set_manufacturer_name("ESP-CPP");
+  device_info_service.set_model_number("esp-hid-01");
+  device_info_service.set_serial_number("1234567890");
+  device_info_service.set_software_version("1.0.0");
+  device_info_service.set_firmware_version("1.0.0");
+  device_info_service.set_hardware_version("1.0.0");
+
+  // NOTE: iOS does not seem to show ext advertisements in their bluetooth
+  // settings menu (even if you turn on legacy advertising)
+
+  // now lets start advertising
+  uint32_t advertise_duration_ms = 0; // 0 means never stop
+  espp::BleGattServer::AdvertisedData adv_data;
+  // uint8_t flags = BLE_HS_ADV_F_DISC_LTD;
+  uint8_t flags = BLE_HS_ADV_F_DISC_GEN;
+  adv_data.setFlags(flags);
+  adv_data.setName(device_name);
+  adv_data.setAppearance((uint16_t)espp::BleAppearance::GAMEPAD);
+  adv_data.setPartialServices16({hid_service.uuid()});
+  adv_data.addTxPower();
+  ble_gatt_server.set_advertisement_data(adv_data);
+  ble_gatt_server.start_advertising(advertise_duration_ms);
+
+  // now lets update the battery level and send an input report every second
+  uint8_t battery_level = 99;
+  // change the gamepad inputs every second
+  int button_index = 1;
+  bool was_connected = false;
+  while (true) {
+    auto start = std::chrono::steady_clock::now();
+
+    // if we are now connected, but were not, then get the services
+    if (ble_gatt_server.is_connected() && !was_connected) {
+      was_connected = true;
+      auto connected_device_infos = ble_gatt_server.get_connected_device_infos();
+      logger.info("Connected devices: {}", connected_device_infos.size());
+      std::vector<std::string> connected_device_names;
+      std::transform(connected_device_infos.begin(), connected_device_infos.end(),
+                     std::back_inserter(connected_device_names),
+                     [&](auto &info) { return ble_gatt_server.get_connected_device_name(info); });
+      logger.info("            Names: {}", connected_device_names);
+      std::vector<int> connected_device_rssis;
+      std::transform(connected_device_infos.begin(), connected_device_infos.end(),
+                     std::back_inserter(connected_device_rssis),
+                     [&](auto &info) { return ble_gatt_server.get_connected_device_rssi(info); });
+      logger.info("            RSSIs: {}", connected_device_rssis);
+    } else if (!ble_gatt_server.is_connected()) {
+      was_connected = false;
+    }
+
+    if (!ble_gatt_server.is_connected()) {
+      // sleep
+      std::this_thread::sleep_until(start + 1s);
+      continue;
+    }
+
+    // update the battery level
+    battery_service.set_battery_level(battery_level);
+    battery_input_report.reset();
+    battery_input_report.set_rechargeable(true);
+    battery_input_report.set_charging(false);
+    battery_input_report.set_battery_level(battery_level);
+    battery_report->notify(battery_input_report.get_report());
+    battery_level = (battery_level % 100) + 1;
+
+    // cycle through the possible d-pad states
+    GamepadInput::Hat hat = (GamepadInput::Hat)button_index;
+    // use the button index to set the position of the right joystick
+    float angle = 2.0f * M_PI * button_index / num_buttons;
+
+    gamepad_input_report.reset();
+    gamepad_input_report.set_hat(hat);
+    gamepad_input_report.set_button(button_index, true);
+    // joystick inputs are in the range [-1, 1] float
+    gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
+    gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
+    // trigger inputs are in the range [0, 1] float
+    gamepad_input_report.set_accelerator(std::abs(sin(angle)));
+    gamepad_input_report.set_brake(std::abs(cos(angle)));
+
+    logger.debug("Setting left joystick: ({:.1f}, {:.1f})", sin(angle), cos(angle));
+    logger.debug("Setting right joystick: ({:.1f}, {:.1f})", cos(angle), sin(angle));
+    logger.debug("Setting brake: {:.1f}", std::abs(cos(angle)));
+    logger.debug("Setting accelerator: {:.1f}", std::abs(sin(angle)));
+    logger.debug("Setting hat: {}", (int)hat);
+    logger.debug("Setting button: {}", button_index);
+
+    button_index = (button_index % num_buttons) + 1;
+
+    // send an input report
+    auto report = gamepad_input_report.get_report();
+    logger.debug("Sending report data ({}): {::#02x}", report.size(), report);
+
+    // Get the stored pointer (we could use the one above, but this is just to
+    // show how to get it)
+    auto report_char = hid_service.input_report(input_report_id);
+    report_char->notify(report);
+
+    // sleep
+    std::this_thread::sleep_until(start + 1s);
+  }
+
+
+
+
+

Public Functions

+
+
+inline explicit HidService(espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor.

+
+
Parameters
+

log_level – The verbosity of the logger

+
+
+
+ +
+
+inline explicit HidService(NimBLEServer *server, espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN)
+

Constructor.

+
+
Parameters
+
    +
  • server – The BLE server to use for the HID service.

  • +
  • log_level – The verbosity of the logger

  • +
+
+
+
+ +
+
+inline ~HidService()
+

Destructor.

+
+ +
+
+inline void init(NimBLEServer *server)
+

Initialize the HID service.

+
+ +
+
+inline void deinit()
+

Deinitialize the HID service.

+
+

Note

+

This should only be called after NimBLEDevice::deinit(true) has been called, since that will free the memory used by the service.

+
+
+ +
+
+inline void start()
+

Start the HID service.

+
+ +
+
+inline NimBLEService *service()
+

Get the HID service.

+
+
Returns
+

The HID service.

+
+
+
+ +
+
+inline NimBLEUUID uuid()
+

Get the UUID of the HID service.

+
+
Returns
+

The UUID of the HID service.

+
+
+
+ +
+
+inline void set_report_map(const std::vector<uint8_t> &report_map)
+

Set the report map for the HID service.

+
+
Parameters
+

report_map – The report map as a vector of bytes.

+
+
+
+ +
+
+inline void set_report_map(std::string_view report_map)
+

Set the report map for the HID service.

+
+
Parameters
+

report_map – The report map as a string view.

+
+
+
+ +
+
+inline void set_report_map(const uint8_t *report_map, size_t report_map_len)
+

Set the report map for the HID service.

+
+

Note

+

The report map is a descriptor that describes the format of the HID reports. It is used to tell the host how to interpret the reports that are sent by the HID device.

+
+
+
Parameters
+
    +
  • report_map – The report map bytes

  • +
  • report_map_len – The length of the report map.

  • +
+
+
+
+ +
+
+inline void set_info(uint8_t country, uint8_t flags)
+

Set the HID information for the HID service.

+
+
Parameters
+
    +
  • country – The country code.

  • +
  • flags – The HID information flags.

  • +
+
+
+
+ +
+
+inline NimBLECharacteristic *get_control()
+

Get the control characteristic for the HID service.

+
+
Returns
+

The control characteristic.

+
+
+
+ +
+
+inline NimBLECharacteristic *get_protocol_mode()
+

Get the protocol mode characteristic for the HID service.

+
+
Returns
+

The protocol mode characteristic.

+
+
+
+ +
+
+inline NimBLECharacteristic *input_report(uint8_t report_id)
+

Create an input report characteristic.

+
+
Parameters
+

report_id – The report ID. This should be the same as the report ID in the report descriptor for the input object that is related to the characteristic.

+
+
Returns
+

The input report characteristic.

+
+
+
+ +
+
+inline void remove_input_report(uint8_t report_id)
+

Remove an input report characteristic.

+
+

Note

+

This will delete the characteristic, and remove it from the list. Any stored pointers to the characteristic will be invalid after this call.

+
+
+
Parameters
+

report_id – The report ID of the input report characteristic to remove.

+
+
+
+ +
+
+inline NimBLECharacteristic *output_report(uint8_t report_id)
+

Create an output report characteristic.

+
+
Parameters
+

report_id – The report ID. This should be the same as the report ID in the report descriptor for the output object that is related to the characteristic.

+
+
Returns
+

The output report characteristic.

+
+
+
+ +
+
+inline void remove_output_report(uint8_t report_id)
+

Remove an output report characteristic.

+
+

Note

+

This will delete the characteristic, and remove it from the list. Any stored pointers to the characteristic will be invalid after this call.

+
+
+
Parameters
+

report_id – The report ID of the output report characteristic to remove.

+
+
+
+ +
+
+inline NimBLECharacteristic *feature_report(uint8_t report_id)
+

Create a feature report characteristic.

+
+
Parameters
+

report_id – The report ID. This should be the same as the report ID in the report descriptor for the feature object that is related to the characteristic.

+
+
Returns
+

The feature report characteristic.

+
+
+
+ +
+
+inline void remove_feature_report(uint8_t report_id)
+

Remove a feature report characteristic.

+
+

Note

+

This will delete the characteristic, and remove it from the list. Any stored pointers to the characteristic will be invalid after this call.

+
+
+
Parameters
+

report_id – The report ID of the feature report characteristic to remove.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/hid_service_example.html b/ble/hid_service_example.html new file mode 100644 index 000000000..8c8049bca --- /dev/null +++ b/ble/hid_service_example.html @@ -0,0 +1,244 @@ + + + + + + + BLE HID Service Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLE HID Service Example

+

This example shows how to use the espp::HidService class together with the +espp::BleGattServer class to create and manage a BLE GATT server that provides +an HID service. It uses the hid-rp component’s espp::GamepadReport<> to +define a HID gamepad report descriptor and generate input reports.

+

https://github.com/esp-cpp/espp/assets/213467/36d3d04d-1d8e-4b1d-9661-4ce115c7e9cc

+

https://github.com/esp-cpp/espp/assets/213467/fd64e526-8c63-4456-8235-056edb418135

+
+

How to use example

+
+

Hardware Required

+

This example should run on any ESP32s3 development board as it requires no +peripheral connections.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-02-28 at 17 23 49

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ble/index.html b/ble/index.html new file mode 100644 index 000000000..6b07de25a --- /dev/null +++ b/ble/index.html @@ -0,0 +1,220 @@ + + + + + + + BLE APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLE APIs

+ +

These components provide some interfaces for implementing a BLE peripheral - +namely a BLE GATT Server hosting various services.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/button.html b/button.html new file mode 100644 index 000000000..94d40796a --- /dev/null +++ b/button.html @@ -0,0 +1,840 @@ + + + + + + + Button APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Button APIs

+

The Button class provides a simple way to read the state of a button. There +are two ways to configure the functionality of the button.

+

The first uses Button::Config to configure the button to call a function when +the button is pressed or released and uses the Interrupt class’ task and ISR +for signaling. At any time, a user may also call the is_pressed method to read +the current state of the button’s input pin.

+

The second uses Button::SimpleConfig to simply configure the button as an +input with configurable pull-up or pull-down resistors and a configurable active +state (high or low). In this configuration, the input is read manually any time +the user calls the is_pressed method.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Button : protected espp::Interrupt
+

A class to handle a button connected to a GPIO.

+

This class uses the ESP-IDF GPIO interrupt handler to detect button presses and releases. It then calls the callback function with the event.

+
+

Simple Button Example (No Callback / Interrupt)

+
  // create the button
+  espp::Button simple_button({
+      .name = "Button 12",
+      .gpio_num = GPIO_NUM_12,
+      .active_level = espp::Interrupt::ActiveLevel::LOW,
+      .pullup_enabled = false,
+      .pulldown_enabled = false,
+      .log_level = espp::Logger::Verbosity::WARN,
+  });
+
+  for (int i = 0; i < 10; i++) {
+    logger.info("Button 12 state: {}", simple_button.is_pressed());
+    std::this_thread::sleep_for(1s);
+  }
+
+
+
+
+

Button Example (With Callback / Interrupt)

+
  static auto start = std::chrono::high_resolution_clock::now();
+  std::string button_topic = "button/state";
+  std::string button_component_name = "button";
+
+  // create a button
+  espp::Button button({
+      .name = "Button 12",
+      .interrupt_config =
+          {
+              .gpio_num = GPIO_NUM_12,
+              .callback =
+                  [&](const espp::Interrupt::Event &event) {
+                    auto now = std::chrono::high_resolution_clock::now();
+                    auto elapsed = std::chrono::duration<float>(now - start).count();
+                    logger.info("[Callback][{:.3f}] Button {} state changed to: {}", elapsed,
+                                event.gpio_num, event.active);
+                    // serialize the event
+                    std::error_code ec;
+                    std::vector<uint8_t> buffer;
+                    auto bytes_written = espp::serialize(event, buffer);
+                    if (bytes_written > 0) {
+                      // publish the event
+                      espp::EventManager::get().publish(button_topic, buffer);
+                    } else {
+                      logger.error("Failed to serialize button state");
+                    }
+                  },
+              .active_level = espp::Interrupt::ActiveLevel::LOW,
+              .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
+              .pullup_enabled = false,
+              .pulldown_enabled = false,
+          },
+      .task_config =
+          {
+              .name = "Button 12 task",
+              .stack_size_bytes = 8192,
+              .priority = 5,
+          },
+      .log_level = espp::Logger::Verbosity::WARN,
+  });
+
+  logger.info("Initial button state: {}", button.is_pressed());
+
+  // register subscriber on the button topic
+  auto &em = espp::EventManager::get();
+  auto did_sub =
+      em.add_subscriber(button_topic, "example subscriber", [&](const std::vector<uint8_t> &data) {
+        auto now = std::chrono::high_resolution_clock::now();
+        auto elapsed = std::chrono::duration<float>(now - start).count();
+        // deserialize the data
+        std::error_code ec;
+        auto state = espp::deserialize<espp::Interrupt::Event>(data, ec);
+        if (!ec) {
+          logger.info("[Subscriber][{:.3f}]: button {} state changed to: {}", elapsed,
+                      state.gpio_num, state.active);
+        } else {
+          logger.error("Failed to deserialize button state: {}", ec.message());
+        }
+      });
+  logger.info("Subscribed: {}", did_sub);
+
+  // create another button
+  espp::Button button_2({
+      .name = "Button 0",
+      .interrupt_config =
+          {
+              .gpio_num = GPIO_NUM_0,
+              .callback =
+                  [&](const espp::Interrupt::Event &event) {
+                    logger.info("Button {} state changed to: {}", event.gpio_num, event.active);
+                  },
+              .active_level = espp::Interrupt::ActiveLevel::LOW,
+              .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
+              .pullup_enabled = false,
+              .pulldown_enabled = false,
+              .filter_type = espp::Interrupt::FilterType::PIN_GLITCH_FILTER,
+          },
+      .task_config =
+          {
+              .name = "Button 0 task",
+              .stack_size_bytes = 8192,
+              .priority = 5,
+          },
+      .log_level = espp::Logger::Verbosity::WARN,
+  });
+
+  while (true) {
+    std::this_thread::sleep_for(1s);
+  }
+
+
+
+
+

Public Types

+
+
+using Event = Interrupt::Event
+

The event type for the button.

+
+ +
+
+using InterruptType = Interrupt::Type
+

The type of interrupt for the button.

+
+ +
+
+using ActiveLevel = Interrupt::ActiveLevel
+

The active level of the button.

+
+ +
+
+using callback_t = Interrupt::event_callback_fn
+

The callback function type for the button.

+
+ +
+
+

Public Functions

+
+
+inline explicit Button(const Config &config)
+

Construct a button.

+

+This constructor is useful for buttons that require a custom task or interrupt configuration and need to register a callback function.

+
+
Parameters
+

config – The configuration for the button

+
+
+
+ +
+
+inline explicit Button(const SimpleConfig &config)
+

Construct a button with a simple configuration.

+

+This constructor is useful for simple buttons that don’t require a custom task or interrupt configuration and do not need to register a callback function.

+
+
Parameters
+

config – The simple configuration for the button

+
+
+
+ +
+
+inline bool is_pressed() const
+

Whether the button is currently pressed.

+
+
Returns
+

True if the button is pressed, false otherwise

+
+
+
+ +
+
+

Protected Types

+
+
+enum class Type
+

The type of interrupt to use for the GPIO.

+

Values:

+
+
+enumerator ANY_EDGE
+

Interrupt on any edge.

+
+ +
+
+enumerator RISING_EDGE
+

Interrupt on rising edge.

+
+ +
+
+enumerator FALLING_EDGE
+

Interrupt on falling edge.

+
+ +
+
+enumerator LOW_LEVEL
+

Interrupt on low level.

+
+ +
+
+enumerator HIGH_LEVEL
+

Interrupt on high level.

+
+ +
+ +
+
+typedef std::function<void(const Event&)> event_callback_fn
+

The callback for the event.

+
+ +
+
+

Protected Functions

+
+
+inline size_t get_min_queue_size() const
+

Get the minimum number of free spaces in the queue.

+

+This will return the minimum number of free spaces in the queue Over the lifetime of the object. This can be used to determine if the queue size is too small for the number of interrupts that are being received. It may also help indicate if the interrupt task priority is too low, preventing the queue from being serviced. Finally, it may also help to indicate if additional filtering may be needed on the interrupt line (either using the FilterType or with hardware filtering).

+
+
Returns
+

The minimum number of free spaces in the queue

+
+
+
+ +
+
+inline void add_interrupt(const PinConfig &interrupt)
+

Add an interrupt to the interrupt handler.

+
+
Parameters
+

interrupt – The interrupt to add

+
+
+
+ +
+
+inline void remove_all()
+

Remove all the interrupts from the interrupt handler.

+

This will remove all the interrupts that are currently registered with the interrupt handler. This will also disable all the interrupts that are currently enabled.

+
+ +
+
+inline void remove_interrupt(const PinConfig &interrupt)
+

Remove an interrupt from the interrupt handler.

+

+This will find a registered interrupt with the given GPIO number and remove it from the list of interrupts. It will also disable the interrupt for that GPIO number. If no interrupt is found with the given GPIO number, then nothing is done.

+
+
Parameters
+

interrupt – The interrupt to remove

+
+
+
+ +
+
+inline void remove_interrupt(int gpio_num)
+

Remove an interrupt from the interrupt handler.

+

+This will find a registered interrupt with the given GPIO number and remove it from the list of interrupts. It will also disable the interrupt for that GPIO number. If no interrupt is found with the given GPIO number, then nothing is done.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to remove

+
+
+
+ +
+
+inline void disable_all()
+

Disable all the interrupts.

+

This will disable all the interrupts that are currently registered with the interrupt handler. This will not remove the interrupts from the list of interrupts, so they can be reenabled later.

+
+ +
+
+inline void disable_interrupt(const PinConfig &interrupt)
+

Disable the interrupt for the interrupt PinConfig.

+

+This will disable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

interrupt – The interrupt to disable

+
+
+
+ +
+
+inline void disable_interrupt(int gpio_num)
+

Disable the interrupt for the GPIO.

+

+This will disable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to disable

+
+
+
+ +
+
+inline void enable_interrupt(const PinConfig &interrupt)
+

Enable the interrupt for the GPIO.

+

+This will enable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

interrupt – The interrupt to enable

+
+
+
+ +
+
+inline void enable_interrupt(int gpio_num)
+

Enable the interrupt for the GPIO.

+

+This will enable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to enable

+
+
+
+ +
+
+inline bool is_active(const PinConfig &interrupt) const
+

Get the state of the interrupt.

+

+This will check the raw logic level of the GPIO and return whether the interrupt is active or not according to the active level that was set in the configuration.

+
+
Parameters
+

interrupt – The interrupt to check

+
+
Returns
+

Whether the interrupt is active

+
+
+
+ +
+
+inline std::vector<std::pair<int, bool>> get_active_states()
+

Get the state of all the interrupts.

+
+
Returns
+

A vector of the states of the interrupts as pairs of the GPIO number and whether the interrupt is active

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

The configuration for the button.

+
+

Public Members

+
+
+std::string_view name = {"Button"}
+

Name of the button.

+
+ +
+
+int isr_core_id = -1
+

The core ID to run the interrupt service routine on.

+
+ +
+
+Interrupt::PinConfig interrupt_config
+

Configuration for the GPIO interrupt.

+
+ +
+
+Task::BaseConfig task_config = {}
+

Configuration for the button task.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

Log level for this class.

+
+ +
+
+ +
+
+struct SimpleConfig
+

The simple configuration for the button.

+

This is a simplified configuration for the button that only requires the GPIO number and the active level of the button. This is useful for simple buttons that don’t require a custom task or interrupt configuration and do not need to register a callback function.

+
+

Public Members

+
+
+std::string_view name = {"Button"}
+

Name of the button.

+
+ +
+
+gpio_num_t gpio_num
+

The GPIO number for the button.

+
+ +
+
+ActiveLevel active_level = ActiveLevel::LOW
+

The active level of the button.

+
+ +
+
+bool pullup_enabled = true
+

Whether to enable the internal pullup resistor for the button

+
+ +
+
+bool pulldown_enabled = false
+

Whether to enable the internal pulldown resistor for the button

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

Log level for this class.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/button_example.html b/button_example.html new file mode 100644 index 000000000..1cb8eb6eb --- /dev/null +++ b/button_example.html @@ -0,0 +1,236 @@ + + + + + + + Button Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Button Example

+

This example shows how to use the espp::Button class to handle input events +from a physical button connected to an ESP32 GPIO pin.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on an ESP32 board which has a digital button +connected to GPIO2 of the ESP32, with the button having a hardware pull-down +resistor so that its resting state is logic low and its active / pressed state +is logic high.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-03-11 at 12 01 03

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/cli.html b/cli.html new file mode 100644 index 000000000..10a8aea14 --- /dev/null +++ b/cli.html @@ -0,0 +1,259 @@ + + + + + + + Command Line Interface (CLI) APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Command Line Interface (CLI) APIs

+

The cli.hpp header provides a convenience include / wrapper around +daniele77/cli. It also exposes cli’s +include folder, so including “cli.hpp” is completely equivalent to including +<cli/cli.h> - but you can additionally include other files from +<cli/>. It also provides a few conveniences:

+
    +
  1. a espp::Cli class which inherits from cli::CliSession and has a +near-identical implementation as cli’s CliFileSesson, with the exception +that it explicitly reads character by character instead of line by line and +prints out the characters as they are being input, and

  2. +
  3. a static espp::Cli::configure_stdin_stdout() function which sets up the esp +UART to enable blocking std::cin read, which is needed for std::cin to +work (and therefore - currently - for cli to work). This function is +automatically called by the espp::Cli constructor, but it can also be +called manually without needing to create a espp::Cli object if you wish to +simply use the std::cin and related functions.

  4. +
  5. a espp::LineInput class which provides support for an interactive input +system which can optionally have history with navigation. It allows for +getting the user input as an arbitrary input string while enabling some +keyboard movement and editing commands. The espp::Cli uses the +espp::LineInput class internally to handle the input aspects of the Cli, +but the espp::LineInput class can be re-used anywhere you want to get one +or more lines of user input in a reusable way. Note that if you use it in +another class / outside the espp::Cli class, you will need to call the +espp::Cli::configure_stdin_stdout() as mentioned above.

  6. +
+

Please see the documentation for the cli submodule if you have any questions about usage +beyond the examples provided here.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/cli_example.html b/cli_example.html new file mode 100644 index 000000000..7033db4d0 --- /dev/null +++ b/cli_example.html @@ -0,0 +1,241 @@ + + + + + + + Cli Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cli Example

+

This example shows how to use the Cli component to setup and run a command +line interface (CLI) on the ESP.

+

The Cli and associated LineInput classes support:

+
    +
  • ctrl+a (move to beginning of line)

  • +
  • ctrl+e (move to end of line)

  • +
  • ctrl+n (move up a line / previous input history)

  • +
  • ctrl+p (move down a line / next input history)

  • +
  • ctrl+k (delete from the cursor to the end of the line)

  • +
  • ctrl+b (move the cursor back one character)

  • +
  • ctrl+f (move the cursor forward one character)

  • +
  • ctrl+l (clear the screen)

  • +
+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+

https://user-images.githubusercontent.com/213467/231188170-47f45641-fc44-4cc6-b673-506e643a5e02.mp4

+

Showing terminal resize and support for ctrl+l:

+

https://github.com/esp-cpp/espp/assets/213467/54c362a7-99f2-4d8a-aa26-4498646f86e6

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/color.html b/color.html new file mode 100644 index 000000000..3425f4220 --- /dev/null +++ b/color.html @@ -0,0 +1,494 @@ + + + + + + + Color APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Color APIs

+

The color.hpp header provides two classes for performing color management, +interpolation, and conversion - espp::Rgb and espp::Hsv which can be +converted between each other. The RGB color space provides support for additive +blending (which includes averaging, as opposed to light-model-based mixing) and +is therefore suited for producing gradients.

+

Please see Computer Graphics and Geometric Modeling: Implementation and +Algorithms, specifically section +8.6 for more information.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Rgb
+

Class representing a color using RGB color space.

+
+

Public Functions

+
+
+explicit Rgb(const float &r, const float &g, const float &b)
+

Construct an Rgb object from the provided rgb values.

+
+

Note

+

If provided values outside the range [0,1], it will rescale them to be within the range [0,1] by dividing by 255.

+
+
+
Parameters
+
    +
  • r – Floating point value for the red channel, should be in range [0, 1]

  • +
  • g – Floating point value for the green channel, should be in range [0, 1]

  • +
  • b – Floating point value for the blue channel, should be in range [0, 1]

  • +
+
+
+
+ +
+
+Rgb(const Rgb &rgb)
+

Copy-construct an Rgb object from the provided object.

+
+

Note

+

If provided values outside the range [0,1], it will rescale them to be within the range [0,1] by dividing by 255.

+
+
+
Parameters
+

rgbRgb struct containing the values to copy.

+
+
+
+ +
+
+explicit Rgb(const Hsv &hsv)
+

Construct an Rgb object from the provided Hsv object.

+
+

Note

+

This calls hsv.rgb() on the provided object, which means that invalid HSV data (not in the ranges [0,360], [0,1], and [0,1]) could lead to bad RGB data. The Rgb constructor will automatically convert the values to be in the proper range, but the perceived color will be changed.

+
+
+
Parameters
+

hsvHsv object to copy.

+
+
+
+ +
+
+explicit Rgb(const uint32_t &hex)
+

Construct an Rgb object from the provided hex value.

+
+
Parameters
+

hex – Hex value to convert to RGB. The hex value should be in the format 0xRRGGBB.

+
+
+
+ +
+
+Rgb &operator=(const Rgb &other) = default
+

Assign the values of the provided Rgb object to this Rgb object.

+
+
Parameters
+

other – The Rgb object to copy.

+
+
+
+ +
+
+Rgb &operator=(const Hsv &hsv)
+

Assign the values of the provided Hsv object to this Rgb object.

+
+

Note

+

This calls hsv.rgb() on the provided object, which means that invalid HSV data (not in the ranges [0,360], [0,1], and [0,1])

+
+
+ +
+
+Rgb operator+(const Rgb &rhs) const
+

Perform additive color blending (averaging)

+
+
Parameters
+

rhs – Other color to add to this color to create the resultant color

+
+
Returns
+

Resultant color from blending this color with the rhs color.

+
+
+
+ +
+
+Rgb &operator+=(const Rgb &rhs)
+

Perform additive color blending (averaging)

+
+
Parameters
+

rhs – Other color to add to this color

+
+
+
+ +
+
+Hsv hsv() const
+

Get a HSV representation of this RGB color.

+
+
Returns
+

An HSV object containing the HSV representation.

+
+
+
+ +
+
+uint32_t hex() const
+

Get the hex representation of this RGB color.

+
+
Returns
+

The hex representation of this RGB color.

+
+
+
+ +
+
+

Public Members

+
+
+float r = {0}
+

Red value ∈ [0, 1].

+
+ +
+
+float g = {0}
+

Green value ∈ [0, 1].

+
+ +
+
+float b = {0}
+

Blue value ∈ [0, 1].

+
+ +
+
+ +
+
+class Hsv
+

Class representing a color using HSV color space.

+
+

Public Functions

+
+
+explicit Hsv(const float &h, const float &s, const float &v)
+

Construct a Hsv object from the provided values.

+
+
Parameters
+
    +
  • h – Hue - will be clamped to be in range [0, 360]

  • +
  • s – Saturation - will be clamped to be in range [0, 1]

  • +
  • v – Value - will be clamped to be in range [0, 1]

  • +
+
+
+
+ +
+
+Hsv(const Hsv &hsv)
+

Copy-construct the Hsv object.

+
+
Parameters
+

hsv – Object to copy from.

+
+
+
+ +
+
+explicit Hsv(const Rgb &rgb)
+

Construct Hsv object from Rgb object. Calls rgb.hsv() to perform the conversion.

+
+
Parameters
+

rgb – The Rgb object to convert and copy.

+
+
+
+ +
+
+Hsv &operator=(const Hsv &other) = default
+

Assign the values of the provided Hsv object to this Hsv object.

+
+
Parameters
+

other – The Hsv object to copy.

+
+
+
+ +
+
+Hsv &operator=(const Rgb &rgb)
+

Assign the values of the provided Rgb object to this Hsv object.

+
+
Parameters
+

rgb – The Rgb object to convert and copy.

+
+
+
+ +
+
+Rgb rgb() const
+

Get a RGB representation of this HSV color.

+
+
Returns
+

An RGB object containing the RGB representation.

+
+
+
+ +
+
+

Public Members

+
+
+float h = {0}
+

Hue ∈ [0, 360].

+
+ +
+
+float s = {0}
+

Saturation ∈ [0, 1].

+
+ +
+
+float v = {0}
+

Value ∈ [0, 1].

+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/color_example.html b/color_example.html new file mode 100644 index 000000000..158bd38a3 --- /dev/null +++ b/color_example.html @@ -0,0 +1,232 @@ + + + + + + + Color Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Color Example

+

This example shows how to use the various classes exposed in the color +component to manipulate and convert between color data.

+

The classes provided are:

+
    +
  • espp::Rgb

  • +
  • espp::Hsv

  • +
+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/controller.html b/controller.html new file mode 100644 index 000000000..b77a76684 --- /dev/null +++ b/controller.html @@ -0,0 +1,1098 @@ + + + + + + + Controller APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Controller APIs

+

The Controller class provides a convenience for reading multiple GPIOs at once +and mapping their state to common controller buttons. It can optionally be +configured to support joystick select, as well as to convert analog joystick +values into digital directional values (up/down/left/right). It can also be used +for just a subset of the buttons, should you wish to do so, by providing the +GPIO configuration for the unused buttons to be -1.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Controller : public espp::BaseComponent
+

Class for managing controller input.

+

The controller can be configured to either use a digital d-pad or an analog 2-axis joystick with select button.

+

Digital configuration can support ABXY, start, select, and 4 digital directional inputs.

+

Anaolg Joystick Configuration can support ABXY, start, select, two axis (analog) joystick, and joystick select button. It will also convert the joystick analog values into digital d-pad buttons.

+
+

Digital Controller Example

+
    // make the controller - NOTE: this was designed for connecting the Sparkfun
+    // Joystick Shield to the ESP32 S3 BOX
+    espp::Controller controller(espp::Controller::DigitalConfig{
+        // buttons short to ground, so they are active low. this will enable the
+        // GPIO_PULLUP and invert the logic
+        .active_low = true,
+        .gpio_a = 38,      // D3 on the joystick shield
+        .gpio_b = 39,      // D5 on the joystick shield
+        .gpio_start = 42,  // D4 on the joystick shield
+        .gpio_select = 21, // D6 on the joystick shield
+        .log_level = espp::Logger::Verbosity::WARN});
+    // and finally, make the task to periodically poll the controller and print
+    // the state
+    auto task_fn = [&quit_test, &controller](std::mutex &m, std::condition_variable &cv) {
+      controller.update();
+      bool is_a_pressed = controller.is_pressed(espp::Controller::Button::A);
+      bool is_b_pressed = controller.is_pressed(espp::Controller::Button::B);
+      bool is_select_pressed = controller.is_pressed(espp::Controller::Button::SELECT);
+      bool is_start_pressed = controller.is_pressed(espp::Controller::Button::START);
+      fmt::print("Controller buttons:\n"
+                 "\tA:      {}\n"
+                 "\tB:      {}\n"
+                 "\tSelect: {}\n"
+                 "\tStart:  {}\n",
+                 is_a_pressed, is_b_pressed, is_select_pressed, is_start_pressed);
+      quit_test = is_start_pressed && is_select_pressed;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Controller Task",
+                                    .stack_size_bytes = 6 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Analog Controller Example

+
    // make the adc we'll be reading from
+    std::vector<espp::AdcConfig> channels{
+        {.unit = ADC_UNIT_2,
+         .channel = ADC_CHANNEL_1, // (x) Analog 0 on the joystick shield
+         .attenuation = ADC_ATTEN_DB_12},
+        {.unit = ADC_UNIT_2,
+         .channel = ADC_CHANNEL_2, // (y) Analog 1 on the joystick shield
+         .attenuation = ADC_ATTEN_DB_12}};
+    espp::OneshotAdc adc(espp::OneshotAdc::Config{
+        .unit = ADC_UNIT_2,
+        .channels = channels,
+    });
+    // make the function which will get the raw data from the ADC and convert to
+    // uncalibrated [-1,1]
+    auto read_joystick = [&adc, &channels](float *x, float *y) -> bool {
+      auto maybe_x_mv = adc.read_mv(channels[0]);
+      auto maybe_y_mv = adc.read_mv(channels[1]);
+      if (maybe_x_mv.has_value() && maybe_y_mv.has_value()) {
+        auto x_mv = maybe_x_mv.value();
+        auto y_mv = maybe_y_mv.value();
+        *x = (x_mv / 1700.0f - 1.0f);
+        *y = (y_mv / 1700.0f - 1.0f);
+        return true;
+      }
+      return false;
+    };
+    // make the controller - NOTE: this was designed for connecting the Sparkfun
+    // Joystick Shield to the ESP32 S3 BOX
+    espp::Controller controller(espp::Controller::AnalogJoystickConfig{
+        // buttons short to ground, so they are active low. this will enable the
+        // GPIO_PULLUP and invert the logic
+        .active_low = true,
+        .gpio_a = 38,               // D3 on the joystick shield
+        .gpio_b = 39,               // D5 on the joystick shield
+        .gpio_x = -1,               // we're using this as start...
+        .gpio_y = -1,               // we're using this as select...
+        .gpio_start = 42,           // D4 on the joystick shield
+        .gpio_select = 21,          // D6 on the joystick shield
+        .gpio_joystick_select = -1, // D2 on the joystick shield
+        .joystick_config = {.x_calibration = {.center = 0.0f,
+                                              .center_deadband = 0.2f,
+                                              .minimum = -1.0f,
+                                              .maximum = 1.0f},
+                            .y_calibration = {.center = 0.0f,
+                                              .center_deadband = 0.2f,
+                                              .minimum = -1.0f,
+                                              .maximum = 1.0f},
+                            .get_values = read_joystick,
+                            .log_level = espp::Logger::Verbosity::WARN},
+        .log_level = espp::Logger::Verbosity::WARN});
+    // and finally, make the task to periodically poll the controller and print
+    // the state
+    auto task_fn = [&quit_test, &controller](std::mutex &m, std::condition_variable &cv) {
+      controller.update();
+      bool is_a_pressed = controller.is_pressed(espp::Controller::Button::A);
+      bool is_b_pressed = controller.is_pressed(espp::Controller::Button::B);
+      bool is_select_pressed = controller.is_pressed(espp::Controller::Button::SELECT);
+      bool is_start_pressed = controller.is_pressed(espp::Controller::Button::START);
+      bool is_up_pressed = controller.is_pressed(espp::Controller::Button::UP);
+      bool is_down_pressed = controller.is_pressed(espp::Controller::Button::DOWN);
+      bool is_left_pressed = controller.is_pressed(espp::Controller::Button::LEFT);
+      bool is_right_pressed = controller.is_pressed(espp::Controller::Button::RIGHT);
+      fmt::print("Controller buttons:\n"
+                 "\tA:      {}\n"
+                 "\tB:      {}\n"
+                 "\tSelect: {}\n"
+                 "\tStart:  {}\n"
+                 "\tUp:     {}\n"
+                 "\tDown:   {}\n"
+                 "\tLeft:   {}\n"
+                 "\tRight:  {}\n",
+                 is_a_pressed, is_b_pressed, is_select_pressed, is_start_pressed, is_up_pressed,
+                 is_down_pressed, is_left_pressed, is_right_pressed);
+      quit_test = is_start_pressed && is_select_pressed;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Controller Task",
+                                    .stack_size_bytes = 6 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

I2C Analog Controller Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_1,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+    // make the actual ads class
+    espp::Ads1x15 ads(espp::Ads1x15::Ads1015Config{
+        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3)});
+    // make the task which will get the raw data from the I2C ADC and convert to
+    // uncalibrated [-1,1]
+    std::atomic<float> joystick_x{0};
+    std::atomic<float> joystick_y{0};
+    auto ads_read_task_fn = [&joystick_x, &joystick_y, &ads](std::mutex &m,
+                                                             std::condition_variable &cv) {
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        using namespace std::chrono_literals;
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 20ms);
+      }
+      std::error_code ec;
+      auto x_mv = ads.sample_mv(1, ec);
+      if (ec) {
+        fmt::print("error reading x: {}\n", ec.message());
+        return false;
+      }
+      auto y_mv = ads.sample_mv(0, ec);
+      if (ec) {
+        fmt::print("error reading y: {}\n", ec.message());
+        return false;
+      }
+      joystick_x.store(x_mv / 1700.0f - 1.0f);
+      // y is inverted so negate it
+      joystick_y.store(-(y_mv / 1700.0f - 1.0f));
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto ads_task = espp::Task::make_unique({.callback = ads_read_task_fn,
+                                             .task_config =
+                                                 {
+                                                     .name = "ADS Task",
+                                                     .stack_size_bytes{4 * 1024},
+                                                 },
+                                             .log_level = espp::Logger::Verbosity::INFO});
+    ads_task->start();
+    // make the read joystick function used by the controller
+    auto read_joystick = [&joystick_x, &joystick_y](float *x, float *y) -> bool {
+      *x = joystick_x.load();
+      *y = joystick_y.load();
+      return true;
+    };
+    // make the controller - NOTE: this was designed for connecting the Adafruit
+    // JoyBonnet to the ESP32 S3 BOX
+    espp::Controller controller(espp::Controller::AnalogJoystickConfig{
+        // buttons short to ground, so they are active low. this will enable the
+        // GPIO_PULLUP and invert the logic
+        .active_low = true,
+        .gpio_a = 38,      // pin 32 on the joybonnet
+        .gpio_b = 39,      // pin 31 on the joybonnet
+        .gpio_x = -1,      // pin 36 on the joybonnet
+        .gpio_y = -1,      // pin 33 on the joybonnet
+        .gpio_start = 42,  // pin 37 on the joybonnet
+        .gpio_select = 21, // pin 38 on the joybonnet
+        .gpio_joystick_select = -1,
+        .joystick_config = {.x_calibration = {.center = 0.0f,
+                                              .center_deadband = 0.2f,
+                                              .minimum = -1.0f,
+                                              .maximum = 1.0f},
+                            .y_calibration = {.center = 0.0f,
+                                              .center_deadband = 0.2f,
+                                              .minimum = -1.0f,
+                                              .maximum = 1.0f},
+                            .get_values = read_joystick,
+                            .log_level = espp::Logger::Verbosity::WARN},
+        .log_level = espp::Logger::Verbosity::WARN});
+    // and finally, make the task to periodically poll the controller and print
+    // the state
+    auto task_fn = [&quit_test, &controller](std::mutex &m, std::condition_variable &cv) {
+      controller.update();
+      bool is_a_pressed = controller.is_pressed(espp::Controller::Button::A);
+      bool is_b_pressed = controller.is_pressed(espp::Controller::Button::B);
+      bool is_select_pressed = controller.is_pressed(espp::Controller::Button::SELECT);
+      bool is_start_pressed = controller.is_pressed(espp::Controller::Button::START);
+      bool is_up_pressed = controller.is_pressed(espp::Controller::Button::UP);
+      bool is_down_pressed = controller.is_pressed(espp::Controller::Button::DOWN);
+      bool is_left_pressed = controller.is_pressed(espp::Controller::Button::LEFT);
+      bool is_right_pressed = controller.is_pressed(espp::Controller::Button::RIGHT);
+      fmt::print("Controller buttons:\n"
+                 "\tA:      {}\n"
+                 "\tB:      {}\n"
+                 "\tSelect: {}\n"
+                 "\tStart:  {}\n"
+                 "\tUp:     {}\n"
+                 "\tDown:   {}\n"
+                 "\tLeft:   {}\n"
+                 "\tRight:  {}\n",
+                 is_a_pressed, is_b_pressed, is_select_pressed, is_start_pressed, is_up_pressed,
+                 is_down_pressed, is_left_pressed, is_right_pressed);
+      quit_test = is_start_pressed && is_select_pressed;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // we don't want to stop, return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Controller Task",
+                                    .stack_size_bytes = 6 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+enum class Button : int
+

The buttons that the controller supports.

+

Values:

+
+
+enumerator A
+
+ +
+
+enumerator B
+
+ +
+
+enumerator X
+
+ +
+
+enumerator Y
+
+ +
+
+enumerator SELECT
+
+ +
+
+enumerator START
+
+ +
+
+enumerator UP
+
+ +
+
+enumerator DOWN
+
+ +
+
+enumerator LEFT
+
+ +
+
+enumerator RIGHT
+
+ +
+
+enumerator JOYSTICK_SELECT
+
+ +
+
+enumerator LAST_UNUSED
+
+ +
+ +
+
+

Public Functions

+
+
+inline explicit Controller(const DigitalConfig &config)
+

Create a Digital controller.

+
+ +
+
+inline explicit Controller(const AnalogJoystickConfig &config)
+

Create an analog joystick controller.

+
+ +
+
+inline explicit Controller(const DualConfig &config)
+

Create a dual d-pad + analog joystick controller.

+
+ +
+
+inline ~Controller()
+

Destroys the controller and deletes the associated dedicated GPIO bundle.

+
+ +
+
+inline State get_state()
+

Get the most recent state structure for the controller.

+
+
Returns
+

State structure for the inputs - updated when update() was last called.

+
+
+
+ +
+
+inline bool is_pressed(const Button input)
+

Return true if the input was pressed, false otherwise.

+
+
Parameters
+

input – The Button of interest.

+
+
Returns
+

True if input was pressed last time update() was called.

+
+
+
+ +
+
+inline void update()
+

Read the current button values and update the internal input state accordingly.

+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct AnalogJoystickConfig
+

Configuration for the controller to be used with a joystick (which has a center-press / select button), no d-pad.

+
+

Note

+

In this configuration, the controller will create and manage a joystick component to read the analog axes of the joystick and convert them into digital up/down/left/right signals as a virtual d-pad.

+
+
+

Public Members

+
+
+bool active_low = {true}
+

Whether the buttons are active-low (default) or not.

+
+ +
+
+int gpio_a = {-1}
+

GPIO for the A button.

+
+ +
+
+int gpio_b = {-1}
+

GPIO for the B button.

+
+ +
+
+int gpio_x = {-1}
+

GPIO for the X button.

+
+ +
+
+int gpio_y = {-1}
+

GPIO for the Y button.

+
+ +
+
+int gpio_start = {-1}
+

GPIO for the START button.

+
+ +
+
+int gpio_select = {-1}
+

GPIO for the SELECT button.

+
+ +
+
+int gpio_joystick_select = {-1}
+

GPIO for the JOYSTICK SELECT button.

+
+ +
+
+espp::Joystick::Config joystick_config
+

Configuration for the analog joystick which will be used to read digital direction values.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+
+struct DigitalConfig
+

Configuration for the controller to use d-pad only, no joystick.

+
+

Public Members

+
+
+bool active_low = {true}
+

Whether the buttons are active-low (default) or not.

+
+ +
+
+int gpio_a = {-1}
+

GPIO for the A button.

+
+ +
+
+int gpio_b = {-1}
+

GPIO for the B button.

+
+ +
+
+int gpio_x = {-1}
+

GPIO for the X button.

+
+ +
+
+int gpio_y = {-1}
+

GPIO for the Y button.

+
+ +
+
+int gpio_start = {-1}
+

GPIO for the START button.

+
+ +
+
+int gpio_select = {-1}
+

GPIO for the SELECT button.

+
+ +
+
+int gpio_up = {-1}
+

GPIO for the UP button.

+
+ +
+
+int gpio_down = {-1}
+

GPIO for the DOWN button.

+
+ +
+
+int gpio_left = {-1}
+

GPIO for the LEFT button.

+
+ +
+
+int gpio_right = {-1}
+

GPIO for the RIGHT button.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+
+struct DualConfig
+

Configuration for the controller to be used with both a joystick (which has a center-press / select button), and a d-pad.

+
+

Note

+

In this configuration, the controller will NOT create / manage a joystick component. The configured d-pad provides the digital directions so the analog joystick values should be retrieved from a separately managed joystick component.

+
+
+

Public Members

+
+
+bool active_low = {true}
+

Whether the buttons are active-low (default) or not.

+
+ +
+
+int gpio_a = {-1}
+

GPIO for the A button.

+
+ +
+
+int gpio_b = {-1}
+

GPIO for the B button.

+
+ +
+
+int gpio_x = {-1}
+

GPIO for the X button.

+
+ +
+
+int gpio_y = {-1}
+

GPIO for the Y button.

+
+ +
+
+int gpio_start = {-1}
+

GPIO for the START button.

+
+ +
+
+int gpio_select = {-1}
+

GPIO for the SELECT button.

+
+ +
+
+int gpio_up = {-1}
+

GPIO for the UP button.

+
+ +
+
+int gpio_down = {-1}
+

GPIO for the DOWN button.

+
+ +
+
+int gpio_left = {-1}
+

GPIO for the LEFT button.

+
+ +
+
+int gpio_right = {-1}
+

GPIO for the RIGHT button.

+
+ +
+
+int gpio_joystick_select = {-1}
+

GPIO for the JOYSTICK SELECT button.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the logger.

+
+ +
+
+ +
+
+struct State
+

Packed bit structure containing the state (pressed=1) of each button.

+
+

Public Members

+
+
+uint32_t a
+

State of the A button.

+
+ +
+
+uint32_t b
+

State of the B button.

+
+ +
+
+uint32_t x
+

State of the X button.

+
+ +
+
+uint32_t y
+

State of the Y button.

+
+ +
+
+uint32_t select
+

State of the SELECT button.

+
+ +
+
+uint32_t start
+

State of the START button.

+
+ +
+
+uint32_t up
+

State of the UP button.

+
+ +
+
+uint32_t down
+

State of the DOWN button.

+
+ +
+
+uint32_t left
+

State of the LEFT button.

+
+ +
+
+uint32_t right
+

State of the RIGHT button.

+
+ +
+
+uint32_t joystick_select
+

State of the Joystick Select button.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/controller_example.html b/controller_example.html new file mode 100644 index 000000000..f7f6f17b5 --- /dev/null +++ b/controller_example.html @@ -0,0 +1,238 @@ + + + + + + + Controller Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Controller Example

+

This example shows how to use the Controller component to create various +different controller interface objects, such as:

+
    +
  • Digital input only controller (using the DigitalConfig) with only a couple of buttons (such as NES)

  • +
  • Analog and digital controller (with 1 joystick that has x/y axes) using the espp::OneshotAdc class with the Joystick

  • +
  • Analog controller with 2 joysticks using the espp::Ads1x15 component to read 4 analog axes over I2C.

  • +
+
+

How to use example

+

NOTE: this example cannot be run as-is. It’s designed to be illustrative and to +check various interfaces. To run the example, you should comment out / remove +the code for all tests except the one you wish to run.

+
+

Hardware Required

+

You may require analog inputs (raw) or an analog expander (ADS1015) if you want +to run those parts of the example. This was tested with the SparkFun Gamepad +Arduino Shield (for the raw input), and the Adafruit Controller PiHat (for the +Ads1015 test).

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/csv.html b/csv.html new file mode 100644 index 000000000..662d22159 --- /dev/null +++ b/csv.html @@ -0,0 +1,314 @@ + + + + + + + CSV APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CSV APIs

+

The csv.hpp header provides a convenience include / wrapper around +`p-ranav/csv2 <https://github.com/p-pranav/csv2`_. It also exposes csv2’s +include folder, so including csv.hpp is completely equivalent to including +both csv2/reader.hpp and csv2/writer.hpp. Please see the documentation for +csv2 if you have any questions about usage beyond the examples provided here.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Macros

+
+
+__gnu_linux__
+
+ +
+
+

Classes

+
+
+class __csv_documentation__
+

Comma Separated Value (CSV) reader/writer convenience wrapper around p-ranav/csv2 which exposes csv2::Reader and csv2::Writer classes for managing efficient (lazy-loaded) parsing and serizaliztion of human-readable CSV-formatted data.

+
+

CSV Reader Example

+
    std::string csv_data =
+        "filename, boxart filename, display name\n"
+        "mario.nes, boxart/mario.jpg, Mario Bros.\n"
+        "super_mario_1.nes, boxart/super_mario_bros_1.jpg, Super Mario Bros.\n"
+        "super_mario_3.nes, boxart/super_mario_bros_3.jpg, Super Mario Bros. 3\n"
+        "zelda.nes, boxart/zelda1.jpg, The Legend of Zelda\n"
+        "zelda_2.nes, boxart/zelda2.jpg, The Legend of Zelda 2: the Adventure of Link\n"
+        "mega_man.nes, boxart/megaman1.jpg, MegaMan\n"
+        "metroid.nes, boxart/metroid1.jpg, Metroid\n"
+        "pokemon_blue.gb, boxart/pokemon_blue.jpg, Pokemon Blue\n"
+        "pokemon_red.gb, boxart/pokemon_red.jpg, Pokemon Red\n"
+        "pokemon_yellow.gbc, boxart/pokemon_yellow.jpg, Pokemon Yellow\n"
+        "links_awakening.gb, boxart/tloz_links_awakening.jpg, The Legend of Zelda: Link's "
+        "Awakening\n"
+        "links_awakening.gbc, boxart/tloz_links_awakening_dx.jpg, The Legend of Zelda: Link's "
+        "Awakening DX";
+
+    // create the csv reader object
+    csv2::Reader<csv2::delimiter<','>, csv2::quote_character<'"'>, csv2::first_row_is_header<true>,
+                 csv2::trim_policy::trim_whitespace>
+        csv;
+    if (csv.parse(csv_data)) {
+      // print the header
+      const auto header = csv.header();
+      fmt::print("Header:\n\t");
+      for (const auto cell : header) {
+        std::string value;
+        cell.read_value(value);
+        fmt::print("'{}', ", value);
+      }
+      fmt::print("\n");
+      // now print the items
+      size_t row_index = 0;
+      for (const auto row : csv) {
+        fmt::print("Row {} values:\n\t", row_index);
+        for (const auto cell : row) {
+          std::string value;
+          cell.read_value(value);
+          fmt::print("'{}', ", value);
+        }
+        fmt::print("\n");
+        row_index++;
+      }
+    }
+
+
+
+
+

Complex CSV Writer Example

+
    std::ostringstream stream("");
+    csv2::Writer<csv2::delimiter<','>, std::ostringstream> writer(stream);
+
+    std::vector<std::vector<std::string>> rows = {
+        {"a", "b", "c"}, {"1", "2", "3"}, {"4", "5", "6"}};
+
+    writer.write_rows(rows);
+    fmt::print("Wrote:\n'{}'\n", stream.str());
+
+
+
+
+

Note

+

This class does not really exist or do anything, but it’s the only way I could figure out how to get this documentation built into the system :(

+
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/csv_example.html b/csv_example.html new file mode 100644 index 000000000..6db59a1a5 --- /dev/null +++ b/csv_example.html @@ -0,0 +1,226 @@ + + + + + + + CSV Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CSV Example

+

This example shows the use of the csv component to read and write CSV data.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/display/display.html b/display/display.html new file mode 100644 index 000000000..e27d2fb38 --- /dev/null +++ b/display/display.html @@ -0,0 +1,715 @@ + + + + + + + Display - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Display

+

The display component is responsible for managing the memory associated the +display buffer / video RAM (vram) and is also responsible for managing the +high-priority lvgl update task which sends data to the display.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<typename Pixel>
class Display : public espp::BaseComponent
+

Wrapper class around LVGL display buffer and display driver.

+

Optionally allocates and owns the memory associated with the pixel display buffers. Initializes the LVGL subsystem then starts and maintains a task which runs the high priority lv_tick_inc() function every update period (default = 10 ms).

+

For more information, see https://docs.lvgl.io/9.1/porting/display.html#display-interface

+
+
Template Parameters
+

Pixel – The pixel format to be used for the display. This allows the class to be used with displays of different color depths and formats.

+
+
+
+

Public Types

+
+
+using flush_fn = lv_display_flush_cb_t
+

Callback for lvgl to flush segments of pixel data from the pixel buffers to the display.

+
+ +
+
+typedef void (*rotation_fn)(const DisplayRotation &rotation)
+

Callback for lvgl event handler to reconfigure the display hardware.

+
+ +
+
+

Public Functions

+
+
+inline explicit Display(const AllocatingConfig &config)
+

Allocate the dsiplay buffers, initialize LVGL, then start the update task.

+
+
Parameters
+

configDisplay configuration including buffer size and flush callback.

+
+
+
+ +
+
+inline explicit Display(const NonAllocatingConfig &config)
+

Initialize LVGL then start the update task.

+
+
Parameters
+

configDisplay configuration including pointers to display buffer memory, the pixel buffer size and flush callback.

+
+
+
+ +
+
+inline ~Display()
+

Stops the upate task and frees the display buffer memory.

+
+ +
+
+inline size_t width() const
+

Return the configured width of the display in pixels.

+
+
Returns
+

size_t width of the display.

+
+
+
+ +
+
+inline size_t height() const
+

Return the configured height of the display in pixels.

+
+
Returns
+

size_t height of the display.

+
+
+
+ +
+
+inline void set_brightness(float brightness)
+

Set the brightness of the display.

+
+
Parameters
+

brightness – Brightness value between 0.0 and 1.0.

+
+
+
+ +
+
+inline float get_brightness() const
+

Get the brightness of the display.

+
+
Returns
+

float Brightness value between 0.0 and 1.0.

+
+
+
+ +
+
+inline void pause()
+

Pause the display update task, to prevent LVGL from writing to the display.

+
+ +
+
+inline void resume()
+

Resume the display update task, to allow LVGL to write to the display.

+
+ +
+
+inline void force_refresh() const
+

Force a redraw / refresh of the display.

+
+

Note

+

This is mainly useful after you have called pause() on the display (to draw to it with something other than LVGL) and want to switch back to the LVGL gui. Normally you should not call this function.

+
+
+ +
+
+inline Pixel *vram0()
+

Get pointer to main display buffer for custom writing.

+
+
Returns
+

uint16_t* Pointer to the main display buffer.

+
+
+
+ +
+
+inline Pixel *vram1()
+

Get pointer to secondary display buffer for custom writing.

+
+
Returns
+

uint16_t* Pointer to the secondary display buffer.

+
+
+
+ +
+
+inline size_t vram_size_px() const
+

Return the number of pixels that vram() can hold.

+
+
Returns
+

size_t Number of pixels that fit in the display buffer.

+
+
+
+ +
+
+inline size_t vram_size_bytes() const
+

Return the number of bytes that vram() can hold.

+
+
Returns
+

size_t Number of bytes that fit in the display buffer.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct AllocatingConfig
+

Used if you want the Display to manage the allocation / lifecycle of the display buffer memory itself.

+
+

Public Members

+
+
+size_t width
+

Width of th display, in pixels.

+
+ +
+
+size_t height
+

Height of the display, in pixels.

+
+ +
+
+size_t pixel_buffer_size
+

Size of the display buffer in pixels.

+
+ +
+
+flush_fn flush_callback
+

Function provided to LVGL for it to flush data to the display.

+
+ +
+
+rotation_fn rotation_callback{nullptr}
+

Function used to configure display with new rotation setting.

+
+ +
+
+gpio_num_t backlight_pin
+

GPIO pin for the backlight.

+
+ +
+
+bool backlight_on_value{true}
+

Value to write to the backlight pin to turn the backlight on.

+
+ +
+
+Task::BaseConfig task_config  {.name = "Display",.stack_size_bytes = 4096,.priority = 20,.core_id = 0}
+

Task configuration.

+
+ +
+
+std::chrono::duration<float> update_period{0.01}
+

How frequently to run the update function.

+
+ +
+
+bool double_buffered{true}
+

Whether to use double buffered rendering (two display buffers) or not.

+
+ +
+
+uint32_t allocation_flags{MALLOC_CAP_8BIT | MALLOC_CAP_DMA}
+

For configuring how the display buffer is allocated

+
+ +
+
+DisplayRotation rotation = {DisplayRotation::LANDSCAPE}
+

Default / Initial rotation of the display.

+
+ +
+
+bool software_rotation_enabled{true}
+

Enable LVGL software display rotation, incurs additional overhead.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Verbosity for the Display logger_.

+
+ +
+
+ +
+
+struct NonAllocatingConfig
+

Used if you want to manage allocation / lifecycle of the display buffer memory separately from this class. This structure allows you to configure the Display with up to two display buffers.

+
+

Public Members

+
+
+Pixel *vram0
+

Pointer to display buffer 1, that lvgl will use.

+
+ +
+
+Pixel *vram1
+

Pointer to display buffer 2 (if double buffered), that lvgl will use.

+
+ +
+
+size_t width
+

Width of th display, in pixels.

+
+ +
+
+size_t height
+

Height of the display, in pixels.

+
+ +
+
+size_t pixel_buffer_size
+

Size of the display buffer in pixels.

+
+ +
+
+flush_fn flush_callback
+

Function provided to LVGL for it to flush data to the display.

+
+ +
+
+rotation_fn rotation_callback{nullptr}
+

Function used to configure display with new rotation setting.

+
+ +
+
+gpio_num_t backlight_pin
+

GPIO pin for the backlight.

+
+ +
+
+bool backlight_on_value{true}
+

Value to write to the backlight pin to turn the backlight on.

+
+ +
+
+Task::BaseConfig task_config  {.name = "Display",.stack_size_bytes = 4096,.priority = 20,.core_id = 0}
+

Task configuration.

+
+ +
+
+std::chrono::duration<float> update_period{0.01}
+

How frequently to run the update function.

+
+ +
+
+DisplayRotation rotation = {DisplayRotation::LANDSCAPE}
+

Default / Initial rotation of the display.

+
+ +
+
+bool software_rotation_enabled{true}
+

Enable LVGL software display rotation, incurs additional overhead.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Verbosity for the Display logger_.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/display/display_drivers.html b/display/display_drivers.html new file mode 100644 index 000000000..b7f7bf9c3 --- /dev/null +++ b/display/display_drivers.html @@ -0,0 +1,1159 @@ + + + + + + + Display Drivers - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Display Drivers

+

ESPP contains a few different display drivers in the display_drivers +component, corresponding to common display drivers on espressif development +boards.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Gc9a01
+

Display driver for the GC9A01 display controller.

+

This code is modified from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/GC9A01.c

+

See also: https://github.com/espressif/esp-bsp/blob/master/components/lcd/esp_lcd_gc9a01/esp_lcd_gc9a01.c

+
+

SmartKnob Config

+
  static constexpr std::string_view dev_kit = "Smartknob-HA";
+  int clock_speed = 80 * 1000 * 1000;
+  auto spi_num = SPI2_HOST;
+  gpio_num_t mosi = GPIO_NUM_6;
+  gpio_num_t sclk = GPIO_NUM_5;
+  gpio_num_t spics = GPIO_NUM_15;
+  gpio_num_t reset = GPIO_NUM_4;
+  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
+  gpio_num_t backlight = GPIO_NUM_7;
+  size_t width = 240;
+  size_t height = 240;
+  size_t pixel_buffer_size = width * 50;
+  bool backlight_on_value = true;
+  bool reset_value = false;
+  bool invert_colors = true;
+  int offset_x = 0;
+  int offset_y = 0;
+  bool mirror_x = true;
+  bool mirror_y = true;
+  using DisplayDriver = espp::Gc9a01;
+  auto rotation = espp::DisplayRotation::LANDSCAPE;
+
+
+
+
+

Gc9a01 Example

+
    // create the spi host
+    spi_bus_config_t buscfg;
+    memset(&buscfg, 0, sizeof(buscfg));
+    buscfg.mosi_io_num = mosi;
+    buscfg.miso_io_num = -1;
+    buscfg.sclk_io_num = sclk;
+    buscfg.quadwp_io_num = -1;
+    buscfg.quadhd_io_num = -1;
+    buscfg.max_transfer_sz = (int)(pixel_buffer_size * sizeof(lv_color_t));
+    // create the spi device
+    spi_device_interface_config_t devcfg;
+    memset(&devcfg, 0, sizeof(devcfg));
+    devcfg.mode = 0;
+    devcfg.clock_speed_hz = clock_speed;
+    devcfg.input_delay_ns = 0;
+    devcfg.spics_io_num = spics;
+    devcfg.queue_size = spi_queue_size;
+    devcfg.pre_cb = lcd_spi_pre_transfer_callback;
+    devcfg.post_cb = lcd_spi_post_transfer_callback;
+    esp_err_t ret;
+    // Initialize the SPI bus
+    ret = spi_bus_initialize(spi_num, &buscfg, SPI_DMA_CH_AUTO);
+    ESP_ERROR_CHECK(ret);
+    // Attach the LCD to the SPI bus
+    ret = spi_bus_add_device(spi_num, &devcfg, &spi);
+    ESP_ERROR_CHECK(ret);
+
+    // initialize the controller
+    DisplayDriver::initialize(espp::display_drivers::Config{
+        .lcd_write = lcd_write,
+        .lcd_send_lines = lcd_send_lines,
+        .reset_pin = reset,
+        .data_command_pin = dc_pin,
+        .reset_value = reset_value,
+        .invert_colors = invert_colors,
+        .offset_x = offset_x,
+        .offset_y = offset_y,
+        .mirror_x = mirror_x,
+        .mirror_y = mirror_y,
+    });
+    // initialize the display / lvgl
+    auto display = std::make_shared<Display>(
+        Display::AllocatingConfig{.width = width,
+                                  .height = height,
+                                  .pixel_buffer_size = pixel_buffer_size,
+                                  .flush_callback = DisplayDriver::flush,
+                                  .rotation_callback = DisplayDriver::rotate,
+                                  .backlight_pin = backlight,
+                                  .backlight_on_value = backlight_on_value,
+                                  .rotation = rotation});
+
+    // initialize the gui
+    Gui gui({});
+    size_t iterations = 0;
+    while (true) {
+      auto label = fmt::format("Iterations: {}", iterations);
+      gui.set_label(label);
+      gui.set_meter(iterations % 100);
+      iterations++;
+      std::this_thread::sleep_for(100ms);
+    }
+
+
+
+
+

Public Static Functions

+
+
+static inline void initialize(const display_drivers::Config &config)
+

Store the config data and send the initialization commands to the display controller.

+
+
Parameters
+

config – display_drivers::Config structure

+
+
+
+ +
+
+static inline void rotate(const DisplayRotation &rotation)
+

Set the display rotation.

+
+
Parameters
+

rotation – New display rotation.

+
+
+
+ +
+
+static inline void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
+
+
+
+ +
+
+static inline void set_drawing_area(const lv_area_t *area)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+

*area – Pointer to lv_area_t strcuture with start/end x/y coordinates.

+
+
+
+ +
+
+static inline void set_drawing_area(size_t xs, size_t ys, size_t xe, size_t ye)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+
    +
  • xs – Starting x coordinate of the area.

  • +
  • ys – Starting y coordinate of the area.

  • +
  • xe – Ending x coordinate of the area.

  • +
  • ye – Ending y coordinate of the area.

  • +
+
+
+
+ +
+
+static inline void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
  • flags – uint32_t user data / flags to pass to the lcd_write transfer function.

  • +
+
+
+
+ +
+
+static inline void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000)
+

Clear the display area, filling it with the provided color.

+
+
Parameters
+
    +
  • x – X coordinate of the upper left corner of the display area.

  • +
  • y – Y coordinate of the upper left corner of the display area.

  • +
  • width – Width of the display area to clear.

  • +
  • height – Height of the display area to clear.

  • +
  • color – 16 bit color (default 0x0000) to fill with.

  • +
+
+
+
+ +
+
+static inline void send_command(uint8_t command)
+

Sends the command, sets flags such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_command(Command command)
+

Sends the command, sets flags such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_data(const uint8_t *data, size_t length, uint32_t flags = 0)
+

Send data to the display. Adds (1<<DC_LEVEL_BIT) to the flags so that the pre-cb receives it in user data and can configure the DC pin to data mode.

+
+
Parameters
+
    +
  • data – Pointer to array of bytes to be sent

  • +
  • length – Number of bytes of data to send.

  • +
  • flags – Optional (default = 0) flags associated with transfer.

  • +
+
+
+
+ +
+
+static inline void set_offset(int x, int y)
+

Set the offset (upper left starting coordinate) of the display.

+
+

Note

+

This modifies internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – New starting x coordinate (so writing to x address 0 later will actually write to this offset).

  • +
  • y – New starting y coordinate (so writing to y address 0 later will actually write to this offset).

  • +
+
+
+
+ +
+
+static inline void get_offset(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset().

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset().

  • +
+
+
+
+ +
+
+static inline void get_offset_rotated(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display after rotation.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class Ili9341
+

Display driver for the ILI9341 display controller.

+

This code is modified from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/ili9341.c and https://github.com/espressif/esp-dev-kits/blob/master/esp32-s2-hmi-devkit-1/components/screen/controller_driver/ili9341/ili9341.c

+

See also: https://github.com/espressif/esp-bsp/blob/master/components/lcd/esp_lcd_ili9341/esp_lcd_ili9341.c

+
+

WROVER-KIT ILI9341 Config

+
  static constexpr std::string_view dev_kit = "ESP-WROVER-DevKit";
+  int clock_speed = 20 * 1000 * 1000;
+  auto spi_num = SPI2_HOST;
+  gpio_num_t mosi = GPIO_NUM_23;
+  gpio_num_t sclk = GPIO_NUM_19;
+  gpio_num_t spics = GPIO_NUM_22;
+  gpio_num_t reset = GPIO_NUM_18;
+  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
+  gpio_num_t backlight = GPIO_NUM_5;
+  size_t width = 320;
+  size_t height = 240;
+  size_t pixel_buffer_size = 16384;
+  bool backlight_on_value = false;
+  bool reset_value = false;
+  bool invert_colors = false;
+  int offset_x = 0;
+  int offset_y = 0;
+  bool mirror_x = false;
+  bool mirror_y = false;
+  using DisplayDriver = espp::Ili9341;
+  auto rotation = espp::DisplayRotation::LANDSCAPE;
+
+
+
+
+

ili9341 Example

+
    // create the spi host
+    spi_bus_config_t buscfg;
+    memset(&buscfg, 0, sizeof(buscfg));
+    buscfg.mosi_io_num = mosi;
+    buscfg.miso_io_num = -1;
+    buscfg.sclk_io_num = sclk;
+    buscfg.quadwp_io_num = -1;
+    buscfg.quadhd_io_num = -1;
+    buscfg.max_transfer_sz = (int)(pixel_buffer_size * sizeof(lv_color_t));
+    // create the spi device
+    spi_device_interface_config_t devcfg;
+    memset(&devcfg, 0, sizeof(devcfg));
+    devcfg.mode = 0;
+    devcfg.clock_speed_hz = clock_speed;
+    devcfg.input_delay_ns = 0;
+    devcfg.spics_io_num = spics;
+    devcfg.queue_size = spi_queue_size;
+    devcfg.pre_cb = lcd_spi_pre_transfer_callback;
+    devcfg.post_cb = lcd_spi_post_transfer_callback;
+    esp_err_t ret;
+    // Initialize the SPI bus
+    ret = spi_bus_initialize(spi_num, &buscfg, SPI_DMA_CH_AUTO);
+    ESP_ERROR_CHECK(ret);
+    // Attach the LCD to the SPI bus
+    ret = spi_bus_add_device(spi_num, &devcfg, &spi);
+    ESP_ERROR_CHECK(ret);
+
+    // initialize the controller
+    DisplayDriver::initialize(espp::display_drivers::Config{
+        .lcd_write = lcd_write,
+        .lcd_send_lines = lcd_send_lines,
+        .reset_pin = reset,
+        .data_command_pin = dc_pin,
+        .reset_value = reset_value,
+        .invert_colors = invert_colors,
+        .offset_x = offset_x,
+        .offset_y = offset_y,
+        .mirror_x = mirror_x,
+        .mirror_y = mirror_y,
+    });
+    // initialize the display / lvgl
+    auto display = std::make_shared<Display>(
+        Display::AllocatingConfig{.width = width,
+                                  .height = height,
+                                  .pixel_buffer_size = pixel_buffer_size,
+                                  .flush_callback = DisplayDriver::flush,
+                                  .rotation_callback = DisplayDriver::rotate,
+                                  .backlight_pin = backlight,
+                                  .backlight_on_value = backlight_on_value,
+                                  .rotation = rotation});
+
+    // initialize the gui
+    Gui gui({});
+    size_t iterations = 0;
+    while (true) {
+      auto label = fmt::format("Iterations: {}", iterations);
+      gui.set_label(label);
+      gui.set_meter(iterations % 100);
+      iterations++;
+      std::this_thread::sleep_for(100ms);
+    }
+
+
+
+
+

Public Static Functions

+
+
+static inline void initialize(const display_drivers::Config &config)
+

Store the config data and send the initialization commands to the display controller.

+
+
Parameters
+

config – display_drivers::Config structure

+
+
+
+ +
+
+static inline void rotate(const DisplayRotation &rotation)
+

Set the display rotation.

+
+
Parameters
+

rotation – New display rotation.

+
+
+
+ +
+
+static inline void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
+
+
+
+ +
+
+static inline void set_drawing_area(const lv_area_t *area)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+

*area – Pointer to lv_area_t strcuture with start/end x/y coordinates.

+
+
+
+ +
+
+static inline void set_drawing_area(size_t xs, size_t ys, size_t xe, size_t ye)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+
    +
  • xs – Starting x coordinate of the area.

  • +
  • ys – Starting y coordinate of the area.

  • +
  • xe – Ending x coordinate of the area.

  • +
  • ye – Ending y coordinate of the area.

  • +
+
+
+
+ +
+
+static inline void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
  • flags – uint32_t user data / flags to pass to the lcd_write transfer function.

  • +
+
+
+
+ +
+
+static inline void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000)
+

Clear the display area, filling it with the provided color.

+
+
Parameters
+
    +
  • x – X coordinate of the upper left corner of the display area.

  • +
  • y – Y coordinate of the upper left corner of the display area.

  • +
  • width – Width of the display area to clear.

  • +
  • height – Height of the display area to clear.

  • +
  • color – 16 bit color (default 0x0000) to fill with.

  • +
+
+
+
+ +
+
+static inline void send_command(uint8_t command)
+

Sends the command, sets flags such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_command(Command command)
+

Sends the command, sets flags such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_data(const uint8_t *data, size_t length, uint32_t flags = 0)
+

Send data to the display. Adds (1<<DC_LEVEL_BIT) to the flags so that the pre-cb receives it in user data and can configure the DC pin to data mode.

+
+
Parameters
+
    +
  • data – Pointer to array of bytes to be sent

  • +
  • length – Number of bytes of data to send.

  • +
  • flags – Optional (default = 0) flags associated with transfer.

  • +
+
+
+
+ +
+
+static inline void set_offset(int x, int y)
+

Set the offset (upper left starting coordinate) of the display.

+
+

Note

+

This modifies internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – New starting x coordinate (so writing to x address 0 later will actually write to this offset).

  • +
  • y – New starting y coordinate (so writing to y address 0 later will actually write to this offset).

  • +
+
+
+
+ +
+
+static inline void get_offset(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset().

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset().

  • +
+
+
+
+ +
+
+static inline void get_offset_rotated(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display after rotation.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class St7789
+

Display driver for the ST7789 display controller.

+

This code is modified from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/st7789.c and https://github.com/Bodmer/TFT_eSPI/blob/master/TFT_Drivers/ST7789_Defines.h

+

See also: https://github.com/espressif/esp-who/blob/master/components/screen/controller_driver/st7789/st7789.c or https://github.com/espressif/tflite-micro-esp-examples/blob/master/components/screen/controller_driver/st7789/st7789.c or https://esphome.io/api/st7789v_8h_source.html or https://github.com/mireq/esp32-st7789-demo/blob/master/components/st7789/include/st7789.h or https://github.com/mireq/esp32-st7789-demo/blob/master/components/st7789/st7789.c

+
+

TTGO St7789 Config

+
  static constexpr std::string_view dev_kit = "TTGO T-Display";
+  int clock_speed = 60 * 1000 * 1000;
+  auto spi_num = SPI2_HOST;
+  gpio_num_t mosi = GPIO_NUM_19;
+  gpio_num_t sclk = GPIO_NUM_18;
+  gpio_num_t spics = GPIO_NUM_5;
+  gpio_num_t reset = GPIO_NUM_23;
+  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
+  gpio_num_t backlight = GPIO_NUM_4;
+  size_t width = 240;
+  size_t height = 135;
+  size_t pixel_buffer_size = 12800;
+  bool backlight_on_value = false;
+  bool reset_value = false;
+  bool invert_colors = false;
+  int offset_x = 40;
+  int offset_y = 53;
+  bool mirror_x = false;
+  bool mirror_y = false;
+  using DisplayDriver = espp::St7789;
+  auto rotation = espp::DisplayRotation::PORTRAIT;
+
+
+
+
+

ESP32-S3-BOX St7789 Config

+
  static constexpr std::string_view dev_kit = "ESP32-S3-BOX";
+  int clock_speed = 60 * 1000 * 1000;
+  auto spi_num = SPI2_HOST;
+  gpio_num_t mosi = GPIO_NUM_6;
+  gpio_num_t sclk = GPIO_NUM_7;
+  gpio_num_t spics = GPIO_NUM_5;
+  gpio_num_t reset = GPIO_NUM_48;
+  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
+  gpio_num_t backlight = GPIO_NUM_45;
+  size_t width = 320;
+  size_t height = 240;
+  size_t pixel_buffer_size = width * 50;
+  bool backlight_on_value = true;
+  bool reset_value = false;
+  bool invert_colors = true;
+  int offset_x = 0;
+  int offset_y = 0;
+  bool mirror_x = true;
+  bool mirror_y = true;
+  using DisplayDriver = espp::St7789;
+  auto rotation = espp::DisplayRotation::LANDSCAPE;
+
+
+
+
+

st7789 Example

+
    // create the spi host
+    spi_bus_config_t buscfg;
+    memset(&buscfg, 0, sizeof(buscfg));
+    buscfg.mosi_io_num = mosi;
+    buscfg.miso_io_num = -1;
+    buscfg.sclk_io_num = sclk;
+    buscfg.quadwp_io_num = -1;
+    buscfg.quadhd_io_num = -1;
+    buscfg.max_transfer_sz = (int)(pixel_buffer_size * sizeof(lv_color_t));
+    // create the spi device
+    spi_device_interface_config_t devcfg;
+    memset(&devcfg, 0, sizeof(devcfg));
+    devcfg.mode = 0;
+    devcfg.clock_speed_hz = clock_speed;
+    devcfg.input_delay_ns = 0;
+    devcfg.spics_io_num = spics;
+    devcfg.queue_size = spi_queue_size;
+    devcfg.pre_cb = lcd_spi_pre_transfer_callback;
+    devcfg.post_cb = lcd_spi_post_transfer_callback;
+    esp_err_t ret;
+    // Initialize the SPI bus
+    ret = spi_bus_initialize(spi_num, &buscfg, SPI_DMA_CH_AUTO);
+    ESP_ERROR_CHECK(ret);
+    // Attach the LCD to the SPI bus
+    ret = spi_bus_add_device(spi_num, &devcfg, &spi);
+    ESP_ERROR_CHECK(ret);
+
+    // initialize the controller
+    DisplayDriver::initialize(espp::display_drivers::Config{
+        .lcd_write = lcd_write,
+        .lcd_send_lines = lcd_send_lines,
+        .reset_pin = reset,
+        .data_command_pin = dc_pin,
+        .reset_value = reset_value,
+        .invert_colors = invert_colors,
+        .offset_x = offset_x,
+        .offset_y = offset_y,
+        .mirror_x = mirror_x,
+        .mirror_y = mirror_y,
+    });
+    // initialize the display / lvgl
+    auto display = std::make_shared<Display>(
+        Display::AllocatingConfig{.width = width,
+                                  .height = height,
+                                  .pixel_buffer_size = pixel_buffer_size,
+                                  .flush_callback = DisplayDriver::flush,
+                                  .rotation_callback = DisplayDriver::rotate,
+                                  .backlight_pin = backlight,
+                                  .backlight_on_value = backlight_on_value,
+                                  .rotation = rotation});
+
+    // initialize the gui
+    Gui gui({});
+    size_t iterations = 0;
+    while (true) {
+      auto label = fmt::format("Iterations: {}", iterations);
+      gui.set_label(label);
+      gui.set_meter(iterations % 100);
+      iterations++;
+      std::this_thread::sleep_for(100ms);
+    }
+
+
+
+
+

Public Static Functions

+
+
+static inline void initialize(const display_drivers::Config &config)
+

Store the config data and send the initialization commands to the display controller.

+
+
Parameters
+

config – display_drivers::Config structure

+
+
+
+ +
+
+static inline void rotate(const DisplayRotation &rotation)
+

Set the display rotation.

+
+
Parameters
+

rotation – New display rotation.

+
+
+
+ +
+
+static inline void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
+
+
+
+ +
+
+static inline void set_drawing_area(const lv_area_t *area)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+

*area – Pointer to lv_area_t strcuture with start/end x/y coordinates.

+
+
+
+ +
+
+static inline void set_drawing_area(size_t xs, size_t ys, size_t xe, size_t ye)
+

Set the drawing area for the display, resets the cursor to the starting position of the area.

+
+
Parameters
+
    +
  • xs – Starting x coordinate of the area.

  • +
  • ys – Starting y coordinate of the area.

  • +
  • xe – Ending x coordinate of the area.

  • +
  • ye – Ending y coordinate of the area.

  • +
+
+
+
+ +
+
+static inline void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
+

Flush the pixel data for the provided area to the display.

+
+
Parameters
+
    +
  • *drv – Pointer to the LVGL display driver.

  • +
  • *area – Pointer to the structure describing the pixel area.

  • +
  • *color_map – Pointer to array of colors to flush to the display.

  • +
  • flags – uint32_t user data / flags to pass to the lcd_write transfer function.

  • +
+
+
+
+ +
+
+static inline void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000)
+

Clear the display area, filling it with the provided color.

+
+
Parameters
+
    +
  • x – X coordinate of the upper left corner of the display area.

  • +
  • y – Y coordinate of the upper left corner of the display area.

  • +
  • width – Width of the display area to clear.

  • +
  • height – Height of the display area to clear.

  • +
  • color – 16 bit color (default 0x0000) to fill with.

  • +
+
+
+
+ +
+
+static inline void send_command(uint8_t command)
+

Sends the command, sets flags (to 0) such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_command(Command command)
+

Sends the command, sets flags such that the pre-cb should set the DC pin to command mode.

+
+
Parameters
+

command – Command code to send

+
+
+
+ +
+
+static inline void send_data(const uint8_t *data, size_t length, uint32_t flags = 0)
+

Send data to the display. Adds (1<<DC_LEVEL_BIT) to the flags so that the pre-cb receives it in user data and can configure the DC pin to data mode.

+
+
Parameters
+
    +
  • data – Pointer to array of bytes to be sent

  • +
  • length – Number of bytes of data to send.

  • +
  • flags – Optional (default = 0) flags associated with transfer.

  • +
+
+
+
+ +
+
+static inline void set_offset(int x, int y)
+

Set the offset (upper left starting coordinate) of the display.

+
+

Note

+

This modifies internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – New starting x coordinate (so writing to x address 0 later will actually write to this offset).

  • +
  • y – New starting y coordinate (so writing to y address 0 later will actually write to this offset).

  • +
+
+
+
+ +
+
+static inline void get_offset(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset().

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset().

  • +
+
+
+
+ +
+
+static inline void get_offset_rotated(int &x, int &y)
+

Get the offset (upper left starting coordinate) of the display after rotation.

+
+

Note

+

This returns internal variables that are used when sending coordinates / filling parts of the display.

+
+
+
Parameters
+
    +
  • x – Reference variable that will be filled with the currently configured starting x coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
  • y – Reference variable that will be filled with the currently configured starting y coordinate that was provided in the config or set by set_offset(), updated for the current rotation.

  • +
+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/display/display_drivers_example.html b/display/display_drivers_example.html new file mode 100644 index 000000000..8750357b0 --- /dev/null +++ b/display/display_drivers_example.html @@ -0,0 +1,257 @@ + + + + + + + Display Drivers Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Display Drivers Example

+

This example is designed to show how the display_drivers component can be used +to drive various different displays with LVGL and a simple GUI (that is +contained within the example: main/gui.hpp).

+
+

How to use example

+
+

Hardware Required

+

This example can be configured to run on the following dev boards:

+
    +
  • ESP32-WROVER-Kit

  • +
  • TTGO T-Display

  • +
  • ESP32-S3-BOX

  • +
  • Smartknob-HA

  • +
+
+
+

Configure the project

+
idf.py menuconfig
+
+
+

When configuring the project, select the Display Drivers Example Configuration +value that matches the board you’ve selected (must be one of the 4 boards +mentioned above.)

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Breakdown

+

The example has the following functionality:

+
    +
  • SPI pre and post transfer callbacks for handling the data/command (DC_LEVEL) +GPIO for the screens and the lvgl flush flag management

  • +
  • lcd_write for polling (blocking) transmit example

  • +
  • lcd_send_lines and lcd_wait_lines for queued (non-blocking) transmit example

  • +
  • Gui class (contained in main/gui.hpp) which encapsulates some very basic +LVGL components into an object that manages gui update task and synchronization.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/display/index.html b/display/index.html new file mode 100644 index 000000000..2b597d935 --- /dev/null +++ b/display/index.html @@ -0,0 +1,208 @@ + + + + + + + Display APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/encoder/abi_encoder.html b/encoder/abi_encoder.html new file mode 100644 index 000000000..f59b797a3 --- /dev/null +++ b/encoder/abi_encoder.html @@ -0,0 +1,621 @@ + + + + + + + ABI Encoder - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ABI Encoder

+

The AbiEncoder allow the user a configurable container wrapping the pulse +count +ESP peripheral api as it would be configured for an incremental encoder with +quadrature output (see Wikipedia). The AbiEncoder can be +configured to be either LINEAR or ROTATIONAL, and provides access to the +current count of the encoder (including the overflow underflow conditions).

+

Code examples for the ABI Encoder are provided in the encoder example folder.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<EncoderType T = EncoderType::ROTATIONAL>
class AbiEncoder : public espp::BaseComponent
+

Class providing ABI/Z encoder functionality using the pulse count hardware in the ESP chips. Can be configured to measure purely linear (EncoderType::LINEAR) position or rotational (EncoderType::ROTATIONAL) position.

+
+

AbiEncoder (ROTATIONAL) Example

+
    espp::AbiEncoder<espp::EncoderType::ROTATIONAL> encoder({
+        .a_gpio = 9,
+        .b_gpio = 10,
+        .high_limit = 8192,
+        .low_limit = -8192,
+        .counts_per_revolution = 4096,
+    });
+    encoder.start();
+    auto task_fn = [&encoder](std::mutex &m, std::condition_variable &cv) {
+      auto count = encoder.get_count();
+      auto radians = encoder.get_radians();
+      auto degrees = encoder.get_degrees();
+      fmt::print("CRD: [{}, {:.3f}, {:.1f}]\n", count, radians, degrees);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 250ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Abi Encoder"},
+                            .log_level = espp::Logger::Verbosity::INFO});
+    task.start();
+
+
+
+
+

AbiEncoder (LINEAR) Example

+
    espp::AbiEncoder<espp::EncoderType::LINEAR> encoder({
+        .a_gpio = 9,
+        .b_gpio = 10,
+        .high_limit = 8192,
+        .low_limit = -8192,
+    });
+    encoder.start();
+    auto task_fn = [&encoder](std::mutex &m, std::condition_variable &cv) {
+      // EncoderType::LINEAR only supports get_count
+      auto count = encoder.get_count();
+      fmt::print("Count: {}\n", count);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 250ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Abi Encoder"},
+                            .log_level = espp::Logger::Verbosity::INFO});
+    task.start();
+
+
+
+
+

Public Functions

+
+
+template<EncoderType type = T>
inline explicit AbiEncoder(const Config &config)
+

Initialize the pulse count hardware for the ABI encoder.

+
+

Note

+

This does not start the pulse count hardware, for that you must call the start() method at least once.

+
+
+ +
+
+inline ~AbiEncoder()
+

Stop the pulse count hardware then disable and delete the channels / units associated with this AbiEncoder.

+
+ +
+
+inline int get_count()
+

Get the total count (including under/overflows) since it was created or clear()-ed last.

+
+
Returns
+

Total count as a signed integer.

+
+
+
+ +
+
+inline float get_revolutions()
+

Get the total number of revolutions this ABI encoder has measured since it was created or clear()-ed last.

+
+

Note

+

This is only available if the AbiEncoder is EncoderType::ROTATIONAL.

+
+
+
Returns
+

Number of revolutions, as a floating point number.

+
+
+
+ +
+
+inline float get_radians()
+

Get the total number of radians this ABI encoder has measured since it was created or clear()-ed last.

+
+

Note

+

This is only available if the AbiEncoder is EncoderType::ROTATIONAL.

+
+
+
Returns
+

Number of radians, as a floating point number.

+
+
+
+ +
+
+inline float get_degrees()
+

Get the total number of degrees this ABI encoder has measured since it was created or clear()-ed last.

+
+

Note

+

This is only available if the AbiEncoder is EncoderType::ROTATIONAL.

+
+
+
Returns
+

Number of degrees, as a floating point number.

+
+
+
+ +
+
+inline bool start()
+

Start the pulse count hardware.

+
+
Returns
+

True if it was successfully started.

+
+
+
+ +
+
+inline bool stop()
+

Stop the pulse count hardware.

+
+

Note

+

This does not clear the counter so calling start() later will allow it to pick up where it left off.

+
+
+
Returns
+

True if it was successfully stopped.

+
+
+
+ +
+
+inline bool clear()
+

Clear the hardware counter and internal accumulator.

+
+
Returns
+

True if the pulse count hardware was cleared.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+
+

Public Members

+
+
+int a_gpio
+

GPIO number for the a channel pulse.

+
+ +
+
+int b_gpio
+

GPIO number for the b channel pulse.

+
+ +
+
+int i_gpio = {-1}
+

GPIO number for the index (I/Z) pulse).

+
+

Note

+

This is currently unused.

+
+
+ +
+
+int16_t high_limit
+

High limit for the hardware counter before it resets to 0. Lowering (to zero) this value increases the number of interrupts / overflows of the counter.

+
+ +
+
+int16_t low_limit
+

Low limit for the hardware counter before it resets to 0. Lowering (to zero) this value increases the number of interrupts / overflows of the counter.

+
+ +
+
+size_t counts_per_revolution = {0}
+

How many counts equate to a single revolution.

+
+

Note

+

this unused if the type is not EncoderType::ROTATIONAL.

+
+
+ +
+
+size_t max_glitch_ns = {1000}
+

Max glitch witdth in nanoseconds that is ignored. 0 will disable the glitch filter.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the adc logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/as5600.html b/encoder/as5600.html new file mode 100644 index 000000000..f4453b0cf --- /dev/null +++ b/encoder/as5600.html @@ -0,0 +1,912 @@ + + + + + + + AS5600 Magnetic Encoder - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AS5600 Magnetic Encoder

+

The AS5600 magnetic encoder component provides the user a convenient way to +measure

+
    +
  • Raw count

  • +
  • Raw radians

  • +
  • Raw degrees

  • +
  • Accumulated count (since the component was created)

  • +
  • Accumulated radians (since the component was created)

  • +
  • Accumulated degrees (since the component was created)

  • +
  • Speed (rotations per minute / RPM)

  • +
+

It does so by spawning a task which periodically reads the magnetic encoder, +updates the accumulator, and computes the velocity. The component can be +configured to optionally filter the velocity.

+

The periodicity / update rate of the encoder can be configured at time of +creation.

+

The encoder is designed to fulfill the needs of the BldcMotor API, to provide +closed-loop motor control.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class As5600 : public espp::BasePeripheral<>
+

Class for position and velocity measurement using a AS5600 magnetic encoder. This class starts its own measurement task at the specified frequency which reads the current angle, updates the accumulator, and filters / updates the velocity measurement. The datasheet for the AS5600 can be found here: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf/649ee61c-8f9a-20df-9e10-43173a3eb323.

+
+

As5600 Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_1,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+
+    // make the velocity filter
+    static constexpr float filter_cutoff_hz = 4.0f;
+    static constexpr float encoder_update_period = 0.01f; // seconds
+    espp::ButterworthFilter<2, espp::BiquadFilterDf2> filter(
+        {.normalized_cutoff_frequency = 2.0f * filter_cutoff_hz * encoder_update_period});
+    // NOTE: we could just as easily disable filtering by simply returning the
+    // raw value from this function
+    auto filter_fn = [&filter](float raw) -> float { return filter.update(raw); };
+
+    // now make the as5600 which decodes the data
+    espp::As5600 as5600(
+        {.write_then_read =
+             std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                       std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
+         .velocity_filter = filter_fn,
+         .update_period = std::chrono::duration<float>(encoder_update_period),
+         .log_level = espp::Logger::Verbosity::WARN});
+
+    // and finally, make the task to periodically poll the as5600 and print the
+    // state. NOTE: the As5600 runs its own task to maintain state, so we're
+    // just polling the current state.
+    auto task_fn = [&quit_test, &as5600](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds = std::chrono::duration<float>(now - start).count();
+      auto count = as5600.get_count();
+      auto radians = as5600.get_radians();
+      auto degrees = as5600.get_degrees();
+      auto rpm = as5600.get_rpm();
+      fmt::print("{:.3f}, {}, {:.3f}, {:.3f}, {:.3f}\n", seconds, count, radians, degrees, rpm);
+      quit_test = degrees <= -720.0f;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "As5600 Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    fmt::print("%time(s), count, radians, degrees, rpm\n");
+    task.start();
+
+
+
+
+

Note

+

There is an implicit assumption in this class regarding the maximum velocity it can measure (above which there will be aliasing). The fastest velocity it can measure will be (0.5f * update_period * 60.0f) which is half a rotation in one update period.

+
+
+

Note

+

The assumption above also affects the reliability of the accumulator, since it is based on accumulating position differences every update period.

+
+
+

Public Types

+
+
+typedef std::function<float(float raw)> velocity_filter_fn
+

Filter the input raw velocity and return it.

+
+
Param raw
+

Most recent raw velocity measured.

+
+
Return
+

Filtered velocity.

+
+
+
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit As5600(const Config &config)
+

Construct the As5600 and start the update task.

+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the sensor.

+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline bool needs_zero_search() const
+

Return whether the sensor has found absolute 0 yet.

+
+

Note

+

The AS5600 (using I2C/SPI) does not need to search for absolute 0 and will always know it on startup. Therefore this function always returns false.

+
+
+
Returns
+

True because the magnetic sensor (using I2C/SPI) does not need to sarch for 0.

+
+
+
+ +
+
+inline int get_count() const
+

Get the most recently updated raw count value from the encoder.

+
+

Note

+

This value always represents the angle of the encoder modulo one rotation, meaning it only represents the range 0 to 360 degrees. It is not recommended to use this function, but is provided for edge use cases.

+
+
+
Returns
+

Raw count value in the range [0, 16384] (0 to 360 degrees).

+
+
+
+ +
+
+inline int get_accumulator() const
+

Return the accumulated count that the encoder has generated since it was initialized.

+
+

Note

+

This value is a raw counter value that can be +/-, meaning COUNTS_PER_REVOLUTION can be used to convert it to revolutions.

+
+
+
Returns
+

Raw accumulator value.

+
+
+
+ +
+
+inline float get_mechanical_radians() const
+

Return the mechanical / shaft angle of the encoder, in radians, within the range [0, 2pi].

+
+
Returns
+

Angle in radians of the encoder within the range [0, 2pi].

+
+
+
+ +
+
+inline float get_mechanical_degrees() const
+

Return the mechanical / shaft angle of the encoder, in degrees, within the range [0, 360].

+
+
Returns
+

Angle in degrees of the encoder within the range [0, 360].

+
+
+
+ +
+
+inline float get_radians() const
+

Return the accumulated position of the encoder, in radians.

+
+

Note

+

This can be any value, it is not restricted to [-2pi, 2pi].

+
+
+
Returns
+

Position in radians of the encoder.

+
+
+
+ +
+
+inline float get_degrees() const
+

Return the accumulated position of the encoder, in degrees.

+
+

Note

+

This can be any value, it is not restricted to [-360, 360].

+
+
+
Returns
+

Position in degrees of the encoder.

+
+
+
+ +
+
+inline float get_rpm() const
+

Return the filtered velocity of the encoder, in RPM.

+
+
Returns
+

Filtered velocity (revolutions / minute, RPM).

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0b0110110)
+

I2C address of the AS5600.

+
+ +
+
+static constexpr int COUNTS_PER_REVOLUTION = 16384
+

Int number of counts per revolution for the magnetic encoder.

+
+ +
+
+static constexpr float COUNTS_PER_REVOLUTION_F = 16384.0f
+

Float number of counts per revolution for the magnetic encoder.

+
+ +
+
+static constexpr float COUNTS_TO_RADIANS = 2.0f * M_PI / COUNTS_PER_REVOLUTION_F
+

Conversion factor to convert from count value to radians.

+
+ +
+
+static constexpr float COUNTS_TO_DEGREES = 360.0f / COUNTS_PER_REVOLUTION_F
+

Conversion factor to convert from count value to degrees.

+
+ +
+
+static constexpr float SECONDS_PER_MINUTE = 60.0f
+

Conversion factor to convert from seconds to minutes.

+
+ +
+
+
+struct Config
+

Configuration information for the As5600.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address for this device.

+
+ +
+
+BasePeripheral::write_then_read_fn write_then_read
+

Function to write then read from the device.

+
+ +
+
+velocity_filter_fn velocity_filter = {nullptr}
+

Function to filter the veolcity.

+
+

Note

+

Will be called once every update_period seconds.

+
+
+ +
+
+std::chrono::duration<float> update_period{.01f}
+

Update period (1/sample rate) in seconds. This determines the periodicity of the task which will read the position, update the accumulator, and update/filter velocity.

+
+ +
+
+bool auto_init = {true}
+

Whether to automatically initialize the accumulator to the current position.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/as5600_example.html b/encoder/as5600_example.html new file mode 100644 index 000000000..6016fe4f0 --- /dev/null +++ b/encoder/as5600_example.html @@ -0,0 +1,254 @@ + + + + + + + As5600 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + + + + +

Supported Targets

ESP32-S3

+

This example currently uses GPIO 40 and 41 as the I2C lines, so it only supports +ESP32-S3. If you wish to use a different chip / board, changes those and rebuild.

+
+

As5600 Example

+

This example shows the use of the As5600 component to communicate with an +AS5600 I2C magnetic encoder chip.

+

It uses the task component to periodically read the raw count, position, and +velocity of the encoder, the filters component (specifically the +espp::ButterworthFilter class) to filter the raw values from the sensor, and +the format component to print the data to the console in CSV format.

+
+

How to use example

+
+

Hardware Required

+

This requires a AS5600 magnetic encoder dev board with an diametric magnet and +the AS5600 dev board should be connected to the ESP dev board you choose via +I2C.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

Here is some example output plotted using the uart serial +plotter:

+

example outputplotted

+

For more information, see the original PR that included this component: +https://github.com/esp-cpp/espp/pull/5

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/encoder_example.html b/encoder/encoder_example.html new file mode 100644 index 000000000..2cbb93e62 --- /dev/null +++ b/encoder/encoder_example.html @@ -0,0 +1,233 @@ + + + + + + + Encoder Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Encoder Example

+

This example shows the use of the espp::AbiEncoder from the encoder +component. It showcases both the EncoderType::ROTATIONAL and +EncoderType::LINEAR uses of the AbiEncoder.

+
+

How to use example

+
+

Hardware Required

+

This example requires some hardware attached which provides ABI/ABZ (quadrature +encoder) input. An example is the ABI/ABZ output provided by the Mt6701 +encoder and the AS5600 encoder.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/encoder_types.html b/encoder/encoder_types.html new file mode 100644 index 000000000..1e49704a5 --- /dev/null +++ b/encoder/encoder_types.html @@ -0,0 +1,220 @@ + + + + + + + Encoder Types - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Encoder Types

+

Type definitions for the different kinds of encoders supported. Used as template +specialization parameters when constructing encoders.

+
+

API Reference

+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/index.html b/encoder/index.html new file mode 100644 index 000000000..e1f7f935e --- /dev/null +++ b/encoder/index.html @@ -0,0 +1,213 @@ + + + + + + + Encoder APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Encoder APIs

+ +

There are several different types of encoders provided, some within the encoder +component directly, as well as some that are standalone components for +interacting with encoder chips over a serial interface such as I2C.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/mt6701.html b/encoder/mt6701.html new file mode 100644 index 000000000..df0ef61a4 --- /dev/null +++ b/encoder/mt6701.html @@ -0,0 +1,1168 @@ + + + + + + + MT6701 Magnetic Encoder - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MT6701 Magnetic Encoder

+

The MT6701 magnetic encoder component provides the user a convenient way to +measure

+
    +
  • Raw count

  • +
  • Raw radians

  • +
  • Raw degrees

  • +
  • Accumulated count (since the component was created)

  • +
  • Accumulated radians (since the component was created)

  • +
  • Accumulated degrees (since the component was created)

  • +
  • Speed (rotations per minute / RPM)

  • +
+

It does so by spawning a task which periodically reads the magnetic encoder, +updates the accumulator, and computes the velocity. The component can be +configured to optionally filter the velocity.

+

The periodicity / update rate of the encoder can be configured at time of +creation.

+

The encoder is designed to fulfill the needs of the BldcMotor API, to provide +closed-loop motor control.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<Mt6701Interface Interface = Mt6701Interface::I2C>
class Mt6701 : public espp::BasePeripheral<uint8_t, Mt6701Interface::I2C == Mt6701Interface::I2C>
+

Class for position and velocity measurement using a MT6701 magnetic encoder. This class starts its own measurement task at the specified frequency which reads the current angle, updates the accumulator, and filters / updates the velocity measurement. The Mt6701 supports I2C, SSI, ABZ, UVW, Analog/PWM, and Push-Button interfaces.

+
+

Mt6701 I2C Example

+
    std::atomic<bool> quit_test = false;
+
+    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .clk_speed = 1 * 1000 * 1000, // MT6701 supports 1 MHz I2C
+    });
+
+    // make the velocity filter
+    static constexpr float filter_cutoff_hz = 10.0f;
+    static constexpr float encoder_update_period = 0.001f; // seconds
+    espp::ButterworthFilter<2, espp::BiquadFilterDf2> filter(
+        {.normalized_cutoff_frequency = 2.0f * filter_cutoff_hz * encoder_update_period});
+    auto filter_fn = [&filter](float raw) -> float { return filter.update(raw); };
+
+    // now make the mt6701 which decodes the data
+    using Mt6701 = espp::Mt6701<espp::Mt6701Interface::I2C>;
+    Mt6701 mt6701(
+        Mt6701::Config{.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                          std::placeholders::_2, std::placeholders::_3),
+                       .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                         std::placeholders::_2, std::placeholders::_3),
+                       .velocity_filter = filter_fn,
+                       .update_period = std::chrono::duration<float>(encoder_update_period),
+                       .run_task = true, // run a task which calls the update function at the update
+                                         // period
+                       .log_level = espp::Logger::Verbosity::WARN});
+
+    // NOTE: since this is I2C, we cannot get the magnetic field strength,
+    // tracking status, or push button state
+
+    // and finally, make the task to periodically poll the mt6701 and print the
+    // state. NOTE: the Mt6701 runs its own task to maintain state, so we're
+    // just polling the current state.
+    auto task_fn = [&quit_test, &mt6701](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds = std::chrono::duration<float>(now - start).count();
+      auto count = mt6701.get_count();
+      auto radians = mt6701.get_radians();
+      auto degrees = mt6701.get_degrees();
+      auto rpm = mt6701.get_rpm();
+      fmt::print("{:.3f}, {}, {:.3f}, {:.3f}, {:.3f}\n", seconds, count, radians, degrees, rpm);
+      quit_test = degrees <= -720.0f;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 10ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Mt6701 Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    fmt::print("% time(s), count, radians, degrees, rpm\n");
+    task.start();
+
+
+
+
+

Mt6701 SSI / SPI Example

+
    std::atomic<bool> quit_test = false;
+
+    // make the SSI (SPI) that we'll use to communicate
+
+    // create the spi host
+    spi_device_handle_t encoder_spi_handle;
+    spi_bus_config_t buscfg;
+    memset(&buscfg, 0, sizeof(buscfg));
+    buscfg.mosi_io_num = -1;
+    buscfg.miso_io_num = CONFIG_EXAMPLE_SPI_MISO_GPIO;
+    buscfg.sclk_io_num = CONFIG_EXAMPLE_SPI_SCLK_GPIO;
+    buscfg.quadwp_io_num = -1;
+    buscfg.quadhd_io_num = -1;
+    buscfg.max_transfer_sz = 32;
+
+    // create the spi device
+    spi_device_interface_config_t devcfg;
+    memset(&devcfg, 0, sizeof(devcfg));
+    devcfg.mode = 0;
+    devcfg.clock_speed_hz = CONFIG_EXAMPLE_SPI_CLOCK_SPEED; // Supports 64ns clock period, 15.625MHz
+    devcfg.input_delay_ns = 0;
+    devcfg.spics_io_num = CONFIG_EXAMPLE_SPI_CS_GPIO;
+    devcfg.queue_size = 1;
+
+    esp_err_t ret;
+    // Initialize the SPI bus
+    auto spi_num = SPI2_HOST;
+    ret = spi_bus_initialize(spi_num, &buscfg, SPI_DMA_CH_AUTO);
+    ESP_ERROR_CHECK(ret);
+    // Attach the LCD to the SPI bus
+    ret = spi_bus_add_device(spi_num, &devcfg, &encoder_spi_handle);
+    ESP_ERROR_CHECK(ret);
+
+    // make the velocity filter
+    static constexpr float filter_cutoff_hz = 10.0f;
+    static constexpr float encoder_update_period = 0.001f; // seconds
+    espp::ButterworthFilter<2, espp::BiquadFilterDf2> filter(
+        {.normalized_cutoff_frequency = 2.0f * filter_cutoff_hz * encoder_update_period});
+    auto filter_fn = [&filter](float raw) -> float { return filter.update(raw); };
+
+    // now make the mt6701 which decodes the data
+    using Mt6701 = espp::Mt6701<espp::Mt6701Interface::SSI>;
+    Mt6701 mt6701({.read = [&](uint8_t *data, size_t len) -> bool {
+                     // we can use the SPI_TRANS_USE_RXDATA since our length is <= 4 bytes (32
+                     // bits), this means we can directly use the tarnsaction's rx_data field
+                     static constexpr uint8_t SPIBUS_READ = 0x80;
+                     spi_transaction_t t = {
+                         .flags = 0,
+                         .cmd = 0,
+                         .addr = SPIBUS_READ,
+                         .length = len * 8,
+                         .rxlength = len * 8,
+                         .user = nullptr,
+                         .tx_buffer = nullptr,
+                         .rx_buffer = data,
+                     };
+                     if (len <= 4) {
+                       t.flags = SPI_TRANS_USE_RXDATA;
+                       t.rx_buffer = nullptr;
+                     }
+                     esp_err_t err = spi_device_transmit(encoder_spi_handle, &t);
+                     if (err != ESP_OK) {
+                       return false;
+                     }
+                     if (len <= 4) {
+                       // copy the data from the rx_data field
+                       for (size_t i = 0; i < len; i++) {
+                         data[i] = t.rx_data[i];
+                       }
+                     }
+                     return true;
+                   },
+                   .velocity_filter = filter_fn,
+                   .update_period = std::chrono::duration<float>(encoder_update_period),
+                   .run_task = true, // run a task which calls the update function at the update
+                                     // period
+                   .log_level = espp::Logger::Verbosity::WARN});
+
+    // get the initial state
+    auto field_strength = mt6701.get_magnetic_field_strength();
+    auto tracking_status = mt6701.get_tracking_status();
+    bool push_button = mt6701.get_push_button();
+    fmt::print("Initial state: field_strength: {}, tracking_status: {}, push_button: {}\n",
+               field_strength, tracking_status, push_button);
+
+    // and finally, make the task to periodically poll the mt6701 and print the
+    // state. NOTE: the Mt6701 runs its own task to maintain state, so we're
+    // just polling the current state.
+    auto task_fn = [&quit_test, &mt6701](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds = std::chrono::duration<float>(now - start).count();
+      auto count = mt6701.get_count();
+      auto radians = mt6701.get_radians();
+      auto degrees = mt6701.get_degrees();
+      auto rpm = mt6701.get_rpm();
+      fmt::print("{:.3f}, {}, {:.3f}, {:.3f}, {:.3f}\n", seconds, count, radians, degrees, rpm);
+      quit_test = degrees <= -720.0f;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 10ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Mt6701 Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    fmt::print("% time(s), count, radians, degrees, rpm\n");
+    task.start();
+
+
+
+
+

Note

+

This implementation currently only supports I2C and SSI interfaces.

+
+
+

Note

+

There is an implicit assumption in this class regarding the maximum velocity it can measure (above which there will be aliasing). The fastest velocity it can measure will be (0.5f / update_period * 60.0f) RPM which is half a rotation in one update period.

+
+
+

Note

+

The assumption above also affects the reliability of the accumulator, since it is based on accumulating position differences every update period.

+
+
+

Public Types

+
+
+enum class MagneticFieldStrength : uint8_t
+

Enum class for the magnetic field strength of the MT6701.

+

Values:

+
+
+enumerator NORMAL
+

The magnetic field is normal.

+
+ +
+
+enumerator TOO_STRONG
+

The magnetic field is too strong to measure the angle.

+
+ +
+
+enumerator TOO_WEAK
+

The magnetic field is too weak to measure the angle.

+
+ +
+ +
+
+enum class TrackingStatus : uint8_t
+

Enum class for the tracking status of the MT6701.

+

Values:

+
+
+enumerator NORMAL
+

Normal tracking status.

+
+ +
+
+enumerator LOST
+

Tracking has been lost.

+
+ +
+ +
+
+typedef std::function<float(float raw)> velocity_filter_fn
+

Filter the input raw velocity and return it.

+
+
Param raw
+

Most recent raw velocity measured.

+
+
Return
+

Filtered velocity.

+
+
+
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Mt6701(const Config &config)
+

Construct the Mt6701 and start the update task.

+
+ +
+
+inline void initialize(bool run_task, std::error_code &ec)
+

Initialize the accumulator to the current position and start the update task.

+
+

Note

+

If you do not start the task, you must call update() manually.

+
+
+
Parameters
+
    +
  • run_task – Whether to start the update task.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline bool needs_zero_search() const
+

Return whether the sensor has found absolute 0 yet.

+
+

Note

+

The MT6701 (using I2C/SPI) does not need to search for absolute 0 and will always know it on startup. Therefore this function always returns false.

+
+
+
Returns
+

True because the magnetic sensor (using I2C/SPI) does not need to sarch for 0.

+
+
+
+ +
+
+inline int get_count() const
+

Get the most recently updated raw count value from the encoder.

+
+

Note

+

This value always represents the angle of the encoder modulo one rotation, meaning it only represents the range 0 to 360 degrees. It is not recommended to use this function, but is provided for edge use cases.

+
+
+
Returns
+

Raw count value in the range [0, 16384] (0 to 360 degrees).

+
+
+
+ +
+
+inline int get_accumulator() const
+

Return the accumulated count that the encoder has generated since it was initialized.

+
+

Note

+

This value is a raw counter value that can be +/-, meaning COUNTS_PER_REVOLUTION can be used to convert it to revolutions.

+
+
+
Returns
+

Raw accumulator value.

+
+
+
+ +
+
+inline float get_mechanical_radians() const
+

Return the mechanical / shaft angle of the encoder, in radians, within the range [0, 2pi].

+
+
Returns
+

Angle in radians of the encoder within the range [0, 2pi].

+
+
+
+ +
+
+inline float get_mechanical_degrees() const
+

Return the mechanical / shaft angle of the encoder, in degrees, within the range [0, 360].

+
+
Returns
+

Angle in degrees of the encoder within the range [0, 360].

+
+
+
+ +
+
+inline float get_radians() const
+

Return the accumulated position of the encoder, in radians.

+
+

Note

+

This can be any value, it is not restricted to [0, 2pi].

+
+
+
Returns
+

Position in radians of the encoder.

+
+
+
+ +
+
+inline float get_degrees() const
+

Return the accumulated position of the encoder, in degrees.

+
+

Note

+

This can be any value, it is not restricted to [0, 360].

+
+
+
Returns
+

Position in degrees of the encoder.

+
+
+
+ +
+
+inline float get_rpm() const
+

Return the filtered velocity of the encoder, in RPM.

+
+
Returns
+

Filtered velocity (revolutions / minute, RPM).

+
+
+
+ +
+
+inline MagneticFieldStrength get_magnetic_field_strength() const
+

Return the magnetic field strength of the encoder.

+
+

Note

+

This function is only available when using SSI communications.

+
+
+
Returns
+

Magnetic field strength of the encoder.

+
+
+
+ +
+
+inline TrackingStatus get_tracking_status() const
+

Return the tracking status of the encoder.

+
+

Note

+

This function is only available when using SSI communications.

+
+
+
Returns
+

Tracking status of the encoder.

+
+
+
+ +
+
+inline bool get_push_button() const
+

Return whether the push button is currently pressed.

+
+

Note

+

This function is only available when using SSI communications.

+
+
+
Returns
+

True if the push button is pressed, false otherwise.

+
+
+
+ +
+
+inline void update(std::error_code &ec)
+

Update the state of the encoder by reading the latest data from the encoder and updating the associated state.

+
+

Note

+

You should not call this function if you have started the encoder’s update task (e.g. run_task = true in the constructor, or you called initialize(true)).

+
+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0b0000110)
+

I2C address of the MT6701. It can be programmed to be 0b1000110 as well. Only used if Interface == Mt6701Interface::I2C.

+
+ +
+
+static constexpr int COUNTS_PER_REVOLUTION = 16384
+

Int number of counts per revolution for the magnetic encoder.

+
+ +
+
+static constexpr float COUNTS_PER_REVOLUTION_F = 16384.0f
+

Float number of counts per revolution for the magnetic encoder.

+
+ +
+
+static constexpr float COUNTS_TO_RADIANS = 2.0f * M_PI / COUNTS_PER_REVOLUTION_F
+

Conversion factor to convert from count value to radians.

+
+ +
+
+static constexpr float COUNTS_TO_DEGREES = 360.0f / COUNTS_PER_REVOLUTION_F
+

Conversion factor to convert from count value to degrees.

+
+ +
+
+static constexpr float SECONDS_PER_MINUTE = 60.0f
+

Conversion factor to convert from seconds to minutes.

+
+ +
+
+
+struct Config
+

Configuration information for the Mt6701.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device. Only used if Interface == Mt6701Interface::I2C.

+
+ +
+
+BasePeripheral<uint8_t, Interface == Mt6701Interface::I2C>::write_fn write{nullptr}
+

Function to write to the device.

+
+ +
+
+BasePeripheral<uint8_t, Interface == Mt6701Interface::I2C>::read_fn read{nullptr}
+

Function to read data from the device.

+
+ +
+
+velocity_filter_fn velocity_filter = {nullptr}
+

Function to filter the veolcity.

+
+

Note

+

Will be called once every update_period seconds.

+
+
+ +
+
+std::chrono::duration<float> update_period{.01f}
+

Update period (1/sample rate) in seconds. This determines the periodicity of the task which will read the position, update the accumulator, and update/filter velocity.

+
+ +
+
+bool auto_init = {true}
+

Whether to automatically initialize the accumulator to the current position on startup.

+
+ +
+
+bool run_task = {true}
+

Whether to run the task on startup. If false, you must call update() manually.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/encoder/mt6701_example.html b/encoder/mt6701_example.html new file mode 100644 index 000000000..1eb4612db --- /dev/null +++ b/encoder/mt6701_example.html @@ -0,0 +1,245 @@ + + + + + + + Mt6701 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Mt6701 Example

+

This example shows the use of the Mt6701 component to communicate with a +MT6701 magnetic encoder chip.

+
+

How to use example

+

It uses the task component to periodically read the raw count, position, and +velocity of the encoder, the filters component (specifically the +espp::ButterworthFilter class) to filter the raw values from the sensor, and +the format component to print the data to the console in CSV format.

+
+

Hardware Required

+

This requires a MT6701 magnetic encoder dev board with an diametric magnet and +the MT6701 dev board should be connected to the ESP dev board you choose via +I2C.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

Here is some example output plotted using the uart serial +plotter:

+

example outputplotted

+

For more information, see the original PR that included this component: +https://github.com/esp-cpp/espp/pull/5

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/esp32_timer_cam.html b/esp32_timer_cam.html new file mode 100644 index 000000000..5dc25799a --- /dev/null +++ b/esp32_timer_cam.html @@ -0,0 +1,778 @@ + + + + + + + ESP32 TimerCam - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESP32 TimerCam

+
+

Esp32-Timer-Cam

+

The ESP32 TimerCam is a little usb-c webcamera using the ESP32. It has a little +blue LED, a real-time clock (RTC), and supports battery operation with battery +voltage monitoring as well.

+

The espp::EspTimerCam component provides a singleton hardware abstraction for +initializing the I2C, LED, RTC, and ADC subsystems.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class EspTimerCam : public espp::BaseComponent
+

The EspTimerCam class provides an interface to the ESP32-S3-BOX and ESP32-S3-BOX-3 development boards.

+

The class provides access to the following features:

    +
  • I2C

  • +
  • LED

  • +
  • Battery Voltage Measurement

  • +
  • RTC

  • +
  • Camera pin definition

  • +
+

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::EspTimerCam &timer_cam = espp::EspTimerCam::get();
+
+  // initialize the LED
+  static constexpr float led_breathing_period = 3.5f;
+  if (!timer_cam.initialize_led(led_breathing_period)) {
+    logger.error("Failed to initialize LED!");
+    return;
+  }
+
+  // initialize the rtc
+  if (!timer_cam.initialize_rtc()) {
+    logger.error("Failed to initialize RTC!");
+    return;
+  }
+
+  // start the LED breathing
+  timer_cam.start_led_breathing();
+
+  // loop forever
+  while (true) {
+    // print out the battery voltage
+    logger.info("Battery voltage: {:.02f} V", timer_cam.get_battery_voltage());
+    std::this_thread::sleep_for(100ms);
+    // go up a line to overwrite the previous message
+    logger.move_up();
+    logger.clear_line();
+  }
+
+
+
+
+

Public Functions

+
+
+I2c &internal_i2c()
+

Get a reference to the internal I2C bus

+
+

Note

+

The internal I2C bus is used for the touchscreen and audio codec

+
+
+
Returns
+

A reference to the internal I2C bus

+
+
+
+ +
+
+espp::Interrupt &interrupts()
+

Get a reference to the interrupts

+
+
Returns
+

A reference to the interrupts

+
+
+
+ +
+
+bool initialize_led(float breathing_period = 3.5f)
+

Initialize the LED.

+
+
Parameters
+

breathing_period – The period of the LED breathing effect

+
+
Returns
+

True if the LED was successfully initialized, false otherwise

+
+
+
+ +
+
+void start_led_breathing()
+

Start the LED breathing effect.

+
+ +
+
+void stop_led_breathing()
+

Stop the LED breathing effect.

+
+ +
+
+bool set_led_brightness(float brightness)
+

Set the LED brightness.

+
+

Note

+

The LED brightness can only be set if the LED is not currently breathing

+
+
+
Parameters
+

brightness – The brightness of the LED, in the range [0, 1]

+
+
Returns
+

True if the LED brightness was successfully set, false otherwise

+
+
+
+ +
+
+float get_led_brightness()
+

Get the LED brightness.

+
+
Returns
+

The brightness of the LED, in the range [0, 1]

+
+
+
+ +
+
+bool set_led_breathing_period(float period)
+

Set the LED breathing period.

+
+
Parameters
+

period – The period of the LED breathing effect in seconds

+
+
Returns
+

True if the LED breathing period was successfully set, false otherwise

+
+
+
+ +
+
+float get_led_breathing_period()
+

Get the LED breathing period.

+
+
Returns
+

The period of the LED breathing effect in seconds

+
+
+
+ +
+
+std::shared_ptr<espp::Led> led()
+

Get the LED.

+
+
Returns
+

A shared pointer to the LED

+
+
+
+ +
+
+espp::Gaussian &gaussian()
+

Get the Gaussian waveform used for the LED breathing effect.

+
+
Returns
+

A reference to the Gaussian waveform used for the LED breathing effect

+
+
+
+ +
+
+float get_battery_voltage()
+

Get the battery voltage.

+
+
Returns
+

The battery voltage in volts

+
+
+
+ +
+
+bool initialize_rtc()
+

Initialize the RTC.

+
+
Returns
+

True if the RTC was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Rtc> rtc()
+

Get the RTC.

+
+
Returns
+

A shared pointer to the RTC

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline EspTimerCam &get()
+

Access the singleton instance of the EspTimerCam class.

+
+
Returns
+

Reference to the singleton instance of the EspTimerCam class

+
+
+
+ +
+
+static inline gpio_num_t get_camera_reset_pin()
+

Get the camera reset pin.

+
+
Returns
+

The camera reset pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_xclk_pin()
+

Get the camera XCLK pin.

+
+
Returns
+

The camera XCLK pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_sda_pin()
+

Get the camera SDA pin.

+
+
Returns
+

The camera SDA pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_scl_pin()
+

Get the camera SCL pin.

+
+
Returns
+

The camera SCL pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d0_pin()
+

Get the camera D0 pin.

+
+
Returns
+

The camera D0 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d1_pin()
+

Get the camera D1 pin.

+
+
Returns
+

The camera D1 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d2_pin()
+

Get the camera D2 pin.

+
+
Returns
+

The camera D2 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d3_pin()
+

Get the camera D3 pin.

+
+
Returns
+

The camera D3 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d4_pin()
+

Get the camera D4 pin.

+
+
Returns
+

The camera D4 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d5_pin()
+

Get the camera D5 pin.

+
+
Returns
+

The camera D5 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d6_pin()
+

Get the camera D6 pin.

+
+
Returns
+

The camera D6 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_d7_pin()
+

Get the camera D7 pin.

+
+
Returns
+

The camera D7 pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_vsync_pin()
+

Get the camera VSYNC pin.

+
+
Returns
+

The camera VSYNC pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_href_pin()
+

Get the camera HREF pin.

+
+
Returns
+

The camera HREF pin

+
+
+
+ +
+
+static inline gpio_num_t get_camera_pclk_pin()
+

Get the camera PCLK pin.

+
+
Returns
+

The camera PCLK pin

+
+
+
+ +
+
+static inline int get_camera_xclk_freq_hz()
+

Get the camera XCLK frequency.

+
+
Returns
+

The camera XCLK frequency in Hz

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/esp32_timer_cam_example.html b/esp32_timer_cam_example.html new file mode 100644 index 000000000..e45a90d5b --- /dev/null +++ b/esp32_timer_cam_example.html @@ -0,0 +1,237 @@ + + + + + + + ESP32-TIMER-CAM Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESP32-TIMER-CAM Example

+

This example shows how to use the espp::EspTimerCam hardware abstraction +component to automatically detect and initialize components on the +ESP32-TimerCam.

+

It initializes the LED, RTC, I2C, and ADC.

+

https://github.com/user-attachments/assets/b0c0eb28-0ce1-466d-b6e5-debbc0e7f3f6

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the ESP32-TimerCam.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT -b 1500000 flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

Note: the baudrate for the ESP32 TimerCam cannot go up to 2 MBaud, so 1.5MBaud +is recommended.

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-08-27 at 11 31 16

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/esp_box.html b/esp_box.html new file mode 100644 index 000000000..90705635d --- /dev/null +++ b/esp_box.html @@ -0,0 +1,1085 @@ + + + + + + + ESP BOX - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESP BOX

+
+

Esp-Box

+

The ESP32-S3-BOX and ESP32-S3-BOX-3 are development boards for the ESP32-S3 +module. They feature a nice touchscreen display, a speaker, microphones, and +expansion headers.

+

The espp::EspBox component provides a singleton hardware abstraction for +initializing the touch, display, and audio subsystems, as well as automatically +determining which version of the Box it’s running on.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class EspBox : public espp::BaseComponent
+

The EspBox class provides an interface to the ESP32-S3-BOX and ESP32-S3-BOX-3 development boards.

+

The class provides access to the following features:

+

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::EspBox &box = espp::EspBox::get();
+  box.set_log_level(espp::Logger::Verbosity::INFO);
+  logger.info("Running on {}", box.box_type());
+
+  auto touch_callback = [&](const auto &touch) {
+    // NOTE: since we're directly using the touchpad data, and not using the
+    // TouchpadInput + LVGL, we'll need to ensure the touchpad data is
+    // converted into proper screen coordinates instead of simply using the
+    // raw values.
+    static auto previous_touchpad_data = box.touchpad_convert(touch);
+    auto touchpad_data = box.touchpad_convert(touch);
+    if (touchpad_data != previous_touchpad_data) {
+      logger.info("Touch: {}", touchpad_data);
+      previous_touchpad_data = touchpad_data;
+      // if the button is pressed, clear the circles
+      if (touchpad_data.btn_state) {
+        std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+        clear_circles();
+      }
+      // if there is a touch point, draw a circle and play a click sound
+      if (touchpad_data.num_touch_points > 0) {
+        play_click(box);
+        std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+        draw_circle(touchpad_data.x, touchpad_data.y, 10);
+      }
+    }
+  };
+
+  // initialize the sound
+  if (!box.initialize_sound()) {
+    logger.error("Failed to initialize sound!");
+    return;
+  }
+  // initialize the LCD
+  if (!box.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // 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,
+  };
+  // initialize the LVGL display for the esp-box
+  if (!box.initialize_display(pixel_buffer_size, display_task_config)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+  // initialize the touchpad
+  if (!box.initialize_touch(touch_callback)) {
+    logger.error("Failed to initialize touchpad!");
+    return;
+  }
+
+  // set the background color to black
+  lv_obj_t *bg = lv_obj_create(lv_screen_active());
+  lv_obj_set_size(bg, box.lcd_width(), box.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Touch the screen!\nPress the home button to clear circles.");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // add a button in the top left which (when pressed) will rotate the display
+  // through 0, 90, 180, 270 degrees
+  lv_obj_t *btn = lv_btn_create(lv_screen_active());
+  lv_obj_set_size(btn, 50, 50);
+  lv_obj_align(btn, LV_ALIGN_TOP_LEFT, 0, 0);
+  lv_obj_t *label_btn = lv_label_create(btn);
+  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<std::recursive_mutex> lock(lvgl_mutex);
+        clear_circles();
+        static auto rotation = LV_DISPLAY_ROTATION_0;
+        rotation = static_cast<lv_display_rotation_t>((static_cast<int>(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)
+  lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF);
+  lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                      }});
+  lv_task.start();
+
+  // load the audio file (wav file bundled in memory)
+  size_t wav_size = load_audio();
+  logger.info("Loaded {} bytes of audio", wav_size);
+
+  // unmute the audio and set the volume to 60%
+  box.mute(false);
+  box.volume(60.0f);
+
+  // set the display brightness to be 75%
+  box.brightness(75.0f);
+
+  // loop forever
+  while (true) {
+    std::this_thread::sleep_for(1s);
+  }
+
+
+
+
+

Public Types

+
+
+enum class BoxType
+

The type of the box.

+

Values:

+
+
+enumerator UNKNOWN
+

unknown box

+
+ +
+
+enumerator BOX
+

ESP32-S3-BOX.

+
+ +
+
+enumerator BOX3
+

ESP32-S3-BOX-3.

+
+ +
+ +
+
+using Pixel = lv_color16_t
+

Alias for the pixel type used by the ESP-Box display.

+
+ +
+
+using DisplayDriver = espp::St7789
+

Alias for the display driver used by the ESP-Box display.

+
+ +
+
+

Public Functions

+
+
+inline BoxType box_type() const
+

Get the type of the box

+

See also

+

BoxType

+
+

+
+
Returns
+

The type of the box that was detected

+
+
+
+ +
+
+inline I2c &internal_i2c()
+

Get a reference to the internal I2C bus

+
+

Note

+

The internal I2C bus is used for the touchscreen and audio codec

+
+
+
Returns
+

A reference to the internal I2C bus

+
+
+
+ +
+
+inline espp::Interrupt &interrupts()
+

Get a reference to the interrupts

+
+
Returns
+

A reference to the interrupts

+
+
+
+ +
+
+bool initialize_touch(const touch_callback_t &callback = nullptr)
+

Initialize the touchpad

+
+

Note

+

This will configure the touchpad interrupt pin which will automatically call the touch callback function when the touchpad is touched

+
+
+

Warning

+

This method should be called after the display has been initialized if you want the touchpad to be recognized and used with LVGL and its objects.

+
+
+
Parameters
+

callback – The touchpad callback

+
+
Returns
+

true if the touchpad was successfully initialized, false otherwise

+
+
+
+ +
+
+inline std::shared_ptr<TouchpadInput> touchpad_input() const
+

Get the touchpad input

+
+
Returns
+

A shared pointer to the touchpad input

+
+
+
+ +
+
+inline TouchpadData touchpad_data() const
+

Get the most recent touchpad data

+
+
Returns
+

The touchpad data

+
+
+
+ +
+
+void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)
+

Get the most recent touchpad data

+

See also

+

touchpad_data()

+
+

+
+

Note

+

This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the touchpad_data() method

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points

  • +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • btn_state – The button state (0 = button released, 1 = button pressed)

  • +
+
+
+
+ +
+
+TouchpadData touchpad_convert(const TouchpadData &data) const
+

Convert touchpad data from raw reading to display coordinates

+
+

Note

+

Uses the touch_invert_x and touch_invert_y settings to determine if the x and y coordinates should be inverted

+
+
+
Parameters
+

data – The touchpad data to convert

+
+
Returns
+

The converted touchpad data

+
+
+
+ +
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+inline std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+bool initialize_sound (uint32_t default_audio_rate=48000, const espp::Task::BaseConfig &task_config={ .name="audio",.stack_size_bytes=4096,.priority=19,.core_id=1, })
+

Initialize the sound subsystem

+
+
Parameters
+
    +
  • default_audio_rate – The default audio rate

  • +
  • task_config – The task configuration for the audio task

  • +
+
+
Returns
+

true if the sound subsystem was successfully initialized, false otherwise

+
+
+
+ +
+
+void enable_sound(bool enable)
+

Enable or disable sound

+
+

Note

+

This method sets the power pin to the appropriate value

+
+
+ +
+
+uint32_t audio_sample_rate() const
+

Get the audio sample rate

+
+
Returns
+

The audio sample rate, in Hz

+
+
+
+ +
+
+void audio_sample_rate(uint32_t sample_rate)
+

Set the audio sample rate

+
+
Parameters
+

sample_rate – The audio sample rate, in Hz

+
+
+
+ +
+
+size_t audio_buffer_size() const
+

Get the audio buffer size

+
+
Returns
+

The audio buffer size, in bytes

+
+
+
+ +
+
+void mute(bool mute)
+

Mute or unmute the audio

+
+
Parameters
+

mute – true to mute the audio, false to unmute the audio

+
+
+
+ +
+
+bool is_muted() const
+

Check if the audio is muted

+
+
Returns
+

true if the audio is muted, false otherwise

+
+
+
+ +
+
+void volume(float volume)
+

Set the volume

+
+
Parameters
+

volume – The volume in percent (0 - 100)

+
+
+
+ +
+
+float volume() const
+

Get the volume

+
+
Returns
+

The volume in percent (0 - 100)

+
+
+
+ +
+
+void play_audio(const std::vector<uint8_t> &data)
+

Play audio

+
+
Parameters
+

data – The audio data to play

+
+
+
+ +
+
+void play_audio(const uint8_t *data, uint32_t num_bytes)
+

Play audio

+
+
Parameters
+
    +
  • data – The audio data to play

  • +
  • num_bytes – The number of bytes to play

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline EspBox &get()
+

Access the singleton instance of the EspBox class.

+
+
Returns
+

Reference to the singleton instance of the EspBox class

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+static inline constexpr auto get_mute_pin()
+

Get the GPIO pin for the mute button (top of the box)

+
+
Returns
+

The GPIO pin for the mute button

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/esp_box_example.html b/esp_box_example.html new file mode 100644 index 000000000..b6ee23d75 --- /dev/null +++ b/esp_box_example.html @@ -0,0 +1,243 @@ + + + + + + + ESP-BOX Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESP-BOX Example

+

This example shows how to use the espp::EspBox hardware abstraction component +to automatically detect and initialize components on both the ESP32-S3-BOX and +the ESP32-S3-BOX-3.

+

It initializes the touch, display, and audio subsystems. It reads the touchpad +state and each time you touch the scren it 1) uses LVGL to draw a circle where +you touch, and 2) play a click sound (wav file bundled with the firmware). If +you press the home button on the display, it will clear the circles.

+

https://github.com/esp-cpp/espp/assets/213467/d5379983-9bc2-4d56-a9fc-9e37f54af15e

+

image +image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the ESP32-S3-BOX or ESP32-S3-BOX-3.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

BOX3: +CleanShot 2024-07-01 at 08 47 31

+

BOX: +CleanShot 2024-07-01 at 09 56 23

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/event_manager.html b/event_manager.html new file mode 100644 index 000000000..e17e1c4e5 --- /dev/null +++ b/event_manager.html @@ -0,0 +1,710 @@ + + + + + + + Event Manager APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Event Manager APIs

+

The EventManager class enables anonymous publish/subscribe interactions +between different software components and contexts in the system. It provides a +singleton class which manages the registry of publishers and subscribers in the +system and provides loose coupling between them. To subscribe to events/data, a +component must register itself with the manager by calling add_subscriber() - +which will register a callback function associated with that component for the +event/topic provided. All callback functions for a given topic/event are called +from the same thread/context - a thread that is started and managed by the +EventManager. As noted in a few places, it is recommended to use a +(de-)serialization library such as espp::serialization / alpaca for transforming +data structures to/from std::vector<uint8_t> for publishing/subscribing.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class EventManager : public espp::BaseComponent
+

Singleton class for managing events. Provides mechanisms for anonymous publish / subscribe interactions - enabling one to one, one to many, many to one, and many to many data distribution with loose coupling and low overhead. Each topic runs a thread for that topic’s subscribers, executing all the callbacks in sequence and then going to sleep again until new data is published.

+
+

Event Manager Example

+
  espp::EventManager::get().set_log_level(espp::Logger::Verbosity::WARN);
+
+  // NOTE: we'll use a simple string for publishing on drive/control, but
+  // normally you'd use a struct and a serialization library like alpaca, so
+  // that's what we'll do for battery/state
+
+  // let's define a struct to contain data for an event
+  struct BatteryState {
+    float voltage{48.0f};
+    float current{0.0f};
+    bool is_charging{false};
+    float temperature_celsius{25.0f};
+    float state_of_charge{100.0f};
+  };
+
+  // let's make some event names that we'll use for this example
+  const std::string event1 = "battery/state";
+  const std::string event2 = "drive/control";
+
+  static int num_published = 0;
+  static int num_received = 0;
+
+  // Make a task which has a pub/sub in it. NOTE: in real code, this would
+  // likely be within a custom class and the registration would happen in the
+  // constructor, with the remove_publisher / remove_subscriber calls in its
+  // destructor. Also NOTE: you would likely use a serialization library like
+  // alpaca (wrapped in espp serialization component) for serializing and
+  // deserializing the data structures being passed to string data.
+  auto task_1_fn = [&](auto &m, auto &cv) {
+    {
+      // Just for fun, we'll only define the subscriber callback within the
+      // context of this task function
+      static auto event2_cb = [&](const std::vector<uint8_t> &data) {
+        // we know this is a string, so just convert it to a string and
+        // print it
+        std::string data_str(data.begin(), data.end());
+        logger.debug("Task 1 cb got data: '{}'", data_str);
+        num_received++;
+        // block here like we're doing work
+        std::this_thread::sleep_for(10ms);
+      };
+      // we only want to register once, so ust the std::call_once /
+      // std::once_flag functionality to only register the first time the
+      // task is run
+      static std::once_flag flag;
+      std::call_once(flag, [&]() {
+        auto &em = espp::EventManager::get();
+        logger.info("Task 1 registering!");
+        auto did_pub = em.add_publisher(event1, "task 1");
+        auto did_sub = em.add_subscriber(event2, "task 1", event2_cb);
+        logger.info("Task 1 publishing:  {}", did_pub);
+        logger.info("Task 1 subscribing: {}", did_sub);
+        // sleep for a little bit to let the other task register its
+        // subscribers/publishers before we start publishing ensuring that the
+        // subscriber callback is registered before the publisher publishes
+        std::this_thread::sleep_for(10ms);
+      });
+      // periodically publish on event1
+      logger.debug("Task 1 publishing on {}", event1);
+      static BatteryState bs;
+      bs.current = 1.0f;
+      bs.voltage -= 0.1f;
+      bs.state_of_charge -= 5.0f;
+      bs.temperature_celsius += 0.2f;
+      std::vector<uint8_t> buffer;
+      espp::serialize(bs, buffer);
+      espp::EventManager::get().publish(event1, buffer);
+      num_published++;
+      buffer.clear();
+      bs.current = -1.0f;
+      espp::serialize(bs, buffer);
+      espp::EventManager::get().publish(event1, buffer);
+      num_published++;
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 500ms);
+    }
+    // we don't want to stop, so return false
+    return false;
+  };
+  auto task1 = espp::Task({.callback = task_1_fn, .task_config = {.name = "Task 1"}});
+
+  // Now let's make another task which will have pub/sub as well
+  auto task_2_fn = [&](auto &m, auto &cv) {
+    {
+      // Just for fun, we'll only define the subscriber callback within the
+      // context of this task function
+      static auto event1_cb = [&](const std::vector<uint8_t> &data) {
+        // we know the data is a BatteryState struct, so deserialize it and
+        // print it
+        std::error_code ec;
+        auto bs = espp::deserialize<BatteryState>(data, ec);
+        if (ec) {
+          logger.error("Couldn't deserialize BatteryState: {}", ec.message());
+          return;
+        }
+        logger.debug("Task 2 got battery state data:\n"
+                     "  voltage:             {:.2f}\n"
+                     "  current:             {:.2f}\n"
+                     "  is_charging:         {}\n"
+                     "  temperature_celsius: {:.2f}\n"
+                     "  state_of_charge:     {:.2f}",
+                     bs.voltage, bs.current, bs.is_charging, bs.temperature_celsius,
+                     bs.state_of_charge);
+        num_received++;
+        // block here like we're doing work
+        std::this_thread::sleep_for(10ms);
+      };
+      // we only want to register once, so ust the std::call_once /
+      // std::once_flag functionality to only register the first time the
+      // task is run
+      static std::once_flag flag;
+      std::call_once(flag, [&]() {
+        auto &em = espp::EventManager::get();
+        logger.info("Task 2 registering!");
+        auto did_pub = em.add_publisher(event2, "task 2");
+        // NOTE: we're using a custom task config here to show how you can
+        // configure the task that the subscriber callback will run in
+        // (priority, stack size, etc.). Only the first subscription on a topic
+        // will use the task config, any subsequent subscriptions will use the
+        // same task as the first subscription.
+        espp::Task::BaseConfig task_config{
+            .name = "Task 2 subscriber task",
+            .stack_size_bytes = 8192,
+            .priority = 10, // 5 is default, 10 is higher
+        };
+        auto did_sub = em.add_subscriber(event1, "task 2", event1_cb, task_config);
+        logger.info("Task 2 publishing:  {}", did_pub);
+        logger.info("Task 2 subscribing: {}", did_sub);
+        // sleep for a little bit to let the other task register its
+        // subscribers/publishers, ensuring that the subscriber callback is
+        // registered before the publisher publishes
+        std::this_thread::sleep_for(10ms);
+      });
+      // periodically publish on event2
+      logger.debug("Task 2 publishing on {}", event2);
+      static int iteration = 0;
+      std::string data = fmt::format("Task 2 data {}", iteration++);
+      std::vector<uint8_t> buffer(data.begin(), data.end());
+      espp::EventManager::get().publish(event2, buffer);
+      num_published++;
+      espp::EventManager::get().publish(event2, buffer);
+      num_published++;
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 500ms);
+    }
+    // we don't want to stop, so return false
+    return false;
+  };
+  auto task2 = espp::Task({.callback = task_2_fn, .task_config = {.name = "Task 2"}});
+
+  // now start the tasks
+  task1.start();
+  task2.start();
+
+  // Now let's just wait for a little while for those tasks to run, showcasing
+  // the pub/sub interactions in the log output.
+  logger.info("Sleeping for 5s...");
+  std::this_thread::sleep_for(5s);
+
+  task1.stop();
+  task2.stop();
+
+  // since the tasks are done, let's remove their publishers/subscibers here
+  // (though as noted above, this would normally be done in a class
+  // destructor)
+  auto &em = espp::EventManager::get();
+  em.remove_publisher(event1, "task 1");
+  em.remove_subscriber(event2, "task 1");
+  em.remove_publisher(event2, "task 2");
+  em.remove_subscriber(event1, "task 2");
+
+
+
+
+

Note

+

In c++ objects, it’s recommended to call the add_publisher/add_subscriber functions in the class constructor and then to call the remove_publisher/remove_subscriber functions in the class destructor.

+
+
+

Note

+

It is recommended (unless you are only interested in events and not data or are only needing to transmit actual strings) to use a serialization library (such as espp::serialization - which wraps alpaca) to serialize your data structures to string when publishing and then deserialize your data from string in the subscriber callbacks.

+
+
+

Public Types

+
+
+typedef std::function<void(const std::vector<uint8_t>&)> event_callback_fn
+

Function definition for function prototypes to be called when subscription/event data is available.

+
+
Param std::vector<uint8_t>&
+

The data associated with the event

+
+
+
+ +
+
+

Public Functions

+
+
+bool add_publisher(const std::string &topic, const std::string &component)
+

Register a publisher for component on topic.

+
+
Parameters
+
    +
  • topic – Topic name for the data being published.

  • +
  • component – Name of the component publishing data.

  • +
+
+
Returns
+

True if the publisher was added, false if it was already registered for that component.

+
+
+
+ +
+
+bool add_subscriber(const std::string &topic, const std::string &component, const espp::EventManager::event_callback_fn &callback, const size_t stack_size_bytes = 8192)
+

Register a subscriber for component on topic.

+
+

Note

+

The stack size is only used if a subscriber is not already registered for that topic. If a subscriber is already registered for that topic, the stack size is ignored.

+
+
+
Parameters
+
    +
  • topic – Topic name for the data being subscribed to.

  • +
  • component – Name of the component publishing data.

  • +
  • callback – The event_callback_fn to be called when receicing data on topic.

  • +
  • stack_size_bytes – The stack size in bytes to use for the subscriber

  • +
+
+
Returns
+

True if the subscriber was added, false if it was already registered for that component.

+
+
+
+ +
+
+bool add_subscriber(const std::string &topic, const std::string &component, const espp::EventManager::event_callback_fn &callback, const espp::Task::BaseConfig &task_config)
+

Register a subscriber for component on topic.

+
+

Note

+

The task_config is only used if a subscriber is not already registered for that topic. If a subscriber is already registered for that topic, the task_config is ignored.

+
+
+
Parameters
+
    +
  • topic – Topic name for the data being subscribed to.

  • +
  • component – Name of the component publishing data.

  • +
  • callback – The event_callback_fn to be called when receicing data on topic.

  • +
  • task_config – The task configuration to use for the subscriber.

  • +
+
+
Returns
+

True if the subscriber was added, false if it was already registered for that component.

+
+
+
+ +
+
+bool publish(const std::string &topic, const std::vector<uint8_t> &data)
+

Publish data on topic.

+
+
Parameters
+
    +
  • topic – Topic to publish data on.

  • +
  • data – Data to publish, within a vector container.

  • +
+
+
Returns
+

True if data was successfully published to topic, false otherwise. Publish will not occur (and will return false) if there are no subscribers for this topic.

+
+
+
+ +
+
+bool remove_publisher(const std::string &topic, const std::string &component)
+

Remove component's publisher for topic.

+
+
Parameters
+
    +
  • topic – The topic that component was publishing on.

  • +
  • component – The component for which the publisher was registered.

  • +
+
+
Returns
+

True if the publisher was removed, false if it was not registered.

+
+
+
+ +
+
+bool remove_subscriber(const std::string &topic, const std::string &component)
+

Remove component's subscriber for topic.

+
+
Parameters
+
    +
  • topic – The topic that component was subscribing to.

  • +
  • component – The component for which the subscriber was registered.

  • +
+
+
Returns
+

True if the subscriber was removed, false if it was not registered.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline EventManager &get()
+

Get the singleton instance of the EventManager.

+
+
Returns
+

A reference to the EventManager singleton.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/event_manager_example.html b/event_manager_example.html new file mode 100644 index 000000000..7effec401 --- /dev/null +++ b/event_manager_example.html @@ -0,0 +1,229 @@ + + + + + + + Event Manager Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Event Manager Example

+

This example shows some basic usage for the EventManager which allows +asynchronous communications between multiple tasks following the anonymous +pub/sub interaction pattern - supporting one to one, one to many, many to one, +and many to many data and event dissemination.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2023-06-22 at 16 25 55

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/file_system.html b/file_system.html new file mode 100644 index 000000000..542739f2f --- /dev/null +++ b/file_system.html @@ -0,0 +1,1102 @@ + + + + + + + File System APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

File System APIs

+

The FileSystem class provides a simple interface for interacting with the +filesystem. It provides a singleton class which manages the filesystem and also +includes the relevant POSIX, newlib, and C++ standard library headers providing +access to the filesystem. It is a wrapper around the LittleFS library and +can be configured using menuconfig to use a custom partition label.

+

It also provides some utility functions for interacting with the filesystem +and performing operations such as getting the total, used, and free space on +the filesystem, and listing files in a directory.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class FileSystem : public espp::BaseComponent
+

File system class.

+

This class is a singleton and should be accessed via the get()

method. The class is responsible for mounting the file system and providing access to the file system. It is configured via the menuconfig system and will use the partition with the label specified in the menuconfig. The partition must be formatted with the LittleFS file system. The file system is mounted at the root directory of the partition such that all files will be stored under the path “/<partition_label>/”.

+

The class provides methods to get the amount of free, used and total space on the file system. It also provides a method to get a human readable string for a byte size.

+
+

See also

+

get_partition_label()

+
+

+
+

File System Info Example

+
    auto &fs = espp::FileSystem::get();
+    // NOTE: partition label is configured by menuconfig and should match the
+    //       partition label in the partition table (partitions.csv).
+    // returns a const char*
+    auto partition_label = fs.get_partition_label();
+    // returns a std::string
+    auto mount_point = fs.get_mount_point();
+    // returns a std::filesystem::path
+    auto root_path = fs.get_root_path();
+    logger.info("Partition label: {}", partition_label);
+    logger.info("Mount point:     {}", mount_point);
+    logger.info("Root path:       {}", root_path.string());
+    // human_readable returns a string with the size and unit, e.g. 1.2 MB
+    auto total_space = fs.human_readable(fs.get_total_space());
+    auto free_space = fs.human_readable(fs.get_free_space());
+    auto used_space = fs.human_readable(fs.get_used_space());
+    logger.info("Total space: {}", total_space);
+    logger.info("Free space:  {}", free_space);
+    logger.info("Used space:  {}", used_space);
+
+
+
+
+

File System POSIX / NEWLIB Example

+
    auto mount_point = espp::FileSystem::get_mount_point();
+    const std::string sandbox = std::string(mount_point) + "/" + std::string(test_dir);
+    struct stat st;
+    // check that it exists - IT SHOULDN'T
+    logger.info("Directory {} exists: {}", sandbox,
+                stat(sandbox.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
+
+    // make a directory
+    mkdir(sandbox.c_str(), 0755);
+    logger.info("Created directory {}", sandbox);
+
+    // check that it exists - IT SHOULD
+    logger.info("Directory {} exists: {}", sandbox,
+                stat(sandbox.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
+
+    // write to a file
+    std::string file = sandbox + "/" + std::string(test_file);
+    FILE *fp = fopen(file.c_str(), "w");
+    if (fp == nullptr) {
+      logger.error("Couldn't open {} for writing!", file);
+    } else {
+      fwrite(file_contents.data(), 1, file_contents.size(), fp);
+      fclose(fp);
+      logger.info("Wrote '{}' to {}", file_contents, file);
+    }
+
+    // get the file size
+    stat(file.c_str(), &st);
+    size_t file_size = st.st_size;
+    logger.info("File '{}' is {}", file, espp::FileSystem::human_readable(file_size));
+
+    // read from a file
+    fp = fopen(file.c_str(), "r"); // NOTE: could use rb for binary
+    if (fp == nullptr) {
+      logger.error("Couldn't open {} for reading!", file);
+    } else {
+      // // alternative way to get the file size if you've already opened it
+      // fseek(f, 0, SEEK_END); // go to end
+      // size_t file_size = ftell(f); // another way to get the file size
+      // fseek(f, 0, SEEK_SET); // go back to beginning
+
+      std::vector<char> bytes;
+      bytes.resize(file_size);
+      fread(bytes.data(), 1, file_size, fp);
+      fclose(fp);
+      logger.info("Read bytes from file {}", bytes);
+    }
+
+    // rename the file
+    std::string file2 = sandbox + "/test2.csv";
+    // Check if destination file exists before renaming
+    if (stat(file2.c_str(), &st) == 0) {
+      // Delete it if it exists
+      unlink(file2.c_str());
+    }
+    // Rename original file
+    if (rename(file.c_str(), file2.c_str()) != 0) {
+      logger.error("Could not rename {} to {}", file, file2);
+    } else {
+      logger.info("Renamed '{}' to '{}'", file, file2);
+    }
+
+    // make a subdirectory
+    std::string sub = sandbox + "/" + std::string(sub_dir);
+    mkdir(sub.c_str(), 0755);
+    logger.info("Created subdirectory {}", sub);
+
+    // make a file in the subdirectory
+    std::string sub_file = sub + "/subfile.txt";
+    FILE *sub_fp = fopen(sub_file.c_str(), "w");
+    if (sub_fp == nullptr) {
+      logger.error("Couldn't open {} for writing!", sub_file);
+    } else {
+      fwrite(file_contents.data(), 1, file_contents.size(), sub_fp);
+      fclose(sub_fp);
+      logger.info("Wrote '{}' to {}", file_contents, sub_file);
+    }
+
+    // list files in a directory
+    auto &fs = espp::FileSystem::get();
+    espp::FileSystem::ListConfig config;
+    std::string directory_listing = fs.list_directory(sandbox, config);
+    logger.info("Directory listing for {}:\n{}", sandbox, directory_listing);
+
+    // list all files recursively
+    config.recursive = true;
+    auto root = fs.get_root_path();
+    std::string root_listing = fs.list_directory(root, config);
+    logger.info("Recursive directory listing for {}:\n{}", root.string(), root_listing);
+
+    // get a lsit of files in a directory
+    auto files = fs.get_files_in_path(sandbox);
+    logger.info("Files in {}: ", sandbox);
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+    files = fs.get_files_in_path(root, true); // include directories
+    logger.info("Files in {} (including directories): ", root.string());
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+    files = fs.get_files_in_path(root, true, true); // include directories, recursive
+    logger.info("Files in {} (including directories, recursive): ", root.string());
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+    files = fs.get_files_in_path(root, false, true); // do not include directories, recursive
+    logger.info("Files in {} (not including directories, recursive): ", root.string());
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+    // cleanup
+    auto items = {sub_file, sub, file, file2, sandbox};
+    for (auto &item : items) {
+      // use stat to figure out if it exists
+      auto code = stat(item.c_str(), &st);
+      bool exists = code == 0;
+      if (!exists) {
+        logger.warn("Not removing '{}', it doesn't exist!", item);
+        continue;
+      }
+      // and if it is a directory
+      bool is_dir = S_ISDIR(st.st_mode);
+      int ec = is_dir ? rmdir(item.c_str()) : unlink(item.c_str());
+      if (ec) {
+        logger.error("Could not remove {}, error code: {}", item, ec);
+      } else {
+        logger.info("Cleaned up {}", item);
+      }
+    }
+
+
+
+
+

File System Info std::filesystem Example

+
    // NOTE: use the overloads that take ec as parameter, else it will throw
+    //       exception on error.
+    std::error_code ec;
+    namespace fs = std::filesystem;
+    // NOTE: cannot use chdir on littlefs , so we need to always use absolute
+    //       paths.
+    const fs::path sandbox = espp::FileSystem::get().get_root_path() / fs::path{test_dir};
+
+    // check that it exists - IT SHOULDN'T
+    logger.info("Directory {} exists: {}", sandbox.string(), fs::exists(sandbox));
+
+    // make a directory
+    fs::create_directory(sandbox, ec);
+    if (ec) {
+      logger.error("Could not create directory {} - {}", sandbox.string(), ec.message());
+    } else {
+      logger.info("Created directory {}: {}", sandbox.string(), fs::exists(sandbox));
+    }
+
+    // check that it exists - IT SHOULD
+    logger.info("Directory {} exists: {}", sandbox.string(), fs::exists(sandbox));
+
+    fs::path file = sandbox / fs::path{test_file};
+
+    // write to a file
+    std::ofstream ofs(file);
+    ofs << file_contents;
+    ofs.close();
+    ofs.flush();
+    logger.info("Wrote '{}' to {}", file_contents, file.string());
+
+    // Get file size
+    size_t file_size = fs::file_size(file, ec);
+    if (ec) {
+      logger.error("Could not get file size of '{}' - {}", file.string(), ec.message());
+    } else {
+      logger.info("File '{}' has a file size of {}", file.string(),
+                  espp::FileSystem::human_readable(file_size));
+    }
+
+    // read from a file
+    std::ifstream ifs(file, std::ios::in | std::ios::binary | std::ios::ate); // at the end
+    // ifstream::pos_type file_size = ifs.tellg(); // an alternate way to get size
+    ifs.seekg(0, std::ios::beg);
+    // read bytes
+    std::vector<char> file_bytes(file_size);
+    ifs.read(file_bytes.data(), file_size);
+    // convert bytes to string_view
+    std::string_view file_string(file_bytes.data(), file_size);
+    logger.info("Read bytes from file: {}", file_bytes);
+    logger.info("Read string from file: {}", file_string);
+    ifs.close();
+
+    // rename the file
+    fs::path file2 = sandbox / "test2.csv";
+    fs::rename(file, file2, ec);
+    if (ec) {
+      logger.error("Could not rename {} to {} - {}", file.string(), file2.string(), ec.message());
+    } else {
+      logger.info("Renamed {} to {}", file.string(), file2.string());
+    }
+
+    // make a subdirectory
+    fs::path sub = sandbox / fs::path{sub_dir};
+    fs::create_directory(sub, ec);
+    if (ec) {
+      logger.error("Could not create directory {} - {}", sub.string(), ec.message());
+    } else {
+      logger.info("Created subdirectory {}", sub.string());
+    }
+
+    // make a file in the subdirectory
+    fs::path sub_file = sub / "subfile.txt";
+    std::ofstream sub_ofs(sub_file);
+    sub_ofs << file_contents;
+    sub_ofs.close();
+    sub_ofs.flush();
+    logger.info("Wrote '{}' to {}", file_contents, sub_file.string());
+
+    // list files in a directory
+    logger.info("Directory iterator:");
+    logger.warn(
+        "NOTE: directory_iterator is not implemented in esp-idf right now :( (as of v5.2.2)");
+    // NOTE: directory_iterator is not implemented in esp-idf right now :(
+    // directory_iterator can be iterated using a range-for loop
+    for (auto const &dir_entry : fs::recursive_directory_iterator{sandbox, ec}) {
+      logger.info("\t{}", dir_entry.path().string());
+    }
+    if (ec) {
+      logger.error("Could not iterate over directory '{}': {}", sandbox.string(), ec.message());
+      logger.info("\tThis is expected since directory_iterator is not implemented in esp-idf.");
+    }
+
+    logger.info("Recursive directory listing:");
+    auto &espp_fs = espp::FileSystem::get();
+    auto files = espp_fs.get_files_in_path(sandbox, true, true);
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+    // cleanup, use convenience functions
+    // NOTE: cannot use fs::remove since it seems POSIX remove() doesn't work
+    // We'll use espp::FileSystem::remove, which works for both files and
+    // directories, and will recursively remove all the contents of the
+    // directory.
+    espp_fs.set_log_level(espp::Logger::Verbosity::DEBUG);
+    if (!espp_fs.remove(sandbox, ec)) {
+      logger.error("Could not remove {}", sandbox.string());
+    } else {
+      logger.info("Cleaned up {}", sandbox.string());
+    }
+
+    // now list entries in root (recursively) after cleanup
+    logger.info("Recursive directory listing after cleanup:");
+    files = espp_fs.get_files_in_path(espp_fs.get_root_path(), true, true);
+    for (const auto &f : files) {
+      logger.info("\t{}", f);
+    }
+
+
+
+
+

Public Functions

+
+
+size_t get_free_space() const
+

Get the amount of free space on the file system.

+
+
Returns
+

The amount of free space in bytes

+
+
+
+ +
+
+size_t get_total_space() const
+

Get the total amount of space on the file system.

+
+
Returns
+

The total amount of space in bytes

+
+
+
+ +
+
+size_t get_used_space() const
+

Get the amount of used space on the file system.

+
+
Returns
+

The amount of used space in bytes

+
+
+
+ +
+
+std::string get_file_time_as_string(const std::filesystem::path &path) const
+

Get the time of a file as a string.

+

This method gets the time of a file as a string in the format “Jan 01 00:00”.

+

See also

+

file_time_to_string()

+
+

+
+
Parameters
+

path – The path to the file

+
+
Returns
+

The time of the file as a string

+
+
+
+ +
+
+std::vector<std::filesystem::path> get_files_in_path(const std::filesystem::path &path, bool include_directories = false, bool recursive = false)
+

Get a vector of files in a directory.

+

This method returns a vector of paths to the files in a directory.

+
+
Parameters
+
    +
  • path – The path to the directory

  • +
  • include_directories – Whether to include directories in the output

  • +
  • recursive – Whether to include files in subdirectories

  • +
+
+
Returns
+

A vector of paths to the files in the directory

+
+
+
+ +
+
+bool remove(const std::filesystem::path &path, std::error_code &ec)
+

Completely remove a file or directory (including contents)

+

This method removes a file or directory and all of its contents. If the path is a directory, it will iterate over the contents and remove them recursively. If the path is a file, it will remove the file. If the path does not exist, it will return false.

+
+
Parameters
+
    +
  • path – The path to the file or directory

  • +
  • ec – The error code to set if an error occurs

  • +
+
+
Returns
+

Whether the file or directory was successfully removed

+
+
+
+ +
+
+bool remove_contents(const std::filesystem::path &path, std::error_code &ec)
+

Remove the contents of a directory, but not the directory itself.

+

This method removes the contents of a directory, but not the directory itself. If the path is not a directory, it will return false. If the path does not exist, it will return false. If the path is a directory, it will iterate over the contents and remove them recursively.

+
+
Parameters
+
    +
  • path – The path to the directory

  • +
  • ec – The error code to set if an error occurs

  • +
+
+
Returns
+

Whether the contents of the directory were successfully removed

+
+
+
+ +
+
+inline std::string list_directory(const std::filesystem::path &path, const ListConfig &config, const std::string &prefix = "")
+

List the contents of a directory.

+

This method lists the contents of a directory. It returns a string containing the contents of the directory. The contents are formatted according to the config. The config is a struct with boolean values for each of the fields to include in the output. The fields are:

    +
  • type: The type of the file (directory, file, etc.)

  • +
  • permissions: The permissions of the file

  • +
  • number_of_links: The number of links to the file

  • +
  • owner: The owner of the file

  • +
  • group: The group of the file

  • +
  • size: The size of the file

  • +
  • date_time: The date and time of the file

  • +
  • recursive: Whether to list the contents of subdirectories

  • +
+

+
+
Parameters
+
    +
  • path – The path to the directory

  • +
  • config – The config for the output

  • +
  • prefix – The prefix to use for the output

  • +
+
+
Returns
+

The contents of the directory

+
+
+
+ +
+
+std::string list_directory(const std::string &path, const ListConfig &config, const std::string &prefix = "")
+

List the contents of a directory.

+

This method lists the contents of a directory. It returns a string containing the contents of the directory. The contents are formatted according to the config. The config is a struct with boolean values for each of the fields to include in the output. The fields are:

    +
  • type: The type of the file (directory, file, etc.)

  • +
  • permissions: The permissions of the file

  • +
  • number_of_links: The number of links to the file

  • +
  • owner: The owner of the file

  • +
  • group: The group of the file

  • +
  • size: The size of the file

  • +
  • date_time: The date and time of the file

  • +
  • recursive: Whether to list the contents of subdirectories

  • +
+

+
+
Parameters
+
    +
  • path – The path to the directory

  • +
  • config – The config for the output

  • +
  • prefix – The prefix to use for the output

  • +
+
+
Returns
+

The contents of the directory

+
+
+
+ +
+
+std::string file_entry_string(const std::filesystem::path &path, const ListConfig &config, const std::string &prefix = "")
+

Get a file entry formatted as a string.

+

This method returns a string formatted as a file entry. The file entry contains the type, permissions, number of links, owner, group, size, date and time, and name of the file. The file entry is formatted according to the config. The config is a struct with boolean values for each of the fields to include in the output. The fields are:

    +
  • type: The type of the file (directory, file, etc.)

  • +
  • permissions: The permissions of the file

  • +
  • number_of_links: The number of links to the file

  • +
  • owner: The owner of the file

  • +
  • group: The group of the file

  • +
  • size: The size of the file

  • +
  • date_time: The date and time of the file

    +

    See also

    +

    file_entry_string()

    +
    +

  • +
+

+
+
Parameters
+
    +
  • path – The path to the file

  • +
  • config – The config for the output

  • +
  • prefix – The prefix to use for the output

  • +
+
+
Returns
+

The file entry as a string

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline void set_mount_as_read_only(bool read_only)
+

Set whether to mount the file system as read only.

+
+

Note

+

This only has an effect if called before the file system is mounted, i.e. before the first call to get()

+
+
+
Parameters
+

read_only – Whether the file system is mounted as read only

+
+
+
+ +
+
+static inline bool is_mount_as_read_only()
+

Get whether the file system is mounted as read only.

+
+
Returns
+

Whether the file system is mounted as read only

+
+
+
+ +
+
+static inline void set_grow_on_mount(bool grow_on_mount)
+

Set whether to grow the file system on mount.

+
+

Note

+

This only has an effect if called before the file system is mounted, i.e. before the first call to get()

+
+
+
Parameters
+

grow_on_mount – Whether to grow the file system on mount

+
+
+
+ +
+
+static inline bool is_grow_on_mount()
+

Get whether the file system was grown on mount.

+
+
Returns
+

Whether the file system was grown on mount

+
+
+
+ +
+
+static std::string human_readable(size_t bytes)
+

Get a human readable string for a byte size.

+

This method returns a human readable string for a byte size. It is copied from the example on the page: https://en.cppreference.com/w/cpp/filesystem/file_size

+
+
Parameters
+

bytes – The byte size

+
+
Returns
+

The human readable string

+
+
+
+ +
+
+static inline const char *get_partition_label()
+

Get the partition label.

+
+
Returns
+

The partition label

+
+
+
+ +
+
+static std::string get_mount_point()
+

Get the mount point.

+

The mount point is the root directory of the file system. It is the root directory of the partition with the partition label.

+

See also

+

get_root_path()

+
+

+
+
Returns
+

The mount point

+
+
+
+ +
+
+static std::filesystem::path get_root_path()
+

Get the root path.

+

The root path is the root directory of the file system.

+

See also

+

get_mount_point()

+
+

+
+
Returns
+

The root path

+
+
+
+ +
+
+static std::string to_string(const std::filesystem::perms &permissions)
+

Convert file permissions to a string.

+

This method converts file permissions to a string in the format “rwxrwxrwx”.

+
+
Parameters
+

permissions – The file permissions

+
+
Returns
+

The file permissions as a string

+
+
+
+ +
+
+static std::string to_string(time_t time)
+

Convert a time_t to a string.

+

This method converts a time_t to a string in the format “Jan 01 00:00”.

+
+
Parameters
+

time – The time_t to convert

+
+
Returns
+

The time as a string

+
+
+
+ +
+
+static inline FileSystem &get()
+

Access the singleton instance of the file system.

+
+
Returns
+

Reference to the file system instance

+
+
+
+ +
+
+template<typename TP>
static inline std::time_t to_time_t(TP tp)
+

Function to convert a time_point to a time_t.

+

This function converts a time_point to a time_t. This function is needed because the standard library does not provide a function to convert a time_point to a time_t (until c++20 but support seems lacking on esp32). This function is taken from https://stackoverflow.com/a/61067330

+
+
Template Parameters
+

TP – The type of the time_point.

+
+
Parameters
+

tp – The time_point to convert.

+
+
Returns
+

The time_t.

+
+
+
+ +
+
+
+struct ListConfig
+

Config for listing the contents of a directory.

+

This struct is used to configure the output of the list_directory() method. It contains boolean values for each of the fields to include in the output.

+
+

Public Members

+
+
+bool type = true
+

The type of the file (directory, file, etc.)

+
+ +
+
+bool permissions = true
+

The permissions of the file.

+
+ +
+
+bool number_of_links = true
+

The number of links to the file.

+
+ +
+
+bool owner = true
+

The owner of the file.

+
+ +
+
+bool group = true
+

The group of the file.

+
+ +
+
+bool size = true
+

The size of the file.

+
+ +
+
+bool date_time = true
+

The date and time of the file.

+
+ +
+
+bool recursive = false
+

Whether to list the contents of subdirectories.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/file_system_example.html b/file_system_example.html new file mode 100644 index 000000000..d8887212a --- /dev/null +++ b/file_system_example.html @@ -0,0 +1,231 @@ + + + + + + + File System Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

File System Example

+

This example shows how the file_system component can be used to manage files +on a littlefs file system +(wrapping the associated esp_littlefs +component).

+

The example further shows how POSIX / newlib APIs can be used alongside (most +of) the std::filesystem APIs.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-02 at 10 09 29

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/biquad.html b/filters/biquad.html new file mode 100644 index 000000000..d4afbfa4b --- /dev/null +++ b/filters/biquad.html @@ -0,0 +1,325 @@ + + + + + + + Biquad Filter - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Biquad Filter

+

The BiquadFilter class provides an implementation of a Digital Biequad Filter with implementations for +both the Direct Form 1 and Direct Form 2.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class BiquadFilterDf1
+

Digital Biquadratic Filter (Direct Form 1).

+

+Implements the following difference equation:

+

+\[ +y[n] = \frac{b_0 * x[n] + b_1 * x[n-1] + b_2 * x[n-2] + - a_1 * y[n-1] - a_2 * y[n-2]}{a_0} +\]
+

+ + +
+

Note

+

This filter is normalized (meaning the coefficients it uses will have already been divided by a[0])

+
+
+

Public Functions

+
+
+inline float update(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+ +
+
+class BiquadFilterDf2
+

Digital Biquadratic Filter (Direct Form 2). Direct form 2 only needs N delay units (N is the order), which is potentially half as much as Direct Form 1, however with Direct Form 2 there is a higher risk of arithmetic overflow. This implementation uses the esp-dsp implementation of optimized biquad direct form 2 filter function.

+

+Implements the following difference equation:

+

+\[ +y[n] = \frac{b_0 * x[n] + b_1 * x[n-1] + b_2 * x[n-2] + - a_1 * y[n-1] - a_2 * y[n-2]}{a_0} +\]
+

+ +
+

Note

+

This filter is normalized (meaning the coefficients it uses will have already been divided by a[0])

+
+
+

Public Functions

+
+
+inline void update(const float *input, float *output, size_t length)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+
    +
  • input – Pointer to (floating point) array of new samples of the input data

  • +
  • output – Pointer to (floating point) array which will be filled with the filtered input.

  • +
  • length – Number of samples, should be >= length of input & output memory.

  • +
+
+
+
+ +
+
+inline float update(const float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/butterworth.html b/filters/butterworth.html new file mode 100644 index 000000000..618f7a165 --- /dev/null +++ b/filters/butterworth.html @@ -0,0 +1,303 @@ + + + + + + + Butterworth Filter - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Butterworth Filter

+

The ButterworthFilter class provides an implementation of a Digital +Butterworth Filter, +implemented as biquad sections (second order sections).

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<size_t ORDER, class Impl = BiquadFilterDf1>
class ButterworthFilter : public espp::SosFilter<(ORDER + 1) / 2, BiquadFilterDf1>
+

Digital butterworth filter, implemented as biquad sections (Second Order Sections).

+
+

Note

+

See https://en.wikipedia.org/wiki/Butterworth_filter for more information.

+
+
+
Template Parameters
+
    +
  • ORDER – The order of the filter.

  • +
  • Impl – Which Biquad implementation form to use.

  • +
+
+
+
+

Public Functions

+
+
+inline explicit ButterworthFilter(const Config &config)
+

Construct the butterworth filter for the given config.

+
+
Parameters
+

config – The configuration struct for the Butterworth Filter

+
+
+
+ +
+
+inline float update(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+inline float operator()(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+
+struct Config
+

Butterworth configuration.

+
+

Public Members

+
+
+float normalized_cutoff_frequency
+

Filter cutoff frequency in the range [0.0, 0.5] (normalizd to sample frequency, = 2 * f_cutoff / f_sample).

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/filters_example.html b/filters/filters_example.html new file mode 100644 index 000000000..c9adabb1f --- /dev/null +++ b/filters/filters_example.html @@ -0,0 +1,233 @@ + + + + + + + Filters Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Filters Example

+

This example shows how to use a LowpassFilter, ButterworthFilter, and +SimpleLowpassFilter from the filters component to filter signals. This +example simply operates on random perturbations of auto-generated data.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/index.html b/filters/index.html new file mode 100644 index 000000000..6016d2e6d --- /dev/null +++ b/filters/index.html @@ -0,0 +1,218 @@ + + + + + + + Filter APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Filter APIs

+ +

There are several different types of filters provided, as well as some base +classes from which to build more generic filters.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/lowpass.html b/filters/lowpass.html new file mode 100644 index 000000000..f75ddcbd7 --- /dev/null +++ b/filters/lowpass.html @@ -0,0 +1,340 @@ + + + + + + + Lowpass Filter - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lowpass Filter

+

The LowpassFilter class provides an implementation of a digial lowpass +infinite impulse response (IIR) filter, which leverages the hardware +acceleration provided by esp-dsp and +which leverages the vector instructions on the espressif processors.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class LowpassFilter
+

Lowpass infinite impulse response (IIR) filter.

+
+

Public Functions

+
+
+LowpassFilter() = default
+

Default constructor.

+
+ +
+
+explicit LowpassFilter(const Config &config)
+

Initialize the lowpass filter coefficients based on the config.

+
+
Parameters
+

config – Configuration struct.

+
+
+
+ +
+
+void configure(const Config &config)
+

Set the filter coefficients based on the config.

+
+
Parameters
+

config – Configuration struct.

+
+
+
+ +
+
+void update(const float *input, float *output, size_t length)
+

Filter the input samples, updating internal state, and writing the filtered values to the data pointed to by output.

+
+

Note

+

On ESP32, the input and output arrays must have attribute((aligned(16))) to ensure proper alignment for the ESP32 DSP functions.

+
+
+
Parameters
+
    +
  • input – Pointer to (floating point) array of new samples of the input data

  • +
  • output – Pointer to (floating point) array which will be filled with the filtered input.

  • +
  • length – Number of samples, should be >= length of input & output memory.

  • +
+
+
+
+ +
+
+float update(const float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+float operator()(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+void reset()
+

Reset the filter state to zero.

+
+ +
+
+
+struct Config
+

Configuration for the lowpass filter.

+
+

Public Members

+
+
+float normalized_cutoff_frequency
+

Filter cutoff frequency in the range [0.0, 0.5] (normalizd to sample frequency, = 2 * f_cutoff / f_sample).

+
+ +
+
+float q_factor
+

Quality (Q) factor of the filter. The higher the Q the better the filter.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/simple_lowpass.html b/filters/simple_lowpass.html new file mode 100644 index 000000000..da1169f67 --- /dev/null +++ b/filters/simple_lowpass.html @@ -0,0 +1,324 @@ + + + + + + + Simple Lowpass Filter - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Simple Lowpass Filter

+

The SimpleLowpassFilter class provides an implementation of a simple moving +average filter with a configurable time constant.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class SimpleLowpassFilter
+

Simple lowpass filter using a time constant and a stored value.

+
+

Public Functions

+
+
+SimpleLowpassFilter() = default
+

Construct a new SimpleLowpassFilter object.

+
+ +
+
+explicit SimpleLowpassFilter(const Config &config)
+

Initialize the lowpass filter based on the config.

+
+
Parameters
+

config – Configuration struct.

+
+
+
+ +
+
+void set_time_constant(const float time_constant)
+

Set the time constant of the filter.

+
+
Parameters
+

time_constant – Time constant of the filter.

+
+
+
+ +
+
+float get_time_constant() const
+

Get the time constant of the filter.

+
+
Returns
+

Time constant of the filter.

+
+
+
+ +
+
+float update(const float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input, time, and history.

+
+
+
+ +
+
+float operator()(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input, time, and history.

+
+
+
+ +
+
+void reset()
+

Reset the filter to its initial state.

+
+ +
+
+
+struct Config
+

Configuration for the lowpass filter.

+
+

Public Members

+
+
+float time_constant = 0.0f
+

Time constant of the filter.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/sos.html b/filters/sos.html new file mode 100644 index 000000000..553114ac5 --- /dev/null +++ b/filters/sos.html @@ -0,0 +1,285 @@ + + + + + + + Second Order Sections (SoS) Filter - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Second Order Sections (SoS) Filter

+

The SosFilter class provides an implementation of a Second Order Sections +(SoS) filter. For more information please see series second-order sections +as well as Digital Biquad Filter.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<size_t N, class SectionImpl>
class SosFilter
+

Second Order Sections Filter.

+ + +

Subclassed by espp::ButterworthFilter< ORDER, Impl >

+
+

Public Functions

+
+
+inline explicit SosFilter(const std::array<TransferFunction<3>, N> &config)
+

Construct a second order sections filter.

+
+
Parameters
+

config – Array of TransferFunction<3> for configuring each of the biquad sections.

+
+
+
+ +
+
+inline float update(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+inline float operator()(float input)
+

Filter the signal sampled by input, updating internal state, and returning the filtered output.

+
+
Parameters
+

input – New sample of the input data.

+
+
Returns
+

Filtered output based on input and history.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/filters/transfer_function.html b/filters/transfer_function.html new file mode 100644 index 000000000..1f2aaf7a7 --- /dev/null +++ b/filters/transfer_function.html @@ -0,0 +1,223 @@ + + + + + + + Transfer Function API - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Transfer Function API

+

The TransferFunction struct provides a simple container for storing the A and +B coefficients for an N-th order transfer function.

+
+

API Reference

+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ftp/ftp_server.html b/ftp/ftp_server.html new file mode 100644 index 000000000..7304ad0df --- /dev/null +++ b/ftp/ftp_server.html @@ -0,0 +1,643 @@ + + + + + + + FTP Server - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FTP Server

+

The FtpServer class implements a simple FTP server. It accepts new connections +and spawns a new FtpClientSession for each one. Each session is handled in its +own thread.

+

The FtpClientSession class implements the FTP protocol. It is responsible for +handling the commands and sending the responses.

+

Note that the FTP server does not implement any authentication mechanism. It +accepts any username and password.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class FtpServer : public espp::BaseComponent
+

A class that implements a FTP server.

+
+

Public Functions

+
+
+inline FtpServer(std::string_view ip_address, uint16_t port, const std::filesystem::path &root)
+

A class that implements a FTP server.

+
+

Note

+

The IP Address is not currently used to select the right interface, but is instead passed to the FtpClientSession so that it can be used in the PASV command.

+
+
+
Parameters
+
    +
  • ip_address – The IP address to listen on.

  • +
  • port – The port to listen on.

  • +
  • root – The root directory of the FTP server.

  • +
+
+
+
+ +
+
+inline ~FtpServer()
+

Destroy the FTP server.

+
+ +
+
+inline bool start()
+

Start the FTP server. Bind to the port and start accepting connections.

+
+
Returns
+

True if the server was started, false otherwise.

+
+
+
+ +
+
+inline void stop()
+

Stop the FTP server.

+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class FtpClientSession : public espp::BaseComponent
+

Class representing a client that is connected to the FTP server. This class is used by the FtpServer class to handle the client’s requests.

+
+

Public Functions

+
+
+inline int id() const
+

Get the id of the client session.

+
+
Returns
+

The id of the client session.

+
+
+
+ +
+
+inline std::filesystem::path current_directory() const
+

Get the current directory of the client session.

+
+
Returns
+

The current directory of the client session.

+
+
+
+ +
+
+inline bool is_connected() const
+

Check if the client session has a valid control connection.

+

This function checks if the client session has a valid control connection. A control connection is valid if the control socket is valid and connected.

+
+
Returns
+

True if the control connection is valid, false otherwise.

+
+
+
+ +
+
+inline bool is_passive_data_connection() const
+

Check if the client is using a passive data connection.

+

This function checks if the client is using a passive data connection. A client is using a passive data connection if the client has sent a PASV command and the session was able to create a passive socket.

+
+
Returns
+

True if the client is using a passive data connection, false otherwise.

+
+
+
+ +
+
+inline bool is_alive() const
+

Check if the client session is alive.

+

This function checks if the client session is alive. A client session is alive if the task is running.

+
+
Returns
+

True if the client session is alive, false otherwise.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ftp/ftp_server_example.html b/ftp/ftp_server_example.html new file mode 100644 index 000000000..820547e23 --- /dev/null +++ b/ftp/ftp_server_example.html @@ -0,0 +1,236 @@ + + + + + + + FTP Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FTP Example

+

This example showcases the use of the FtpServer from the ftp component.

+
+

How to use example

+
+

Configure the project

+
idf.py menuconfig
+
+
+

You’ll need to configure the WiFi information that you wish the ESP to connect +to. You can optionally configure the FTP server port if you wish to use a +non-standard port.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/ftp/index.html b/ftp/index.html new file mode 100644 index 000000000..67ba48b01 --- /dev/null +++ b/ftp/index.html @@ -0,0 +1,207 @@ + + + + + + + FTP APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FTP APIs

+
+ +
+

FTP can be used to transfer files between computers. ESPP currently provides an +implementation of the FTP server side. The FTP client side is not yet +implemented.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 000000000..2486fcb1d --- /dev/null +++ b/genindex.html @@ -0,0 +1,6385 @@ + + + + + + Index - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +

Index

+ +
+ _ + | C + | E + | M + | P + | S + +
+

_

+ + + +
+ +

C

+ + +
+ +

E

+ + + +
+ +

M

+ + +
+ +

P

+ + +
+ +

S

+ + +
+ + + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/haptics/bldc_haptics.html b/haptics/bldc_haptics.html new file mode 100644 index 000000000..18f684cbb --- /dev/null +++ b/haptics/bldc_haptics.html @@ -0,0 +1,644 @@ + + + + + + + BLDC Haptics - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLDC Haptics

+

The BldcHaptics class is a high-level interface for controlling a BLDC motor +with a haptic feedback loop. It is designed to be used to provide haptic +feedback as part of a rotary input device (the BLDC motor). The component +provides a DetentConfig interface for configuring the input / haptic feedback +profile for the motor dynamically with configuration of:

+
+
    +
  • Range of motion (min/max position + width of each position)

  • +
  • Width of each position in the range (which will be used to calculate the +actual range of motion based on the number of positions)

  • +
  • Strength of the haptic feedback at each position (detent)

  • +
  • Strength of the haptic feedback at the edges of the range of motion

  • +
  • Specific positions to provide haptic feedback at (detents)

  • +
  • Snap point (percentage of position width which will trigger a snap to the +nearest position)

  • +
+
+

The component also provides a HapticConfig interface for configuring the +haptic feedback loop with configuration of:

+
+
    +
  • Strength of the haptic feedback

  • +
  • Frequency of the haptic feedback [currently not implemented]

  • +
  • Duration of the haptic feedback [currently not implemented]

  • +
+
+ +
+

API Reference

+
+

Header File

+ +
+
+

Header File

+ +
+
+

Header File

+ +
+
+

Classes

+
+
+template<MotorConcept M>
class BldcHaptics : public espp::BaseComponent
+

Class which creates haptic feedback for the user by vibrating the motor This class is based on the work at https://github.com/scottbez1/smartknob to use a small BLDC gimbal motor as a haptic feedback device. It does so by varying the control type, setpoints, and gains of the motor to create a vibration. The motor is driven using the ESP32’s MCPWM peripheral. The motor is driven in a closed loop using the encoder feedback.

+

+The haptics provided by this class enable configuration of:

    +
  • Positions (with non-magnetic detents) - evenly spaced across the allowed range of motion

  • +
  • Number of magnetic detents - where the

  • +
  • Width of the detents

  • +
  • Strength of the detents

  • +
  • Snap point (position at which the motor will snap to the next detent / position)

  • +
  • Bounds on the rotation of the motor - can be unbounded, bounded within a single revolution, or bounded within multiple revolutions

  • +
+

+

The haptics provided by this class provide the following functionality:

    +
  • Positions: Evenly spaced positions across the allowed range of motion (specified by the min and max position) will have a detent.

  • +
  • Detents: Manually specified detents will be placed at the specified positions. The detents will have a specified width and strength.

  • +
  • End Stops: The motor will vibrate when it is at the min or max position. This is useful for providing feedback when the motor is at the end of its range of motion. The end stops are configured by specifying the strength of the end stops.

  • +
  • Snap point: The snap point is the position at which the motor will snap to the next detent / position. This is useful for providing feedback when the motor is at a certain position. The snap point is configured by specifying the snap point (percentage of the way through the detent) and the snap point bias (percentage of the way through the detent to bias the snap point).

  • +
+

+

Some example configurations are provided as static constexpr in espp::detail. They are:

    +
  • UNBOUNDED_NO_DETENTS: No detents, no end stops, no snap point, no bounds

  • +
  • BOUNDED_NO_DETENTS: No detents, no end stops, no snap point, bounded within a single revolution

  • +
  • MULTI_REV_NO_DETENTS: No detents, no end stops, no snap point, bounded within multiple revolutions

  • +
  • COARSE_VALUES_STRONG_DETENTS: detents, end stops, snap point, bounded within a single revolution

  • +
  • FINE_VALUES_NO_DETENTS: No detents, end stops, snap point, bounded

  • +
  • FINE_VALUES_WITH_DETENTS: detents, end stops, snap point, bounded

  • +
  • RETURN_TO_CENTER_WITH_DETENTS: 3 detents, end stops, snap point, bounded within a single revolution

  • +
  • RETURN_TO_CENTER_WITH_DETENTS_AND_MULTIPLE_REVOLUTIONS: 3 detents, end stops, snap point, bounded within multiple revolutions

  • +
+

+

Some haptic behaviors that can be implemented with this library are:

    +
  • Unbounded with no detents

  • +
  • Bounded with no detents

  • +
  • Multiple revolutions

  • +
  • On/off with strong detent

  • +
  • Return to center without detents

  • +
  • Return to center with detents

  • +
  • Fine values with no detents

  • +
  • Fine values with detents

  • +
  • Coarse values with strong detents

  • +
  • Coarse values with weak detents

  • +
+

+
+

Example 1: Basic usage

+
    using BldcHaptics = espp::BldcHaptics<BldcMotor>;
+
+    auto haptic_motor = BldcHaptics({.motor = motor,
+                                     .kp_factor = 2,
+                                     .kd_factor_min = 0.01,
+                                     .kd_factor_max = 0.04,
+                                     .log_level = espp::Logger::Verbosity::INFO});
+
+    // auto detent_config = espp::detail::UNBOUNDED_NO_DETENTS;
+    // auto detent_config = espp::detail::BOUNDED_NO_DETENTS;
+    // auto detent_config = espp::detail::MULTI_REV_NO_DETENTS;
+    // auto detent_config = espp::detail::ON_OFF_STRONG_DETENTS;
+    auto detent_config = espp::detail::COARSE_VALUES_STRONG_DETENTS;
+    // auto detent_config = espp::detail::FINE_VALUES_NO_DETENTS;
+    // auto detent_config = espp::detail::FINE_VALUES_WITH_DETENTS;
+    // auto detent_config = espp::detail::MAGNETIC_DETENTS;
+    // auto detent_config = espp::detail::RETURN_TO_CENTER_WITH_DETENTS;
+
+    logger.info("{}", detent_config);
+
+    haptic_motor.update_detent_config(detent_config);
+    // this will start the haptic motor thread which will run in the background.
+    // If we want to change the detent config we can call update_detent_config()
+    // and it will update the detent config in the background thread.
+    haptic_motor.start();
+
+
+
+
+

Example 2: Playing a haptic click / buzz

+
      haptic_motor.play_haptic(espp::detail::HapticConfig{
+          .strength = 5.0f,
+          .frequency = 200.0f, // Hz, NOTE: frequency is unused for now
+          .duration = 1s       // NOTE: duration is unused for now
+      });
+
+
+
+
+

Note

+

The motor is configured to be driven in an open-loop mode, so that the PID contained in the motor controller does not interfere with the haptic feedback.

+
+
+

Public Functions

+
+
+inline explicit BldcHaptics(const Config &config)
+

Constructor for the haptic motor.

+
+
Parameters
+

config – Configuration for the haptic motor

+
+
+
+ +
+
+inline ~BldcHaptics()
+

Destructor for the haptic motor.

+
+

Note

+

This will stop the motor if it is running

+
+
+ +
+
+inline bool is_running() const
+

Check if the haptic motor is running.

+
+
Returns
+

True if the haptic motor is running, false otherwise

+
+
+
+ +
+
+inline void start()
+

Start the haptic motor.

+
+ +
+
+inline void stop()
+

Stop the haptic motor.

+
+ +
+
+inline float get_position() const
+

Get the current position of the haptic motor.

+
+
Returns
+

Current position of the haptic motor

+
+
+
+ +
+
+inline void update_detent_config(const detail::DetentConfig &config)
+

Configure the detents for the haptic motor.

+
+ +
+
+inline void play_haptic(const detail::HapticConfig &config)
+

Play haptic feedback.

+
+

Note

+

Plays a somewhat-configurable haptic “buzz” / “click” for the user

+
+
+

Note

+

This is a blocking call that will wait for the haptic feedback to finish before returning. It will also block the motor/detent task from running until the haptic feedback is finished.

+
+
+
Parameters
+

config – Configuration for the haptic feedback

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the haptic motor.

+
+

Public Members

+
+
+std::reference_wrapper<M> motor
+

Pointer to the motor to use for haptics.

+
+ +
+
+float kp_factor = {2}
+

Factor to multiply the detent strength by to get kp (default 2). Used for both detents and end stops.

+
+

Note

+

Depending on the motor, this may need to be adjusted to get the desired behavior.

+
+
+ +
+
+float kd_factor_min = {0.01}
+

Min Factor to multiply the detent strength by to get kd (default 0.01).

+
+

Note

+

Depending on the motor, this may need to be adjusted to get the desired behavior.

+
+
+ +
+
+float kd_factor_max = {0.04}
+

Max Factor to multiply the detent strength by to get kd (default 0.04).

+
+

Note

+

Depending on the motor, this may need to be adjusted to get the desired behavior.

+
+
+ +
+
+Logger::Verbosity log_level
+

Log level to use for the haptics.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/haptics/bldc_haptics_example.html b/haptics/bldc_haptics_example.html new file mode 100644 index 000000000..b79d8b7db --- /dev/null +++ b/haptics/bldc_haptics_example.html @@ -0,0 +1,298 @@ + + + + + + + BLDC Haptics Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BLDC Haptics Example

+

This example shows the use of the BldcHaptics component to drive a BLDC motor +(such as a tiny gimbal motor) as a user input / output device that provides +haptic feedback (such as might be used as a rotary encoder input).

+
+

How to use example

+
+

Hardware Required

+

This example requires a lot of hardware such as:

+
    +
  • Magnetic encoder chip (this example uses Mt6701)

  • +
  • BLDC Motor Driver chip (this example was tested with the TMC6300 BOB dev board)

  • +
  • Some mounting hardware to mount the motor, magnet, encoder, etc.

  • +
+

:warning:

+
+

NOTE: you MUST make sure that you run the example with the +zero_electrical_offset value set to 0 (or not provided) at least once +otherwise the sample will not work and could potentially damage your motor.

+
+

Currently, this is designed to be run on a TinyS3 connected to the motor +driver and encoder via breadboard with the motor powered via a benchtop power +supply at 5V.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

This example can be re-run (by modifying the code to change the selected +DetentConfig from one of the predefined configurations or by making your own) +to produce various behaviors. Additionally, at the end of each demo, it will +play a haptic buzz / click using the motor.

+

For more information, see the documentation or the original PR: +https://github.com/esp-cpp/espp/pull/60

+

Some examples:

+
+

coarse values strong detents (best with sound)

+

https://github.com/esp-cpp/espp/assets/213467/a256b401-6e45-4284-89c7-2dec9a49daa7

+
+
+

magnetic detents (best with sound)

+

https://github.com/esp-cpp/espp/assets/213467/ab1ace5c-f967-4cfc-b304-7736fdb35bcb

+
+
+

On / Off Strong Detents (best with sound)

+

https://github.com/esp-cpp/espp/assets/213467/038d79b1-7cd9-4af9-b7e8-1b4daf6a363a

+
+
+

Multi-rev no detents

+

https://github.com/esp-cpp/espp/assets/213467/2af81edb-67b8-488b-ae7a-3549be36b8cc

+
+
+
+

Troubleshooting

+

Make sure to run the example once with zero_electrical_offset set to 0 so that +the motor will go through a calibration / zero offset routine. At the end of +this startup routine it will print the measured zero electrical offset that you +can then provide within the code, at which point it will not need to run the +calibration routine.

+

You must run this calibration any time you change your hardware configuration +(such as by remounting your motor, magnet, encoder chip).

+
+
+

Example Breakdown

+

This example is relatively complex, but builds complex haptic behavior using the +following components:

+
    +
  • espp::Mt6701

  • +
  • espp::BldcDriver

  • +
  • espp::BldcMotor

  • +
  • espp::BldcHaptics

  • +
  • ESP-IDF’s i2c peripheral driver

  • +
+

You combine the Mt6701 and BldcDriver together when creating the BldcMotor +and then simply pass the BldcMotor to the BldcHaptics component. At that +point, you only have to interface to the BldcHaptics to read the input +position or reconfigure the haptics.

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/haptics/drv2605.html b/haptics/drv2605.html new file mode 100644 index 000000000..fb02256cf --- /dev/null +++ b/haptics/drv2605.html @@ -0,0 +1,1050 @@ + + + + + + + DRV2605 Haptic Motor Driver - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

DRV2605 Haptic Motor Driver

+

The DRV2605 haptic motor driver component allows the user to configure and +play custom or preconfigured haptic feedback sequences via a serial interface +such as I2C. It supports directly driving ECM (eccentric rotating mass) and LRA +(linear resonant actuator) type haptic motors. It also supports fully custom +waveforms (e.g. via using the audio, pwm / analog functions) as well as a preset +library of 123 different haptic waveforms which can be played in sequences of up +to 8 waveforms.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Drv2605 : public espp::BasePeripheral<>
+

Class for controlling the Texas Instruments DRV2605 Haptic Motor Driver. Drives ECM (eccentric rotating mass) and LRA (linear resonant actuator) types of haptic motors. The datasheet for the DRV2605 can be found here: https://www.ti.com/lit/ds/symlink/drv2605.pdf?ts=1678892742599.

+
+

DRV2605 Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_1,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+    // make the actual drv2605 class
+    espp::Drv2605 drv2605(espp::Drv2605::Config{
+        .device_address = espp::Drv2605::DEFAULT_ADDRESS,
+        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+        .read_register =
+            std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+                      std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+        .motor_type = espp::Drv2605::MotorType::LRA});
+    std::error_code ec;
+    // we're using an ERM motor, so select an ERM library (1-5).
+    // drv2605.select_library(1, ec);
+    // we're using an LRA motor, so select an LRA library (6).
+    drv2605.select_library(espp::Drv2605::Library::LRA, ec);
+    if (ec) {
+      logger.error("select library failed: {}", ec.message());
+    }
+    // make the task which will cycle through all the waveforms
+    auto task_fn = [&drv2605](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - start).count();
+      static uint8_t waveform = 0;
+      std::error_code ec;
+      drv2605.stop(ec);
+      if (ec) {
+        logger.error("stop failed: {}", ec.message());
+        return false;
+      }
+      drv2605.set_waveform(0, (espp::Drv2605::Waveform)waveform, ec);
+      if (ec) {
+        logger.error("set waveform failed: {}", ec.message());
+        return false;
+      }
+      drv2605.set_waveform(1, espp::Drv2605::Waveform::END, ec);
+      if (ec) {
+        logger.error("set waveform failed: {}", ec.message());
+        return false;
+      }
+      drv2605.start(ec);
+      if (ec) {
+        logger.error("start failed: {}", ec.message());
+        return false;
+      }
+      waveform++;
+      if (waveform > (uint8_t)espp::Drv2605::Waveform::MAX) {
+        waveform = 0;
+      }
+      logger.info("{:.3f}, {}", elapsed, waveform);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        using namespace std::chrono_literals;
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 1s);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task::make_unique({.callback = task_fn,
+                                         .task_config =
+                                             {
+                                                 .name = "example",
+                                                 .stack_size_bytes{4 * 1024},
+                                             },
+                                         .log_level = espp::Logger::Verbosity::INFO});
+    task->start();
+
+
+
+
+

Public Types

+
+
+enum class Mode : uint8_t
+

The mode of the vibration.

+

Values:

+
+
+enumerator INTTRIG
+

Internal Trigger (call star() to start playback)

+
+ +
+
+enumerator EXTTRIGEDGE
+

External edge trigger (rising edge on IN pin starts playback)

+
+ +
+
+enumerator EXTTRIGLVL
+

External level trigger (playback follows state of IN pin)

+
+ +
+
+enumerator PWMANALOG
+

PWM/Analog input.

+
+ +
+
+enumerator AUDIOVIBE
+

Audio-to-vibe mode.

+
+ +
+
+enumerator REALTIME
+

Real-time playback (RTP)

+
+ +
+
+enumerator DIAGNOS
+

Diagnostics.

+
+ +
+
+enumerator AUTOCAL
+

Auto-calibration.

+
+ +
+ +
+
+enum class Waveform : uint8_t
+

The waveforms supported by the DRV2605. It has 123 different waveforms, with waveform ID 0 being a special END identifier used when playing multiple waveforms in sequence.

+
+

Note

+

All of the waveform names have not been enumerated here. For a complete list, please see https://learn.adafruit.com/assets/72593

+
+

Values:

+
+
+enumerator END
+

Signals this is the end of the waveforms to play.

+
+ +
+
+enumerator STRONG_CLICK
+
+ +
+
+enumerator SHARP_CLICK
+
+ +
+
+enumerator SOFT_BUMP
+
+ +
+
+enumerator DOUBLE_CLICK
+
+ +
+
+enumerator TRIPLE_CLICK
+
+ +
+
+enumerator SOFT_FUZZ
+
+ +
+
+enumerator STRONG_BUZZ
+
+ +
+
+enumerator ALERT_750MS
+
+ +
+
+enumerator ALERT_1000MS
+
+ +
+
+enumerator BUZZ1
+
+ +
+
+enumerator BUZZ2
+
+ +
+
+enumerator BUZZ3
+
+ +
+
+enumerator BUZZ4
+
+ +
+
+enumerator BUZZ5
+
+ +
+
+enumerator PULSING_STRONG_1
+
+ +
+
+enumerator PULSING_STRONG_2
+
+ +
+
+enumerator TRANSITION_CLICK_1
+
+ +
+
+enumerator TRANSITION_HUM_1
+
+ +
+
+enumerator MAX
+

Values >= to this do not correspond to valid waveforms.

+
+ +
+ +
+
+enum class MotorType
+

The type of vibration motor connected to the Drv2605.

+

Values:

+
+
+enumerator ERM
+

Eccentric Rotating Mass (more common, therefore default)

+
+ +
+
+enumerator LRA
+

Linear Resonant Actuator.

+
+ +
+ +
+
+enum class Library
+

The library of waveforms to use.

+
+

Note

+

The DRV2605 has 7 different libraries of waveforms. The first library is empty, and the next 5 are ERM (eccentric rotating mass) libraries. The last library is an LRA (linear resonant actuator) library.

+
+

Values:

+
+
+enumerator EMPTY
+
+ +
+
+enumerator ERM_0
+
+ +
+
+enumerator ERM_1
+
+ +
+
+enumerator ERM_2
+
+ +
+
+enumerator ERM_3
+
+ +
+
+enumerator ERM_4
+
+ +
+
+enumerator LRA
+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Drv2605(const Config &config)
+

Construct and initialize the DRV2605.

+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the DRV2605.

+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline void start(std::error_code &ec)
+

Start playing the configured waveform / sequence.

+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline void stop(std::error_code &ec)
+

Stop playing the waveform / sequence.

+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline void set_mode(Mode mode, std::error_code &ec)
+

Set the mode of the vibration.

+
+
Parameters
+
    +
  • mode – Mode to set to.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_waveform(uint8_t slot, Waveform w, std::error_code &ec)
+

Set the waveform slot at slot to \w.

+
+

Note

+

When calling start() to play the configured waveform slots, the driver will always start playing from slot 0 and will continue until it reaches a slot that has been configured with the Waveform::END.

+
+
+
Parameters
+
    +
  • slot – The slot (0-8) to set.

  • +
  • w – The Waveform to play in slot slot.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void select_library(Library lib, std::error_code &ec)
+

Select the waveform library to use.

+
+
Parameters
+
    +
  • lib – Library to use, 0=Empty, 1-5 are ERM, 6 is LRA

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure for the DRV2605.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of the device.

+
+ +
+
+BasePeripheral::write_fn write
+

Function for writing a byte to a register on the Drv2605.

+
+ +
+
+BasePeripheral::read_register_fn read_register
+

Function for reading a register from the Drv2605.

+
+ +
+
+MotorType motor_type = {MotorType::ERM}
+

MotorType that this driver is driving.

+
+ +
+
+bool auto_init = {true}
+

If true, the driver will initialize the DRV2605 on construction.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the Drv2605.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/haptics/drv2605_example.html b/haptics/drv2605_example.html new file mode 100644 index 000000000..de4acc9a6 --- /dev/null +++ b/haptics/drv2605_example.html @@ -0,0 +1,234 @@ + + + + + + + Drv2605 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Drv2605 Example

+

This example shows the use of the drv2605 component to communicate with and +control a DRV2605 I2C haptic motor driver for linear resonant actuator (LRA) and +eccentric rotating mass (ERM) haptic motors.

+

image

+
+

How to use example

+
+

Hardware Required

+

This example can be used with the Adafruit DRV2605 +Breakout over I2C.

+

The sample has code for both ERM and LRA, but make sure to update the call to +drv2605.select_library(...) depending on which type of motor you have (ERM is +1-5, LRA is 6).

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/haptics/index.html b/haptics/index.html new file mode 100644 index 000000000..dd7b04b7e --- /dev/null +++ b/haptics/index.html @@ -0,0 +1,210 @@ + + + + + + + Haptics APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Haptics APIs

+ +

There are multiple components which provide haptic feedback functionality, +ranging from haptics driven using BLDC motors to specific peripheral drivers +designed for directly driving ERM (eccentric rotating mass) and LRA (linear +resonant actuator) haptic motors.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/hid/hid-rp.html b/hid/hid-rp.html new file mode 100644 index 000000000..427010dad --- /dev/null +++ b/hid/hid-rp.html @@ -0,0 +1,800 @@ + + + + + + + HID-RP - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HID-RP

+

The hid-rp component provides a wrapper around +https://github.com/intergatedcircuits/hid-rp and also provides an example +implementation of a configurable HID Gamepad using hid-rp.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Header File

+ +
+
+

Classes

+
+
+template<size_t BUTTON_COUNT = 15, typename JOYSTICK_TYPE = std::uint16_t, typename TRIGGER_TYPE = std::uint16_t, JOYSTICK_TYPE JOYSTICK_MIN = 0, JOYSTICK_TYPE JOYSTICK_MAX = 65534, TRIGGER_TYPE TRIGGER_MIN = 0, TRIGGER_TYPE TRIGGER_MAX = 1023, uint8_t REPORT_ID = 1>
class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, 1>
+

HID Gamepad Input Report This class implements a HID Gamepad with a configurable number of buttons, a hat switch, 4 joystick axes and two trigger axes. It supports setting the buttons, hat switch, joysticks, and triggers, as well as serializing the input report and getting the report descriptor.

+
+

HID-RP Example

+
  static constexpr uint8_t input_report_id = 1;
+  static constexpr uint8_t battery_report_id = 4;
+  static constexpr size_t num_buttons = 15;
+  static constexpr int joystick_min = 0;
+  static constexpr int joystick_max = 65534;
+  static constexpr int trigger_min = 0;
+  static constexpr int trigger_max = 1023;
+
+  using GamepadInput =
+      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
+                               joystick_max, trigger_min, trigger_max, input_report_id>;
+  GamepadInput gamepad_input_report;
+
+  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
+  BatteryReport battery_input_report;
+
+  static constexpr uint8_t output_report_id = 2;
+  static constexpr size_t num_leds = 4;
+  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, output_report_id>;
+  GamepadLeds gamepad_leds_report;
+
+  using namespace hid::page;
+  using namespace hid::rdf;
+  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
+                                   collection::application(gamepad_input_report.get_descriptor(),
+                                                           battery_input_report.get_descriptor(),
+                                                           gamepad_leds_report.get_descriptor()));
+
+  // Generate the report descriptor for the gamepad
+  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());
+
+  logger.info("Report Descriptor:");
+  logger.info("  Size: {}", descriptor.size());
+  logger.info("  Data: {::#02x}", descriptor);
+
+  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
+  int button_index = 5;
+  float angle = 2.0f * M_PI * button_index / num_buttons;
+
+  // update the gamepad input report
+  gamepad_input_report.reset();
+  gamepad_input_report.set_hat(hat);
+  gamepad_input_report.set_button(button_index, true);
+  // joystick inputs are in the range [-1, 1] float
+  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
+  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
+  // trigger inputs are in the range [0, 1] float
+  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
+  gamepad_input_report.set_brake(std::abs(cos(angle)));
+
+  button_index = (button_index % num_buttons) + 1;
+
+  // send an input report
+  auto report = gamepad_input_report.get_report();
+  logger.info("Input report:");
+  logger.info("  Size: {}", report.size());
+  logger.info("  Data: {::#02x}", report);
+
+  // update the battery input report
+  battery_input_report.reset();
+  battery_input_report.set_rechargeable(true);
+  battery_input_report.set_charging(false);
+  battery_input_report.set_rechargeable(true);
+  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
+  battery_input_report.set_battery_level(50);
+
+  // send a battery report
+  report = battery_input_report.get_report();
+  logger.info("Battery report:");
+  logger.info("  Size: {}", report.size());
+  logger.info("  Data: {::#02x}", report);
+
+
+
+
+

Public Types

+
+
+enum class Hat
+

Possible Hat switch directions.

+

Values:

+
+
+enumerator CENTERED
+

Centered, no direction pressed.

+
+ +
+
+enumerator UP
+
+ +
+
+enumerator UP_RIGHT
+
+ +
+
+enumerator RIGHT
+
+ +
+
+enumerator DOWN_RIGHT
+
+ +
+
+enumerator DOWN
+
+ +
+
+enumerator DOWN_LEFT
+
+ +
+
+enumerator LEFT
+
+ +
+
+enumerator UP_LEFT
+
+ +
+ +
+
+

Public Functions

+
+
+inline constexpr void reset()
+

Reset the gamepad inputs.

+
+ +
+
+inline constexpr void set_left_joystick(float lx, float ly)
+

Set the left joystick X and Y axis values

+
+
Parameters
+
    +
  • lx – left joystick x axis value, in the range [-1, 1]

  • +
  • ly – left joystick y axis value, in the range [-1, 1]

  • +
+
+
+
+ +
+
+inline constexpr void set_right_joystick(float rx, float ry)
+

Set the right joystick X and Y axis values

+
+
Parameters
+
    +
  • rx – right joystick x axis value, in the range [-1, 1]

  • +
  • ry – right joystick y axis value, in the range [-1, 1]

  • +
+
+
+
+ +
+
+inline constexpr void set_brake(float value)
+

Set the brake trigger value

+
+
Parameters
+

value – brake trigger value, in the range [0, 1]

+
+
+
+ +
+
+inline constexpr void set_accelerator(float value)
+

Set the accelerator trigger value

+
+
Parameters
+

value – accelerator trigger value, in the range [0, 1]

+
+
+
+ +
+
+inline constexpr void set_hat(Hat hat)
+

Set the hat switch (d-pad) value

+
+
Parameters
+

hat – Hat enum / direction to set

+
+
+
+ +
+
+inline constexpr void set_button(int button_index, bool value)
+

Set the button value

+
+
Parameters
+
    +
  • button_index – The button for which you want to set the value. Should be between 1 and BUTTON_COUNT, inclusive.

  • +
  • value – The true/false value you want to se the button to.

  • +
+
+
+
+ +
+
+inline constexpr auto get_report()
+

Get the input report as a vector of bytes

+
+

Note

+

The report id is not included in the returned vector.

+
+
+
Returns
+

The input report as a vector of bytes.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline constexpr auto get_descriptor()
+

Get the report descriptor as a hid::rdf::descriptor

+
+

Note

+

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
+using namespace hid::rdf;
+auto gamepad_descriptor = gamepad_input_report.get_descriptor();
+auto rdf_descriptor = descriptor(
+    usage_page<generic_desktop>(),
+    usage(generic_desktop::GAMEPAD),
+    collection::application(
+        gamepad_descriptor
+    )
+);
+auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());
+
+
+

+
+
+
Returns
+

The report descriptor as a hid::rdf::descriptor.

+
+
+
+ +
+
+ +
+
+template<uint8_t REPORT_ID = 4>
class XboxBatteryInputReport : public hid::report::base<hid::report::type::INPUT, 4>
+

HID Xbox Battery Input Report This class implements a copy of the Xbox Battery input report. It is a single byte input which contains information about the type of the battery, its battery level, as well as a few other things.

+
+

HID-RP Example

+
  static constexpr uint8_t input_report_id = 1;
+  static constexpr uint8_t battery_report_id = 4;
+  static constexpr size_t num_buttons = 15;
+  static constexpr int joystick_min = 0;
+  static constexpr int joystick_max = 65534;
+  static constexpr int trigger_min = 0;
+  static constexpr int trigger_max = 1023;
+
+  using GamepadInput =
+      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
+                               joystick_max, trigger_min, trigger_max, input_report_id>;
+  GamepadInput gamepad_input_report;
+
+  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
+  BatteryReport battery_input_report;
+
+  static constexpr uint8_t output_report_id = 2;
+  static constexpr size_t num_leds = 4;
+  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, output_report_id>;
+  GamepadLeds gamepad_leds_report;
+
+  using namespace hid::page;
+  using namespace hid::rdf;
+  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
+                                   collection::application(gamepad_input_report.get_descriptor(),
+                                                           battery_input_report.get_descriptor(),
+                                                           gamepad_leds_report.get_descriptor()));
+
+  // Generate the report descriptor for the gamepad
+  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());
+
+  logger.info("Report Descriptor:");
+  logger.info("  Size: {}", descriptor.size());
+  logger.info("  Data: {::#02x}", descriptor);
+
+  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
+  int button_index = 5;
+  float angle = 2.0f * M_PI * button_index / num_buttons;
+
+  // update the gamepad input report
+  gamepad_input_report.reset();
+  gamepad_input_report.set_hat(hat);
+  gamepad_input_report.set_button(button_index, true);
+  // joystick inputs are in the range [-1, 1] float
+  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
+  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
+  // trigger inputs are in the range [0, 1] float
+  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
+  gamepad_input_report.set_brake(std::abs(cos(angle)));
+
+  button_index = (button_index % num_buttons) + 1;
+
+  // send an input report
+  auto report = gamepad_input_report.get_report();
+  logger.info("Input report:");
+  logger.info("  Size: {}", report.size());
+  logger.info("  Data: {::#02x}", report);
+
+  // update the battery input report
+  battery_input_report.reset();
+  battery_input_report.set_rechargeable(true);
+  battery_input_report.set_charging(false);
+  battery_input_report.set_rechargeable(true);
+  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
+  battery_input_report.set_battery_level(50);
+
+  // send a battery report
+  report = battery_input_report.get_report();
+  logger.info("Battery report:");
+  logger.info("  Size: {}", report.size());
+  logger.info("  Data: {::#02x}", report);
+
+
+
+
+

Public Types

+
+
+enum class Error
+

The possible errors for the battery.

+

Values:

+
+
+enumerator NONE
+

No error.

+
+ +
+
+enumerator BATTERY_LOW
+

The battery is low.

+
+ +
+
+enumerator BATTERY_CRITICAL
+

The battery is critically low.

+
+ +
+ +
+
+

Public Functions

+
+
+inline constexpr void reset()
+

Reset the battery status.

+
+ +
+
+inline constexpr void set_rechargeable(bool rechargeable)
+

Set whether the battery is rechargeable

+
+
Parameters
+

rechargeable – True if the battery is rechargeable, false otherwise.

+
+
+
+ +
+
+inline constexpr void set_battery_level(int level)
+

Set the battery level

+
+
Parameters
+

level – The battery level as a percentage, from 0 to 100.

+
+
+
+ +
+
+inline constexpr void set_cable_connected(bool connected)
+

Set whether the battery is connected to a cable

+
+
Parameters
+

connected – True if the battery is connected to a cable, false otherwise.

+
+
+
+ +
+
+inline constexpr void set_charging(bool charging)
+

Set whether the battery is charging

+
+
Parameters
+

charging – True if the battery is charging, false otherwise.

+
+
+
+ +
+
+inline constexpr void set_error(Error error)
+

Set the error state of the battery

+
+
Parameters
+

error – The error state of the battery.

+
+
+
+ +
+
+inline constexpr auto get_report()
+

Get the input report as a vector of bytes

+
+

Note

+

The report id is not included in the returned vector.

+
+
+
Returns
+

The input report as a vector of bytes.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline constexpr auto get_descriptor()
+

Get the report descriptor as a hid::rdf::descriptor

+
+

Note

+

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
+using namespace hid::rdf;
+auto gamepad_descriptor = gamepad_input_report.get_descriptor();
+auto rdf_descriptor = descriptor(
+    usage_page<generic_desktop>(),
+    usage(generic_desktop::GAMEPAD),
+    collection::application(
+        gamepad_descriptor
+    )
+);
+auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());
+
+
+

+
+
+
Returns
+

The report descriptor as a hid::rdf::descriptor.

+
+
+
+ +
+
+ +
+
+template<size_t LED_COUNT = 4, uint8_t REPORT_ID = 2>
class GamepadLedOutputReport : public hid::report::base<hid::report::type::OUTPUT, 2>
+

HID Gamepad LED Output Report This class implements a HID Gamepad with a configurable number of LEDs. It supports setting the LEDs, as well as serializing the output report and getting the report descriptor.

+
+

Public Functions

+
+
+inline constexpr void set_led(int led_index, bool value)
+

Set the LED value

+
+
Parameters
+
    +
  • led_index – The LED for which you want to set the value. Should be between 1 and LED_COUNT, inclusive.

  • +
  • value – The true/false value you want to se the LED to.

  • +
+
+
+
+ +
+
+inline constexpr auto get_report()
+

Get the output report as a vector of bytes

+
+

Note

+

The report id is not included in the returned vector.

+
+
+
Returns
+

The output report as a vector of bytes.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline constexpr auto get_descriptor()
+

Get the report descriptor as a hid::rdf::descriptor

+
+

Note

+

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
+using namespace hid::rdf;
+auto led_descriptor = gamepad_led_report.get_descriptor();
+auto rdf_descriptor = descriptor(
+    usage_page<generic_desktop>(),
+    usage(generic_desktop::GAMEPAD),
+    collection::application(
+        led_descriptor
+    )
+);
+auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());
+
+
+

+
+
+
Returns
+

The report descriptor as a hid::rdf::descriptor.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/hid/hid-rp_example.html b/hid/hid-rp_example.html new file mode 100644 index 000000000..7ddb5326e --- /dev/null +++ b/hid/hid-rp_example.html @@ -0,0 +1,236 @@ + + + + + + + HID-RP Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HID-RP Example

+

This example shows how to use the +hid-rp library which is +bundled into the hid-rp component within espp.

+

It provides an example of a somewhat configurable HID Gamepad using the +esppp::GamepadReport<> template class.

+
+

How to use example

+
+

Hardware Required

+

This example should run on any ESP32s3 development board as it requires no +peripheral connections.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-03-08 at 10 41 32

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/hid/index.html b/hid/index.html new file mode 100644 index 000000000..fb8dd0fb9 --- /dev/null +++ b/hid/index.html @@ -0,0 +1,206 @@ + + + + + + + HID APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HID APIs

+
+ +
+

These components provide interfaces for creating and managing HID reports, +report maps, etc.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/i2c.html b/i2c.html new file mode 100644 index 000000000..3636bcbbe --- /dev/null +++ b/i2c.html @@ -0,0 +1,756 @@ + + + + + + + I2C - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

I2C

+

The I2C class provides a simple interface to the I2C bus. It is a wrapper +around the esp-idf I2C driver.

+

A helper I2cMenu is also provided which can be used to interactively test +I2C buses - scanning the bus, probing devices, reading and writing to devices.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class I2c : public espp::BaseComponent
+

I2C driver.

+

This class is a wrapper around the ESP-IDF I2C driver.

+
+

Example

+
    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+    });
+
+    // probe the bus for all addresses and store the ones that were found /
+    // responded. NOTE: this will take a while to run, as it will probe all 128
+    // possible addresses and the hard-coded timeout on the I2C (inside ESP-IDF)
+    // is 1 second (I2C_CMD_ALIVE_INTERVAL_TICK within
+    // esp-idf/components/driver/i2c/i2c.c).
+    std::vector<uint8_t> found_addresses;
+    for (uint8_t address = 0; address < 128; address++) {
+      if (i2c.probe_device(address)) {
+        found_addresses.push_back(address);
+      }
+    }
+    // print out the addresses that were found
+    logger.info("Found devices at addresses: {::#02x}", found_addresses);
+
+    static constexpr uint8_t device_address = CONFIG_EXAMPLE_I2C_DEVICE_ADDR;
+    static constexpr uint8_t register_address = CONFIG_EXAMPLE_I2C_DEVICE_REG_ADDR;
+    bool device_found = i2c.probe_device(device_address);
+    if (device_found) {
+      logger.info("Found device with address {:#02x}", device_address);
+      std::vector<uint8_t> read_data(CONFIG_EXAMPLE_I2C_DEVICE_REG_SIZE, 0);
+      bool success = i2c.read_at_register(device_address, register_address, read_data.data(),
+                                          read_data.size());
+      if (success) {
+        logger.info("read data: {::#02x}", read_data);
+      } else {
+        logger.error("read failed");
+      }
+    } else {
+      logger.error("Could not find device with address {:#02x}", device_address);
+    }
+
+
+
+
+

Public Functions

+
+
+inline explicit I2c(const Config &config)
+

Construct I2C driver

+
+
Parameters
+

config – Configuration for I2C

+
+
+
+ +
+
+inline ~I2c()
+

Destructor.

+
+ +
+
+inline void init(std::error_code &ec)
+

Initialize I2C driver.

+
+ +
+
+inline void deinit(std::error_code &ec)
+

Deinitialize I2C driver.

+
+ +
+
+inline bool write(const uint8_t dev_addr, const uint8_t *data, const size_t data_len)
+

Write data to I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • data – Data to write

  • +
  • data_len – Length of data to write

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool write_vector(const uint8_t dev_addr, const std::vector<uint8_t> &data)
+

Write data to I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • data – Data to write

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool write_read(const uint8_t dev_addr, const uint8_t *write_data, const size_t write_size, uint8_t *read_data, size_t read_size)
+

Write to and read data from I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • write_data – Data to write

  • +
  • write_size – Length of data to write

  • +
  • read_data – Data to read

  • +
  • read_size – Length of data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool write_read_vector(const uint8_t dev_addr, const std::vector<uint8_t> &write_data, std::vector<uint8_t> &read_data)
+

Write data to and read data from I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • write_data – Data to write

  • +
  • read_data – Data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool read_at_register(const uint8_t dev_addr, const uint8_t reg_addr, uint8_t *data, size_t data_len)
+

Read data from I2C device at register

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • reg_addr – Register address

  • +
  • data – Data to read

  • +
  • data_len – Length of data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool read_at_register_vector(const uint8_t dev_addr, const uint8_t reg_addr, std::vector<uint8_t> &data)
+

Read data from I2C device at register

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • reg_addr – Register address

  • +
  • data – Data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool read(const uint8_t dev_addr, uint8_t *data, size_t data_len)
+

Read data from I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • data – Data to read

  • +
  • data_len – Length of data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool read_vector(const uint8_t dev_addr, std::vector<uint8_t> &data)
+

Read data from I2C device

+
+
Parameters
+
    +
  • dev_addr – I2C device address

  • +
  • data – Data to read

  • +
+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline bool probe_device(const uint8_t dev_addr)
+

Probe I2C device

+

This function sends a start condition, writes the device address, and then sends a stop condition. If the device acknowledges the address, then it is present on the bus.

+

+
+
Parameters
+

dev_addr – I2C device address

+
+
Returns
+

True if successful

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for I2C.

+
+

Public Members

+
+
+int isr_core_id = -1
+

The core to install the I2C interrupt on. If -1, then the I2C interrupt is installed on the core that this constructor is called on. If 0 or 1, then the I2C interrupt is installed on the specified core.

+
+ +
+
+i2c_port_t port = I2C_NUM_0
+

I2C port.

+
+ +
+
+gpio_num_t sda_io_num = GPIO_NUM_NC
+

SDA pin.

+
+ +
+
+gpio_num_t scl_io_num = GPIO_NUM_NC
+

SCL pin.

+
+ +
+
+gpio_pullup_t sda_pullup_en = GPIO_PULLUP_DISABLE
+

SDA pullup.

+
+ +
+
+gpio_pullup_t scl_pullup_en = GPIO_PULLUP_DISABLE
+

SCL pullup.

+
+ +
+
+uint32_t timeout_ms = 10
+

I2C timeout in milliseconds.

+
+ +
+
+uint32_t clk_speed = 400 * 1000
+

I2C clock speed in hertz.

+
+ +
+
+bool auto_init = true
+

Automatically initialize I2C on construction.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

Verbosity of logger.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class I2cMenu
+

A CLI menu for interacting with an I2c bus.

+

This class provides a CLI menu for interacting with an I2c bus. It provides options for setting the log verbosity, scanning the bus for devices, probing for a device at a specific address, reading from a device, and writing to a device.

+
+

Example

+
    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+        .clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_SPEED_HZ,
+        .log_level = espp::Logger::Verbosity::INFO,
+    });
+    // now make a menu for it
+    espp::I2cMenu i2c_menu(i2c);
+    cli::Cli cli(i2c_menu.get());
+    cli::SetColor();
+    cli.ExitAction([](auto &out) { out << "Goodbye and thanks for all the fish.\n"; });
+    espp::Cli input(cli);
+    input.SetInputHistorySize(10);
+
+    input.Start(); // As this is in the primary thread, we hold here until cli
+                   // is complete. This is a blocking call and will not return until
+                   // the user enters the `exit` command.
+
+
+
+
+

Public Functions

+
+
+inline explicit I2cMenu(std::reference_wrapper<espp::I2c> i2c)
+

Construct a new I2cMenu object.

+
+
Parameters
+

i2c – A reference to the I2c bus to interact with.

+
+
+
+ +
+
+inline std::unique_ptr<cli::Menu> get(std::string_view name = "i2c", std::string_view description = "I2c menu")
+

Get the I2c menu.

+
+
Parameters
+
    +
  • name – The name of the menu.

  • +
  • description – The description of the menu.

  • +
+
+
Returns
+

A unique pointer to the I2c menu that you can use to add to a CLI.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/i2c_example.html b/i2c_example.html new file mode 100644 index 000000000..46283fd99 --- /dev/null +++ b/i2c_example.html @@ -0,0 +1,241 @@ + + + + + + + I2C Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

I2C Example

+

This example shows how to use the I2C component to communicate with +peripherals on the I2C bus.

+

It supports using menuconfig to configure

+
    +
  • i2c pins (sda /scl), with configuration pre-selected for QtPy ESP32 PICO and QtPy ESP32s3

  • +
  • i2c device address

  • +
  • i2c device register address

  • +
  • Number of bytes to read from the i2c device register (register size)

  • +
+
+

How to use example

+

Configure the example via menuconfig:

+

CleanShot 2024-01-17 at 13 36 51

+
+

Hardware Required

+

This example requires a connection (via I2C) to an I2C device.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-01-17 at 13 40 38

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..4eceff766 --- /dev/null +++ b/index.html @@ -0,0 +1,493 @@ + + + + + + + ESPP Documentation - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESPP Documentation

+

This is the documentation for the ESP-IDF C++ library esp-cpp/espp.

+

This is the documentation for esp-idf c++ components, ESPP (espp). ESPP provides additional c++ components and abstractions for building applications from reusable components.

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/chsc6x.html b/input/chsc6x.html new file mode 100644 index 000000000..60319bc6d --- /dev/null +++ b/input/chsc6x.html @@ -0,0 +1,773 @@ + + + + + + + CHSC6X Touch Controller - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CHSC6X Touch Controller

+

The Chsc6x class provides an interface to the CHSC6X touch controller.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Chsc6x : public espp::BasePeripheral<>
+

Driver for the Chsc6x touch controller.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+        .timeout_ms = 100,
+        .clk_speed = 400 * 1000,
+    });
+
+    bool has_chsc6x = i2c.probe_device(espp::Chsc6x::DEFAULT_ADDRESS);
+    fmt::print("Touchpad probe: {}\n", has_chsc6x);
+
+    // now make the chsc6x which decodes the data
+    espp::Chsc6x chsc6x({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                            std::placeholders::_2, std::placeholders::_3),
+                         .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                           std::placeholders::_2, std::placeholders::_3),
+                         .log_level = espp::Logger::Verbosity::WARN});
+
+    // and finally, make the task to periodically poll the chsc6x and print
+    // the state
+    auto task_fn = [&chsc6x](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      // update the state
+      bool new_data = chsc6x.update(ec);
+      if (ec) {
+        fmt::print("Could not update state\n");
+        return false;
+      }
+      if (!new_data) {
+        return false; // don't stop the task
+      }
+      // get the state
+      uint8_t num_touch_points = 0;
+      uint16_t x = 0, y = 0;
+      chsc6x.get_touch_point(&num_touch_points, &x, &y);
+      if (ec) {
+        fmt::print("Could not get touch point\n");
+        return false;
+      }
+      fmt::print("num_touch_points: {}, x: {}, y: {}\n", num_touch_points, x, y);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Chsc6x Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Chsc6x(const Config &config)
+

Constructor for the CHSC6X driver.

+
+
Parameters
+

config – The configuration for the driver

+
+
+
+ +
+
+inline bool update(std::error_code &ec)
+

Update the state of the CHSC6X driver.

+
+
Parameters
+

ec – Error code to set if an error occurs

+
+
Returns
+

True if the CHSC6X has new data, false otherwise

+
+
+
+ +
+
+inline uint8_t get_num_touch_points() const
+

Get the number of touch points.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Returns
+

The number of touch points as of the last update

+
+
+
+ +
+
+inline void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y) const
+

Get the touch point data.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points as of the last update

  • +
  • x – The x coordinate of the touch point

  • +
  • y – The y coordinate of the touch point

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x2E
+

Default address for the CHSC6X chip.

+
+ +
+
+
+struct Config
+

Configuration for the CHSC6X driver.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

Function for writing to the CHSC6X chip.

+
+ +
+
+BasePeripheral::read_fn read
+

Function for reading from the CHSC6X chip.

+
+ +
+
+uint8_t address = DEFAULT_ADDRESS
+

Which address to use for this chip?

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/chsc6x_example.html b/input/chsc6x_example.html new file mode 100644 index 000000000..5755cb161 --- /dev/null +++ b/input/chsc6x_example.html @@ -0,0 +1,249 @@ + + + + + + + CHSC6X Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CHSC6X Example

+

This example shows how to use the CHSC6X touch controller with ESP32. It is +designed to run on a Seeed Studio Round Display.

+
+

How to use example

+
+

Hardware Required

+

Seeed Studio Round Display (or any other dev board with a CHSC6X touch +controller)

+
+
+

Configure

+
idf.py menuconfig
+
+
+

Set the hardware configuration for the example.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-08-26 at 08 21 47

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/cst816.html b/input/cst816.html new file mode 100644 index 000000000..c9f0d298a --- /dev/null +++ b/input/cst816.html @@ -0,0 +1,797 @@ + + + + + + + CST816 Touch Controller - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CST816 Touch Controller

+

The Cst816 class provides an interface to the CST816 touch controller.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Cst816 : public espp::BasePeripheral<std::uint8_t>
+

Driver for the CST816 touch controller.

+

+For more information, you can look at some reference code and the datasheet here: https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch_cst816s

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+        .timeout_ms = 100,
+        .clk_speed = 400 * 1000,
+    });
+
+    bool has_cst816 = i2c.probe_device(espp::Cst816::DEFAULT_ADDRESS);
+    fmt::print("Touchpad probe: {}\n", has_cst816);
+
+    // now make the cst816 which decodes the data
+    espp::Cst816 cst816({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                            std::placeholders::_2, std::placeholders::_3),
+                         .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                           std::placeholders::_2, std::placeholders::_3),
+                         .log_level = espp::Logger::Verbosity::WARN});
+
+    // and finally, make the task to periodically poll the cst816 and print
+    // the state
+    auto task_fn = [&cst816](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      // update the state
+      bool new_data = cst816.update(ec);
+      if (ec) {
+        fmt::print("Could not update state\n");
+        return false;
+      }
+      if (!new_data) {
+        return false; // don't stop the task
+      }
+      // get the state
+      bool home_pressed = false;
+      home_pressed = cst816.get_home_button_state();
+      fmt::print("home_pressed: {}\n", home_pressed);
+      uint8_t num_touch_points = 0;
+      uint16_t x = 0, y = 0;
+      cst816.get_touch_point(&num_touch_points, &x, &y);
+      if (ec) {
+        fmt::print("Could not get touch point\n");
+        return false;
+      }
+      fmt::print("num_touch_points: {}, x: {}, y: {}\n", num_touch_points, x, y);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Cst816 Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Note

+

This chip does not respond to I2C commands normally, only after an event. To properly interact with this chip, you should register an interrupt on the chip’s IRQ line. After the IRQ line is asserted, it will respond to I2C reads for a short period of time.

+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Cst816(const Config &config)
+

Constructor for the CST816 driver.

+
+
Parameters
+

config – The configuration for the driver

+
+
+
+ +
+
+inline bool update(std::error_code &ec)
+

Update the state of the CST816 driver.

+
+
Parameters
+

ec – Error code to set if an error occurs

+
+
Returns
+

True if the CST816 has new data, false otherwise

+
+
+
+ +
+
+inline uint8_t get_num_touch_points() const
+

Get the number of touch points.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Returns
+

The number of touch points as of the last update

+
+
+
+ +
+
+inline void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y) const
+

Get the touch point data.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points as of the last update

  • +
  • x – The x coordinate of the touch point

  • +
  • y – The y coordinate of the touch point

  • +
+
+
+
+ +
+
+inline bool get_home_button_state() const
+

Get the home button state.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Returns
+

True if the home button is pressed, false otherwise

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x15
+

Default address for the CST816 chip.

+
+ +
+
+
+struct Config
+

Configuration for the CST816 driver.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

Function for writing to the CST816 chip.

+
+ +
+
+BasePeripheral::read_fn read
+

Function for reading from the CST816 chip.

+
+ +
+
+uint8_t address = DEFAULT_ADDRESS
+

Which address to use for this chip?

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/cst816_example.html b/input/cst816_example.html new file mode 100644 index 000000000..b921050e7 --- /dev/null +++ b/input/cst816_example.html @@ -0,0 +1,254 @@ + + + + + + + CST816 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CST816 Example

+

This example shows how to use the CST816 touch controller with ESP32. It is +designed to run on a Matouch Rotary +Display.

+
+

How to use example

+
+

Hardware Required

+

The Matouch Rotary +Display +is required for this example.

+

If you have other hardware with CST816, you can run menuconfig, and select the +HARDWARE_CUSTOM option. and then select which pins are connected to the +CST816.

+
+
+

Configure

+
idf.py menuconfig
+
+
+

Set the hardware configuration for the example.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-08 at 21 57 00

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/encoder_input.html b/input/encoder_input.html new file mode 100644 index 000000000..e0e9af8c9 --- /dev/null +++ b/input/encoder_input.html @@ -0,0 +1,437 @@ + + + + + + + Encoder Input - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Encoder Input

+

Encoder input provides a light and configurable wrapper around lvgl input +device driver - specifically designed for encoders, which have a single +incremental input and a single button.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class EncoderInput : public espp::BaseComponent
+

Light wrapper around LVGL input device driver, specifically designed for encoders with optional home buttons.

+
+

Public Functions

+
+
+inline explicit EncoderInput(const Config &config)
+

Initialize and register the input drivers associated with the encoder.

+
+
Parameters
+

config – Configuration structure for the EncoderInput.

+
+
+
+ +
+
+inline ~EncoderInput()
+

Unregister the input drivers associated with the Encoder.

+
+ +
+
+inline lv_indev_t *get_encoder_input_device()
+

Get the input device driver associated with the encoder.

+
+
Returns
+

The input device driver associated with the encoder.

+
+
+
+ +
+
+inline lv_indev_t *get_button_input_device()
+

Get the input device driver associated with the button.

+
+
Returns
+

The input device driver associated with the button.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure, containing the read function for the encoder itself.

+
+

Public Members

+
+
+read_fn read
+

Input function for the encoder and button itself.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/ft5x06.html b/input/ft5x06.html new file mode 100644 index 000000000..fb6bc7349 --- /dev/null +++ b/input/ft5x06.html @@ -0,0 +1,790 @@ + + + + + + + FT5x06 Touch Controller - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FT5x06 Touch Controller

+

The FT5x06 is a capacitive touch controller that supports up to 5 touch points.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Ft5x06 : public espp::BasePeripheral<>
+

The FT5x06 touch controller.

+

This class is used to communicate with the FT5x06 touch controller.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+    });
+    // now make the ft5x06 which decodes the data
+    espp::Ft5x06 ft5x06({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                            std::placeholders::_2, std::placeholders::_3),
+                         .read_register = std::bind(&espp::I2c::read_at_register, &i2c,
+                                                    std::placeholders::_1, std::placeholders::_2,
+                                                    std::placeholders::_3, std::placeholders::_4),
+                         .log_level = espp::Logger::Verbosity::WARN});
+    // and finally, make the task to periodically poll the ft5x06 and print
+    // the state
+    auto task_fn = [&ft5x06](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      // get the state
+      uint8_t num_touch_points = 0;
+      uint16_t x = 0, y = 0;
+      ft5x06.get_touch_point(&num_touch_points, &x, &y, ec);
+      if (ec) {
+        fmt::print("Could not get touch point\n");
+        return false;
+      }
+      fmt::print("num_touch_points: {}, x: {}, y: {}\n", num_touch_points, x, y);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Ft5x06 Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+enum class Gesture : uint8_t
+

The gesture that was detected.

+

Values:

+
+
+enumerator NONE
+
+ +
+
+enumerator MOVE_UP
+
+ +
+
+enumerator MOVE_LEFT
+
+ +
+
+enumerator MOVE_DOWN
+
+ +
+
+enumerator MOVE_RIGHT
+
+ +
+
+enumerator ZOOM_IN
+
+ +
+
+enumerator ZOOM_OUT
+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Ft5x06(const Config &config)
+

Construct a new FT5x06.

+
+
Parameters
+

config – The configuration for the FT5x06.

+
+
+
+ +
+
+inline uint8_t get_num_touch_points(std::error_code &ec)
+

Get the number of touch points.

+
+
Parameters
+

ec – The error code if the function fails.

+
+
Returns
+

The number of touch points.

+
+
+
+ +
+
+inline void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, std::error_code &ec)
+

Get the touch point.

+
+
Parameters
+
    +
  • num_touch_points – The number of touch points.

  • +
  • x – The x coordinate of the touch point.

  • +
  • y – The y coordinate of the touch point.

  • +
  • ec – The error code if the function fails.

  • +
+
+
+
+ +
+
+inline Gesture read_gesture(std::error_code &ec)
+

Get the gesture that was detected.

+
+
Parameters
+

ec – The error code if the function fails.

+
+
Returns
+

The gesture that was detected.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x38)
+

The default I2C address for the FT5x06.

+
+ +
+
+
+struct Config
+

The configuration for the FT5x06.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

The function to write data to the I2C bus.

+
+ +
+
+BasePeripheral::read_register_fn read_register
+

The function to write then read data from the I2C bus.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

The log level.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/ft5x06_example.html b/input/ft5x06_example.html new file mode 100644 index 000000000..d6ff9cc1a --- /dev/null +++ b/input/ft5x06_example.html @@ -0,0 +1,242 @@ + + + + + + + FT5x06 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FT5x06 Example

+

This example demonstrates how to use the FT5x06 touch controller driver.

+

NOTE: I do not have an ESP32-S3-BOX variant with this touch controller, so I +have not been able to test this example.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the ESP32-S3-BOX (specifically the variant +that has a FT5x06 touch controller).

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/gt911.html b/input/gt911.html new file mode 100644 index 000000000..eb91d7460 --- /dev/null +++ b/input/gt911.html @@ -0,0 +1,801 @@ + + + + + + + GT911 Touch Controller - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

GT911 Touch Controller

+

The Gt911 class provides an interface to the GT911 touch controller.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Gt911 : public espp::BasePeripheral<std::uint16_t>
+

Driver for the GT911 touch controller.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+        .timeout_ms = 100,
+        .clk_speed = 400 * 1000,
+    });
+
+    bool has_gt911_5d = i2c.probe_device(0x5d);
+    bool has_gt911_14 = i2c.probe_device(0x14);
+    uint8_t address = has_gt911_5d ? 0x5d : 0x14;
+    fmt::print("Touchpad probe: {}\n", has_gt911_5d || has_gt911_14);
+    fmt::print("       address: {:#02x}\n", address);
+
+    // now make the gt911 which decodes the data
+    espp::Gt911 gt911({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                          std::placeholders::_2, std::placeholders::_3),
+                       .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                         std::placeholders::_2, std::placeholders::_3),
+                       .address = address,
+                       .log_level = espp::Logger::Verbosity::WARN});
+
+    // and finally, make the task to periodically poll the gt911 and print
+    // the state
+    auto task_fn = [&gt911](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      // update the state
+      bool new_data = gt911.update(ec);
+      if (ec) {
+        fmt::print("Could not update state\n");
+        return false;
+      }
+      if (!new_data) {
+        return false; // don't stop the task
+      }
+      // get the state
+      bool home_pressed = false;
+      home_pressed = gt911.get_home_button_state();
+      fmt::print("home_pressed: {}\n", home_pressed);
+      uint8_t num_touch_points = 0;
+      uint16_t x = 0, y = 0;
+      gt911.get_touch_point(&num_touch_points, &x, &y);
+      if (ec) {
+        fmt::print("Could not get touch point\n");
+        return false;
+      }
+      fmt::print("num_touch_points: {}, x: {}, y: {}\n", num_touch_points, x, y);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Gt911 Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Gt911(const Config &config)
+

Constructor for the GT911 driver.

+
+
Parameters
+

config – The configuration for the driver

+
+
+
+ +
+
+inline bool update(std::error_code &ec)
+

Update the state of the GT911 driver.

+
+
Parameters
+

ec – Error code to set if an error occurs

+
+
Returns
+

True if the GT911 has new data, false otherwise

+
+
+
+ +
+
+inline uint8_t get_num_touch_points() const
+

Get the number of touch points.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Returns
+

The number of touch points as of the last update

+
+
+
+ +
+
+inline void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y) const
+

Get the touch point data.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points as of the last update

  • +
  • x – The x coordinate of the touch point

  • +
  • y – The y coordinate of the touch point

  • +
+
+
+
+ +
+
+inline bool get_home_button_state() const
+

Get the home button state.

+
+

Note

+

This is a cached value from the last update() call

+
+
+
Returns
+

True if the home button is pressed, false otherwise

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS_1 = 0x5D
+

Default address for the GT911 chip.

+
+ +
+
+static constexpr uint8_t DEFAULT_ADDRESS_2 = 0x14
+

Alternate address for the GT911 chip.

+
+ +
+
+
+struct Config
+

Configuration for the GT911 driver.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

Function for writing to the GT911 chip.

+
+ +
+
+BasePeripheral::read_fn read
+

Function for reading from the GT911 chip.

+
+ +
+
+uint8_t address = DEFAULT_ADDRESS_1
+

Which address to use for this chip?

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/gt911_example.html b/input/gt911_example.html new file mode 100644 index 000000000..fba495711 --- /dev/null +++ b/input/gt911_example.html @@ -0,0 +1,249 @@ + + + + + + + GT911 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

GT911 Example

+

This example shows how to use the GT911 touch controller with ESP32. It is +designed to run on a LilyGo T-Deck (no home button) or the ESP32-S3-BOX-3 (with +home button).

+
+

How to use example

+
+

Hardware Required

+

LilyGo T-Deck orESP32-S3-BOX-3 (or any other ESP32 board with a GT911 touch controller)

+
+
+

Configure

+
idf.py menuconfig
+
+
+

Set the hardware configuration for the example.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-05-18 at 13 58 18

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/index.html b/input/index.html new file mode 100644 index 000000000..e106edc52 --- /dev/null +++ b/input/index.html @@ -0,0 +1,222 @@ + + + + + + + Input APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/keypad_input.html b/input/keypad_input.html new file mode 100644 index 000000000..da1a7d23d --- /dev/null +++ b/input/keypad_input.html @@ -0,0 +1,427 @@ + + + + + + + Keypad Input - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Keypad Input

+

Keypad input provides a light and configurable wrapper around lvgl input device +driver - specifically designed for use with a keypad, which is typically a +matrix of buttons, typically containing buttons such as LEFT, RIGHT, UP, DOWN, +ENTER, ESCAPE, etc.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class KeypadInput : public espp::BaseComponent
+

Light wrapper around LVGL input device driver, specifically designed for keypads.

+
+

Public Functions

+
+
+inline explicit KeypadInput(const Config &config)
+

Initialize and register the input drivers associated with the keypad.

+
+
Parameters
+

config – Configuration structure for the KeypadInput.

+
+
+
+ +
+
+inline ~KeypadInput()
+

Unregister the input drivers associated with the Keypad.

+
+ +
+
+inline lv_indev_t *get_input_device()
+

Get the input device driver associated with the keypad.

+
+
Returns
+

The input device driver associated with the keypad.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure, containing the read function for the keypad itself.

+
+

Public Members

+
+
+read_fn read
+

Input function for the keypad.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/pointer_input.html b/input/pointer_input.html new file mode 100644 index 000000000..31aed885c --- /dev/null +++ b/input/pointer_input.html @@ -0,0 +1,491 @@ + + + + + + + Pointer Input - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Pointer Input

+

Pointer input provides a light and configurable wrapper around lvgl input device +driver - specifically designed for mice, with configurable cursor icons.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class PointerInput : public espp::BaseComponent
+

Light wrapper around LVGL input device driver, specifically designed for pointers / cursors / mice input devices.

+
+

Public Types

+
+
+typedef std::function<void(int &x, int &y, bool &left_pressed, bool &right_pressed)> read_fn
+

Function prototype for getting the latest input data from the pointer.

+
+
Param x
+

[out] Current x position.

+
+
Param y
+

[out] Current y position.

+
+
Param left_pressed
+

[out] Whether the left button is pressed.

+
+
Param right_pressed
+

[out] Whether the right button is pressed.

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit PointerInput(const Config &config)
+

Initialize and register the input drivers associated with the pointer.

+
+
Parameters
+

config – Configuration structure for the PointerInput.

+
+
+
+ +
+
+inline ~PointerInput()
+

Unregister the input drivers associated with the Pointer.

+
+ +
+
+inline lv_indev_t *get_pointer_input_device()
+

Get a pointer to the LVGL input device driver for the pointer.

+
+
Returns
+

Pointer to the LVGL input device driver for the pointer.

+
+
+
+ +
+
+inline lv_obj_t *get_cursor_object()
+

Get a pointer to the cursor object.

+
+
Returns
+

Pointer to the cursor object.

+
+
+
+ +
+
+inline void set_cursor(const lv_image_dsc_t *icon)
+

Set the cursor to a specific icon.

+
+

Note

+

The icon must be a valid LVGL image descriptor.

+
+
+
Parameters
+

icon – The icon to set.

+
+
+
+ +
+
+inline void set_cursor(lv_obj_t *cursor_obj)
+

Set the cursor to a specific object.

+
+
Parameters
+

cursor_obj – The cursor object to set.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure, containing the read function for the pointer itself.

+
+

Public Members

+
+
+read_fn read
+

Input function for the pointer hardware itself.

+
+ +
+
+int cursor_radius = {8}
+

Radius of the cursor object.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/t_keyboard.html b/input/t_keyboard.html new file mode 100644 index 000000000..6ef02df6c --- /dev/null +++ b/input/t_keyboard.html @@ -0,0 +1,801 @@ + + + + + + + LilyGo T-Keyboard - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LilyGo T-Keyboard

+

The TKeyboard component provides a simple interface to the T-Keyboard +keypad. It allows you to read which key is currently pressed.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TKeyboard : public espp::BasePeripheral<>
+

Class for interacting with the LilyGo T-Keyboard.

+

This class is used to interact with the LilyGo T-Keyboard. It is designed as a peripheral component for use with a serial interface such as I2C. On The T-Keyboard, you can press Alt+B to toggle the keyboard backlight.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+    // now make the tkeyboard which decodes the data
+    espp::TKeyboard tkeyboard(
+        {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                            std::placeholders::_3),
+         .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+         .key_cb = [](uint8_t key) { fmt::print("'{}' Pressed!\n", (char)key); },
+         .auto_start = false, // can't auto start since we need to provide power
+         .log_level = espp::Logger::Verbosity::WARN});
+
+    // on the LilyGo T-Deck, the peripheral power control pin must be set high
+    // to enable peripheral power
+    auto power_ctrl = GPIO_NUM_10;
+    gpio_set_direction(power_ctrl, GPIO_MODE_OUTPUT);
+    gpio_set_level(power_ctrl, 1);
+
+    do {
+      fmt::print("Waiting for tkeyboard to boot up...\n");
+      std::this_thread::sleep_for(250ms);
+    } while (!i2c.probe_device(espp::TKeyboard::DEFAULT_ADDRESS));
+
+    fmt::print("Tkeyboard ready!\n");
+    tkeyboard.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<void(uint8_t)> key_cb_fn
+

The function signature for the key callback function.

+

This function is called when a key is pressed.

+
+
Param key
+

The key that was pressed.

+
+
+
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit TKeyboard(const Config &config)
+

Constructor for the TKeyboard class.

+
+
Parameters
+

config – The configuration to use.

+
+
+
+ +
+
+inline uint8_t get_key() const
+

Get the currently pressed key.

+

This function returns the currently pressed key.

+
+

Note

+

This function will return 0 if no key has been pressed.

+
+
+
Returns
+

The currently pressed key.

+
+
+
+ +
+
+inline uint8_t read_key(std::error_code &ec)
+

Read a key from the keyboard.

+

This function reads a key from the keyboard. It will return 0 and set the error code if an error occurs. If the keyboard task is running, it will return 0 and set the error code. If the keyboard task is not running, it will return the key that was read, and update the currently pressed key.

+

See also

+

get_key()

+
+

+
+

Note

+

This function will return 0 if no key was read.

+
+
+

Note

+

This function will return 0 if an error occurs.

+
+
+

Note

+

This function will set the error code if the keyboard task is running.

+
+
+
Parameters
+

ec – The error code to set if an error occurs.

+
+
Returns
+

The key that was read.

+
+
+
+ +
+
+inline bool start()
+

Start the keyboard task.

+

This function starts the keyboard task. It should be called after the keyboard has been initialized.

+
+
Returns
+

True if the task was started, false otherwise.

+
+
+
+ +
+
+inline bool stop()
+

Stop the keyboard task.

+

This function stops the keyboard task.

+
+
Returns
+

True if the task was stopped, false otherwise.

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x55
+

The default address of the keyboard.

+
+ +
+
+
+struct Config
+

The configuration structure for the keyboard.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

The write function to use.

+
+ +
+
+BasePeripheral::read_fn read
+

The read function to use.

+
+ +
+
+key_cb_fn key_cb
+

The key callback function to use. This function will be called when a key is pressed if it is not null and the keyboard task is running.

+
+ +
+
+uint8_t address = DEFAULT_ADDRESS
+

The address of the keyboard.

+
+ +
+
+std::chrono::milliseconds polling_interval = std::chrono::milliseconds(10)
+

The polling interval for the keyboard.

+
+ +
+
+bool auto_start = true
+

Whether or not to automatically start the keyboard task.

+
+ +
+
+Logger::Verbosity log_level = Logger::Verbosity::WARN
+

The log level to use.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/t_keyboard_example.html b/input/t_keyboard_example.html new file mode 100644 index 000000000..c64402e33 --- /dev/null +++ b/input/t_keyboard_example.html @@ -0,0 +1,241 @@ + + + + + + + LilyGo T-Keyboard Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LilyGo T-Keyboard Example

+

This example shows how to get the user input (key presses) from the LilyGo +T-Keyboard. It is designed to run on a LilyGo T-Deck.

+
+

How to use example

+
+

Hardware Required

+

LilyGo T-Deck (or any other board which has a LilyGo T-Keyboard connected)

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+CleanShot 2023-11-10 at 13 17 53@2x +
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/touchpad_input.html b/input/touchpad_input.html new file mode 100644 index 000000000..2b550ac7a --- /dev/null +++ b/input/touchpad_input.html @@ -0,0 +1,478 @@ + + + + + + + Touchpad Input - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Touchpad Input

+

Touchpad input provides a light and configurable wrapper around lvgl input +device driver - specifically designed for touch panels, with an optional home +button (part of the touch panel).

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TouchpadInput : public espp::BaseComponent
+

Light wrapper around LVGL input device driver, specifically designed for touchpads with optional home buttons.

+
+

Public Types

+
+
+typedef std::function<void(uint8_t *num_touches, uint16_t *x, uint16_t *y, uint8_t *state)> touchpad_read_fn
+

Function prototype for getting the latest input data from the touchpad.

+
+
Param num_touches
+

Number of touch points / presses (pointer to data to be filled).

+
+
Param x
+

Current x position (pointer to data to be filled).

+
+
Param y
+

Current y position (pointer to data to be filled).

+
+
Param state
+

Home button state if there is a home button (pointer to data to be filled).

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit TouchpadInput(const Config &config)
+

Initialize and register the input drivers associated with the touchpad.

+
+
Parameters
+

config – Configuration structure for the TouchpadInput.

+
+
+
+ +
+
+inline ~TouchpadInput()
+

Unregister the input drivers associated with the Touchpad.

+
+ +
+
+inline lv_indev_t *get_touchpad_input_device()
+

Get a pointer to the LVGL input device driver for the touchpad.

+
+
Returns
+

Pointer to the LVGL input device driver for the touchpad.

+
+
+
+ +
+
+inline lv_indev_t *get_home_button_input_device()
+

Get a pointer to the LVGL input device driver for the home button.

+
+
Returns
+

Pointer to the LVGL input device driver for the home button.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure, containing the read function for the touchpad itself.

+
+

Public Members

+
+
+touchpad_read_fn touchpad_read
+

Input function for the touchpad itself.

+
+ +
+
+bool swap_xy{false}
+

If true, swap the x/y coordinates retrieved from the touchpad_read_fn.

+
+ +
+
+bool invert_x = {false}
+

If true, Invert the output of the x coordinate.

+
+ +
+
+bool invert_y = {false}
+

If true, Invert the output of the y coordinate.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/tt21100.html b/input/tt21100.html new file mode 100644 index 000000000..70180814c --- /dev/null +++ b/input/tt21100.html @@ -0,0 +1,780 @@ + + + + + + + TT21100 Touch Controller - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

TT21100 Touch Controller

+

The TT21100 is a touch controller that supports up to 10 touch points. It +supports both mutual and self capacitance sensing. It can be used with TT21100 +touchpad sensor. This touch controller can be found in the ESP32-S3-BOX.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Tt21100 : public espp::BasePeripheral<>
+

Driver for the Tt21100 touch controller.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+    });
+    // now make the tt21100
+    auto tt21100 = espp::Tt21100({
+        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3),
+    });
+
+    // and finally, make the task to periodically poll the tt21100 and print
+    // the state
+    auto task_fn = [&tt21100](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      bool new_data = tt21100.update(ec);
+      if (ec) {
+        fmt::print("TT21100 update failed: {}\n", ec.message());
+        return true; // stop the task
+      }
+      if (!new_data) {
+        // no new data, so don't bother printing
+        return false; // don't stop the task
+      }
+      // get the state
+      uint8_t num_touch_points = 0;
+      uint16_t x = 0, y = 0;
+      tt21100.get_touch_point(&num_touch_points, &x, &y);
+      bool button_state = tt21100.get_home_button_state();
+      if (num_touch_points == 0 && !button_state) {
+        // no touch points, so don't bother printing
+      } else if (num_touch_points == 0 && button_state) {
+        fmt::print("home button pressed\n");
+      } else {
+        fmt::print("num_touch_points: {}, x: {}, y: {}, button state: {}\n", num_touch_points, x, y,
+                   button_state);
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "TT21100 Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Tt21100(const Config &config)
+

Constructor.

+
+
Parameters
+

config – The configuration for the driver

+
+
+
+ +
+
+inline bool update(std::error_code &ec)
+

Read the touch data.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
Returns
+

True if there is new touch data

+
+
+
+ +
+
+inline uint8_t get_num_touch_points() const
+

Get the number of touch points.

+
+

Note

+

This is the number of touch points that were present when the last update() was called

+
+
+
Returns
+

The number of touch points

+
+
+
+ +
+
+inline void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y) const
+

Get the touch point data.

+
+

Note

+

This is the touch point data that was present when the last update() was called

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points

  • +
  • x – The x position of the touch point

  • +
  • y – The y position of the touch point

  • +
+
+
+
+ +
+
+inline uint8_t get_home_button_state() const
+

Get the state of the home button.

+
+

Note

+

This is the state of the home button when the last update() was called

+
+
+
Returns
+

True if the home button is pressed

+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x24)
+

The default i2c address.

+
+ +
+
+
+struct Config
+

Configuration for the Tt21100 driver.

+
+

Public Members

+
+
+BasePeripheral::write_fn write = nullptr
+

Function for writing to the i2c device (unused)

+
+ +
+
+BasePeripheral::read_fn read
+

Function for reading from the i2c device.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log level.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/input/tt21100_example.html b/input/tt21100_example.html new file mode 100644 index 000000000..03d701da1 --- /dev/null +++ b/input/tt21100_example.html @@ -0,0 +1,243 @@ + + + + + + + TT21100 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

TT21100 Example

+

This example demonstrates how to use the TT21100 driver. It is designed to work +with the ESP32-S3-BOX dev board, but can be adapted to work with other boards +which have a TT21100 chip.

+
+

How to use example

+
+

Hardware Required

+

This example can be run on any board which has a TT21100 chip. The example is +designed to work with the ESP32-S3-BOX dev board.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+CleanShot 2023-11-05 at 10 49 03@2x +
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/interrupt.html b/interrupt.html new file mode 100644 index 000000000..80ed0cf60 --- /dev/null +++ b/interrupt.html @@ -0,0 +1,898 @@ + + + + + + + Interrupt APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interrupt APIs

+

The Interrupt class provides APIs to register interrupt handlers for GPIO and +configure the interrupts. Interrupts can be configured to trigger on rising +edge, falling edge, high level, low level, or any change in the input signal. A +single interrupt object can manage multiple GPIO pins with separate callbacks +for each GPIO, or separte Interrupt objects can be created (though that uses +more memory and CPU as each Interrupt will has its own queue, ISR handler, and +task.

+

Finally, the Interrupt class is also designed to be subclassed if desired to +provide additional functionality, or it can of course be included as a member +within another class. The Button class provides a very simple implementation of +a subclass of Interrupt.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Interrupt : public espp::BaseComponent
+

A class to handle a GPIO interrupt.

+

This class uses the ESP-IDF GPIO interrupt handler to detect GPIO interrupts. It then calls the callback function with the event. It can handle multiple GPIO interrupts and call the appropriate callback for each GPIO interrupt.

+

The class uses a FreeRTOS queue to handle the events. The queue is created in the constructor and deleted in the destructor. The queue is used to wake up the task when an interrupt event occurs. The task then calls the appropriate callback for the interrupt. Since all the GPIO interrupts are handled by the same task, all the callbacks are called from the same task. This means that the callbacks should be fast and not block for long periods of time, otherwise the other interrupts will be delayed.

+

Regardless of the callback speed, some interrupts could still be missed if they happen too quickly. For this reason, the queue size can be set in the configuration (default is 10). If the queue is full, then the interrupt event will be missed. If you are expecting a lot of interrupts to happen quickly, then you should increase the queue size.

+

Another way to handle the situation where you have many interrupts and would like to separate out the processing by priority is to have different Interrupt objects for the different priority levels, and assign the interrupt pins/callbacks to the objects according to the priority levels that you want. This will ensure that interrupts at different priority levels / in different objects do not starve the each other, while ensuring that the interupts are still processed in an orderly fashion.

+

If CONFIG_GPIO_CTRL_FUNC_IN_IRAM is enabled, then the ISR handler will be placed in IRAM. In this condition, the interrupt class’ ISR handler will automatically disable the interrupt associated with that GPIO within the ISR handler.

+

If CONFIG_GPIO_CTRL_FUNC_IN_IRAM is enabled and the PinConfig has auto_reenable set to false, then the interrupt will not be reenabled automatically. This is because the ISR handler will disable the interrupt, and it will not be reenabled until the user reenables it. This use-case is recommended for ACTIVE_LOW or ACTIVE_HIGH interrupts which may need some other action to clear the interrupt condition and prevent the ISR from being triggered continuously. In this case, simply re-enable the interrupt when you have cleared the interrupt condition if you want to be able to respond to it again.

+
+

Interrupt Example

+
  static auto start = std::chrono::high_resolution_clock::now();
+
+  auto callback = [&](const espp::Interrupt::Event &event) {
+    auto now = std::chrono::high_resolution_clock::now();
+    auto elapsed = std::chrono::duration<float>(now - start).count();
+    logger.info("[Callback][{:.3f}] Interrupt: pin {} changed to active state: {}", elapsed,
+                event.gpio_num, event.active);
+  };
+
+  espp::Interrupt::PinConfig io0 = {
+      .gpio_num = GPIO_NUM_0,
+      .callback = callback,
+      .active_level = espp::Interrupt::ActiveLevel::LOW,
+      .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
+      .pullup_enabled = true,
+      .pulldown_enabled = false,
+      // flexible filter requiring configuration (default is provided as 5us
+      // threshold in 10us window), but other configurations can be manually
+      // set as below
+      .filter_type = espp::Interrupt::FilterType::FLEX_GLITCH_FILTER,
+      .filter_config = {.window_width_ns = 10000, .window_threshold_ns = 5000},
+  };
+  espp::Interrupt::PinConfig io12 = {
+      .gpio_num = GPIO_NUM_12,
+      .callback = callback,
+      .active_level = espp::Interrupt::ActiveLevel::LOW,
+      .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
+      .pullup_enabled = true,
+      .pulldown_enabled = false,
+      // pre-configured 2 clock pulse width filter
+      .filter_type = espp::Interrupt::FilterType::PIN_GLITCH_FILTER,
+  };
+
+  // make an interrupt for a single gpio
+  {
+    espp::Interrupt interrupt({
+        .isr_core_id = 1,
+        .interrupts = {io0},
+        .task_config =
+            {
+                .name = "Interrupt task",
+                .stack_size_bytes = 6192,
+                .priority = 5,
+            },
+        .log_level = espp::Logger::Verbosity::DEBUG,
+    });
+
+    std::this_thread::sleep_for(5s);
+  }
+
+  // make multiple interrupts for multiple gpios
+  {
+    espp::Interrupt interrupt0({
+        .interrupts = {io0},
+        .task_config =
+            {
+                .name = "Interrupt task",
+                .stack_size_bytes = 6192,
+                .priority = 5,
+            },
+        .log_level = espp::Logger::Verbosity::DEBUG,
+    });
+
+    espp::Interrupt interrupt12({
+        .interrupts = {io12},
+        .task_config =
+            {
+                .name = "Interrupt 0 task",
+                .stack_size_bytes = 6192,
+                .priority = 5,
+            },
+        .log_level = espp::Logger::Verbosity::DEBUG,
+    });
+
+    std::this_thread::sleep_for(2s);
+
+    // now lets read the instantaneous state of the interrupt pins
+    auto is_0_active = interrupt0.is_active(io0);
+    auto is_12_active = interrupt12.is_active(io12);
+    logger.info("Instantaneous state of pin 0: {}", is_0_active);
+    logger.info("Instantaneous state of pin 12: {}", is_12_active);
+
+    std::this_thread::sleep_for(2s);
+  }
+
+  // make a single interrupt for multiple GPIOs
+  // make an interrupt for a single gpio
+  {
+    // Register for interrupts on a few pins (GPIO_NUM_0, GPIO_NUM_12)
+    espp::Interrupt interrupt({
+        .interrupts = {io0},
+        .task_config =
+            {
+                .name = "Interrupt task",
+                .stack_size_bytes = 6192,
+                .priority = 5,
+            },
+        .log_level = espp::Logger::Verbosity::DEBUG,
+    });
+
+    // use the add_interrupt method to add another interrupt
+    interrupt.add_interrupt(io12);
+
+    std::this_thread::sleep_for(2s);
+
+    // now lets read the instantaneous state of the interrupt pins
+    auto active_states = interrupt.get_active_states();
+    logger.info("Instantaneous state of pins: {}", active_states);
+
+    std::this_thread::sleep_for(2s);
+
+    // print out the minimum number of spaces in the interrupt queue over the
+    // last 2 seconds
+    auto min_queue_size = interrupt.get_min_queue_size();
+    logger.info("Minimum queue size over last 4 seconds: {}", min_queue_size);
+  }
+
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
+  esp_intr_dump(stdout);
+#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
+
+
+
+

Subclassed by espp::Button

+
+

Public Types

+
+
+enum class ActiveLevel
+

The active level of the GPIO.

+

Values:

+
+
+enumerator LOW
+

Active low.

+
+ +
+
+enumerator HIGH
+

Active high.

+
+ +
+ +
+
+enum class Type
+

The type of interrupt to use for the GPIO.

+

Values:

+
+
+enumerator ANY_EDGE
+

Interrupt on any edge.

+
+ +
+
+enumerator RISING_EDGE
+

Interrupt on rising edge.

+
+ +
+
+enumerator FALLING_EDGE
+

Interrupt on falling edge.

+
+ +
+
+enumerator LOW_LEVEL
+

Interrupt on low level.

+
+ +
+
+enumerator HIGH_LEVEL
+

Interrupt on high level.

+
+ +
+ +
+
+typedef std::function<void(const Event&)> event_callback_fn
+

The callback for the event.

+
+ +
+
+

Public Functions

+
+
+inline explicit Interrupt(const Config &config)
+

Constructor.

+
+
Parameters
+

config – The configuration for the interrupt

+
+
+
+ +
+
+inline ~Interrupt()
+

Destructor.

+
+ +
+
+inline size_t get_min_queue_size() const
+

Get the minimum number of free spaces in the queue.

+

+This will return the minimum number of free spaces in the queue Over the lifetime of the object. This can be used to determine if the queue size is too small for the number of interrupts that are being received. It may also help indicate if the interrupt task priority is too low, preventing the queue from being serviced. Finally, it may also help to indicate if additional filtering may be needed on the interrupt line (either using the FilterType or with hardware filtering).

+
+
Returns
+

The minimum number of free spaces in the queue

+
+
+
+ +
+
+inline void add_interrupt(const PinConfig &interrupt)
+

Add an interrupt to the interrupt handler.

+
+
Parameters
+

interrupt – The interrupt to add

+
+
+
+ +
+
+inline void remove_all()
+

Remove all the interrupts from the interrupt handler.

+

This will remove all the interrupts that are currently registered with the interrupt handler. This will also disable all the interrupts that are currently enabled.

+
+ +
+
+inline void remove_interrupt(const PinConfig &interrupt)
+

Remove an interrupt from the interrupt handler.

+

+This will find a registered interrupt with the given GPIO number and remove it from the list of interrupts. It will also disable the interrupt for that GPIO number. If no interrupt is found with the given GPIO number, then nothing is done.

+
+
Parameters
+

interrupt – The interrupt to remove

+
+
+
+ +
+
+inline void remove_interrupt(int gpio_num)
+

Remove an interrupt from the interrupt handler.

+

+This will find a registered interrupt with the given GPIO number and remove it from the list of interrupts. It will also disable the interrupt for that GPIO number. If no interrupt is found with the given GPIO number, then nothing is done.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to remove

+
+
+
+ +
+
+inline void disable_all()
+

Disable all the interrupts.

+

This will disable all the interrupts that are currently registered with the interrupt handler. This will not remove the interrupts from the list of interrupts, so they can be reenabled later.

+
+ +
+
+inline void disable_interrupt(const PinConfig &interrupt)
+

Disable the interrupt for the interrupt PinConfig.

+

+This will disable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

interrupt – The interrupt to disable

+
+
+
+ +
+
+inline void disable_interrupt(int gpio_num)
+

Disable the interrupt for the GPIO.

+

+This will disable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to disable

+
+
+
+ +
+
+inline void enable_interrupt(const PinConfig &interrupt)
+

Enable the interrupt for the GPIO.

+

+This will enable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

interrupt – The interrupt to enable

+
+
+
+ +
+
+inline void enable_interrupt(int gpio_num)
+

Enable the interrupt for the GPIO.

+

+This will enable the interrupt for the GPIO that is specified, regardless of whether the interrupt is in the list of interrupts or not.

+
+
Parameters
+

gpio_num – The GPIO number of the interrupt to enable

+
+
+
+ +
+
+inline bool is_active(const PinConfig &interrupt) const
+

Get the state of the interrupt.

+

+This will check the raw logic level of the GPIO and return whether the interrupt is active or not according to the active level that was set in the configuration.

+
+
Parameters
+

interrupt – The interrupt to check

+
+
Returns
+

Whether the interrupt is active

+
+
+
+ +
+
+inline std::vector<std::pair<int, bool>> get_active_states()
+

Get the state of all the interrupts.

+
+
Returns
+

A vector of the states of the interrupts as pairs of the GPIO number and whether the interrupt is active

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

The configuration for the interrupt.

+
+

Public Members

+
+
+int isr_core_id = -1
+

The core to install the ISR service on. If -1, then the ISR service is installed on the core that this constructor is called on. If 0 or 1, then the ISR service is installed on the specified core. If the ISR service is already installed, then this function does nothing. If the core_id is invalid, then an error is logged and the ISR service is not installed.

+
+ +
+
+std::vector<PinConfig> interrupts
+

The configuration for the interrupts.

+
+ +
+
+size_t event_queue_size = 10
+

The size of the event queue.

+
+ +
+
+Task::BaseConfig task_config
+

The configuration for the task.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The log level for the interrupt.

+
+ +
+
+ +
+
+struct Event
+

The event for the interrupt.

+
+

Public Members

+
+
+uint8_t gpio_num
+

The GPIO number of the interrupt.

+
+ +
+
+bool active
+

Whether the interrupt is active or not (based on the active level)

+
+ +
+
+ +
+
+struct FilterConfig
+

The configuration for the filter.

+

+This is used to configure the GPIO flex glitch filter The filter is used to filter out glitches on the GPIO whose pulses are shorter than window_threshold_ns within the window_width_ns sampling window.

+
+

Note

+

This is only supported on some chips (-C and -S series chips) and is only enabled if CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0.

+
+
+

Note

+

This filter config is only supported by the flex_glitch_filter. The pin_glitch_filter is not-configurable.

+
+
+

Public Members

+
+
+uint32_t window_width_ns{10000}
+

The width of the sampling window in nanoseconds. Default is 10us.

+
+ +
+
+uint32_t window_threshold_ns = {5000}
+

The threshold for the sampling window in nanoseconds. If the width of the pulse is less than this, it is filtered out. Default is 5us

+
+ +
+
+ +
+
+struct PinConfig
+

The configuration for an interrupt on a GPIO.

+

This is used to configure the GPIO interrupt

+
+

Public Members

+
+
+int gpio_num
+

GPIO number to for this interrupt.

+
+ +
+
+event_callback_fn callback
+

Callback for the interrupt event.

+
+ +
+
+bool auto_reenable = true
+

Whether to auto reenable the interrupt after it is triggered. If false, the interrupt will need to be reenabled in the callback or some other codepath. If true, the interrupt will be reenabled automatically before the callback is called.

+
+ +
+
+ActiveLevel active_level
+

Active level of the GPIO.

+
+ +
+
+Type interrupt_type = Type::ANY_EDGE
+

Interrupt type to use for the GPIO.

+
+ +
+
+bool pullup_enabled = false
+

Whether to enable the pullup resistor.

+
+ +
+
+bool pulldown_enabled = false
+

Whether to enable the pulldown resistor.

+
+ +
+
+FilterType filter_type = FilterType::NONE
+

The type of filter to use. If set to FLEX_GLITCH_FILTER, the filter_config should be set.

+
+ +
+
+FilterConfig filter_config = {}
+

The configuration for the filter. This is only used if filter_type is set to FLEX_GLITCH_FILTER

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/interrupt_example.html b/interrupt_example.html new file mode 100644 index 000000000..12e82d26a --- /dev/null +++ b/interrupt_example.html @@ -0,0 +1,235 @@ + + + + + + + Interrupt Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interrupt Example

+

This example shows how to use the espp::Interrupt class to configure +interrupts for one or more GPIO pins.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on an ESP32 board which has a digital button +connected to GPIO0 (which is the boot pin and has a button atached on most dev +boards). Additionally, the example assumes an input on GPIO12.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-03-11 at 11 44 35

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/aw9523.html b/io_expander/aw9523.html new file mode 100644 index 000000000..36b264b98 --- /dev/null +++ b/io_expander/aw9523.html @@ -0,0 +1,1241 @@ + + + + + + + AW9523 I/O Expander - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AW9523 I/O Expander

+

The AW9523 I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as I2C. It also supports +dimming control for LEDs attached to the expander’s port pins, when those pins +are configured into a special LED mode.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Aw9523 : public espp::BasePeripheral<>
+

Class for communicating with and controlling a AW9523 GPIO expander including interrupt configuration and LED drive capability. Datasheet hosted by adafruit.com here: https://cdn-shop.adafruit.com/product-files/4886/AW9523+English+Datasheet.pdf

+
+

AW9523 Example

+
  // make the I2C that we'll use to communicate
+  espp::I2c i2c({
+      .port = I2C_NUM_1,
+      .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+      .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+  });
+  // now make the aw9523 which handles GPIO
+  espp::Aw9523 aw9523(
+      {// since this uses LEDs, both of the address pins are pulled up in
+       // hardware to have the LEDs default to off
+       .device_address = espp::Aw9523::DEFAULT_ADDRESS | 0b11,
+       // set P0_0 - P0_5 to be inputs
+       .port_0_direction_mask = 0b00111111,
+       // set P1_0 - P1_1 to be inputs
+       .port_1_direction_mask = 0b00000011,
+       .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3),
+       .write_then_read =
+           std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                     std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
+       .log_level = espp::Logger::Verbosity::WARN});
+  std::error_code ec;
+  aw9523.initialize(ec); // Initialized separately from the constructor.
+  if (ec) {
+    fmt::print("aw9523 initialization failed: {}\n", ec.message());
+    return;
+  }
+  // set P1_5, P1_6, and P1_7 to be leds
+  int r_led = (1 << 13);
+  int g_led = (1 << 14);
+  int b_led = (1 << 15);
+  // for the port led mask, 0 = LED, 1 = GPIO so we invert the pins above
+  uint16_t leds = ~(r_led | g_led | b_led);
+  aw9523.configure_led(leds, ec);
+  if (ec) {
+    fmt::print("aw9523 led configuration failed: {}\n", ec.message());
+    return;
+  }
+  // and finally, make the task to periodically poll the aw9523 and print
+  // the state. NOTE: the Aw9523 does not internally manage its own state
+  // update, so whatever rate we use here is the rate at which the state will
+  // update.
+  auto task_fn = [&](std::mutex &m, std::condition_variable &cv) {
+    static auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    auto seconds = std::chrono::duration<float>(now - start).count();
+    static uint8_t r_brightness = 0;
+    static uint8_t g_brightness = 0;
+    static uint8_t b_brightness = 0;
+    // returns the pins as P0_0 lsb, P1_7 msb
+    auto pins = aw9523.get_pins(ec);
+    if (ec) {
+      fmt::print("aw9523 get pins failed: {}\n", ec.message());
+      return true; // stop the task
+    }
+    // equivalent to:
+    // auto pins = (aw9523.get_pins(espp::Aw9523::Port::PORT1, ec) << 8) |
+    // aw9523.get_pins(espp::Aw9523::Port::PORT0, ec);
+    int r_up = (pins & (1 << 0));   // P0_0
+    int g_up = (pins & (1 << 1));   // P0_1
+    int b_up = (pins & (1 << 9));   // P1_0
+    int r_down = (pins & (1 << 2)); // P0_2
+    int g_down = (pins & (1 << 3)); // P0_3
+    int b_down = (pins & (1 << 8)); // P1_8
+    // use the buttons to modify the brightness values (with wrap)
+    static uint8_t increment = 1;
+    if (r_up) {
+      r_brightness += increment;
+    } else if (r_down) {
+      r_brightness -= increment;
+    }
+    if (g_up) {
+      g_brightness += increment;
+    } else if (g_down) {
+      g_brightness -= increment;
+    }
+    if (b_up) {
+      b_brightness += increment;
+    } else if (b_down) {
+      b_brightness -= increment;
+    }
+    aw9523.led(r_led, r_brightness, ec);
+    aw9523.led(g_led, g_brightness, ec);
+    aw9523.led(b_led, b_brightness, ec);
+    if (ec) {
+      fmt::print("aw9523 led failed: {}\n", ec.message());
+      return true; // stop the task
+    }
+    fmt::print("{:.3f}, {:#x}, {}, {}, {}\n", seconds, pins, r_brightness, g_brightness,
+               b_brightness);
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 50ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+  auto task = espp::Task({.callback = task_fn,
+                          .task_config =
+                              {
+                                  .name = "Aw9523 Task",
+                                  .stack_size_bytes = 5 * 1024,
+                              },
+                          .log_level = espp::Logger::Verbosity::WARN});
+  fmt::print("%time(s), pin values, r, g, b\n");
+  task.start();
+
+
+
+
+

Public Types

+
+
+enum class Port
+

The two GPIO ports the Aw9523 has.

+

Values:

+
+
+enumerator PORT0
+

Port 0.

+
+ +
+
+enumerator PORT1
+

Port 1.

+
+ +
+ +
+
+enum class OutputDriveModeP0 : int
+

The output drive mode configuration for PORT 0 pins.

+

Values:

+
+
+enumerator OPEN_DRAIN
+

In this mode it needs a pull-up reistor. This is the default mode.

+
+ +
+
+enumerator PUSH_PULL
+

In this mode it needs no pull-up resistor.

+
+ +
+ +
+
+enum class MaxLedCurrent : int
+

The max current allowed when driving LEDs.

+

Values:

+
+
+enumerator IMAX
+

Full drive current (37mA), default.

+
+ +
+
+enumerator IMAX_75
+

75% drive current

+
+ +
+
+enumerator IMAX_50
+

50% drive current

+
+ +
+
+enumerator IMAX_25
+

25% drive current

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Aw9523(const Config &config)
+

Construct the Aw9523. Will call initialize() if auto_init is true.

+
+
Parameters
+

configConfig structure for configuring the AW9523

+
+
+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the component class.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline uint8_t get_pins(Port port, std::error_code &ec)
+

Read the pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to read the pins

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The pin values as an 8 bit mask.

+
+
+
+ +
+
+inline uint16_t get_pins(std::error_code &ec)
+

Read the pin values on both Port 0 and Port 1.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

+
+
+
+ +
+
+inline void output(Port port, uint8_t value, std::error_code &ec)
+

Write the pin values on the provided port.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the port.

+
+
+
Parameters
+
    +
  • port – The Port for which to write the pins

  • +
  • value – The pin values to apply.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void output(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Write the pin values on both Port 0 and Port 1.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the ports.

+
+
+
Parameters
+
    +
  • p0 – The pin values to apply to Port 0.

  • +
  • p1 – The pin values to apply to Port 1.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void output(uint16_t value, std::error_code &ec)
+

Write the pin values on both Port 0 and Port 1.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the ports.

+
+
+
Parameters
+
    +
  • value – The pin values to apply as a 16 bit value (P0_0 lsb, P1_7 msb).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(Port port, uint8_t mask, std::error_code &ec)
+

Clear the pin values on the provided port according to the provided mask.

+

Reads the current pin values and clears any bits set in the mask.

+
+
Parameters
+
    +
  • port – The Port for which to clear the pin outputs.

  • +
  • mask – The pin values as an 8 bit mask to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Clear the pin values for Port 0 and Port 1 according to the provided masks.

+

Reads the current pin values and clears any bits set in the masks.

+
+
Parameters
+
    +
  • p0 – The pin values as an 8 bit mask for Port 0 to clear.

  • +
  • p1 – The pin values as an 8 bit mask for Port 1 to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(uint16_t mask, std::error_code &ec)
+

Clear the pin values for Port 0 and Port 1 according to the provided mask.

+

Reads the current pin values and clears any bits set in the mask.

+
+
Parameters
+
    +
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(Port port, uint8_t mask, std::error_code &ec)
+

Set the pin values on the provided port according to the provided mask.

+

Reads the current pin values and sets any bits set in the mask.

+
+
Parameters
+
    +
  • port – The Port for which to set the pin outputs.

  • +
  • mask – The pin values as an 8 bit mask to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set the pin values for Port 0 and Port 1 according to the provided masks.

+

Reads the current pin values and sets any bits set in the masks.

+
+
Parameters
+
    +
  • p0 – The pin values for Port 0 as an 8 bit mask to set.

  • +
  • p1 – The pin values for Port 1 as an 8 bit mask to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(uint16_t mask, std::error_code &ec)
+

Set the pin values for Port 0 and Port 1 according to the provided mask.

+

Reads the current pin values and sets any bits set in the mask.

+
+
Parameters
+
    +
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline uint8_t get_output(Port port, std::error_code &ec)
+

Read the output pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to read the pins

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The pin values as an 8 bit mask.

+
+
+
+ +
+
+inline uint16_t get_output(std::error_code &ec)
+

Read the output pin values on both Port 0 and Port 1.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

+
+
+
+ +
+
+inline void set_interrupt(Port port, uint8_t mask, std::error_code &ec)
+

Configure the provided pins to interrupt on change.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The pin mask to configure for interrupt (0=interrupt).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Configure the provided pins to interrupt on change.

+
+
Parameters
+
    +
  • p0 – The pin mask for Port 0 to configure for interrupt (0=interrupt).

  • +
  • p1 – The pin mask for Port 1 to configure for interrupt (0=interrupt).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_direction(Port port, uint8_t mask, std::error_code &ec)
+

Set the i/o direction for the pins according to mask.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The mask indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_direction(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set the i/o direction for the pins on Port 0 and Port 1.

+
+
Parameters
+
    +
  • p0 – The mask for Port 0 indicating direction (1 = input, 0 = output)

  • +
  • p1 – The mask for Port 1 indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_led(Port port, uint8_t mask, std::error_code &ec)
+

Enable/disable the LED function on the associated port pins.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The mask indicating LED function (1 = GPIO, 0 = LED)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_led(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Enable/disable the LED function on the associated port pins.

+
+
Parameters
+
    +
  • p0 – The mask for Port 0 indicating LED function (1 = GPIO, 0 = LED)

  • +
  • p1 – The mask for Port 1 indicating LED function (1 = GPIO, 0 = LED)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_led(uint16_t mask, std::error_code &ec)
+

Enable/disable the LED function on the associated port pins.

+
+
Parameters
+
    +
  • mask – The bit mask for Port 0 and Port 1 [(Port 1 << 8) | (Port 0)] indicating LED function (1 = GPIO, 0 = LED)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void led(uint16_t pin, uint8_t brightness, std::error_code &ec)
+

Set the pin’s LED to new brightness value.

+
+
Parameters
+
    +
  • pin – The pin bit corresponding to the pin (P0_0 lsb, P1_7 msb).

  • +
  • brightness – The brightness value [0,255] to set the LED to.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_global_control(OutputDriveModeP0 output_drive_mode_p0, MaxLedCurrent max_led_current, std::error_code &ec)
+

Configure the global control register.

+
+
Parameters
+
    +
  • output_drive_mode_p0 – Output drive mode for Port 0.

  • +
  • max_led_current – Maximum LED current for each LED pin.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x58
+

Lower 2 bits are AD1, AD0 pins on the chip.

+
+ +
+
+
+struct Config
+

Configuration information for the Aw9523.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address to use to talk to this AW9523B.

+
+ +
+
+uint8_t port_0_direction_mask = 0x00
+

Direction mask (1 = input) for port 0.

+
+ +
+
+uint8_t port_0_interrupt_mask = 0x00
+

Interrupt mask (1 = disable interrupt) for port 0.

+
+ +
+
+uint8_t port_1_direction_mask = 0x00
+

Direction mask (1 = input) for port 1.

+
+ +
+
+uint8_t port_1_interrupt_mask = 0x00
+

Interrupt mask (1 = disable interrupt) for port 1.

+
+ +
+
+OutputDriveModeP0 output_drive_mode_p0 = OutputDriveModeP0::OPEN_DRAIN
+

Output drive mode for Port 0.

+
+ +
+
+MaxLedCurrent max_led_current = MaxLedCurrent::IMAX
+

Max current allowed on each LED.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the device.

+
+ +
+
+BasePeripheral::write_then_read_fn write_then_read
+

Function to write then read from the device.

+
+ +
+
+bool auto_init = true
+

Automatically initialize the device.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the component.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/aw9523_example.html b/io_expander/aw9523_example.html new file mode 100644 index 000000000..6f251a5f8 --- /dev/null +++ b/io_expander/aw9523_example.html @@ -0,0 +1,241 @@ + + + + + + + AW9523 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AW9523 Example

+

This example shows how to use the Aw9523 component to communicate (via I2C) +with an AW9523 I2C digital IO expander and LED driver.

+

It is currently designed to run on an ESP32-S3, but (by changing the I2C pin +definitions in the main file) can be reconfigured to run on any of the ESP32 +chips.

+
+

How to use example

+
+

Hardware Required

+

This example requires a connection (via I2C) to a dev board which has an AW9523. +To that chip should be attached some digial inputs (such as buttons) as well as +an RGB LED.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

example output

+

An example video:

+

https://user-images.githubusercontent.com/213467/225365600-5ad600e9-68d6-4ddc-96d6-f56b72ec1a0e.mp4

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/index.html b/io_expander/index.html new file mode 100644 index 000000000..17a52aa63 --- /dev/null +++ b/io_expander/index.html @@ -0,0 +1,211 @@ + + + + + + + IO Expander APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

IO Expander APIs

+ +

There are several different types of I/O expanders provided which are standalone +components for interacting with I/O expander chips over a serial interface such +as I2C.

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/kts1622.html b/io_expander/kts1622.html new file mode 100644 index 000000000..78f352fb3 --- /dev/null +++ b/io_expander/kts1622.html @@ -0,0 +1,1496 @@ + + + + + + + KTS1622 I/O Expander - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

KTS1622 I/O Expander

+

The KTS1622 I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as I2C.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Kts1622 : public espp::BasePeripheral<>
+

Class for communicating with and controlling a KTS1622 GPIO expander including interrupt configuration. It supports 16 GPIO pins, 8 on each port, and can support optional input debounce timing (only P0_1-P0_7 and P1_0-P1_7, with P0_0 as clock input) and interrupt memory with trigger/mask/clear/status features. It supports up to 1MHz Fast-mode Plus I2C and can operate [1.65, 5.5]V on the I2C bus and I/O pins (with separate power pins for each).

+
+

KTS1622 Example

+
  // make the I2C that we'll use to communicate
+  espp::I2c i2c({
+      .port = I2C_NUM_1,
+      .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+      .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+      .sda_pullup_en = GPIO_PULLUP_ENABLE,
+      .scl_pullup_en = GPIO_PULLUP_ENABLE,
+      .clk_speed = 1000 * 1000, // 1MHz
+  });
+
+  // now make the kts1622 which handles GPIO
+  espp::Kts1622 kts1622(
+      {.device_address = espp::Kts1622::DEFAULT_ADDRESS,
+       // set P0_0 - P0_7 to be inputs
+       .port_0_direction_mask = 0b11111111,
+       // set P1_0 - P1_7 to be inputs
+       .port_1_direction_mask = 0b11111111,
+       .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                          std::placeholders::_3),
+       .write_then_read =
+           std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                     std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
+       .auto_init = false,
+       .log_level = espp::Logger::Verbosity::INFO});
+  std::error_code ec;
+  kts1622.initialize(
+      ec); // Initialized separately from the constructor since we set auto_init to false
+  if (ec) {
+    logger.error("kts1622 initialization failed: {}", ec.message());
+    return;
+  }
+
+  // and finally, make the task to periodically poll the kts1622 and print
+  // the state. NOTE: the Kts1622 does not internally manage its own state
+  // update, so whatever rate we use here is the rate at which the state will
+  // update.
+  auto task_fn = [&](std::mutex &m, std::condition_variable &cv) {
+    static auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    auto seconds = std::chrono::duration<float>(now - start).count();
+    // returns the pins as P0_0 lsb, P1_7 msb
+    auto pins = kts1622.get_pins(ec);
+    if (ec) {
+      logger.error("kts1622 get pins failed: {}", ec.message());
+      return true; // stop the task
+    }
+    // equivalent to:
+    // auto pins = (kts1622.get_pins(espp::Kts1622::Port::PORT1, ec) << 8) |
+    // kts1622.get_pins(espp::Kts1622::Port::PORT0, ec);
+    fmt::print("{:.3f}, {:#x}\n", seconds, pins);
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 50ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+  auto task = espp::Task({.callback = task_fn,
+                          .task_config =
+                              {
+                                  .name = "Kts1622 Task",
+                                  .stack_size_bytes = 5 * 1024,
+                              },
+                          .log_level = espp::Logger::Verbosity::WARN});
+  fmt::print("% time(s), pin values\n");
+  task.start();
+
+
+
+
+

Public Types

+
+
+enum class Port
+

The two GPIO ports the Kts1622 has.

+

Values:

+
+
+enumerator PORT0
+

Port 0.

+
+ +
+
+enumerator PORT1
+

Port 1.

+
+ +
+ +
+
+enum class OutputDriveMode : int
+

The output drive mode configuration.

+

Values:

+
+
+enumerator PUSH_PULL
+

In this mode it needs no pull-up resistor.

+
+ +
+
+enumerator OPEN_DRAIN
+

In this mode it needs a pull-up reistor. This is the default mode.

+
+ +
+ +
+
+enum class OutputDriveStrength : uint8_t
+

The output drive mode configuration.

+

Values:

+
+
+enumerator F_0_25
+

0.25x drive capability of the I/O pins

+
+ +
+
+enumerator F_0_5
+

0.5x drive capability of the I/O pins

+
+ +
+
+enumerator F_0_75
+

0.75x drive capability of the I/O pins

+
+ +
+
+enumerator F_1
+

1x drive capability of the I/O pins

+
+ +
+ +
+
+enum class PullResistor : uint8_t
+

The Pull Resistor configuration.

+

Values:

+
+
+enumerator NO_PULL
+

No pull resistor enabled.

+
+ +
+
+enumerator PULL_UP
+

Pull-up resistor enabled.

+
+ +
+
+enumerator PULL_DOWN
+

Pull-down resistor enabled.

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Kts1622(const Config &config)
+

Construct the Kts1622. Will call initialize() if auto_init is true.

+
+
Parameters
+

configConfig structure for configuring the KTS1622

+
+
+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the component class.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline uint8_t get_pins(Port port, std::error_code &ec)
+

Read the pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to read the pins

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The pin values as an 8 bit mask.

+
+
+
+ +
+
+inline uint16_t get_pins(std::error_code &ec)
+

Read the pin values on both Port 0 and Port 1.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

+
+
+
+ +
+
+inline void output(Port port, uint8_t value, std::error_code &ec)
+

Write the pin values on the provided port.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the port.

+
+
+
Parameters
+
    +
  • port – The Port for which to write the pins

  • +
  • value – The pin values to apply.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void output(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Write the pin values on both Port 0 and Port 1.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the ports.

+
+
+
Parameters
+
    +
  • p0 – The pin values to apply to Port 0.

  • +
  • p1 – The pin values to apply to Port 1.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void output(uint16_t value, std::error_code &ec)
+

Write the pin values on both Port 0 and Port 1.

+
+

Note

+

This will overwrite any previous pin values on the port for all output pins on the ports.

+
+
+
Parameters
+
    +
  • value – The pin values to apply as a 16 bit value (P0_0 lsb, P1_7 msb).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(Port port, uint8_t mask, std::error_code &ec)
+

Clear the pin values on the provided port according to the provided mask.

+

Reads the current pin values and clears any bits set in the mask.

+
+
Parameters
+
    +
  • port – The Port for which to clear the pin outputs.

  • +
  • mask – The pin values as an 8 bit mask to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Clear the pin values for Port 0 and Port 1 according to the provided masks.

+

Reads the current pin values and clears any bits set in the masks.

+
+
Parameters
+
    +
  • p0 – The pin values as an 8 bit mask for Port 0 to clear.

  • +
  • p1 – The pin values as an 8 bit mask for Port 1 to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_pins(uint16_t mask, std::error_code &ec)
+

Clear the pin values for Port 0 and Port 1 according to the provided mask.

+

Reads the current pin values and clears any bits set in the mask.

+
+
Parameters
+
    +
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to clear.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(Port port, uint8_t mask, std::error_code &ec)
+

Set the pin values on the provided port according to the provided mask.

+

Reads the current pin values and sets any bits set in the mask.

+
+
Parameters
+
    +
  • port – The Port for which to set the pin outputs.

  • +
  • mask – The pin values as an 8 bit mask to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set the pin values for Port 0 and Port 1 according to the provided masks.

+

Reads the current pin values and sets any bits set in the masks.

+
+
Parameters
+
    +
  • p0 – The pin values for Port 0 as an 8 bit mask to set.

  • +
  • p1 – The pin values for Port 1 as an 8 bit mask to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pins(uint16_t mask, std::error_code &ec)
+

Set the pin values for Port 0 and Port 1 according to the provided mask.

+

Reads the current pin values and sets any bits set in the mask.

+
+
Parameters
+
    +
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to set.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline uint8_t get_output(Port port, std::error_code &ec)
+

Read the output pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to read the pins

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
Returns
+

The pin values as an 8 bit mask.

+
+
+
+ +
+
+inline uint16_t get_output(std::error_code &ec)
+

Read the output pin values on both Port 0 and Port 1.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

+
+
+
+ +
+
+inline void set_port_output_drive_mode(Port port, OutputDriveMode mode, std::error_code &ec)
+

Set the output drive mode for the provided pins on the provided port.

+
+
Parameters
+
    +
  • port – The port to set the output drive mode for.

  • +
  • mode – The output drive mode to set for the port.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void enable_interrupt(Port port, uint8_t mask, std::error_code &ec)
+

Configure the provided pins to interrupt.

+

+

See also

+

configure_interrupt

+
+

+
+

Note

+

You should also call configure_interrupt to configure the interrupt type for the pins.

+
+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The pin mask to configure for interrupt (0=interrupt).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void enable_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Configure the provided pins to interrupt on change.

+

+

See also

+

configure_interrupt

+
+

+
+

Note

+

You should also call configure_interrupt to configure the interrupt type for the pins.

+
+
+
Parameters
+
    +
  • p0 – The pin mask for Port 0 to configure for interrupt (0=interrupt).

  • +
  • p1 – The pin mask for Port 1 to configure for interrupt (0=interrupt).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void enable_interrupt(uint16_t mask, std::error_code &ec)
+

Configure the provided pins to interrupt on change.

+

+

See also

+

configure_interrupt

+
+

+
+

Note

+

You should also call configure_interrupt to configure the interrupt type for the pins.

+
+
+
Parameters
+
    +
  • mask – The pin mask to configure for interrupt (0=interrupt).

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_interrupt(Port port, uint8_t mask, InterruptType type, std::error_code &ec)
+

Configure the provided pins to interrupt on the provided type.

+

+

See also

+

enable_interrupt

+
+

+
+

Note

+

You should also call enable_interrupt to enable the interrupt for the pins.

+
+
+

Note

+

This will overwrite any previous interrupt configuration on the port for all pins on the port.

+
+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The pin mask to configure for interrupt.

  • +
  • type – The type of interrupt to configure.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void configure_interrupt(uint8_t p0, uint8_t p1, InterruptType type, std::error_code &ec)
+

Configure the provided pins to interrupt on the provided type.

+

+

See also

+

enable_interrupt

+
+

+
+

Note

+

You should also call enable_interrupt to enable the interrupt for the pins.

+
+
+

Note

+

This will overwrite any previous interrupt configuration on the port for all pins on the port.

+
+
+
Parameters
+
    +
  • p0 – The pin mask for Port 0 to configure for interrupt.

  • +
  • p1 – The pin mask for Port 1 to configure for interrupt.

  • +
  • type – The type of interrupt to configure.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_interrupt(Port port, uint8_t mask, std::error_code &ec)
+

Clear the interrupt for the provided pins.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The pin mask to clear the interrupt for.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Clear the interrupt for the provided pins.

+
+
Parameters
+
    +
  • p0 – The pin mask for Port 0 to clear the interrupt for.

  • +
  • p1 – The pin mask for Port 1 to clear the interrupt for.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_interrupt(uint16_t mask, std::error_code &ec)
+

Clear the interrupt for the provided pins.

+
+
Parameters
+
    +
  • mask – The pin mask to clear the interrupt for.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void clear_interrupts(std::error_code &ec)
+

Clear all interrupts.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
+
+ +
+
+inline void set_direction(Port port, uint8_t mask, std::error_code &ec)
+

Set the i/o direction for the pins according to mask.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The mask indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_direction(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set the i/o direction for the pins on Port 0 and Port 1.

+
+
Parameters
+
    +
  • p0 – The mask for Port 0 indicating direction (1 = input, 0 = output)

  • +
  • p1 – The mask for Port 1 indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_direction(uint16_t mask, std::error_code &ec)
+

Set the i/o direction for the pins according to mask.

+
+
Parameters
+
    +
  • mask – The mask indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_direction(uint16_t mask, bool direction, std::error_code &ec)
+

Set the i/o direction for the pins according to mask.

+
+
Parameters
+
    +
  • mask – The mask indicating pin position

  • +
  • direction – The direction indicating direction (1 = input, 0 = output)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_polarity_inversion(Port port, uint8_t mask, std::error_code &ec)
+

Set polarity inversion for the pins according to mask.

+
+

Note

+

This will overwrite any previous polarity inversion on the port for all pins on the port.

+
+
+

Note

+

This will only affect pins configured as inputs.

+
+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The mask indicating polarity inversion (1 = inverted, 0 = normal)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_polarity_inversion(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set polarity inversion for the pins on Port 0 and Port 1.

+
+

Note

+

This will overwrite any previous polarity inversion on the port for all pins on the port.

+
+
+

Note

+

This will only affect pins configured as inputs.

+
+
+
Parameters
+
    +
  • p0 – The mask for Port 0 indicating polarity inversion (1 = inverted, 0 = normal)

  • +
  • p1 – The mask for Port 1 indicating polarity inversion (1 = inverted, 0 = normal)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_polarity_inversion(uint16_t mask, std::error_code &ec)
+

Set polarity inversion for the pins according to mask.

+
+

Note

+

This will overwrite any previous polarity inversion on the port for all pins on the port.

+
+
+

Note

+

This will only affect pins configured as inputs.

+
+
+
Parameters
+
    +
  • mask – The mask indicating polarity inversion (1 = inverted, 0 = normal)

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_input_latch(Port port, uint8_t latch, std::error_code &ec)
+

Set the input latch for the input pins according to latch.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • latch – The value to set the latch register to. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_input_latch(uint8_t p0, uint8_t p1, std::error_code &ec)
+

Set the input latch for the input pins on Port 0 and Port 1.

+

+ +

+
+

Note

+

This will overwrite any previous latch values on the port for all input pins on the port.

+
+
+
Parameters
+
    +
  • p0 – The value to set the latch register to for Port 0. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

  • +
  • p1 – The value to set the latch register to for Port 1. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_input_latch(uint16_t mask, std::error_code &ec)
+

Set the input latch for the input pins according to latch.

+

+ +

+
+

Note

+

This will overwrite any previous latch values on the port for all input pins on the port.

+
+
+
Parameters
+
    +
  • mask – The value to set the latch register to. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline void set_pull_resistor_for_pin(Port port, uint8_t pin_mask, PullResistor pull, std::error_code &ec)
+

Set the pull resistor for the provided pins.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • pin_mask – The pin mask to configure for pull resistor.

  • +
  • pull – The pull resistor to configure.

  • +
  • ec – Error code to set if an error occurs.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0x20
+

Lower 2 bits are configurable via the ADDR pin (GND, VCC, SCL, SDA -> 00, 01, 02, 03)

+
+ +
+
+
+struct Config
+

Configuration information for the Kts1622.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address to use to talk to this KTS1622B.

+
+ +
+
+uint8_t port_0_direction_mask = 0xFF
+

Direction mask (1 = input) for port 0.

+
+ +
+
+uint8_t port_0_interrupt_mask = 0xFF
+

Interrupt mask (1 = disable interrupt) for port 0.

+
+ +
+
+uint8_t port_1_direction_mask = 0xFF
+

Direction mask (1 = input) for port 1.

+
+ +
+
+uint8_t port_1_interrupt_mask = 0xFF
+

Interrupt mask (1 = disable interrupt) for port 1.

+
+ +
+
+OutputDriveMode output_drive_mode = OutputDriveMode::PUSH_PULL
+

Output drive mode for the ports.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the device.

+
+ +
+
+BasePeripheral::write_then_read_fn write_then_read
+

Function to write then read from the device.

+
+ +
+
+bool auto_init = true
+

Automatically initialize the device.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the component.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/kts1622_example.html b/io_expander/kts1622_example.html new file mode 100644 index 000000000..9e790132a --- /dev/null +++ b/io_expander/kts1622_example.html @@ -0,0 +1,240 @@ + + + + + + + KTS1622 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

KTS1622 Example

+

This example shows how to use the Kts1622 component to communicate (via I2C) +with an KTS1622 I2C digital IO expander.

+

It is currently designed to run on an ESP32-S3, but (by changing the I2C pin +definitions in the main file) can be reconfigured to run on any of the ESP32 +chips.

+
+

How to use example

+
+

Hardware Required

+

This example requires a connection (via I2C) to a dev board which has an KTS1622. +To that chip should be attached some digital inputs (such as buttons).

+

It has been tested on a QtPy ESP32S3 connected to a KTS1622EUAA-MMEV01 +kts1622 evaluation kit via a qwiic / stemma qt cable.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-02-14 at 17 07 57

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/mcp23x17.html b/io_expander/mcp23x17.html new file mode 100644 index 000000000..4b6bbb35e --- /dev/null +++ b/io_expander/mcp23x17.html @@ -0,0 +1,966 @@ + + + + + + + MCP23x17 I/O Expander - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MCP23x17 I/O Expander

+

The MCP23x17 I/O expander component allows the user to configure inputs, +outputs, interrupts, etc. via a serial interface such as SPI or I2C.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Mcp23x17 : public espp::BasePeripheral<>
+

Class for communicating with and controlling a MCP23X17 (23017, 23S17) GPIO expander including interrupt configuration.

+
+

MCP23x17 Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+    // now make the mcp23x17 which handles GPIO
+    espp::Mcp23x17 mcp23x17(
+        {.port_0_direction_mask = (1 << 0), // input on A0
+         .port_0_interrupt_mask = (1 << 0), // interrupt on A0
+         .port_1_direction_mask = (1 << 7), // input on B7
+         .port_1_interrupt_mask = (1 << 7), // interrupt on B7
+         .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                            std::placeholders::_3),
+         .read_register =
+             std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+                       std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+         .log_level = espp::Logger::Verbosity::WARN});
+    // set pull up on the input pins
+    std::error_code ec;
+    mcp23x17.set_pull_up(espp::Mcp23x17::Port::PORT0, (1 << 0), ec);
+    if (ec) {
+      fmt::print("set_pull_up failed: {}\n", ec.message());
+    }
+    mcp23x17.set_pull_up(espp::Mcp23x17::Port::PORT1, (1 << 7), ec);
+    if (ec) {
+      fmt::print("set_pull_up failed: {}\n", ec.message());
+    }
+    // and finally, make the task to periodically poll the mcp23x17 and print
+    // the state. NOTE: the Mcp23x17 does not internally manage its own state
+    // update, so whatever rate we use here is the rate at which the state will
+    // update.
+    auto task_fn = [&quit_test, &mcp23x17](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds = std::chrono::duration<float>(now - start).count();
+      std::error_code ec;
+      auto a_pins = mcp23x17.get_pins(espp::Mcp23x17::Port::PORT0, ec);
+      if (ec) {
+        fmt::print("get_pins failed: {}\n", ec.message());
+        return false;
+      }
+      auto b_pins = mcp23x17.get_pins(espp::Mcp23x17::Port::PORT1, ec);
+      if (ec) {
+        fmt::print("get_pins failed: {}\n", ec.message());
+        return false;
+      }
+      bool on = !(a_pins & (1 << 0));
+      if (on) {
+        mcp23x17.set_pins(espp::Mcp23x17::Port::PORT1, (1 << 3), ec);
+      } else {
+        mcp23x17.set_pins(espp::Mcp23x17::Port::PORT1, 0x00, ec);
+      }
+      if (ec) {
+        fmt::print("set_pins failed: {}\n", ec.message());
+        return false;
+      }
+      fmt::print("{:.3f}, {:#x}, {:#x}\n", seconds, a_pins, b_pins);
+      quit_test = !(b_pins & (1 << 7));
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Mcp23x17 Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    fmt::print("%time(s), port_a pins, port_b pins\n");
+    task.start();
+
+
+
+
+

Public Types

+
+
+enum class Port
+

The two GPIO ports the MCP23x17 has.

+

Values:

+
+
+enumerator PORT0
+

Port 0.

+
+ +
+
+enumerator PORT1
+

Port 1.

+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Mcp23x17(const Config &config)
+

Construct the Mcp23x17 and configure it.

+
+
Parameters
+

configConfig structure for configuring the MCP23X17

+
+
+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the device.

+
+
Parameters
+

ec – Error code to set if there is an error.

+
+
+
+ +
+
+inline uint8_t get_pins(Port port, std::error_code &ec)
+

Read the pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to read the pins

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
Returns
+

The pin values as an 8 bit mask.

+
+
+
+ +
+
+inline uint16_t get_pins(std::error_code &ec)
+

Read the pin values on both Port A and Port B.

+
+
Parameters
+

ec – Error code to set if an error occurs.

+
+
Returns
+

The pin values as a 16 bit mask (PA_0 lsb, PB_7 msb).

+
+
+
+ +
+
+inline void set_pins(Port port, uint8_t output, std::error_code &ec)
+

Set the pin values on the provided port.

+
+
Parameters
+
    +
  • port – The Port for which to set the pin outputs.

  • +
  • output – The pin values as an 8 bit mask to set.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline uint8_t get_interrupt_capture(Port port, std::error_code &ec)
+

Get the pin state at the time of interrupt for the provided port.

+
+
Parameters
+
    +
  • port – The port for which to get the pin states at time of capture.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
Returns
+

An 8 bit mask of pin values for the provided port.

+
+
+
+ +
+
+inline void set_interrupt_on_change(Port port, uint8_t mask, std::error_code &ec)
+

Configure the provided pins to interrupt on change.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The pin mask to configure for interrupt (1=interrupt).

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_interrupt_on_value(Port port, uint8_t pin_mask, uint8_t val_mask, std::error_code &ec)
+

Configure the provided pins to interrupt on value.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • pin_mask – The pin mask to configure for interrupt (1=interrupt).

  • +
  • val_mask – The value mask for the pin level to trigger interrupt.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_direction(Port port, uint8_t mask, std::error_code &ec)
+

Set the i/o direction for the pins according to mask.

+
+
Parameters
+
    +
  • port – The port associated with the provided pin mask.

  • +
  • mask – The mask indicating direction (1 = input)

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_input_polarity(Port port, uint8_t mask, std::error_code &ec)
+

Set the input polarity for the pins according to mask.

+
+
Parameters
+
    +
  • port – The port associated with the provided polarity mask.

  • +
  • mask – Polarity mask for the pins, 1 -> invert the pin value.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_pull_up(Port port, uint8_t mask, std::error_code &ec)
+

Set the internal pull up (100 Kohm) for the port’s pins.

+
+
Parameters
+
    +
  • port – The port associated with the provided pull up mask.

  • +
  • mask – Mask indicating which pins should be pulled up (1).

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_interrupt_mirror(bool mirror, std::error_code &ec)
+

Configure the interrupt mirroring for the MCP23x17.

+
+
Parameters
+
    +
  • mirror – True if the interrupt pins should be internally connected, false otherwise.

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline void set_interrupt_polarity(bool active_high, std::error_code &ec)
+

Set the polarity of the interrupt pins.

+
+
Parameters
+
    +
  • active_high – True if it should be active-high, false for active-low (default).

  • +
  • ec – Error code to set if there is an error.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = 0b0100000
+

Lower 3 bits are A2, A2, A0 pins on the chip.

+
+ +
+
+
+struct Config
+

Configuration information for the Mcp23x17.

+
+

Public Members

+
+
+uint8_t device_address = DEFAULT_ADDRESS
+

I2C address of this device.

+
+ +
+
+uint8_t port_0_direction_mask = 0x00
+

Direction mask (1 = input) for port 0 / A.

+
+ +
+
+uint8_t port_0_interrupt_mask = 0x00
+

Interrupt mask (1 = interrupt) for port 0 / A.

+
+ +
+
+uint8_t port_1_direction_mask = 0x00
+

Direction mask (1 = input) for port 1 / B.

+
+ +
+
+uint8_t port_1_interrupt_mask = 0x00
+

Interrupt mask (1 = interrupt) for port 1 / B.

+
+ +
+
+BasePeripheral::write_fn write
+

Function to write to the device.

+
+ +
+
+BasePeripheral::read_register_fn read_register
+

Function to read bytes at a register address from the device.

+
+ +
+
+bool auto_init = true
+

True if the device should be initialized on construction.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the component.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/io_expander/mcp23x17_example.html b/io_expander/mcp23x17_example.html new file mode 100644 index 000000000..725c69bb4 --- /dev/null +++ b/io_expander/mcp23x17_example.html @@ -0,0 +1,230 @@ + + + + + + + MCP23x17 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MCP23x17 Example

+

This example shows how to communicate with an MCP23017 I2C digital I/O exapander +using the espp::Mcp23x17 component.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be used with an Adafruit MCP23017 I2C +Breakout connected via I2C.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/joystick.html b/joystick.html new file mode 100644 index 000000000..89813eab7 --- /dev/null +++ b/joystick.html @@ -0,0 +1,793 @@ + + + + + + + Joystick APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Joystick APIs

+
+

Joystick

+

The Joystick class provides a wrapper around a 2-axis analog joystick, with an +associated reader function for grabbing the raw values. When the joystick +update() is called, the raw values are mapped into the range [-1,1] for each +axis according to the configuration provided.

+

Code examples for the task API are provided in the joystick example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Joystick : public espp::BaseComponent
+

2-axis Joystick with axis mapping / calibration.

+
+

Basic Circular and Rectangular Joystick Example

+
      float min = 0;
+      float max = 255;
+      float center = 127;
+      float deadband_percent = 0.1;
+      float deadband = deadband_percent * (max - min);
+
+      // circular joystick
+      espp::Joystick js1({
+          .x_calibration = {.center = center, .minimum = min, .maximum = max},
+          .y_calibration = {.center = center, .minimum = min, .maximum = max},
+          .type = espp::Joystick::Type::CIRCULAR,
+          .center_deadzone_radius = deadband_percent,
+          .range_deadzone = deadband_percent,
+      });
+      // square joystick (for comparison)
+      espp::Joystick js2({
+          .x_calibration = {.center = center,
+                            .center_deadband = deadband,
+                            .minimum = min,
+                            .maximum = max,
+                            .range_deadband = deadband},
+          .y_calibration = {.center = center,
+                            .center_deadband = deadband,
+                            .minimum = min,
+                            .maximum = max,
+                            .range_deadband = deadband},
+      });
+      // now make a loop where we update the raw valuse and print out the joystick values
+      fmt::print("raw x, raw y, js1 x, js1 y, js2 x, js2 y\n");
+      for (float x = min - 10.0f; x <= max + 10.0f; x += 10.0f) {
+        for (float y = min - 10.0f; y <= max + 10.0f; y += 10.0f) {
+          js1.update(x, y);
+          js2.update(x, y);
+          fmt::print("{}, {}, {}, {}, {}, {}\n", x, y, js1.x(), js1.y(), js2.x(), js2.y());
+        }
+      }
+
+
+
+
+

ADC Joystick Example

+
      static constexpr adc_unit_t ADC_UNIT = CONFIG_EXAMPLE_ADC_UNIT == 1 ? ADC_UNIT_1 : ADC_UNIT_2;
+      static constexpr adc_channel_t ADC_CHANNEL_X = (adc_channel_t)CONFIG_EXAMPLE_ADC_CHANNEL_X;
+      static constexpr adc_channel_t ADC_CHANNEL_Y = (adc_channel_t)CONFIG_EXAMPLE_ADC_CHANNEL_Y;
+
+      std::vector<espp::AdcConfig> channels{
+          {.unit = ADC_UNIT, .channel = ADC_CHANNEL_X, .attenuation = ADC_ATTEN_DB_12},
+          {.unit = ADC_UNIT, .channel = ADC_CHANNEL_Y, .attenuation = ADC_ATTEN_DB_12}};
+      espp::OneshotAdc adc({
+          .unit = ADC_UNIT_2,
+          .channels = channels,
+      });
+      auto read_joystick = [&adc, &channels](float *x, float *y) -> bool {
+        // this will be in mv
+        auto maybe_x_mv = adc.read_mv(channels[0]);
+        auto maybe_y_mv = adc.read_mv(channels[1]);
+        if (maybe_x_mv.has_value() && maybe_y_mv.has_value()) {
+          auto x_mv = maybe_x_mv.value();
+          auto y_mv = maybe_y_mv.value();
+          *x = (float)(x_mv);
+          *y = (float)(y_mv);
+          return true;
+        }
+        return false;
+      };
+      espp::Joystick js1({
+          // convert [0, 3300]mV to approximately [-1.0f, 1.0f]
+          .x_calibration =
+              {.center = 1700.0f, .center_deadband = 100.0f, .minimum = 0.0f, .maximum = 3300.0f},
+          .y_calibration =
+              {.center = 1700.0f, .center_deadband = 100.0f, .minimum = 0.0f, .maximum = 3300.0f},
+          .get_values = read_joystick,
+      });
+      espp::Joystick js2({
+          // convert [0, 3300]mV to approximately [-1.0f, 1.0f]
+          .x_calibration =
+              {.center = 1700.0f, .center_deadband = 0.0f, .minimum = 0.0f, .maximum = 3300.0f},
+          .y_calibration =
+              {.center = 1700.0f, .center_deadband = 0.0f, .minimum = 0.0f, .maximum = 3300.0f},
+          .type = espp::Joystick::Type::CIRCULAR,
+          .center_deadzone_radius = 0.1f,
+          .get_values = read_joystick,
+      });
+      auto task_fn = [&js1, &js2](std::mutex &m, std::condition_variable &cv) {
+        js1.update();
+        js2.update();
+        fmt::print("{}, {}\n", js1, js2);
+        // NOTE: sleeping in this way allows the sleep to exit early when the
+        // task is being stopped / destroyed
+        {
+          std::unique_lock<std::mutex> lk(m);
+          cv.wait_for(lk, 500ms);
+        }
+        // don't want to stop the task
+        return false;
+      };
+      auto task = espp::Task({.callback = task_fn,
+                              .task_config = {.name = "Joystick"},
+                              .log_level = espp::Logger::Verbosity::INFO});
+      fmt::print("js1 x, js1 y, js2 x, js2 y\n");
+      task.start();
+
+
+
+
+

Public Types

+
+
+enum class Type
+

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.

+
+

Values:

+
+
+enumerator RECTANGULAR
+

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.

+
+ +
+
+enumerator CIRCULAR
+

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.

+
+ +
+ +
+
+typedef std::function<bool(float *x, float *y)> get_values_fn
+

function for gettin x/y values for the joystick.

+
+
Param x
+

Pointer to the x value. Function should fill this variable with the latest reading.

+
+
Param y
+

Pointer to the y value. Function should fill this variable with the latest reading.

+
+
Return
+

True if the values were able to be retrieved, false otherwise.

+
+
+
+ +
+
+

Public Functions

+
+
+explicit Joystick(const espp::Joystick::Config &config)
+

Initalize the joystick using the provided configuration.

+
+
Parameters
+

configConfig structure with initialization information.

+
+
+
+ +
+
+void set_type(espp::Joystick::Type type, float radius = 0, float range_deadzone = 0)
+

Set the type of the joystick.

+

+
+

See also

+

set_range_deadzone

+
+
+

See also

+

set_calibration

+
+

+
+

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.

+
+
+
Parameters
+
    +
  • type – The Type of the joystick.

  • +
  • radius – Optional radius parameter used when 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).

  • +
  • range_deadzone – Optional deadzone around the edge of the unit circle when 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.

  • +
+
+
+
+ +
+
+espp::Joystick::Type type() const
+

Get the type of the joystick.

+
+
Returns
+

The Type of the joystick.

+
+
+
+ +
+
+void set_center_deadzone_radius(float radius)
+

Sets the center deadzone radius.

+
+

Note

+

Radius is only applied when deadzone is Deadzone::CIRCULAR.

+
+
+
Parameters
+

radius – Optional radius parameter used when 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).

+
+
+
+ +
+
+float center_deadzone_radius() const
+

Get the center deadzone radius.

+
+
Returns
+

The center deadzone radius.

+
+
+
+ +
+
+void set_range_deadzone(float range_deadzone)
+

Sets the range deadzone.

+
+

Note

+

Range deadzone is only applied when deadzone is Deadzone::CIRCULAR.

+
+
+
Parameters
+

range_deadzone – Optional deadzone around the edge of the unit circle when 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.

+
+
+
+ +
+
+float range_deadzone() const
+

Get the range deadzone.

+
+
Returns
+

The range deadzone.

+
+
+
+ +
+
+void set_calibration(const espp::FloatRangeMapper::Config &x_calibration, const espp::FloatRangeMapper::Config &y_calibration, float center_deadzone_radius = 0, float range_deadzone = 0)
+

Update the x and y axis mapping.

+

+
+

See also

+

set_range_deadzone

+
+

+
+

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.

+
+
+
Parameters
+
    +
  • x_calibration – New x-axis range mapping configuration to use.

  • +
  • y_calibration – New y-axis range mapping configuration to use.

  • +
  • center_deadzone_radius – The radius of the unit circle’s deadzone [0, 1.0f] around the center, only used when the joystick is configured as Type::CIRCULAR.

  • +
  • range_deadzone – Optional deadzone around the edge of the unit circle when 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.

  • +
+
+
+
+ +
+
+void update()
+

Read the raw values and use the calibration data to update the position.

+
+

Note

+

Requires that the get_values_ function is set.

+
+
+ +
+
+void update(float raw_x, float raw_y)
+

Update the joystick’s position using the provided raw x and y values.

+
+

Note

+

This function is useful when you have the raw values and don’t want to use the get_values_ function.

+
+
+
Parameters
+
    +
  • raw_x – The raw x-axis value.

  • +
  • raw_y – The raw y-axis value.

  • +
+
+
+
+ +
+
+float x() const
+

Get the most recently updated x axis calibrated position.

+
+
Returns
+

The most recent x-axis position (from when update() was last called).

+
+
+
+ +
+
+float y() const
+

Get the most recently updated y axis calibrated position.

+
+
Returns
+

The most recent y-axis position (from when update() was last called).

+
+
+
+ +
+
+espp::Vector2f position() const
+

Get the most recently updated calibrated position.

+
+
Returns
+

The most recent position (from when update() was last called).

+
+
+
+ +
+
+espp::Vector2f raw() const
+

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.

+
+
Returns
+

The most recent raw measurements (from when update() was last called).

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration structure for the joystick.

+
+

Public Members

+
+
+espp::FloatRangeMapper::Config x_calibration
+

Configuration for the x axis.

+
+ +
+
+espp::FloatRangeMapper::Config y_calibration
+

Configuration for the y axis.

+
+ +
+
+espp::Joystick::Type type = {espp::Joystick::Type::RECTANGULAR}
+

The type of the joystick. See Type enum for more information.

+
+ +
+
+float center_deadzone_radius{0}
+

The radius of the unit circle’s deadzone [0, 1.0f] around the center, only used when the joystick is configured as Type::CIRCULAR.

+
+ +
+
+float range_deadzone = {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].

+
+ +
+
+espp::Joystick::get_values_fn get_values = {nullptr}
+

Function to retrieve the latest unmapped joystick values. Required if you want to use update(), unused if you call update(float raw_x, floatraw_y).

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the Joystick logger_.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/joystick_example.html b/joystick_example.html new file mode 100644 index 000000000..2933db6e7 --- /dev/null +++ b/joystick_example.html @@ -0,0 +1,233 @@ + + + + + + + Joystick Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Joystick Example

+

This example shows the use of the Joystick class to manage the input from and +perform mapping / calibration of joystick data from an analog joystick.

+

image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be used with an analog joystick directly connected +to the ESP ADC 2, channels 8 and 9.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/led.html b/led.html new file mode 100644 index 000000000..bad616c52 --- /dev/null +++ b/led.html @@ -0,0 +1,676 @@ + + + + + + + LED APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LED APIs

+
+

LED

+

The LED provides a convenient and thread-safe wrapper around the ESP-IDF LEDC +perhipheral.

+

It allows for both instant and hardware-based timed changing (fading) of duty cycle (in +floating point percent [0,100]).

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Led : public espp::BaseComponent
+

Provides a wrapper around the LEDC peripheral in ESP-IDF which allows for thread-safe control over one or more channels of LEDs using a simpler API.

+
+

Linear LED Example

+
    float num_seconds_to_run = 10.0f;
+    logger.info("Starting linear led example for {:.1f}s!", num_seconds_to_run);
+    int led_fade_time_ms = 1000;
+    std::vector<espp::Led::ChannelConfig> led_channels{{
+        .gpio = 2,
+        .channel = LEDC_CHANNEL_5,
+        .timer = LEDC_TIMER_2,
+    }};
+    espp::Led led(espp::Led::Config{
+        .timer = LEDC_TIMER_2,
+        .frequency_hz = 5000,
+        .channels = led_channels,
+        .duty_resolution = LEDC_TIMER_10_BIT,
+    });
+    auto led_channel = led_channels[0].channel;
+    auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    float elapsed = std::chrono::duration<float>(now - start).count();
+    while (elapsed < num_seconds_to_run) {
+      // if we can change the led, the previous fade is done
+      if (led.can_change(led_channel)) {
+        auto maybe_duty = led.get_duty(led_channel);
+        if (maybe_duty.has_value()) {
+          auto current_duty = maybe_duty.value();
+          float new_duty = (current_duty < 50.0f) ? 100.0f : 0.0f;
+          // start a new fade to the opposite duty cycle
+          led.set_fade_with_time(led_channel, new_duty, led_fade_time_ms);
+        }
+      }
+      // sleep for a little bit
+      std::this_thread::sleep_for(100ms);
+      // update our elapsed time
+      now = std::chrono::high_resolution_clock::now();
+      elapsed = std::chrono::duration<float>(now - start).count();
+    }
+
+
+
+
+

Breathing LED Example

+
    float breathing_period = 3.5f; // seconds
+    float num_periods_to_run = 2.0f;
+    float num_seconds_to_run = num_periods_to_run * breathing_period;
+    logger.info("Starting gaussian led example for {:.1f}s!", num_seconds_to_run);
+    std::vector<espp::Led::ChannelConfig> led_channels{{
+        .gpio = 2,
+        .channel = LEDC_CHANNEL_5,
+        .timer = LEDC_TIMER_2,
+    }};
+    espp::Led led(espp::Led::Config{
+        .timer = LEDC_TIMER_2,
+        .frequency_hz = 5000,
+        .channels = led_channels,
+        .duty_resolution = LEDC_TIMER_10_BIT,
+        .clock_config = LEDC_USE_RC_FAST_CLK,
+    });
+    espp::Gaussian gaussian({.gamma = 0.1f, .alpha = 1.0f, .beta = 0.5f});
+    auto breathe = [&gaussian, &breathing_period]() -> float {
+      static auto breathing_start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - breathing_start).count();
+      float t = std::fmod(elapsed, breathing_period) / breathing_period;
+      return gaussian(t);
+    };
+    auto led_callback = [&breathe, &led, &led_channels](auto &m, auto &cv) -> bool {
+      led.set_duty(led_channels[0].channel, 100.0f * breathe());
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 10ms);
+      return false;
+    };
+    auto led_task =
+        espp::Task::make_unique({.callback = led_callback, .task_config = {.name = "breathe"}});
+    led_task->start();
+    logger.debug("Sleeping for {:.1f}s...", num_seconds_to_run);
+    std::this_thread::sleep_for(num_seconds_to_run * 1.0s);
+
+
+
+
+

Public Functions

+
+
+explicit Led(const Config &config) noexcept
+

Initialize the LEDC subsystem according to the configuration.

+
+
Parameters
+

config – The configuration structure for the LEDC subsystem.

+
+
+
+ +
+
+~Led()
+

Stop the LEDC subsystem and free memory.

+
+ +
+
+bool can_change(ledc_channel_t channel)
+

Can the LED settings can be changed for the channel? If this function returns true, then (threaded race conditions aside), the set_duty() and set_fade_with_time() functions should not block.

+
+
Parameters
+

channel – The channel to check

+
+
Returns
+

True if the channel settings can be changed, false otherwise

+
+
+
+ +
+
+std::optional<float> get_duty(ledc_channel_t channel) const
+

Get the current duty cycle this channel has.

+
+
Parameters
+

channel – The channel in question

+
+
Returns
+

The duty percentage [0.0f, 100.0f] if the channel is managed, std::nullopt otherwise

+
+
+
+ +
+
+void set_duty(ledc_channel_t channel, float duty_percent)
+

Set the duty cycle for this channel.

+
+

Note

+

This function will block until until a current fade process completes (if there is one).

+
+
+
Parameters
+
    +
  • channel – The channel to set the duty cycle for.

  • +
  • duty_percent – The new duty percentage, [0.0, 100.0].

  • +
+
+
+
+ +
+
+void set_fade_with_time(ledc_channel_t channel, float duty_percent, uint32_t fade_time_ms)
+

Set the duty cycle for this channel, fading from the current duty cycle to the new duty cycle over fade_time_ms milliseconds.

+
+

Note

+

This function will block until until a current fade process completes (if there is one).

+
+
+
Parameters
+
    +
  • channel – The channel to fade.

  • +
  • duty_percent – The new duty percentage to fade to, [0.0, 100.0].

  • +
  • fade_time_ms – The number of milliseconds for which to fade.

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static void uninstall_isr()
+

Uninstall the fade service. This should be called if you want to stop the fade service and free up the ISR.

+
+

Note

+

This function should only be called if you are sure that no other Led objects are using the fade service.

+
+
+ +
+
+
+struct ChannelConfig
+

Represents one LED channel.

+
+

Public Members

+
+
+size_t gpio
+

The GPIO pin the LED is connected to.

+
+ +
+
+ledc_channel_t channel
+

The LEDC channel that you want associated with this LED.

+
+ +
+
+ledc_timer_t timer
+

The LEDC timer that you want associated with this LED channel.

+
+ +
+
+float duty{0}
+

The starting duty cycle (%) [0, 100] that you want the LED channel to have.

+
+ +
+
+ledc_mode_t speed_mode{LEDC_LOW_SPEED_MODE}
+

The LEDC speed mode you want for this LED channel.

+
+ +
+
+bool output_invert = {false}
+

Whether to invert the GPIO output for this LED channel.

+
+ +
+
+ledc_sleep_mode_t sleep_mode{LEDC_SLEEP_MODE_KEEP_ALIVE}
+

The LEDC sleep mode you want for this LED channel. Default is LEDC_SLEEP_MODE_KEEP_ALIVE which will keep the LEDC output when the system enters light sleep. Note that this is only useful if the LED’s clock_config is set to a clock source which supports light sleep.

+
+ +
+
+ +
+
+struct Config
+

Configuration Struct for the LEDC subsystem including the different LED channels that should be associated.

+
+

Public Members

+
+
+int isr_core_id = -1
+

The core to install the LEDC fade function (interrupt) on. If -1, then the LEDC interrupt is installed on the core that this constructor is called on. If 0 or 1, then the LEDC interrupt is installed on the specified core.

+
+ +
+
+ledc_timer_t timer
+

The LEDC timer that you want associated with the LEDs.

+
+ +
+
+size_t frequency_hz
+

The frequency that you want to run the PWM hardawre for the LEDs at.

+
+

Note

+

this is inversely related to the duty resolution configuration.

+
+
+ +
+
+std::vector<ChannelConfig> channels
+

The LED channels that you want to control.

+
+ +
+
+ledc_timer_bit_t duty_resolution{LEDC_TIMER_13_BIT}
+

The resolution of the duty cycle for these LEDs.

+
+

Note

+

this is inversely related to the frequency configuration.

+
+
+ +
+
+ledc_clk_cfg_t clock_config{LEDC_AUTO_CLK}
+

The LEDC clock configuration you want for these LED channels.

+
+ +
+
+ledc_mode_t speed_mode{LEDC_LOW_SPEED_MODE}
+

The LEDC speed mode you want for these LED channels.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the task.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/led_example.html b/led_example.html new file mode 100644 index 000000000..1f9923316 --- /dev/null +++ b/led_example.html @@ -0,0 +1,234 @@ + + + + + + + LED Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LED Example

+

This example shows how to use the espp::Led class to control the LED using the +ESP32 hardware.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on the M5Stack ESP32 Timer Cam (using its +LED). If you wish to run on other hardware, just make sure to set the GPIO that +you want to use in the code.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+

https://user-images.githubusercontent.com/213467/232148096-a0061f7b-011a-49b1-9354-aa8a3c81034a.mp4

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/led_strip.html b/led_strip.html new file mode 100644 index 000000000..60a1a14dc --- /dev/null +++ b/led_strip.html @@ -0,0 +1,832 @@ + + + + + + + LED Strip APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LED Strip APIs

+

The LedStrip component provides APIs to control LED strips. It supports +various LED strip types, such as WS2812, WS2811, WS2813, SK6812, APA102, etc. +You can use it directly with an SPI driver to talk to APA102 LED strips, or you +can use it with a RMT driver (such as the Rmt component) to talk to WS2812, +WS2811, WS2813, SK6812, etc. LED strips.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class LedStrip : public espp::BaseComponent
+

Class to control LED strips.

+

This class is used to control LED strips. It is designed to be used with a write function that can be used to write data to the strip. This allows it to be used with different hardware interfaces (e.g. SPI, I2C, RMT, etc.).

+

This class is designed to be used to control various LED strips, which may be using different protocols. The following protocols are supported:

+
    +
  • APA102 (via SPI)

  • +
  • WS2812 (via the RMT peripheral)

  • +
+

+
+

Example 1: APA102 via SPI

+
    // create the rmt object
+    espp::Rmt rmt(espp::Rmt::Config{
+        .gpio_num = NEO_BFF_IO,
+        .resolution_hz = SK6805_FREQ_HZ,
+        .log_level = espp::Logger::Verbosity::INFO,
+    });
+
+    // tell the RMT object to use the led_encoder (espp::RmtEncoder) that's
+    // defined above
+    rmt.set_encoder(std::move(led_encoder));
+
+    // create the write function we'll use
+    auto neopixel_write = [&rmt](const uint8_t *data, size_t len) {
+      if (len == 0) {
+        return;
+      }
+      // send the data to the RMT object
+      rmt.transmit(data, len);
+    };
+
+    // now create the LedStrip object
+    espp::LedStrip led_strip(espp::LedStrip::Config{
+        .num_leds = NEO_BFF_NUM_LEDS,
+        .write = neopixel_write,
+        .send_brightness = false,
+        .byte_order = espp::LedStrip::ByteOrder::GRB,
+        .start_frame = {},
+        .end_frame = {},
+        .log_level = espp::Logger::Verbosity::INFO,
+    });
+
+    // Set all pixels
+    led_strip.set_all(espp::Rgb(0, 0, 0));
+    // And show it
+    led_strip.show();
+
+    std::this_thread::sleep_for(1s);
+
+    // Use a task to rotate the LED through the rainbow using HSV
+    auto task_fn = [&led_strip](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      float t = std::chrono::duration<float>(now - start).count();
+      // shift the LEDs right one
+      led_strip.shift_right();
+      // rotate through rainbow colors in hsv based on time, hue is 0-360
+      float hue = (cos(t) * 0.5f + 0.5f) * 360.0f;
+      espp::Hsv hsv(hue, 1.0f, 1.0f);
+      // full brightness (1.0, default) is _really_ bright, so tone it down
+      led_strip.set_pixel(0, hsv, 0.05f);
+      // show the new colors
+      led_strip.show();
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "LedStrip Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Note

+

This class does not handle the clock signal (if any) for the strip. It is assumed that the clock signal is handled by the hardware interface.

+
+
+

Note

+

This class does not handle the chip select signal (if any) for the strip. It is assumed that the chip select signal is handled by the hardware interface.

+
+
+

Note

+

This class does not handle the power signal (if any) for the strip.

+
+
+

Public Types

+
+
+enum class ByteOrder
+

Byte order for the LEDs.

+

Values:

+
+
+enumerator RGB
+

RGB byte order.

+
+ +
+
+enumerator GRB
+

GRB byte order.

+
+ +
+
+enumerator BGR
+

BGR byte order.

+
+ +
+ +
+
+typedef std::function<void(const uint8_t *data, size_t length)> write_fn
+

Function to write data to the strip.

+

This function is used to write data to the strip. It is assumed that the function will block until the data has been written.

+
+

Note

+

The data is not guaranteed to be valid after the function returns.

+
+
+

Note

+

The length of the data is guaranteed to be at least 4 bytes.

+
+
+

Note

+

The data is guaranteed to be 4-byte aligned.

+
+
+

Note

+

The data is guaranteed to be in the order of the bytes in the strip (i.e. the first byte in the data is the first byte in the strip).

+
+
+
Param data
+

Pointer to the data to write

+
+
Param length
+

Length of the data to write

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit LedStrip(const Config &config)
+

Constructor.

+
+
Parameters
+

config – Configuration for the LedStrip class

+
+
+
+ +
+
+inline size_t num_leds() const
+

Get the number of LEDs in the strip.

+
+
Returns
+

Number of LEDs in the strip

+
+
+
+ +
+
+inline ByteOrder byte_order() const
+

Get the byte order for the LEDs.

+
+
Returns
+

Byte order for the LEDs

+
+
+
+ +
+
+inline void shift_left(int shift_by = 1)
+

Shift the LEDs to the left.

+
+

Note

+

A negative value for shift_by will shift the LEDs to the right

+
+
+
Parameters
+

shift_by – Number of LEDs to shift by

+
+
+
+ +
+
+inline void shift_right(int shift_by = 1)
+

Shift the LEDs to the right.

+
+

Note

+

A negative value for shift_by will shift the LEDs to the left

+
+
+
Parameters
+

shift_by – Number of LEDs to shift by

+
+
+
+ +
+
+inline void set_pixel(int index, Hsv hsv, float brightness = 1.0f)
+

Set the color of a single LED.

+

+

See also

+

Hsv for more information on the HSV color space

+
+
+

See also

+

show

+
+

+
+

Note

+

The index is zero-based.

+
+
+
Parameters
+
    +
  • index – Index of the LED to set

  • +
  • hsv – Color to set the LED to

  • +
  • brightness – Brightness of the LED

  • +
+
+
+
+ +
+
+inline void set_pixel(int index, Rgb rgb, float brightness = 1.0f)
+

Set the color of a single LED.

+

+

See also

+

Rgb for more information on the RGB color space

+
+
+

See also

+

show

+
+

+
+

Note

+

The index is zero-based.

+
+
+
Parameters
+
    +
  • index – Index of the LED to set

  • +
  • rgb – Color to set the LED to

  • +
  • brightness – Brightness of the LED

  • +
+
+
+
+ +
+
+inline void set_pixel(int index, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 0b11111)
+

Set the color of a single LED.

+

+

See also

+

show

+
+

+
+

Note

+

The index is zero-based.

+
+
+
Parameters
+
    +
  • index – Index of the LED to set

  • +
  • r – Red component of the color to set the LED to [0-255]

  • +
  • g – Green component of the color to set the LED to [0-255]

  • +
  • b – Blue component of the color to set the LED to [0-255]

  • +
  • brightness – Brightness of the LED [0-31]

  • +
+
+
+
+ +
+
+inline void set_all(Hsv hsv, float brightness = 1.0f)
+

Set the color of all the LEDs.

+

+

See also

+

set_pixel

+
+
+

See also

+

show

+
+

+
+

Note

+

The index is zero-based.

+
+
+
Parameters
+
    +
  • hsv – Color to set the LEDs to

  • +
  • brightness – Brightness of the LEDs

  • +
+
+
+
+ +
+
+inline void set_all(Rgb rgb, float brightness = 1.0f)
+

Set the color of all the LEDs.

+

+

See also

+

set_pixel

+
+
+

See also

+

show

+
+

+
+
Parameters
+
    +
  • rgb – Color to set the LEDs to

  • +
  • brightness – Brightness of the LEDs

  • +
+
+
+
+ +
+
+inline void set_all(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 0xff)
+

Set the color of all the LEDs.

+

+

See also

+

set_pixel

+
+
+

See also

+

show

+
+

+
+
Parameters
+
    +
  • r – Red component of the color to set the LEDs to

  • +
  • g – Green component of the color to set the LEDs to

  • +
  • b – Blue component of the color to set the LEDs to

  • +
  • brightness – Brightness of the LEDs

  • +
+
+
+
+ +
+
+inline void show()
+

Show the colors on the strip.

+

This function writes the colors to the strip. It should be called after setting the colors of the LEDs.

+

See also

+

set_pixel

+
+
+

See also

+

set_all

+
+

+
+

Note

+

This function blocks until the colors have been written to the strip.

+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static const std::vector<uint8_t> APA102_START_FRAME
+

Start frame for the APA102 protocol.

+
+ +
+
+
+struct Config
+

Configuration for the LedStrip class.

+
+

Public Members

+
+
+size_t num_leds
+

Number of LEDs in the strip.

+
+ +
+
+write_fn write
+

Function to write data to the strip.

+
+ +
+
+bool send_brightness = {true}
+

Whether to use the brightness value for the LEDs.

+
+ +
+
+ByteOrder byte_order = {ByteOrder::RGB}
+

Byte order for the LEDs.

+
+ +
+
+std::vector<uint8_t> start_frame = {}
+

Start frame for the strip. Optional - will be sent before the first LED if not empty.

+
+ +
+
+std::vector<uint8_t> end_frame = {}
+

End frame for the strip. Optional - will be sent after the last LED if not empty.

+
+ +
+
+Logger::Verbosity log_level
+

Log level for this class.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/led_strip_example.html b/led_strip_example.html new file mode 100644 index 000000000..654342f81 --- /dev/null +++ b/led_strip_example.html @@ -0,0 +1,234 @@ + + + + + + + LED Strip Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LED Strip Example

+

This example shows the use of the LedStrip class to control a 5x5 array of RGB +LEDs (SK6805).

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on a QtPy +ESP32-S3 with an Adafruit Neopixel +BFF attached.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

https://github.com/esp-cpp/espp/assets/213467/f5fedece-a503-4a47-9338-0017cf75fd8c

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/logger.html b/logger.html new file mode 100644 index 000000000..ad3ffe78a --- /dev/null +++ b/logger.html @@ -0,0 +1,793 @@ + + + + + + + Logging APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Logging APIs

+
+

Format

+

Format is a simple component which exposes libfmt for use within esp-idf as a +single include.

+
+
+

Logger

+

The logger provides a cross-platform wrapper around libfmt for providing +configurable log output with different levels that can be turned on / off at +runtime.

+

Code examples for the logging API are provided in the logger example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Macros

+
+
+ESPP_LOGGER_LOG_LEVEL_NONE
+
+ +
+
+ESPP_LOGGER_LOG_LEVEL_ERROR
+
+ +
+
+ESPP_LOGGER_LOG_LEVEL_WARN
+
+ +
+
+ESPP_LOGGER_LOG_LEVEL_INFO
+
+ +
+
+ESPP_LOGGER_LOG_LEVEL_DEBUG
+
+ +
+
+CONFIG_ESPP_LOGGER_LOG_LEVEL
+
+ +
+
+ESPP_LOGGER_DEBUG_ENABLED
+
+ +
+
+ESPP_LOGGER_INFO_ENABLED
+
+ +
+
+ESPP_LOGGER_WARN_ENABLED
+
+ +
+
+ESPP_LOGGER_ERROR_ENABLED
+
+ +
+
+ESPP_LOGGER_CURSOR_COMMANDS_ENABLED
+
+ +
+
+

Classes

+
+
+class Logger
+

Logger provides a wrapper around nicer / more robust formatting than standard ESP_LOG* macros with the ability to change the log level at run-time. Logger currently is a light wrapper around libfmt (future std::format).

+

To save on code size, the logger has the ability to be compiled out based on the log level set in the sdkconfig. This means that if the log level is set to ERROR, all debug, info, and warn logs will be compiled out. This is done by 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.

+
+

Basic Example

+
    float num_seconds_to_run = 10.0f;
+    // create loggers
+    auto logger = espp::Logger({.tag = "Cool Logger", .level = espp::Logger::Verbosity::DEBUG});
+    auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    float elapsed = std::chrono::duration<float>(now - start).count();
+    while (elapsed < num_seconds_to_run) {
+      now = std::chrono::high_resolution_clock::now();
+      elapsed = std::chrono::duration<float>(now - start).count();
+      auto remaining = num_seconds_to_run - elapsed;
+      logger.debug("debug: {:%Y-%m-%d %H:%M:%S} - {:%Y-%m-%d %H:%M:%S} = {}", now, start, elapsed);
+      logger.info("elapsed: {:.3f}s", elapsed);
+      logger.warn("remaining: {:.3f}s", remaining);
+      if (remaining < 0) {
+        logger.error("You overstayed your welcome by {:.03}s!", -remaining);
+      }
+      std::this_thread::sleep_for(500ms);
+    }
+
+
+
+
+

Threaded Logging and Verbosity Example

+
    // create loggers
+    auto logger1 = espp::Logger(
+        {.tag = "Thread 1", .rate_limit = 500ms, .level = espp::Logger::Verbosity::INFO});
+    auto logger2 = espp::Logger(
+        {.tag = "Thread 2", .rate_limit = 1s, .level = espp::Logger::Verbosity::DEBUG});
+    // lambda for logging to those two loggers from multiple threads
+    auto logger_fn = [](espp::Logger *logger) {
+      size_t loop_iteration{0};
+      while (true) {
+        // log - note: debug shouldn't be shown!
+        logger->debug("some debug info: {}", loop_iteration);
+        logger->info("some info: {}", loop_iteration);
+        logger->warn("some warning: {}", loop_iteration);
+        logger->error("some error: {}", loop_iteration);
+        logger->info_rate_limited("some rate limited info: {}", loop_iteration);
+        // update loop variables
+        loop_iteration++;
+        // sleep
+        std::this_thread::sleep_for(300ms);
+      }
+    };
+    // start two threads, binding the lambda to each logger
+    auto logger1_thread = std::thread(std::bind(logger_fn, &logger1));
+    auto logger2_thread = std::thread(std::bind(logger_fn, &logger2));
+    uint8_t level{static_cast<uint8_t>(espp::Logger::Verbosity::DEBUG)};
+    // every 1 second, change the loggers' verbosity
+    while (true) {
+      // update the loggers' verbosity
+      level++;
+      if (level > static_cast<uint8_t>(espp::Logger::Verbosity::NONE)) {
+        level = static_cast<uint8_t>(espp::Logger::Verbosity::DEBUG);
+      }
+      espp::Logger::Verbosity verbosity = static_cast<espp::Logger::Verbosity>(level);
+      logger1.set_verbosity(verbosity);
+      logger2.set_verbosity(verbosity);
+      // sleep
+      std::this_thread::sleep_for(1s);
+    }
+
+
+
+
+

Cursor Commands Example

+
    float num_seconds_to_run = 10.0f;
+    // create loggers
+    auto logger = espp::Logger({.tag = "Cursor Commands", .level = espp::Logger::Verbosity::DEBUG});
+    auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    float elapsed = std::chrono::duration<float>(now - start).count();
+    logger.info("Long running log... {}", elapsed);
+    while (elapsed < num_seconds_to_run) {
+      now = std::chrono::high_resolution_clock::now();
+      elapsed = std::chrono::duration<float>(now - start).count();
+      auto remaining = num_seconds_to_run - elapsed;
+      logger.move_up();
+      logger.clear_line();
+      logger.info("Long running log... {}", remaining);
+      std::this_thread::sleep_for(100ms);
+    }
+
+
+
+
+

Public Types

+
+
+enum class Verbosity
+

Verbosity levels for the logger, in order of increasing priority.

+

Values:

+
+
+enumerator DEBUG
+

Debug level verbosity.

+
+ +
+
+enumerator INFO
+

Info level verbosity.

+
+ +
+
+enumerator WARN
+

Warn level verbosity.

+
+ +
+
+enumerator ERROR
+

Error level verbosity.

+
+ +
+
+enumerator NONE
+

No verbosity - logger will not print anything.

+
+ +
+ +
+
+

Public Functions

+
+
+inline explicit Logger(const Config &config)
+

Construct a new Logger object.

+
+
Parameters
+

config – configuration for the logger.

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_verbosity() const
+

Get the current verbosity for the logger.

+

+

See also

+

Logger::Verbosity

+
+

+
+
Returns
+

The current verbosity level.

+
+
+
+ +
+
+inline void set_verbosity(const espp::Logger::Verbosity level)
+

Change the verbosity for the logger.

+

+

See also

+

Logger::Verbosity

+
+

+
+
Parameters
+

level – new verbosity level

+
+
+
+ +
+
+inline void set_tag(const std::string_view tag)
+

Change the tag for the logger.

+
+
Parameters
+

tag – The new tag.

+
+
+
+ +
+
+inline const std::string &get_tag() const
+

Get the current tag for the logger.

+
+
Returns
+

A const reference to the current tag.

+
+
+
+ +
+
+inline void set_include_time(bool include_time)
+

Whether to include the time in the log.

+
+

Note

+

The time is in seconds since boot and is represented as a floating point number with precision to the millisecond.

+
+
+
Parameters
+

include_time – Whether to include the time in the log.

+
+
+
+ +
+
+inline void set_rate_limit(const std::chrono::duration<float> rate_limit)
+

Change the rate limit for the logger.

+
+

Note

+

Only calls that have _rate_limited suffixed will be rate limited.

+
+
+
Parameters
+

rate_limit – The new rate limit.

+
+
+
+ +
+
+inline std::chrono::duration<float> get_rate_limit() const
+

Get the current rate limit for the logger.

+
+
Returns
+

The current rate limit.

+
+
+
+ +
+
+template<typename ...Args>
inline std::string format(std::string_view rt_fmt_str, Args&&... args)
+

Format args into string according to format string. From: https://en.cppreference.com/w/cpp/utility/format/format.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
Returns
+

formatted std::string

+
+
+
+ +
+
+template<typename ...Args>
inline void debug(std::string_view rt_fmt_str, Args&&... args)
+

Print log in GRAY if level is Verbosity::DEBUG or greater.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void info(std::string_view rt_fmt_str, Args&&... args)
+

Print log in GREEN if level is Verbosity::INFO or greater.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void warn(std::string_view rt_fmt_str, Args&&... args)
+

Print log in YELLOW if level is Verbosity::WARN or greater.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void error(std::string_view rt_fmt_str, Args&&... args)
+

Print log in RED if level is Verbosity::ERROR or greater.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void debug_rate_limited(std::string_view rt_fmt_str, Args&&... args)
+

Print log in GRAY if level is Verbosity::DEBUG or greater. This function is rate limited by the rate specified in the constructor.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void info_rate_limited(std::string_view rt_fmt_str, Args&&... args)
+

Print log in GREEN if level is Verbosity::INFO or greater This function is rate limited by the rate specified in the constructor.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void warn_rate_limited(std::string_view rt_fmt_str, Args&&... args)
+

Print log in YELLOW if level is Verbosity::WARN or greater This function is rate limited by the rate specified in the constructor.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+template<typename ...Args>
inline void error_rate_limited(std::string_view rt_fmt_str, Args&&... args)
+

Print log in RED if level is Verbosity::ERROR or greater This function is rate limited by the rate specified in the constructor.

+
+
Parameters
+
    +
  • rt_fmt_str – format string

  • +
  • args – optional arguments passed to be formatted.

  • +
+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline void move_up()
+

Move the cursor up one line.

+
+ +
+
+static inline void move_up(int lines)
+

Move the cursor up a number of lines.

+
+
Parameters
+

lines – The number of lines to move up.

+
+
+
+ +
+
+static inline void move_down()
+

Move the cursor down one line.

+
+ +
+
+static inline void move_down(int lines)
+

Move the cursor down a number of lines.

+
+
Parameters
+

lines – The number of lines to move down.

+
+
+
+ +
+
+static inline void move_to_start()
+

Move the cursor to the beginning of the line.

+
+ +
+
+static inline void clear_line()
+

Clear the line.

+
+ +
+
+static inline void clear_screen()
+

Clear the screen and move the cursor to the top left.

+
+ +
+
+static inline void move_to(int x, int y)
+

Move the cursor to a specific position.

+
+
Parameters
+
    +
  • x – The x position to move to.

  • +
  • y – The y position to move to.

  • +
+
+
+
+ +
+
+static inline std::string get_time()
+

Get the current time in seconds since the start of the logging system.

+
+
Returns
+

time in seconds since the start of the logging system.

+
+
+
+ +
+
+
+struct Config
+

Configuration struct for the logger.

+
+

Public Members

+
+
+std::string_view tag
+

The TAG that will be prepended to all logs.

+
+ +
+
+bool include_time = {true}
+

Include the time in the log.

+
+ +
+
+std::chrono::duration<float> rate_limit = std::chrono::duration<float>(0)
+

The rate limit for the logger. Optional, if <= 0 no rate limit.

+
+

Note

+

Only calls that have _rate_limited suffixed will be rate limited.

+
+
+ +
+
+espp::Logger::Verbosity level = espp::Logger::Verbosity::WARN
+

The verbosity level for the logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/logger_example.html b/logger_example.html new file mode 100644 index 000000000..0ced7884e --- /dev/null +++ b/logger_example.html @@ -0,0 +1,228 @@ + + + + + + + Logger Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Logger Example

+

This example shows how to use the logger component to format and log data to +the console.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

image

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/bezier.html b/math/bezier.html new file mode 100644 index 000000000..db7bc5eef --- /dev/null +++ b/math/bezier.html @@ -0,0 +1,371 @@ + + + + + + + Bezier - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Bezier

+

The bezier header provides a templated implementation of cubic bezier curves +and rational cubic bezier curves. Intended use for these templated functions is +on raw floating point values or on the associated Vector2d class.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<typename T>
class Bezier
+

Implements rational / weighted and unweighted cubic bezier curves between control points.

+
+

Example

+
    using Bezier = espp::Bezier<espp::Vector2f>;
+    std::array<espp::Vector2f, 4> control_points = {espp::Vector2f(6, 220), espp::Vector2f(62, 115),
+                                                    espp::Vector2f(176, 151),
+                                                    espp::Vector2f(217, 50)};
+    Bezier bezier(Bezier::Config{.control_points = control_points});
+    std::array<float, 4> weights = {0.5f, 2.0f, 0.5f, 2.0f};
+    Bezier rational_bezier(
+        Bezier::WeightedConfig{.control_points = control_points, .weights = weights});
+    // NOTE: this is the built-in log format for pyqtgraph
+    fmt::print("\"bezier_x\",\"bezier_y\",\"rational bezier_x\",\"rational bezier_y\"\n");
+    float t = 0;
+    while (t < 1.0f) {
+      auto p0 = bezier(t);
+      auto p1 = rational_bezier(t);
+      fmt::print("{},{},{},{}\n", p0.x(), p0.y(), p1.x(), p1.y());
+      t += 0.05f;
+    }
+
+
+
+
+

Note

+

See https://pomax.github.io/bezierinfo/ for information on bezier curves.

+
+
+

Note

+

Template class which can be used individually on floating point values directly or on containers such as Vector2d<float>.

+
+
+

Note

+

The bezier curve is defined by 4 control points, P0, P1, P2, P3. The curve is defined by the equation: \(B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + 3 * (1-t) * t^2 * P2 + t^3 * P3\) where t is the evaluation parameter, [0, 1].

+
+
+

Note

+

The weighted bezier curve is defined by 4 control points, P0, P1, P2, P3 and 4 weights, W0, W1, W2, W3. The curve is defined by the equation: \(B(t) = (W0 * (1-t)^3 * P0 + W1 * 3 * (1-t)^2 * t * P1 + W2 * 3 * (1-t) * t^2 * P2 + W3 * +t^3 * P3) / (W0 + W1 + W2 + W3)\) where t is the evaluation parameter, [0, 1].

+
+
+
Template Parameters
+

T – The type of the control points, e.g. float or Vector2d<float>.

+
+
+
+

Public Functions

+
+
+inline explicit Bezier(const Config &config)
+

Construct an unweighted cubic bezier curve for evaluation.

+
+
Parameters
+

config – Unweighted Config structure containing the control points.

+
+
+
+ +
+
+inline explicit Bezier(const WeightedConfig &config)
+

Construct a rational / weighted cubic bezier curve for evaluation.

+
+
Parameters
+

config – Rational / weighted WeightedConfig structure containing the control points and their weights.

+
+
+
+ +
+
+inline T at(float t) const
+

Evaluate the bezier at t.

+
+
Parameters
+

t – The evaluation parameter, [0, 1].

+
+
Returns
+

The bezier evaluated at t.

+
+
+
+ +
+
+inline T operator()(float t) const
+

Evaluate the bezier at t.

+
+

Note

+

Convienience wrapper around the at() method.

+
+
+
Parameters
+

t – The evaluation parameter, [0, 1].

+
+
Returns
+

The bezier evaluated at t.

+
+
+
+ +
+
+
+struct Config
+

Unweighted cubic bezier configuration for 4 control points.

+
+

Public Members

+
+
+std::array<T, 4> control_points
+

Array of 4 control points.

+
+ +
+
+ +
+
+struct WeightedConfig
+

Weighted cubic bezier configuration for 4 control points with individual weights.

+
+

Public Members

+
+
+std::array<T, 4> control_points
+

Array of 4 control points.

+
+ +
+
+std::array<float, 4> weights = {1.0f, 1.0f, 1.0f, 1.0f}
+

Array of 4 weights, default is array of 1.0f.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/fast_math.html b/math/fast_math.html new file mode 100644 index 000000000..ba51e95b7 --- /dev/null +++ b/math/fast_math.html @@ -0,0 +1,238 @@ + + + + + + + Fast Math - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Fast Math

+

The Fast Math header provides a set of static functions which implement +optimized approximations of the following functions:

+
    +
  • fast_sqrt

  • +
  • fast_ln

  • +
  • fast_sin

  • +
  • fast_cos

  • +
+

along with some utility functions:

+
    +
  • square (x^2)

  • +
  • cube (x^3)

  • +
  • sgn (sign of a number)

  • +
  • round (round floating point value to nearest integer value)

  • +
  • lerp (linear interpolate between two points)

  • +
  • inv_lerp (inverse linear interpolate between two points)

  • +
  • piecewise_linear (compute the piecewise linear interpolation between a set of points)

  • +
+
+

API Reference

+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/gaussian.html b/math/gaussian.html new file mode 100644 index 000000000..616203277 --- /dev/null +++ b/math/gaussian.html @@ -0,0 +1,487 @@ + + + + + + + Gaussian - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Gaussian

+

The gaussian class provides an implementation of the gaussian function:

+
+\[y(t)= \alpha e^{ -\frac{ (t-\beta)^2 }{ 2\gamma^2 } }\]
+

The class allows for dynamically changing the \(\alpha\), \(\beta\), and +\(\gamma\) parameters.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Gaussian
+

Implements a gaussian function \(y(t)=\alpha\exp(-\frac{(t-\beta)^2}{2\gamma^2})\).

+

Alows you to store the alpha, beta, and gamma coefficients as well as update them dynamically.

+
+

Example

+
      std::array<float, 4> gammas = {
+          0.10f,
+          0.15f,
+          0.20f,
+          0.25f,
+      };
+      espp::Gaussian gaussian({
+          .gamma = gammas[0],
+          .alpha = 1.0f, // default
+          .beta = 0.5f,  // default
+      });
+      float t = 0;
+      fmt::print("% t");
+      for (auto g : gammas) {
+        fmt::print(", gaussian({})", g);
+      }
+      fmt::print("\n");
+      float increment = 0.05f;
+      int num_increments = 1.0f / increment;
+      for (int i = 0; i <= num_increments; i++) {
+        fmt::print("{}", t);
+        for (auto g : gammas) {
+          // update the gamma
+          gaussian.set_gamma(g);
+          // evaluate it
+          float v = gaussian(t);
+          // print it
+          fmt::print(", {}", v);
+        }
+        fmt::print("\n");
+        t += increment;
+      }
+
+
+
+
+

Fade-In/Fade-Out Example

+
      std::array<float, 8> gammas = {
+          0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f,
+      };
+      espp::Gaussian fade_in({
+          .gamma = gammas[0],
+          .alpha = 1.0f, // default
+          .beta = 1.0f,  // default
+      });
+      espp::Gaussian fade_out({
+          .gamma = gammas[0],
+          .alpha = 1.0f, // default
+          .beta = 0.0f,  // default
+      });
+      float t = 0;
+      fmt::print("% t");
+      for (auto g : gammas) {
+        fmt::print(", fade_in({}), fade_out({})", g, g);
+      }
+      fmt::print("\n");
+      float increment = 0.05f;
+      int num_increments = 1.0f / increment;
+      for (int i = 0; i <= num_increments; i++) {
+        fmt::print("{}", t);
+        for (auto g : gammas) {
+          // update the gamma
+          fade_in.set_gamma(g);
+          fade_out.set_gamma(g);
+          // evaluate it
+          float in = fade_in(t);
+          float out = fade_out(t);
+          // print it
+          fmt::print(", {}, {}", in, out);
+        }
+        fmt::print("\n");
+        t += increment;
+      }
+
+
+
+
+

Public Functions

+
+
+inline explicit Gaussian(const Config &config)
+

Construct the gaussian object, configuring its parameters.

+
+
Parameters
+

configConfig structure for the gaussian.

+
+
+
+ +
+
+inline float at(float t) const
+

Evaluate the gaussian at t.

+
+
Parameters
+

t – The evaluation parameter, [0, 1].

+
+
Returns
+

The gaussian evaluated at t.

+
+
+
+ +
+
+inline float operator()(float t) const
+

Evaluate the gaussian at t.

+
+

Note

+

Convienience wrapper around the at() method.

+
+
+
Parameters
+

t – The evaluation parameter, [0, 1].

+
+
Returns
+

The gaussian evaluated at t.

+
+
+
+ +
+
+inline void update(const Config &config)
+

Update the gaussian configuration.

+
+
Parameters
+

config – The new configuration.

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration of the gaussian.

+
+
Parameters
+

config – The new configuration.

+
+
+
+ +
+
+inline Config get_config() const
+

Get the current configuration of the gaussian.

+
+
Returns
+

The current configuration.

+
+
+
+ +
+
+inline float get_gamma() const
+

Get the gamma value.

+
+
Returns
+

The gamma value.

+
+
+
+ +
+
+inline float get_alpha() const
+

Get the alpha value.

+
+
Returns
+

The alpha value.

+
+
+
+ +
+
+inline float get_beta() const
+

Get the beta value.

+
+
Returns
+

The beta value.

+
+
+
+ +
+
+inline void set_gamma(float gamma)
+

Set the gamma value.

+
+
Parameters
+

gamma – The new gamma value.

+
+
+
+ +
+
+inline void set_alpha(float alpha)
+

Set the alpha value.

+
+
Parameters
+

alpha – The new alpha value.

+
+
+
+ +
+
+inline void set_beta(float beta)
+

Set the beta value.

+
+
Parameters
+

beta – The new beta value.

+
+
+
+ +
+
+
+struct Config
+

Configuration structure for initializing the gaussian.

+
+

Public Members

+
+
+float gamma
+

Slope of the gaussian, range [0, 1]. 0 is more of a thin spike from 0 up to max output (alpha), 1 is more of a small wave around the max output (alpha).

+
+ +
+
+float alpha = {1.0f}
+

Max amplitude of the gaussian output, defautls to 1.0.

+
+ +
+
+float beta{0.5f}
+

Beta value for the gaussian, default to be symmetric at 0.5 in range [0,1].

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/index.html b/math/index.html new file mode 100644 index 000000000..35345e68a --- /dev/null +++ b/math/index.html @@ -0,0 +1,214 @@ + + + + + + + Math APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/math/math_example.html b/math/math_example.html new file mode 100644 index 000000000..2bd1198be --- /dev/null +++ b/math/math_example.html @@ -0,0 +1,231 @@ + + + + + + + Math Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Math Example

+

This example showcases some of the math functionality provided by the math +component.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/range_mapper.html b/math/range_mapper.html new file mode 100644 index 000000000..6659733ec --- /dev/null +++ b/math/range_mapper.html @@ -0,0 +1,579 @@ + + + + + + + Range Mapper - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Range Mapper

+

The RangeMapper provides a class which allows you to map from a configurable +input range to a standardized output range of [-1,1].

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<typename T>
class RangeMapper
+

Template class for converting a value from an uncentered [minimum, maximum] range into a centered output range (default [-1,1]). If provided a non-zero deadband, it will convert all values within [center-deadband, center+deadband] to be the configured output_center (default 0).

+

The RangeMapper can be optionally configured to invert the input, so that it will compute the input w.r.t. the configured min/max of the input range when mapping to the output range - this will mean that a values within the ranges [minimum, minimum+deadband] and [maximum-deadband, maximum] will all map to the output_center and the input center will map to both output_max and output_min depending on the sign of the input.

+

+The RangeMapper can be optionally configured to invert the output, so that after converting from the input range to the output range, it will flip the sign on the output.

+
+

Example

+
    static constexpr float deadband = 12.0f;
+    static constexpr float min = 0.0f;
+    static constexpr float center = 127.0f;
+    static constexpr float max = 255.0f;
+    // Default will have output range [-1, 1]
+    espp::RangeMapper<float> rm(
+        {.center = center, .center_deadband = deadband, .minimum = min, .maximum = max});
+    // You can explicitly set output center/range. In this case the output will
+    // be in the range [0, 1024]
+    espp::RangeMapper<float> rm2({.center = center,
+                                  .center_deadband = deadband,
+                                  .minimum = min,
+                                  .maximum = max,
+                                  .output_center = 512,
+                                  .output_range = 512});
+    // You can also use a non-centered input distribution.
+    espp::FloatRangeMapper rm3({.center = center / 2,
+                                .center_deadband = deadband,
+                                .minimum = min,
+                                .maximum = max,
+                                .output_center = 512,
+                                .output_range = 512});
+    // You can even invert the ouput distribution, and add a deadband around the
+    // min/max values
+    espp::FloatRangeMapper rm4({
+        .center = center,
+        .center_deadband = deadband,
+        .minimum = min,
+        .maximum = max,
+        .range_deadband = deadband,
+        .invert_output = true,
+    });
+    // make a vector of float values min - 10 to max + 10 in increments of 5
+    std::vector<float> vals;
+    for (float v = min - 10; v <= max + 10; v += 5) {
+      vals.push_back(v);
+    }
+    // test the mapping and unmapping
+    fmt::print(
+        "% value, mapped [0;255] to [-1;1], unmapped [-1;1] to [0;255], mapped [0;255] to "
+        "[0;1024], unmapped [0;1024] to [0;255], mapped [0;255] to [1024;0], unmapped [1024;0] to "
+        "[0;255], mapped [0;255] to inverted [1;-1], unmapped inverted [1;-1] to [0;255]\n");
+    for (const auto &v : vals) {
+      fmt::print("{}, {}, {}, {}, {}, {}, {}, {}, {}\n", v, rm.map(v), rm.unmap(rm.map(v)),
+                 rm2.map(v), rm2.unmap(rm2.map(v)), rm3.map(v), rm3.unmap(rm3.map(v)), rm4.map(v),
+                 rm4.unmap(rm4.map(v)));
+    }
+
+
+
+
+

Note

+

When inverting the input range, you are introducing a discontinuity between the input distribution and the output distribution at the input center. Noise around the input’s center value will create oscillations in the output which will jump between output maximum and output minimum. Therefore it is advised to use invert_input sparignly, and to set the values robustly.

+
+
+

Public Functions

+
+
+inline RangeMapper()
+

Initialize the range mapper with no config.

+
+ +
+
+inline explicit RangeMapper(const Config &config)
+

Initialize the RangeMapper.

+
+
Parameters
+

config – Configuration describing the input distribution.

+
+
+
+ +
+
+inline void configure(const Config &config)
+

Update the input / output distribution with the new configuration.

+
+

Note

+

The output range will be passed through std::abs() to ensure it is positive.

+
+
+

Note

+

The output range must be non-zero. If it is zero, the configuration will be ignored.

+
+
+
Parameters
+

config – New configuration to use.

+
+
+
+ +
+
+inline T get_center() const
+

Return the configured center of the input distribution.

+
+
Returns
+

Center of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_center_deadband() const
+

Return the configured deadband around the center of the input distribution.

+
+
Returns
+

Deadband around the center of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_minimum() const
+

Return the configured minimum of the input distribution.

+
+
Returns
+

Minimum of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_maximum() const
+

Return the configured maximum of the input distribution.

+
+
Returns
+

Maximum of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_range() const
+

Return the configured range of the input distribution.

+
+

Note

+

Always positive.

+
+
+
Returns
+

Range of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_range_deadband() const
+

Return the configured deadband around the min/max of the input distribution.

+
+
Returns
+

Deadband around the min/max of the input distribution for this range mapper.

+
+
+
+ +
+
+inline T get_output_center() const
+

Return the configured center of the output distribution.

+
+
Returns
+

Center of the output distribution for this range mapper.

+
+
+
+ +
+
+inline T get_output_range() const
+

Return the configured range of the output distribution.

+
+

Note

+

Always positive.

+
+
+
Returns
+

Range of the output distribution for this range mapper.

+
+
+
+ +
+
+inline T get_output_min() const
+

Return the configured minimum of the output distribution.

+
+
Returns
+

Minimum of the output distribution for this range mapper.

+
+
+
+ +
+
+inline T get_output_max() const
+

Return the configured maximum of the output distribution.

+
+
Returns
+

Maximum of the output distribution for this range mapper.

+
+
+
+ +
+
+inline void set_center_deadband(T deadband)
+

Set the deadband around the center of the input distribution.

+
+

Note

+

The deadband must be non-negative.

+
+
+

Note

+

The deadband is applied around the center value of the input distribution.

+
+
+
Parameters
+

deadband – The deadband to use around the center of the input distribution.

+
+
+
+ +
+
+inline void set_range_deadband(T deadband)
+

Set the deadband around the min/max of the input distribution.

+
+

Note

+

The deadband must be non-negative.

+
+
+

Note

+

The deadband is applied around the min/max values of the input distribution.

+
+
+
Parameters
+

deadband – The deadband to use around the min/max of the input distribution.

+
+
+
+ +
+
+inline T map(const T &v) const
+

Map a value v from the input distribution into the configured output range (centered, default [-1,1]).

+
+
Parameters
+

v – Value from the (possibly uncentered and possibly inverted - defined by the previously configured Config) input distribution

+
+
Returns
+

Value within the centered output distribution.

+
+
+
+ +
+
+inline T unmap(const T &v) const
+

Unmap a value v from the configured output range (centered, default [-1,1]) back into the input distribution.

+
+
Parameters
+

T&v – Value from the centered output distribution.

+
+
Returns
+

Value within the input distribution.

+
+
+
+ +
+
+
+struct Config
+

Configuration for the input uncentered range with optional values for the centered output range, default values of 0 output center and 1 output range provide a default output range between [-1, 1].

+
+

Public Members

+
+
+T center
+

Center value for the input range.

+
+ +
+
+T center_deadband = 0
+

Deadband amount around (+-) the center for which output will be 0.

+
+ +
+
+T minimum
+

Minimum value for the input range.

+
+ +
+
+T maximum
+

Maximum value for the input range.

+
+ +
+
+T range_deadband = 0
+

Deadband amount around the minimum and maximum for which output will be min/max output.

+
+ +
+
+T output_center = 0
+

The center for the output. Default 0.

+
+ +
+
+T output_range = 1
+

The range (+/-) from the center for the output. Default 1.

+
+

Note

+

Will be passed through std::abs() to ensure it is positive.

+
+
+ +
+
+bool invert_output = false
+

Whether to invert the output (default false).

+
+

Note

+

If true will flip the sign of the output after converting from the input distribution.

+
+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/math/vector2d.html b/math/vector2d.html new file mode 100644 index 000000000..c8eab64b0 --- /dev/null +++ b/math/vector2d.html @@ -0,0 +1,625 @@ + + + + + + + Vector2d - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Vector2d

+

The Vector2d provides a container for a 2-dimensional vector with associated +math operations implemented.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+template<typename T>
class Vector2d
+

Container representing a 2 dimensional vector.

+

Provides getters/setters, index operator, and vector / scalar math utilities.

+
+

Example

+
    fmt::print("--- uint8_t vector ---\n");
+    espp::Vector2u8 v8(2, 3);
+    fmt::print("original:       {}\n", v8);
+    auto v8_2 = v8;
+    v8 = uint8_t(2) * v8; // NOTE: need explicit cast to avoid ambiguity with auto type
+    v8 /= 2;
+    v8 += espp::Vector2u8(0, 1);
+    v8 -= espp::Vector2u8(0, 1);
+    fmt::print("should be same: {}, {}\n", v8, v8_2);
+    // for good measure, print all the comparisons
+    fmt::print("       v == v2: {}\n", v8 == v8_2);
+    fmt::print("       v != v2: {}\n", v8 != v8_2);
+    fmt::print("       v <  v2: {}\n", v8 < v8_2);
+    fmt::print("       v <= v2: {}\n", v8 <= v8_2);
+    fmt::print("       v >  v2: {}\n", v8 > v8_2);
+    fmt::print("       v >= v2: {}\n", v8 >= v8_2);
+    fmt::print("magnitude:      {}\n", v8.magnitude());
+    fmt::print("normalized:     {}\n", v8.normalized());
+
+    fmt::print("--- float vector ---\n");
+    espp::Vector2f v(1, 1);
+    fmt::print("original:       {}\n", v);
+    auto v2 = v;
+    v = 2.0f * v;
+    v /= 2.0f;
+    v += espp::Vector2f(0, 1);
+    v -= espp::Vector2f(0, 1);
+    fmt::print("should be same: {}, {}\n", v, v2);
+    // for good measure, print all the comparisons
+    fmt::print("       v == v2: {}\n", v == v2);
+    fmt::print("       v != v2: {}\n", v != v2);
+    fmt::print("       v <  v2: {}\n", v < v2);
+    fmt::print("       v <= v2: {}\n", v <= v2);
+    fmt::print("       v >  v2: {}\n", v > v2);
+    fmt::print("       v >= v2: {}\n", v >= v2);
+    fmt::print("magnitude:      {}\n", v.magnitude());
+    fmt::print("normalized:     {}\n", v.normalized());
+    fmt::print("norm mag:       {}\n", v.normalized().magnitude());
+    fmt::print("rotated pi/2:   {}\n", v.rotated(M_PI_2));
+
+
+
+
+

Public Functions

+
+
+inline explicit Vector2d(T x = 0, T y = 0)
+

Constructor for the vector, defaults to 0,0.

+
+
Parameters
+
    +
  • x – The starting X value.

  • +
  • y – The starting Y value.

  • +
+
+
+
+ +
+
+inline Vector2d(const Vector2d &other)
+

Vector copy constructor.

+
+
Parameters
+

other – Vector to copy.

+
+
+
+ +
+
+inline Vector2d &operator=(const Vector2d &other)
+

Assignment operator.

+
+
Parameters
+

other – Vector to assign to this vector.

+
+
Returns
+

This vector, updated to be a copy of other.

+
+
+
+ +
+
+inline T magnitude() const
+

Returns vector magnitude: ||v||.

+
+
Returns
+

The magnitude.

+
+
+
+ +
+
+inline T magnitude_squared() const
+

Returns vector magnitude squared: ||v||^2.

+
+
Returns
+

The magnitude squared.

+
+
+
+ +
+
+inline T x() const
+

Getter for the x value.

+
+
Returns
+

The current x value.

+
+
+
+ +
+
+inline void x(T v)
+

Setter for the x value.

+
+
Parameters
+

v – New value for x.

+
+
+
+ +
+
+inline T y() const
+

Getter for the y value.

+
+
Returns
+

The current y value.

+
+
+
+ +
+
+inline void y(T v)
+

Setter for the y value.

+
+
Parameters
+

v – New value for y.

+
+
+
+ +
+
+inline int operator<=>(const Vector2d &other) const
+

Spaceship operator for comparing two vectors.

+
+
Parameters
+

other – The vector to compare against.

+
+
Returns
+

-1 if this vector is less than other, 0 if they are equal, 1 if this vector is greater than other.

+
+
+
+ +
+
+inline bool operator==(const Vector2d &other) const
+

Equality operator for comparing two vectors.

+
+
Parameters
+

other – The vector to compare against.

+
+
Returns
+

True if the vectors are equal, false otherwise.

+
+
+
+ +
+
+inline T &operator[](int index)
+

Index operator for vector elements.

+
+

Note

+

Returns a mutable reference to the element.

+
+
+
Parameters
+

index – The index to return.

+
+
Returns
+

Mutable reference to the element at index.

+
+
+
+ +
+
+inline Vector2d operator-() const
+

Negate the vector.

+
+
Returns
+

The new vector which is the negative.

+
+
+
+ +
+
+inline Vector2d operator-(const Vector2d &rhs) const
+

Return a new vector which is the provided vector subtracted from this vector.

+
+
Parameters
+

rhs – The vector to subtract from this vector.

+
+
Returns
+

Resultant vector subtraction.

+
+
+
+ +
+
+inline Vector2d &operator-=(const Vector2d &rhs)
+

Return the provided vector subtracted from this vector.

+
+
Parameters
+

rhs – The vector to subtract from this vector.

+
+
Returns
+

Resultant vector subtraction.

+
+
+
+ +
+
+inline Vector2d operator+(const Vector2d &rhs) const
+

Return a new vector, which is the addition of this vector and the provided vector.

+
+
Parameters
+

rhs – The vector to add to this vector.

+
+
Returns
+

Resultant vector addition.

+
+
+
+ +
+
+inline Vector2d &operator+=(const Vector2d &rhs)
+

Return the vector added with the provided vector.

+
+
Parameters
+

rhs – The vector to add to this vector.

+
+
Returns
+

Resultant vector addition.

+
+
+
+ +
+
+inline Vector2d operator*(const T &v) const
+

Return a scaled version of the vector, multiplied by the provided value.

+
+
Parameters
+

v – Value the vector should be multiplied by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline Vector2d &operator*=(const T &v)
+

Return the vector multiplied by the provided value.

+
+
Parameters
+

v – Value the vector should be scaled by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline Vector2d operator/(const T &v) const
+

Return a scaled version of the vector, divided by the provided value.

+
+
Parameters
+

v – Value the vector should be divided by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline Vector2d &operator/=(const T &v)
+

Return the vector divided by the provided value.

+
+
Parameters
+

v – Value the vector should be divided by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline Vector2d operator/(const Vector2d &v) const
+

Return a scaled version of the vector, divided by the provided vector value. Scales x and y independently.

+
+
Parameters
+

v – Vector values the vector should be divided by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline Vector2d &operator/=(const Vector2d &v)
+

Return the vector divided by the provided vector values.

+
+
Parameters
+

v – Vector of values the vector should be divided by.

+
+
Returns
+

Resultant scaled vector.

+
+
+
+ +
+
+inline T dot(const Vector2d &other) const
+

Dot product of this vector with another vector.

+
+
Parameters
+

other – The second vector

+
+
Returns
+

The dot product (x1*x2 + y1*y2)

+
+
+
+ +
+
+inline Vector2d normalized() const
+

Return normalized (unit length) version of the vector.

+
+
Returns
+

The normalized vector.

+
+
+
+ +
+
+template<class U = T, typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
inline Vector2d rotated(T radians) const
+

Rotate the vector by radians.

+
+

Note

+

This function is only available if T is a floating point value.

+
+
+
Parameters
+

radians – Amount of rotation (in radians) to rotate the vector by.

+
+
Returns
+

Rotated vector.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/matouch_rotary_display.html b/matouch_rotary_display.html new file mode 100644 index 000000000..1ea0c894a --- /dev/null +++ b/matouch_rotary_display.html @@ -0,0 +1,971 @@ + + + + + + + MaTouch Rotary Display - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MaTouch Rotary Display

+
+

Matouch-Rotary-Display

+

The Matouch Rotary Display is a development board for the ESP32-S3 module. It +features a nice touchscreen display, a rotary encoder, a push button behind the +screen, and some expansion headers along with other peripherals like a micro-SD +card.

+

The espp::MatouchRotaryDisplay component provides a singleton hardware +abstraction for initializing the touch, display, and button.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class MatouchRotaryDisplay : public espp::BaseComponent
+

The MatouchRotaryDisplay class provides an interface to the MaTouch Rotary Display 1.28” ESP32-S3 development board (Model MTRO128G).

+

The class provides access to the following features:

    +
  • Touchpad (CST816S)

  • +
  • Display (GC9A01)

  • +
  • ABI Encoder

  • +
+

+

For more information see: https://github.com/Makerfabs/MaTouch-ESP32-S3-RotaryIPS-Display1.28-GC9A01

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::MatouchRotaryDisplay &mt_display = espp::MatouchRotaryDisplay::get();
+  mt_display.set_log_level(espp::Logger::Verbosity::INFO);
+
+  auto on_button_pressed = [&](const auto &event) {
+    if (event.active) {
+      logger.info("Button pressed!");
+    } else {
+      logger.info("Button released!");
+      // clear the screen
+      std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+      clear_circles();
+    }
+  };
+
+  auto on_touch = [&](const auto &touch) {
+    // NOTE: since we're directly using the touchpad data, and not using the
+    // TouchpadInput + LVGL, we'll need to ensure the touchpad data is
+    // converted into proper screen coordinates instead of simply using the
+    // raw values.
+    static auto previous_touchpad_data = mt_display.touchpad_convert(touch);
+    auto touchpad_data = mt_display.touchpad_convert(touch);
+    if (touchpad_data != previous_touchpad_data) {
+      logger.info("Touch: {}", touchpad_data);
+      previous_touchpad_data = touchpad_data;
+      // if there is a touch point, draw a circle
+      if (touchpad_data.num_touch_points > 0) {
+        std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+        draw_circle(touchpad_data.x, touchpad_data.y, 10);
+      }
+    }
+    previous_touchpad_data = touchpad_data;
+  };
+
+  // initialize the LCD
+  if (!mt_display.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // set the pixel buffer to be 50 lines high
+  static constexpr size_t pixel_buffer_size = mt_display.lcd_width() * 50;
+  // initialize the LVGL display for the Matouch-Rotary-Display
+  if (!mt_display.initialize_display(pixel_buffer_size)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+  // initialize the touchpad
+  if (!mt_display.initialize_touch(on_touch)) {
+    logger.error("Failed to initialize touchpad!");
+    return;
+  }
+  // initialize the rotary encoder
+  if (!mt_display.initialize_encoder()) {
+    logger.error("Failed to initialize rotary encoder!");
+    return;
+  }
+  // initialize the button
+  if (!mt_display.initialize_button(on_button_pressed)) {
+    logger.error("Failed to initialize button!");
+    return;
+  }
+
+  // set the background color to black
+  lv_obj_t *bg = lv_obj_create(lv_screen_active());
+  lv_obj_set_size(bg, mt_display.lcd_width(), mt_display.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Touch the screen!\nPress the button to clear circles.");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // add a button in the top left which (when pressed) will rotate the display
+  // through 0, 90, 180, 270 degrees
+  lv_obj_t *btn = lv_btn_create(lv_screen_active());
+  lv_obj_set_size(btn, 50, 50);
+  lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 0);
+  lv_obj_t *label_btn = lv_label_create(btn);
+  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<std::recursive_mutex> lock(lvgl_mutex);
+        clear_circles();
+        static auto rotation = LV_DISPLAY_ROTATION_0;
+        rotation = static_cast<lv_display_rotation_t>((static_cast<int>(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)
+  lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF);
+  lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                      }});
+  lv_task.start();
+
+  // set the display brightness to be 75%
+  mt_display.brightness(75.0f);
+
+  while (true) {
+    auto start = esp_timer_get_time();
+    // get the encoder count and update the label with it
+    {
+      std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+      int encoder_count = mt_display.encoder_value();
+      lv_label_set_text_fmt(label,
+                            "Touch the screen!\nPress the button to clear circles.\nEncoder: %d",
+                            encoder_count);
+    }
+    // sleep for the remaining time
+    auto end = esp_timer_get_time();
+    auto elapsed = end - start;
+    std::this_thread::sleep_for(50ms - std::chrono::microseconds(elapsed));
+  }
+
+
+
+
+

Public Types

+
+
+using Pixel = lv_color16_t
+

Alias for the pixel type used by the Matouch display.

+
+ +
+
+using DisplayDriver = espp::Gc9a01
+

Alias for the display driver used by the Matouch display.

+
+ +
+
+

Public Functions

+
+
+I2c &internal_i2c()
+

Get a reference to the internal I2C bus

+
+

Note

+

The internal I2C bus is used for the touchscreen

+
+
+
Returns
+

A reference to the internal I2C bus

+
+
+
+ +
+
+espp::Interrupt &interrupts()
+

Get a reference to the interrupts

+
+
Returns
+

A reference to the interrupts

+
+
+
+ +
+
+bool initialize_encoder()
+

Initialize the encoder

+
+
Returns
+

true if the encoder was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Encoder> encoder() const
+

Get the encoder

+
+
Returns
+

A shared pointer to the encoder

+
+
+
+ +
+
+int encoder_value()
+

Get the encoder value

+
+
Returns
+

The encoder value

+
+
+
+ +
+
+bool initialize_button(const button_callback_t &callback = nullptr)
+

Initialize the button

+
+
Parameters
+

callback – The callback function to call when the button is pressed

+
+
Returns
+

true if the button was successfully initialized, false otherwise

+
+
+
+ +
+
+bool button_state() const
+

Get the button state

+
+
Returns
+

The button state (true = button pressed, false = button released)

+
+
+
+ +
+
+bool initialize_touch(const touch_callback_t &callback = nullptr)
+

Initialize the touchpad

+
+

Note

+

This will also register an interrupt for the touchpad which will automatically update the touchpad data when the touchpad is touched

+
+
+

Warning

+

This method should be called after the display has been initialized if you want the touchpad to be recognized and used with LVGL and its objects.

+
+
+
Parameters
+

callback – The callback function to call when the touchpad is touched. This callback will be called after the touchpad data has been updated and will be passed the updated touchpad data.

+
+
Returns
+

true if the touchpad was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<TouchpadInput> touchpad_input() const
+

Get the touchpad input

+
+
Returns
+

A shared pointer to the touchpad input

+
+
+
+ +
+
+TouchpadData touchpad_data() const
+

Get the most recent touchpad data

+
+
Returns
+

The touchpad data

+
+
+
+ +
+
+void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)
+

Get the most recent touchpad data

+

See also

+

touchpad_data()

+
+

+
+

Note

+

This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the touchpad_data() method

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points

  • +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • btn_state – The button state (0 = button released, 1 = button pressed)

  • +
+
+
+
+ +
+
+TouchpadData touchpad_convert(const TouchpadData &data) const
+

Convert touchpad data from raw reading to display coordinates

+
+

Note

+

Uses the touch_invert_x and touch_invert_y settings to determine if the x and y coordinates should be inverted

+
+
+
Parameters
+

data – The touchpad data to convert

+
+
Returns
+

The converted touchpad data

+
+
+
+ +
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline MatouchRotaryDisplay &get()
+

Access the singleton instance of the MatouchRotaryDisplay class.

+
+
Returns
+

Reference to the singleton instance of the MatouchRotaryDisplay class

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/matouch_rotary_display_example.html b/matouch_rotary_display_example.html new file mode 100644 index 000000000..8eaf118c4 --- /dev/null +++ b/matouch_rotary_display_example.html @@ -0,0 +1,240 @@ + + + + + + + Matouch-Rotary-Display Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Matouch-Rotary-Display Example

+

This example shows how to use the espp::MatouchRotaryDisplay hardware +abstraction component initialize the components on the MaTouch Rotary Display.

+

It initializes the touch, display, and t-keyboard subsystems. It reads the +touchpad state and each time you touch the screen it uses LVGL to draw a circle +where you touch. If you press the home button on the display, it will clear the +circles.

+

https://github.com/esp-cpp/espp/assets/213467/4d88dd97-b23a-49d0-b6a2-2ee3b50a8f62

+

image

+

image

+

image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the MaTouch Rotary Display 1.28”.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-08 at 22 02 08

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/monitor.html b/monitor.html new file mode 100644 index 000000000..e6d1395da --- /dev/null +++ b/monitor.html @@ -0,0 +1,628 @@ + + + + + + + Monitoring APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Monitoring APIs

+
+

Task Monitor

+

The task monitor provides the ability to use the FreeRTOS trace facility to +output information about the CPU utilization (%), stack high water mark (bytes), +and priority of all the tasks running on the system.

+

There is an associated task-monitor +python gui which can parse the output of this component and render it as a chart +or into a table for visualization.

+

Code examples for the monitor API are provided in the monitor example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TaskMonitor : public espp::BaseComponent
+

Class which monitors the currently running tasks in the system and periodically logs their states. See also FreeRTOS::vTaskGetInfo().

+
+

Basic Task Monitor Example

+
    // create the monitor
+    espp::TaskMonitor tm({.period = 500ms});
+    // create threads
+    auto start = std::chrono::high_resolution_clock::now();
+    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
+      // do some work
+      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
+      // sleep
+      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
+      // don't want to stop the task
+      return false;
+    };
+    std::vector<std::unique_ptr<espp::Task>> tasks;
+    size_t num_tasks = 10;
+    tasks.resize(num_tasks);
+    for (size_t i = 0; i < num_tasks; i++) {
+      std::string task_name = fmt::format("Task {}", i);
+      auto task = espp::Task::make_unique(
+          {.callback = std::bind(task_fn, i, _1, _2, _3),
+           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
+      tasks[i] = std::move(task);
+      tasks[i]->start();
+    }
+    // now sleep for a while to let the monitor do its thing
+    std::this_thread::sleep_for(5s);
+
+
+
+
+

get_latest_info_vector() Example

+
    // create threads
+    auto start = std::chrono::high_resolution_clock::now();
+    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
+      // do some work
+      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
+      // sleep
+      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
+      // don't want to stop the task
+      return false;
+    };
+    std::vector<std::unique_ptr<espp::Task>> tasks;
+    size_t num_tasks = 10;
+    tasks.resize(num_tasks);
+    for (size_t i = 0; i < num_tasks; i++) {
+      std::string task_name = fmt::format("Task {}", i);
+      auto task = espp::Task::make_unique(
+          {.callback = std::bind(task_fn, i, _1, _2, _3),
+           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
+      tasks[i] = std::move(task);
+      tasks[i]->start();
+    }
+    // now sleep for a while to let the monitor do its thing
+    std::this_thread::sleep_for(1s);
+    auto task_info = espp::TaskMonitor::get_latest_info_vector();
+    for (const auto &info : task_info) {
+      fmt::print("{}\n", info);
+    }
+
+
+
+
+

get_latest_info_*() Example

+
    // create threads
+    auto start = std::chrono::high_resolution_clock::now();
+    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
+      auto now = std::chrono::high_resolution_clock::now();
+      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
+      // do some work
+      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
+      // sleep
+      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
+      // don't want to stop the task
+      return false;
+    };
+    std::vector<std::unique_ptr<espp::Task>> tasks;
+    size_t num_tasks = 10;
+    tasks.resize(num_tasks);
+    for (size_t i = 0; i < num_tasks; i++) {
+      std::string task_name = fmt::format("Task {}", i);
+      auto task = espp::Task::make_unique(
+          {.callback = std::bind(task_fn, i, _1, _2, _3),
+           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
+      tasks[i] = std::move(task);
+      tasks[i]->start();
+    }
+    // now sleep for a while to let the monitor do its thing
+    std::this_thread::sleep_for(1s);
+    // single line string
+    fmt::print("Task Monitor Info (single line):\n");
+    fmt::print("{}\n", espp::TaskMonitor::get_latest_info_string());
+    // pretty table
+    fmt::print("Task Monitor Info (pretty table):\n");
+    auto task_table = espp::TaskMonitor::get_latest_info_table();
+    std::cout << task_table << std::endl;
+
+
+
+
+

Note

+

you must enable CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS for this class to do anything. This means that you can always instantiate this class in your app_main, and then based on those two config settings it will either do nothing (default) or print out the stats for you to analyze. Finally, the monitoring period can be configured as well.

+
+
+

Note

+

If you wish to also get the core id of the task, you must enable CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID. If you do not enable this option, the core id will be -2.

+
+
+

Public Functions

+
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline std::vector<TaskInfo> get_latest_info_vector()
+

Get information about all the tasks running. Will provide for each task the following information:

+

    +
  • name

  • +
  • % CPU run time the task has used

  • +
  • stack high water mark (bytes)

  • +
  • current priority of the task

  • +
+

+
+
Returns
+

std::vector<TaskInfo> vector containing info for each task.

+
+
+
+ +
+
+static inline std::string get_latest_info_string()
+

Get information about all the tasks running. Will provide for each task the following information:

+

    +
  • name

  • +
  • % CPU run time the task has used

  • +
  • stack high water mark (bytes)

  • +
  • current priority of the task

  • +
  • core the task is running on

  • +
+

+

Where each entry is separated by ‘,’ and each set of task data is separated by ‘;’.

+

+This is a static function, so it can be called without having to instantiate a TaskMonitor object.

+
+

Note

+

There is no newline returned.

+
+
+

Note

+

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a single line string separated by , and ;.

+
+
+
Returns
+

std::string containing sequence of entries, formatted:

name, cpu%, high_water_mark, priority, core_id;;
+
+
+

+
+
+
+ +
+
+static inline auto get_latest_info_table()
+

Print the latest task information in a nice table format. This is a static function, so it can be called without having to instantiate a TaskMonitor object.

+
+

Note

+

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a table using the libfmt library.

+
+
+
Returns
+

A string containing the information in a table format.

+
+
+
+ +
+
+
+struct Config
+

Config structure for TaskMonitor object.

+
+

Public Members

+
+
+std::chrono::duration<float> period
+

Period (s) the TaskMonitor::task_callback runs at.

+
+ +
+
+size_t task_stack_size_bytes{8 * 1024}
+

Stack size (B) allocated to the TaskMonitor::task_callback.

+
+ +
+
+ +
+
+struct TaskInfo
+

Info structure for each task monitored.

+
+

Public Members

+
+
+std::string name
+

Name of the task.

+
+ +
+
+uint32_t cpu_percent
+

% CPU run time the task has used.

+
+ +
+
+uint32_t high_water_mark
+

Stack high water mark (bytes).

+
+ +
+
+uint32_t priority
+

Current priority of the task.

+
+ +
+
+int core_id
+

Core the task is running on. Will be 0,1, or -1 if task is not pinned to a core. Only valid if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set to y, otherwise will be -2.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/monitor_example.html b/monitor_example.html new file mode 100644 index 000000000..f2bdc6ec2 --- /dev/null +++ b/monitor_example.html @@ -0,0 +1,235 @@ + + + + + + + Monitor Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Monitor Example

+

This example shows how to use the monitor component to monitor the executing +tasks.

+
+

How to use example

+
+

Configure the project

+
idf.py menuconfig
+
+
+

Note: the example already configures the FREERTOS_USE_TRACE_FACILITY and +FREERTOS_GENERATE_RUN_TIME_STATS sdkconfig to enable printing the task info.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-03-05 at 14 36 04

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/motorgo_mini.html b/motorgo_mini.html new file mode 100644 index 000000000..a5dc6ebea --- /dev/null +++ b/motorgo_mini.html @@ -0,0 +1,885 @@ + + + + + + + MotorGo Mini - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MotorGo Mini

+
+

MotorGo Mini

+

The MotorGo Mini is a small, low-cost, low-power motor controller that can be +used to control a two motors.

+

https://motorgo.net

+

It’s pretty sweet and the component provides the implementation of the two +channel FOC motor controller, along with other peripheral classes such as the +ADC, LEDs, and I2C.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class MotorGoMini : public espp::BaseComponent
+

This class acts as a board support component for the MotorGo-Mini board. It provides a high-level interface to the board’s functionality. The MotorGo-Mini board is a motor driver board that can drive two DC motors. More information about the board can be found at: https://github.com/Every-Flavor-Robotics/motorgo-mini-hardware

+

High level overview of the board:

    +
  • ESP32s3 module

  • +
  • Two LEDs (yellow and red)

  • +
  • Two BLDC motor drivers (TMC6300)

  • +
  • Two magnetic encoders (connected via two JST-SH 5 pin connectors to EncoderGo boards) (SPI2_HOST)

  • +
  • Two Qwiic connectors for I2C communication (I2C0)

  • +
  • Current sense resistors for each motor on the U and W phases NOTE: on the MotorGo-Mini v1.3, the M2 motor sense is swapped in the schematic, with U and W swapped

  • +
+

+

The class is a singleton and can be accessed using the get() method.

+
+

MotorGo-Mini Example

+
  auto &motorgo_mini = espp::MotorGoMini::get();
+  motorgo_mini.set_log_level(espp::Logger::Verbosity::INFO);
+  motorgo_mini.init_motor_channel_1();
+  motorgo_mini.init_motor_channel_2();
+  auto &motor1 = motorgo_mini.motor1();
+  auto &motor2 = motorgo_mini.motor2();
+  auto &button = motorgo_mini.button();
+
+  static constexpr uint64_t core_update_period_us = 1000;                   // microseconds
+  static constexpr float core_update_period = core_update_period_us / 1e6f; // seconds
+
+  // static constexpr auto motion_control_type = espp::detail::MotionControlType::VELOCITY_OPENLOOP;
+  // static constexpr auto motion_control_type = espp::detail::MotionControlType::VELOCITY;
+  // static const auto motion_control_type = espp::detail::MotionControlType::ANGLE_OPENLOOP;
+  static auto motion_control_type = espp::detail::MotionControlType::ANGLE;
+
+  logger.info("Setting motion control type to {}", motion_control_type);
+  motor1.set_motion_control_type(motion_control_type);
+  motor2.set_motion_control_type(motion_control_type);
+
+  motor1.enable();
+  motor2.enable();
+
+  std::atomic<float> target1 = 60.0f;
+  std::atomic<float> target2 = 60.0f;
+  static bool target_is_angle =
+      motion_control_type == espp::detail::MotionControlType::ANGLE ||
+      motion_control_type == espp::detail::MotionControlType::ANGLE_OPENLOOP;
+  // Function for initializing the target based on the motion control type
+  auto initialize_target = [&]() {
+    if (target_is_angle) {
+      target1 = motor1.get_shaft_angle();
+      target2 = motor2.get_shaft_angle();
+    } else {
+      target1 = 50.0f * espp::RPM_TO_RADS;
+      target2 = 50.0f * espp::RPM_TO_RADS;
+    }
+  };
+  // run it once
+  initialize_target();
+
+  auto dual_motor_fn = [&]() -> bool {
+    motor1.loop_foc();
+    motor2.loop_foc();
+    motor1.move(target1);
+    motor2.move(target2);
+    return false; // don't want to stop the task
+  };
+
+  auto dual_motor_timer = espp::HighResolutionTimer({.name = "Motor Timer",
+                                                     .callback = dual_motor_fn,
+                                                     .log_level = espp::Logger::Verbosity::WARN});
+  dual_motor_timer.periodic(core_update_period_us);
+
+  static constexpr float sample_freq_hz = 100.0f;
+  static constexpr float filter_cutoff_freq_hz = 5.0f;
+  static constexpr float normalized_cutoff_frequency =
+      2.0f * filter_cutoff_freq_hz / sample_freq_hz;
+  static constexpr size_t ORDER = 2;
+  // NOTE: using the Df2 since it's hardware accelerated :)
+  using Filter = espp::ButterworthFilter<ORDER, espp::BiquadFilterDf2>;
+  Filter filter1({.normalized_cutoff_frequency = normalized_cutoff_frequency});
+  Filter filter2({.normalized_cutoff_frequency = normalized_cutoff_frequency});
+
+  // if it's a velocity setpoint then target is RPM
+  fmt::print("%time(s), "
+             "motor 1 target, " // target is either RPM or radians
+             "motor 1 angle (radians), "
+             "motor 1 speed (rpm), "
+             "motor 2 target, " // target is either RPM or radians
+             "motor 2 angle (radians), "
+             "motor 2 speed (rpm)\n");
+
+  // make the task to periodically poll the encoders and print the state. NOTE:
+  // the encoders run their own tasks to maintain state, so we're just polling
+  // the current state.
+  auto logging_fn = [&](std::mutex &m, std::condition_variable &cv) {
+    static auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    auto seconds = std::chrono::duration<float>(now - start).count();
+    auto _target1 = target1.load();
+    if (!target_is_angle)
+      _target1 *= espp::RADS_TO_RPM;
+    auto _target2 = target2.load();
+    if (!target_is_angle)
+      _target2 *= espp::RADS_TO_RPM;
+    auto rpm1 = filter1(motor1.get_shaft_velocity() * espp::RADS_TO_RPM);
+    auto rpm2 = filter2(motor2.get_shaft_velocity() * espp::RADS_TO_RPM);
+    auto rads1 = motor1.get_shaft_angle();
+    auto rads2 = motor2.get_shaft_angle();
+    fmt::print("{:.3f}, {:.3f}, {:.3f}, {:.3f}, {:.3f}, {:.3f}, {:.3f}\n", seconds, _target1, rads1,
+               rpm1, _target2, rads2, rpm2);
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_for(lk, 10ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+  auto logging_task = espp::Task({.callback = logging_fn,
+                                  .task_config =
+                                      {
+                                          .name = "Logging Task",
+                                          .stack_size_bytes = 5 * 1024,
+                                      },
+                                  .log_level = espp::Logger::Verbosity::WARN});
+  logging_task.start();
+
+  std::this_thread::sleep_for(1s);
+  logger.info("Starting target task");
+
+  enum class IncrementDirection { DOWN = -1, HOLD = 0, UP = 1 };
+  static IncrementDirection increment_direction1 = IncrementDirection::UP;
+  static IncrementDirection increment_direction2 = IncrementDirection::DOWN;
+
+  auto update_target = [&](auto &target, auto &increment_direction) {
+    float max_target = target_is_angle ? (2.0f * M_PI) : (200.0f * espp::RPM_TO_RADS);
+    float target_delta =
+        target_is_angle ? (M_PI / 4.0f) : (50.0f * espp::RPM_TO_RADS * core_update_period);
+    // update target
+    if (increment_direction == IncrementDirection::UP) {
+      target += target_delta;
+      if (target >= max_target) {
+        increment_direction = IncrementDirection::DOWN;
+      }
+    } else if (increment_direction == IncrementDirection::DOWN) {
+      target -= target_delta;
+      if (target <= -max_target) {
+        increment_direction = IncrementDirection::UP;
+      }
+    }
+  };
+
+  // make a task which will update the target (velocity or angle)
+  auto target_task_fn = [&](std::mutex &m, std::condition_variable &cv) {
+    auto delay = std::chrono::duration<float>(target_is_angle ? 1.0f : core_update_period);
+    auto start = std::chrono::high_resolution_clock::now();
+    update_target(target1, increment_direction1);
+    update_target(target2, increment_direction2);
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_until(lk, start + delay);
+    }
+    // don't want to stop the task
+    return false;
+  };
+  auto target_task = espp::Task({
+      .callback = target_task_fn,
+      .task_config = {.name = "Target Task"},
+  });
+  target_task.start();
+
+  bool button_state = false;
+
+  while (true) {
+    bool new_button_state = button.is_pressed();
+    if (new_button_state != button_state) {
+      button_state = new_button_state;
+      if (button_state) {
+        logger.info("Button pressed, changing motion control type");
+        // switch between ANGLE and VELOCITY
+        if (motion_control_type == espp::detail::MotionControlType::ANGLE ||
+            motion_control_type == espp::detail::MotionControlType::ANGLE_OPENLOOP) {
+          motion_control_type = espp::detail::MotionControlType::VELOCITY;
+          target_is_angle = false;
+        } else {
+          motion_control_type = espp::detail::MotionControlType::ANGLE;
+          target_is_angle = true;
+        }
+        initialize_target();
+        motor1.set_motion_control_type(motion_control_type);
+        motor2.set_motion_control_type(motion_control_type);
+      } else {
+        logger.info("Button released");
+      }
+    }
+    std::this_thread::sleep_for(50ms);
+  }
+
+
+
+
+

Public Functions

+
+
+I2c &get_external_i2c()
+

Get a reference to the external I2C bus

+
+
Returns
+

A reference to the external I2C bus

+
+
+
+ +
+
+espp::Button &button()
+

Get a reference to the boot button.

+
+ +
+
+espp::Led::ChannelConfig &yellow_led()
+

Get a reference to the yellow LED channel (channel 0)

+
+
Returns
+

A reference to the yellow LED channel (channel 0)

+
+
+
+ +
+
+espp::Led::ChannelConfig &led_channel0()
+

Get a reference to the yellow LED channel (channel 0)

+
+
Returns
+

A reference to the yellow LED channel (channel 0)

+
+
+
+ +
+
+void set_yellow_led_duty(float duty)
+

Set the duty cycle of the yellow LED

+
+

Note

+

The duty cycle is a percentage of the maximum duty cycle (which is 100.0) 0.0 is off, 100.0 is fully on

+
+
+

Note

+

For this function to have an effect, the LED timer must NOT be running (i.e. stop_breathing() must be called)

+
+
+
Parameters
+

duty – The duty cycle of the yellow LED (0.0 - 100.0)

+
+
+
+ +
+
+espp::Led::ChannelConfig &red_led()
+

Get a reference to the red LED channel (channel 1)

+
+
Returns
+

A reference to the red LED channel (channel 1)

+
+
+
+ +
+
+espp::Led::ChannelConfig &led_channel1()
+

Get a reference to the red LED channel (channel 1)

+
+
Returns
+

A reference to the red LED channel (channel 1)

+
+
+
+ +
+
+void set_red_led_duty(float duty)
+

Set the duty cycle of the red LED

+
+

Note

+

The duty cycle is a percentage of the maximum duty cycle (which is 100.0) 0.0 is off, 100.0 is fully on

+
+
+

Note

+

For this function to have an effect, the LED timer must NOT be running (i.e. stop_breathing() must be called)

+
+
+
Parameters
+

duty – The duty cycle of the red LED (0.0 - 100.0)

+
+
+
+ +
+
+espp::Led &led()
+

Get a reference to the LED object which controls the LEDs

+
+
Returns
+

A reference to the Led object

+
+
+
+ +
+
+espp::Gaussian &gaussian()
+

Get a reference to the Gaussian object which is used for breathing the LEDs.

+
+
Returns
+

A reference to the Gaussian object

+
+
+
+ +
+
+void start_breathing()
+

Start breathing the LEDs

+

This function starts the LED timer which will periodically update the LED duty cycle using the gaussian to create a breathing efect.

+
+ +
+
+void stop_breathing()
+

Stop breathing the LEDs

+

This function stops the LED timer which will stop updating the LED duty cycle. It will also set the LED duty cycle to 0, effectively turning off the LEDs.

+
+ +
+
+void init_motor_channel_1()
+

Initialize the MotorGo-Mini’s components for motor channel 1

+

This function initializes the encoder and motor for motor channel

    +
  1. This consists of initializing encoder1 and motor1.

  2. +
+

+
+ +
+
+void init_motor_channel_2()
+

Initialize the MotorGo-Mini’s components for motor channel 2

+

This function initializes the encoder and motor for motor channel

    +
  1. This consists of initializing encoder2 and motor2.

  2. +
+

+
+ +
+
+Encoder &encoder1()
+

Get a reference to the encoder 1

+
+
Returns
+

A reference to the encoder 1

+
+
+
+ +
+
+Encoder &encoder2()
+

Get a reference to the encoder 2

+
+
Returns
+

A reference to the encoder 2

+
+
+
+ +
+
+espp::BldcDriver &motor1_driver()
+

Get a reference to the motor 1 driver

+
+
Returns
+

A reference to the motor 1 driver

+
+
+
+ +
+
+espp::BldcDriver &motor2_driver()
+

Get a reference to the motor 2 driver

+
+
Returns
+

A reference to the motor 2 driver

+
+
+
+ +
+
+BldcMotor &motor1()
+

Get a reference to the motor 1

+
+
Returns
+

A reference to the motor 1

+
+
+
+ +
+
+BldcMotor &motor2()
+

Get a reference to the motor 2

+
+
Returns
+

A reference to the motor 2

+
+
+
+ +
+
+espp::OneshotAdc &adc1()
+

Get a reference to the ADC_UNIT_1 OneshotAdc object

+
+
Returns
+

A reference to the ADC_UNIT_1 OneshotAdc object

+
+
+
+ +
+
+espp::OneshotAdc &adc2()
+

Get a reference to the ADC_UNIT_2 OneshotAdc object

+
+
Returns
+

A reference to the ADC_UNIT_2 OneshotAdc object

+
+
+
+ +
+
+float motor1_current_u_amps()
+

Get the current sense value for motor 1 phase U

+
+
Returns
+

The current sense value for motor 1 phase U in amps

+
+
+
+ +
+
+float motor1_current_w_amps()
+

Get the current sense value for motor 1 phase W

+
+
Returns
+

The current sense value for motor 1 phase W in amps

+
+
+
+ +
+
+float motor2_current_u_amps()
+

Get the current sense value for motor 2 phase U

+
+
Returns
+

The current sense value for motor 2 phase U in amps

+
+
+
+ +
+
+float motor2_current_w_amps()
+

Get the current sense value for motor 2 phase W

+
+
Returns
+

The current sense value for motor 2 phase W in amps

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline MotorGoMini &get()
+

Access the singleton instance of the MotorGoMini class.

+
+
Returns
+

Reference to the singleton instance of the MotorGoMini class

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/motorgo_mini_example.html b/motorgo_mini_example.html new file mode 100644 index 000000000..2b3ec9fe6 --- /dev/null +++ b/motorgo_mini_example.html @@ -0,0 +1,240 @@ + + + + + + + MotorGo-Mini Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MotorGo-Mini Example

+

This example demonstrates how to use the espp::MotorGoMini component to +initialize the hardware on the MotorGo Mini board which +is connected to two encoders and two BLDC motors. It uses those hardware to +drive the motors and outputs the state as a CSV.

+

If you press the boot button it will toggle between closed-loop angle control +and closed-loop velocity control.

+

https://github.com/esp-cpp/espp/assets/213467/1e7cd53b-2c87-4529-b711-e9f0ba2bcaf6

+
+

How to use example

+
+

Hardware Required

+

This example requires a MotorGo Mini board, two EncoderGo boards, and two +motors. The MotorGo Mini board should be connected to the two EncoderGo boards +and the motors.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-05-16 at 14 10 38

+

https://github.com/esp-cpp/espp/assets/213467/709e2aa4-84bb-48e6-882d-bad559eaa4f2

+

CleanShot 2024-05-16 at 14 22 20

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/network/index.html b/network/index.html new file mode 100644 index 000000000..1dc9d9e1a --- /dev/null +++ b/network/index.html @@ -0,0 +1,215 @@ + + + + + + + Network APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Network APIs

+ +

The network APIs provide a useful abstraction over POSIX sockets enabling easily +starting client/server sockets and allowing their use with std::function +callbacks for servers.

+

Currently, UDP and TCP sockets are supported.

+

Code examples for the network API are provided in the socket example folder..

+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/network/socket.html b/network/socket.html new file mode 100644 index 000000000..82e4f7a93 --- /dev/null +++ b/network/socket.html @@ -0,0 +1,665 @@ + + + + + + + Sockets - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Sockets

+

The socket provides the base abstraction around the socket file descriptor and +includes some initialization, cleanup, and conversion utilities.

+

The socket class is subclassed into UdpSocket and TcpSocket.

+
+

API Reference

+
+

Header File

+ +
+
+

Type Definitions

+
+
+typedef int sock_type_t
+
+ +
+
+

Classes

+
+
+class Socket : public espp::BaseComponent
+

Class for a generic socket with some helper functions for configuring the socket.

+

Subclassed by espp::TcpSocket, espp::UdpSocket

+
+

Public Types

+
+
+typedef std::function<std::optional<std::vector<uint8_t>>(std::vector<uint8_t> &data, const Info &sender_info)> receive_callback_fn
+

Callback function to be called when receiving data from a client.

+
+
Param data
+

Byte array of data received from client

+
+
Param sender_info
+

Sender information (address, port)

+
+
Return
+

std::optional<std::vector<uint8_t>> optional data to return to sender.

+
+
+
+ +
+
+typedef std::function<void(std::vector<uint8_t> &data)> response_callback_fn
+

Callback function to be called with data returned after transmitting data to a server.

+
+
Param data
+

The data that the server responded with

+
+
+
+ +
+
+

Public Functions

+
+
+explicit Socket(sock_type_t socket_fd, const espp::Logger::Config &logger_config)
+

Construct the socket, setting its internal socket file descriptor.

+
+

Note

+

This constructor does not check the validity of the socket file descriptor.

+
+
+
Parameters
+
    +
  • socket_fdSocket file descriptor.

  • +
  • logger_config – configuration for the logger associated with the socket.

  • +
+
+
+
+ +
+
+explicit Socket(Type type, const espp::Logger::Config &logger_config)
+

Initialize the socket (calling init()).

+
+
Parameters
+
    +
  • type – The Socket::Type of the socket to make.

  • +
  • logger_config – configuration for the logger associated with the socket.

  • +
+
+
+
+ +
+
+~Socket()
+

Tear down any resources associted with the socket.

+
+ +
+
+bool is_valid() const
+

Is the socket valid.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+std::optional<Info> get_ipv4_info()
+

Get the Socket::Info for the socket.

+

This will call getsockname() on the socket to get the sockaddr_storage structure, and then fill out the Socket::Info structure.

+
+
Returns
+

Socket::Info for the socket.

+
+
+
+ +
+
+bool set_receive_timeout(const std::chrono::duration<float> &timeout)
+

Set the receive timeout on the provided socket.

+
+
Parameters
+

timeout – requested timeout, must be > 0.

+
+
Returns
+

true if SO_RECVTIMEO was successfully set.

+
+
+
+ +
+
+bool enable_reuse()
+

Allow others to use this address/port combination after we’re done with it.

+
+
Returns
+

true if SO_REUSEADDR and SO_REUSEPORT were successfully set.

+
+
+
+ +
+
+bool make_multicast(uint8_t time_to_live = 1, uint8_t loopback_enabled = true)
+

Configure the socket to be multicast (if time_to_live > 0). Sets the IP_MULTICAST_TTL (number of multicast hops allowed) and optionally configures whether this node should receive its own multicast packets (IP_MULTICAST_LOOP).

+
+
Parameters
+
    +
  • time_to_live – number of multicast hops allowed (TTL).

  • +
  • loopback_enabled – Whether to receive our own multicast packets.

  • +
+
+
Returns
+

true if IP_MULTICAST_TTL and IP_MULTICAST_LOOP were set.

+
+
+
+ +
+
+bool add_multicast_group(const std::string &multicast_group)
+

If this is a server socket, add it to the provided the multicast group.

+

+See https://en.wikipedia.org/wiki/Multicast_address for more information.

+
+

Note

+

Multicast groups must be Class D addresses (224.0.0.0 to 239.255.255.255)

+
+
+
Parameters
+

multicast_group – multicast group to join.

+
+
Returns
+

true if IP_ADD_MEMBERSHIP was successfully set.

+
+
+
+ +
+
+int select(const std::chrono::microseconds &timeout)
+

Select on the socket for read events.

+
+
Parameters
+

timeout – how long to wait for an event.

+
+
Returns
+

number of events that occurred.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static bool is_valid_fd(sock_type_t socket_fd)
+

Is the socket valid.

+
+
Parameters
+

socket_fdSocket file descriptor.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+
+struct Info
+

Storage for socket information (address, port) with convenience functions to convert to/from POSIX structures.

+
+

Public Functions

+
+
+void init_ipv4(const std::string &addr, size_t prt)
+

Initialize the struct as an ipv4 address/port combo.

+
+
Parameters
+
    +
  • addr – IPv4 address string

  • +
  • prt – port number

  • +
+
+
+
+ +
+
+struct sockaddr_in *ipv4_ptr()
+

Gives access to IPv4 sockaddr structure (sockaddr_in) for use with low level socket calls like sendto / recvfrom.

+
+
Returns
+

*sockaddr_in pointer to ipv4 data structure

+
+
+
+ +
+
+struct sockaddr_in6 *ipv6_ptr()
+

Gives access to IPv6 sockaddr structure (sockaddr_in6) for use with low level socket calls like sendto / recvfrom.

+
+
Returns
+

*sockaddr_in6 pointer to ipv6 data structure

+
+
+
+ +
+
+void update()
+

Will update address and port based on the curent data in raw.

+
+ +
+
+void from_sockaddr(const struct sockaddr_storage &source_address)
+

Fill this Info from the provided sockaddr struct.

+
+
Parameters
+

&source_address – sockaddr info filled out by recvfrom.

+
+
+
+ +
+
+void from_sockaddr(const struct sockaddr_in &source_address)
+

Fill this Info from the provided sockaddr struct.

+
+
Parameters
+

&source_address – sockaddr info filled out by recvfrom.

+
+
+
+ +
+
+void from_sockaddr(const struct sockaddr_in6 &source_address)
+

Fill this Info from the provided sockaddr struct.

+
+
Parameters
+

&source_address – sockaddr info filled out by recvfrom.

+
+
+
+ +
+
+

Public Members

+
+
+std::string address
+

IP address of the endpoint as a string.

+
+ +
+
+size_t port
+

Port of the endpoint as an integer.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/network/socket_example.html b/network/socket_example.html new file mode 100644 index 000000000..b97c38b92 --- /dev/null +++ b/network/socket_example.html @@ -0,0 +1,233 @@ + + + + + + + Socket Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Socket Example

+

This example shows the use of the classes provided by the socket component, +including:

+
    +
  • UdpSocket (as both client and server, including unicast and multicast configurations)

  • +
  • TcpSocket (as both client and server)

  • +
+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/network/tcp_socket.html b/network/tcp_socket.html new file mode 100644 index 000000000..7a45770e3 --- /dev/null +++ b/network/tcp_socket.html @@ -0,0 +1,971 @@ + + + + + + + TCP Sockets - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

TCP Sockets

+

TCP sockets provide reliable, ordered communication over IP network sockets and +have built-in protocols for handling packet acknowledgement as well as +transmission speed / bandwidth adjustment.

+

TCP sockets cannot be used with multicast (many to one, one to many).

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TcpSocket : public espp::Socket
+

Class for managing sending and receiving data using TCP/IP. Can be used to create client or server sockets.

+
+

TCP Client Example

+
  espp::TcpSocket client_socket({});
+  client_socket.connect({.ip_address = server_address, .port = port});
+  // create thread for sending data using the socket
+  auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) {
+    static size_t iterations = 0;
+    std::vector<uint8_t> data{0, 1, 2, 3, 4};
+    std::transform(data.begin(), data.end(), data.begin(),
+                   [](const auto &d) { return d + iterations; });
+    client_socket.transmit(data);
+    iterations++;
+    std::this_thread::sleep_for(1s);
+    // don't want to stop the task
+    return false;
+  };
+  auto client_task = espp::Task::make_unique(
+      {.callback = client_task_fn,
+       .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}});
+  client_task->start();
+
+
+
+
+

TCP Server Example

+
  std::string server_address = "127.0.0.1";
+  size_t port = 5000;
+  int max_connections = 1;
+  espp::TcpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN});
+  server_socket.bind(port);
+  server_socket.listen(max_connections);
+  auto server_task_fn = [&server_socket](auto &m, auto &cv) -> bool {
+    static std::unique_ptr<espp::TcpSocket> client_socket;
+    if (!client_socket) {
+      client_socket = server_socket.accept();
+      if (client_socket) {
+        auto info = client_socket->get_remote_info();
+        fmt::print("Server accepted connection from: {}\n", info);
+      }
+    }
+    if (client_socket) {
+      std::vector<uint8_t> data;
+      size_t max_receive_size = 1024;
+      if (client_socket->receive(data, max_receive_size)) {
+        fmt::print("Server received: {}\n", data);
+      }
+    }
+    {
+      std::unique_lock<std::mutex> lock(m);
+      cv.wait_for(lock, 10ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+
+  auto server_task_config = espp::Task::Config{
+      .callback = server_task_fn,
+      .task_config =
+          {
+              .name = "TcpServer",
+              .stack_size_bytes = 6 * 1024,
+          },
+  };
+  auto server_task = espp::Task::make_unique(server_task_config);
+  server_task->start();
+
+
+
+
+

TCP Client Response Example

+
  espp::TcpSocket client_socket({.log_level = espp::Logger::Verbosity::WARN});
+  client_socket.connect({
+      .ip_address = server_address,
+      .port = port,
+  });
+  // create threads
+  auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) {
+    static size_t iterations = 0;
+    std::vector<uint8_t> data{0, 1, 2, 3, 4};
+    std::transform(data.begin(), data.end(), data.begin(),
+                   [](const auto &d) { return d + iterations; });
+    auto transmit_config = espp::TcpSocket::TransmitConfig{
+        .wait_for_response = true,
+        .response_size = 128,
+        .on_response_callback =
+            [](auto &response) { fmt::print("Client received: {}\n", response); },
+    };
+    // NOTE: now this call blocks until the response is received
+    client_socket.transmit(data, transmit_config);
+    iterations++;
+    std::this_thread::sleep_for(1s);
+    // don't want to stop the task
+    return false;
+  };
+  auto client_task = espp::Task::make_unique(
+      {.callback = client_task_fn,
+       .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}});
+  client_task->start();
+
+
+
+
+

TCP Server Response Example

+
  std::string server_address = "127.0.0.1";
+  size_t port = 5000;
+  int max_connections = 1;
+  espp::TcpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN});
+  server_socket.bind(port);
+  server_socket.listen(max_connections);
+  auto server_task_fn = [&server_socket](auto &m, auto &cv) -> bool {
+    static std::unique_ptr<espp::TcpSocket> client_socket;
+    if (!client_socket) {
+      client_socket = server_socket.accept();
+      if (client_socket) {
+        auto info = client_socket->get_remote_info();
+        fmt::print("Server accepted connection from: {}\n", info);
+      }
+    }
+    if (client_socket) {
+      std::vector<uint8_t> data;
+      size_t max_receive_size = 1024;
+      if (client_socket->receive(data, max_receive_size)) {
+        fmt::print("Server received: {}\n", data);
+        // reverse the data
+        std::reverse(data.begin(), data.end());
+        // and send it back
+        client_socket->transmit(data);
+      }
+    }
+    {
+      std::unique_lock<std::mutex> lock(m);
+      cv.wait_for(lock, 10ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+
+  auto server_task_config = espp::Task::Config{
+      .callback = server_task_fn,
+      .task_config =
+          {
+              .name = "TcpServer",
+              .stack_size_bytes = 6 * 1024,
+          },
+  };
+  auto server_task = espp::Task::make_unique(server_task_config);
+  server_task->start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<std::optional<std::vector<uint8_t>>(std::vector<uint8_t> &data, const Info &sender_info)> receive_callback_fn
+

Callback function to be called when receiving data from a client.

+
+
Param data
+

Byte array of data received from client

+
+
Param sender_info
+

Sender information (address, port)

+
+
Return
+

std::optional<std::vector<uint8_t>> optional data to return to sender.

+
+
+
+ +
+
+typedef std::function<void(std::vector<uint8_t> &data)> response_callback_fn
+

Callback function to be called with data returned after transmitting data to a server.

+
+
Param data
+

The data that the server responded with

+
+
+
+ +
+
+

Public Functions

+
+
+explicit TcpSocket(const espp::TcpSocket::Config &config)
+

Initialize the socket and associated resources.

+
+

Note

+

Enables keepalive on the socket.

+
+
+
Parameters
+

configConfig for the socket.

+
+
+
+ +
+
+~TcpSocket()
+

Tear down any resources associted with the socket.

+
+ +
+
+void reinit()
+

Reinitialize the socket, cleaning it up if first it is already initalized.

+
+ +
+
+void close()
+

Close the socket.

+
+ +
+
+bool is_connected() const
+

Check if the socket is connected to a remote endpoint.

+
+
Returns
+

true if the socket is connected to a remote endpoint.

+
+
+
+ +
+
+bool connect(const espp::TcpSocket::ConnectConfig &connect_config)
+

Open a connection to the remote TCP server.

+
+
Parameters
+

connect_configConnectConfig struct describing the server endpoint.

+
+
Returns
+

true if the client successfully connected to the server.

+
+
+
+ +
+
+const espp::Socket::Info &get_remote_info() const
+

Get the remote endpoint info.

+
+
Returns
+

The remote endpoint info.

+
+
+
+ +
+
+bool transmit(const std::vector<uint8_t> &data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
+

Send data to the endpoint already connected to by TcpSocket::connect. Can be configured to block waiting for a response from the remote.

+

If response is requested, a callback can be provided in send_config which will be provided the response data for processing.

+
+
Parameters
+
    +
  • data – vector of bytes to send to the remote endpoint.

  • +
  • transmit_configTransmitConfig struct indicating whether to wait for a response.

  • +
+
+
Returns
+

true if the data was sent, false otherwise.

+
+
+
+ +
+
+bool transmit(const std::vector<char> &data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
+

Send data to the endpoint already connected to by TcpSocket::connect. Can be configured to block waiting for a response from the remote.

+

If response is requested, a callback can be provided in send_config which will be provided the response data for processing.

+
+
Parameters
+
    +
  • data – vector of bytes to send to the remote endpoint.

  • +
  • transmit_configTransmitConfig struct indicating whether to wait for a response.

  • +
+
+
Returns
+

true if the data was sent, false otherwise.

+
+
+
+ +
+
+bool transmit(std::string_view data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
+

Send data to the endpoint already connected to by TcpSocket::connect. Can be configured to block waiting for a response from the remote.

+

If response is requested, a callback can be provided in send_config which will be provided the response data for processing.

+
+
Parameters
+
    +
  • data – string view of bytes to send to the remote endpoint.

  • +
  • transmit_configTransmitConfig struct indicating whether to wait for a response.

  • +
+
+
Returns
+

true if the data was sent, false otherwise.

+
+
+
+ +
+
+bool receive(std::vector<uint8_t> &data, size_t max_num_bytes)
+

Call read on the socket, assuming it has already been configured appropriately.

+
+
Parameters
+
    +
  • data – Vector of bytes of received data.

  • +
  • max_num_bytes – Maximum number of bytes to receive.

  • +
+
+
Returns
+

true if successfully received, false otherwise.

+
+
+
+ +
+
+size_t receive(uint8_t *data, size_t max_num_bytes)
+

Call read on the socket, assuming it has already been configured appropriately.

+
+

Note

+

This function will block until max_num_bytes are received or the receive timeout is reached.

+
+
+

Note

+

The data pointed to by data must be at least max_num_bytes in size.

+
+
+
Parameters
+
    +
  • data – Pointer to buffer to receive data.

  • +
  • max_num_bytes – Maximum number of bytes to receive.

  • +
+
+
Returns
+

Number of bytes received.

+
+
+
+ +
+
+bool bind(int port)
+

Bind the socket as a server on port.

+
+
Parameters
+

port – The port to which to bind the socket.

+
+
Returns
+

true if the socket was bound.

+
+
+
+ +
+
+bool listen(int max_pending_connections)
+

Listen for incoming client connections.

+

+

See also

+

bind

+
+
+

See also

+

accept

+
+

+
+

Note

+

Must be called after bind and before accept.

+
+
+
Parameters
+

max_pending_connections – Max number of allowed pending connections.

+
+
Returns
+

True if socket was able to start listening.

+
+
+
+ +
+
+std::unique_ptr<espp::TcpSocket> accept()
+

Accept an incoming connection.

+
+

Note

+

Blocks until a connection is accepted.

+
+
+

Note

+

Must be called after listen.

+
+
+

Note

+

This function will block until a connection is accepted.

+
+
+
Returns
+

A unique pointer to a TcpClientSession if a connection was accepted, nullptr otherwise.

+
+
+
+ +
+
+bool is_valid() const
+

Is the socket valid.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+std::optional<Info> get_ipv4_info()
+

Get the Socket::Info for the socket.

+

This will call getsockname() on the socket to get the sockaddr_storage structure, and then fill out the Socket::Info structure.

+
+
Returns
+

Socket::Info for the socket.

+
+
+
+ +
+
+bool set_receive_timeout(const std::chrono::duration<float> &timeout)
+

Set the receive timeout on the provided socket.

+
+
Parameters
+

timeout – requested timeout, must be > 0.

+
+
Returns
+

true if SO_RECVTIMEO was successfully set.

+
+
+
+ +
+
+bool enable_reuse()
+

Allow others to use this address/port combination after we’re done with it.

+
+
Returns
+

true if SO_REUSEADDR and SO_REUSEPORT were successfully set.

+
+
+
+ +
+
+bool make_multicast(uint8_t time_to_live = 1, uint8_t loopback_enabled = true)
+

Configure the socket to be multicast (if time_to_live > 0). Sets the IP_MULTICAST_TTL (number of multicast hops allowed) and optionally configures whether this node should receive its own multicast packets (IP_MULTICAST_LOOP).

+
+
Parameters
+
    +
  • time_to_live – number of multicast hops allowed (TTL).

  • +
  • loopback_enabled – Whether to receive our own multicast packets.

  • +
+
+
Returns
+

true if IP_MULTICAST_TTL and IP_MULTICAST_LOOP were set.

+
+
+
+ +
+
+bool add_multicast_group(const std::string &multicast_group)
+

If this is a server socket, add it to the provided the multicast group.

+

+See https://en.wikipedia.org/wiki/Multicast_address for more information.

+
+

Note

+

Multicast groups must be Class D addresses (224.0.0.0 to 239.255.255.255)

+
+
+
Parameters
+

multicast_group – multicast group to join.

+
+
Returns
+

true if IP_ADD_MEMBERSHIP was successfully set.

+
+
+
+ +
+
+int select(const std::chrono::microseconds &timeout)
+

Select on the socket for read events.

+
+
Parameters
+

timeout – how long to wait for an event.

+
+
Returns
+

number of events that occurred.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static bool is_valid_fd(sock_type_t socket_fd)
+

Is the socket valid.

+
+
Parameters
+

socket_fdSocket file descriptor.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+
+struct Config
+

Config struct for the TCP socket.

+
+

Public Members

+
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity level for the TCP socket logger.

+
+ +
+
+ +
+
+struct ConnectConfig
+

Config struct for connecting to a remote TCP server.

+
+

Public Members

+
+
+std::string ip_address
+

Address to send data to.

+
+ +
+
+size_t port
+

Port number to send data to.

+
+ +
+
+ +
+
+struct TransmitConfig
+

Config struct for sending data to a remote TCP socket.

+
+

Note

+

This is only used when waiting for a response from the remote.

+
+
+

Public Members

+
+
+bool wait_for_response = false
+

Whether to wait for a response from the remote or not.

+
+ +
+
+size_t response_size = 0
+

If waiting for a response, this is the maximum size response we will receive.

+
+ +
+
+espp::Socket::response_callback_fn on_response_callback = nullptr
+

If waiting for a response, this is an optional handler which is provided the response data.

+
+ +
+
+std::chrono::duration<float> response_timeout = std::chrono::duration<float>(0.5f)
+

If waiting for a response, this is the maximum timeout to wait.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/network/udp_socket.html b/network/udp_socket.html new file mode 100644 index 000000000..e9ee534fb --- /dev/null +++ b/network/udp_socket.html @@ -0,0 +1,880 @@ + + + + + + + UDP Sockets - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

UDP Sockets

+

UDP sockets provide unreliable, unordered communication over IP network sockets.

+

UDP sockets can be used in unicast (point to point), multicast (one to many and +many to one), and broadcast (one to all).

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class UdpSocket : public espp::Socket
+

Class for managing sending and receiving data using UDP/IP. Can be used to create client or server sockets.

+

See https://github.com/espressif/esp-idf/tree/master/examples/protocols/sockets/udp_multicast for more information on udp multicast sockets.

+
+

UDP Client Example

+
espp::UdpSocket client_socket({});
+// create thread for sending data using the socket
+auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) {
+  static size_t iterations = 0;
+  std::vector<uint8_t> data{0, 1, 2, 3, 4};
+  std::transform(data.begin(), data.end(), data.begin(),
+                 [](const auto &d) { return d + iterations; });
+  auto send_config = espp::UdpSocket::SendConfig{.ip_address = server_address, .port = port};
+  client_socket.send(data, send_config);
+  iterations++;
+  std::this_thread::sleep_for(1s);
+  // don't want to stop the task
+  return false;
+};
+auto client_task =
+    espp::Task::make_unique({.callback = client_task_fn,
+                             .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}});
+client_task->start();
+
+
+
+
+

UDP Server Example

+
    std::string server_address = "127.0.0.1";
+    size_t port = 5000;
+    espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN});
+    auto server_task_config = espp::Task::BaseConfig{
+        .name = "UdpServer",
+        .stack_size_bytes = 6 * 1024,
+    };
+    auto server_config = espp::UdpSocket::ReceiveConfig{
+        .port = port,
+        .buffer_size = 1024,
+        .on_receive_callback =
+            [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n"
+                                                            "    from source: {}\n",
+                                                            data, source);
+    return std::nullopt;
+  }
+};
+server_socket.start_receiving(server_task_config, server_config);
+
+
+
+
+

UDP Client Response Example

+
espp::UdpSocket client_socket({.log_level = espp::Logger::Verbosity::WARN});
+// create threads
+auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) {
+  static size_t iterations = 0;
+  std::vector<uint8_t> data{0, 1, 2, 3, 4};
+  std::transform(data.begin(), data.end(), data.begin(),
+                 [](const auto &d) { return d + iterations; });
+  auto send_config = espp::UdpSocket::SendConfig{
+      .ip_address = server_address,
+      .port = port,
+      .wait_for_response = true,
+      .response_size = 128,
+      .on_response_callback = [](auto &response) { fmt::print("Client received: {}\n", response); },
+  };
+  // NOTE: now this call blocks until the response is received
+  client_socket.send(data, send_config);
+  iterations++;
+  std::this_thread::sleep_for(1s);
+  // don't want to stop the task
+  return false;
+};
+auto client_task =
+    espp::Task::make_unique({.callback = client_task_fn,
+                             .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}});
+client_task->start();
+
+
+
+
+

UDP Server Response Example

+
  std::string server_address = "127.0.0.1";
+  size_t port = 5000;
+  espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN});
+  auto server_task_config =
+      espp::Task::BaseConfig{.name = "UdpServer", .stack_size_bytes = 6 * 1024};
+  auto server_config = espp::UdpSocket::ReceiveConfig{
+      .port = port,
+      .buffer_size = 1024,
+      .on_receive_callback =
+          [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n"
+                                                          "    from source: {}\n",
+                                                          data, source);
+  // reverse the data
+  std::reverse(data.begin(), data.end());
+  // and send it back
+  return data;
+}
+}
+;
+server_socket.start_receiving(server_task_config, server_config);
+
+
+
+
+

UDP Multicast Client Example

+
espp::UdpSocket client_socket({});
+// create threads
+auto client_task_fn = [&client_socket, &port, &multicast_group](auto &, auto &) {
+  static size_t iterations = 0;
+  std::vector<uint8_t> data{0, 1, 2, 3, 4};
+  std::transform(data.begin(), data.end(), data.begin(),
+                 [](const auto &d) { return d + iterations; });
+  auto send_config = espp::UdpSocket::SendConfig{.ip_address = multicast_group,
+                                                 .port = port,
+                                                 .is_multicast_endpoint = true,
+                                                 .wait_for_response = true,
+                                                 .response_size = 128,
+                                                 .on_response_callback = [](auto &response) {
+                                                   fmt::print("Client received: {}\n", response);
+                                                 }};
+  // NOTE: now this call blocks until the response is received
+  client_socket.send(data, send_config);
+  iterations++;
+  std::this_thread::sleep_for(1s);
+  // don't want to stop the task
+  return false;
+};
+auto client_task =
+    espp::Task::make_unique({.callback = client_task_fn,
+                             .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}});
+client_task->start();
+
+
+
+
+

UDP Multicast Server Example

+
  std::string multicast_group = "239.1.1.1";
+  size_t port = 5000;
+  espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN});
+  auto server_task_config = espp::Task::BaseConfig{
+      .name = "UdpServer",
+      .stack_size_bytes = 6 * 1024,
+  };
+  auto server_config = espp::UdpSocket::ReceiveConfig{
+      .port = port,
+      .buffer_size = 1024,
+      .is_multicast_endpoint = true,
+      .multicast_group = multicast_group,
+      .on_receive_callback =
+          [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n"
+                                                          "    from source: {}\n",
+                                                          data, source);
+  // reverse the data
+  std::reverse(data.begin(), data.end());
+  // and send it back
+  return data;
+}
+}
+;
+server_socket.start_receiving(server_task_config, server_config);
+
+
+
+
+

Public Types

+
+
+typedef std::function<std::optional<std::vector<uint8_t>>(std::vector<uint8_t> &data, const Info &sender_info)> receive_callback_fn
+

Callback function to be called when receiving data from a client.

+
+
Param data
+

Byte array of data received from client

+
+
Param sender_info
+

Sender information (address, port)

+
+
Return
+

std::optional<std::vector<uint8_t>> optional data to return to sender.

+
+
+
+ +
+
+typedef std::function<void(std::vector<uint8_t> &data)> response_callback_fn
+

Callback function to be called with data returned after transmitting data to a server.

+
+
Param data
+

The data that the server responded with

+
+
+
+ +
+
+

Public Functions

+
+
+explicit UdpSocket(const Config &config)
+

Initialize the socket and associated resources.

+
+
Parameters
+

configConfig for the socket.

+
+
+
+ +
+
+~UdpSocket()
+

Tear down any resources associted with the socket.

+
+ +
+
+bool send(const std::vector<uint8_t> &data, const SendConfig &send_config)
+

Send data to the endpoint specified by the send_config. Can be configured to multicast (within send_config) and can be configured to block waiting for a response from the remote.

+

+If response is requested, a callback can be provided in send_config which will be provided the response data for processing.

+
+

Note

+

in the case of multicast, it will block only until the first response.

+
+
+
Parameters
+
    +
  • data – vector of bytes to send to the remote endpoint.

  • +
  • send_configSendConfig struct indicating where to send and whether to wait for a response.

  • +
+
+
Returns
+

true if the data was sent, false otherwise.

+
+
+
+ +
+
+bool send(std::string_view data, const SendConfig &send_config)
+

Send data to the endpoint specified by the send_config. Can be configured to multicast (within send_config) and can be configured to block waiting for a response from the remote.

+

+If response is requested, a callback can be provided in send_config which will be provided the response data for processing.

+
+

Note

+

in the case of multicast, it will block only until the first response.

+
+
+
Parameters
+
    +
  • data – String view of bytes to send to the remote endpoint.

  • +
  • send_configSendConfig struct indicating where to send and whether to wait for a response.

  • +
+
+
Returns
+

true if the data was sent, false otherwise.

+
+
+
+ +
+
+bool receive(size_t max_num_bytes, std::vector<uint8_t> &data, Socket::Info &remote_info)
+

Call recvfrom on the socket, assuming it has already been configured appropriately.

+
+
Parameters
+
    +
  • max_num_bytes – Maximum number of bytes to receive.

  • +
  • data – Vector of bytes of received data.

  • +
  • remote_infoSocket::Info containing the sender’s information. This will be populated with the information about the sender.

  • +
+
+
Returns
+

true if successfully received, false otherwise.

+
+
+
+ +
+
+bool start_receiving(Task::BaseConfig &task_config, const ReceiveConfig &receive_config)
+

Configure a server socket and start a thread to continuously receive and handle data coming in on that socket.

+
+
Parameters
+
    +
  • task_configTask::BaseConfig struct for configuring the receive task.

  • +
  • receive_configReceiveConfig struct with socket and callback info.

  • +
+
+
Returns
+

true if the socket was created and task was started, false otherwise.

+
+
+
+ +
+
+bool is_valid() const
+

Is the socket valid.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+std::optional<Info> get_ipv4_info()
+

Get the Socket::Info for the socket.

+

This will call getsockname() on the socket to get the sockaddr_storage structure, and then fill out the Socket::Info structure.

+
+
Returns
+

Socket::Info for the socket.

+
+
+
+ +
+
+bool set_receive_timeout(const std::chrono::duration<float> &timeout)
+

Set the receive timeout on the provided socket.

+
+
Parameters
+

timeout – requested timeout, must be > 0.

+
+
Returns
+

true if SO_RECVTIMEO was successfully set.

+
+
+
+ +
+
+bool enable_reuse()
+

Allow others to use this address/port combination after we’re done with it.

+
+
Returns
+

true if SO_REUSEADDR and SO_REUSEPORT were successfully set.

+
+
+
+ +
+
+bool make_multicast(uint8_t time_to_live = 1, uint8_t loopback_enabled = true)
+

Configure the socket to be multicast (if time_to_live > 0). Sets the IP_MULTICAST_TTL (number of multicast hops allowed) and optionally configures whether this node should receive its own multicast packets (IP_MULTICAST_LOOP).

+
+
Parameters
+
    +
  • time_to_live – number of multicast hops allowed (TTL).

  • +
  • loopback_enabled – Whether to receive our own multicast packets.

  • +
+
+
Returns
+

true if IP_MULTICAST_TTL and IP_MULTICAST_LOOP were set.

+
+
+
+ +
+
+bool add_multicast_group(const std::string &multicast_group)
+

If this is a server socket, add it to the provided the multicast group.

+

+See https://en.wikipedia.org/wiki/Multicast_address for more information.

+
+

Note

+

Multicast groups must be Class D addresses (224.0.0.0 to 239.255.255.255)

+
+
+
Parameters
+

multicast_group – multicast group to join.

+
+
Returns
+

true if IP_ADD_MEMBERSHIP was successfully set.

+
+
+
+ +
+
+int select(const std::chrono::microseconds &timeout)
+

Select on the socket for read events.

+
+
Parameters
+

timeout – how long to wait for an event.

+
+
Returns
+

number of events that occurred.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static bool is_valid_fd(sock_type_t socket_fd)
+

Is the socket valid.

+
+
Parameters
+

socket_fdSocket file descriptor.

+
+
Returns
+

true if the socket file descriptor is >= 0.

+
+
+
+ +
+
+
+struct Config
+
+

Public Members

+
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity level for the UDP socket logger.

+
+ +
+
+ +
+
+struct ReceiveConfig
+
+

Public Members

+
+
+size_t port
+

Port number to bind to / receive from.

+
+ +
+
+size_t buffer_size
+

Max size of data we can receive at one time.

+
+ +
+
+bool is_multicast_endpoint = {false}
+

Whether this should be a multicast endpoint.

+
+ +
+
+std::string multicast_group{""}
+

If this is a multicast endpoint, this is the group it belongs to.

+
+ +
+
+espp::Socket::receive_callback_fn on_receive_callback{nullptr}
+

Function containing business logic to handle data received.

+
+ +
+
+ +
+
+struct SendConfig
+
+

Public Members

+
+
+std::string ip_address
+

Address to send data to.

+
+ +
+
+size_t port
+

Port number to send data to.

+
+ +
+
+bool is_multicast_endpoint = {false}
+

Whether this should be a multicast endpoint.

+
+ +
+
+bool wait_for_response = {false}
+

Whether to wait for a response from the remote or not.

+
+ +
+
+size_t response_size{0}
+

If waiting for a response, this is the maximum size response we will receive.

+
+ +
+
+espp::Socket::response_callback_fn on_response_callback{nullptr}
+

If waiting for a response, this is an optional handler which is provided the response data.

+
+ +
+
+std::chrono::duration<float> response_timeout = std::chrono::duration<float>(0.5f)
+

If waiting for a response, this is the maximum timeout to wait.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/nfc/index.html b/nfc/index.html new file mode 100644 index 000000000..a2236e8e6 --- /dev/null +++ b/nfc/index.html @@ -0,0 +1,206 @@ + + + + + + + NFC APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nfc/ndef.html b/nfc/ndef.html new file mode 100644 index 000000000..4e2d1d375 --- /dev/null +++ b/nfc/ndef.html @@ -0,0 +1,1270 @@ + + + + + + + NDEF - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

NDEF

+

The NDEF component provides a utility class for dealing with NFC Data Exchange +Format (NDEF) records, which are used by NFC Tags.

+
+

API Reference

+
+

Header File

+ +
+
+

Unions

+
+
+espp::Ndef::Flags.__unnamed7__
+
+

Public Members

+
+
+struct espp::Ndef::Flags
+
+ +
+
+uint8_t raw
+
+ +
+
+ +
+
+

Classes

+
+
+class Ndef
+

implements serialization & deserialization logic for NFC Data Exchange Format (NDEF) records which can be stored on and transmitted from NFC devices.

+

NDEF records can be composed the following way:

Bit 7     6       5       4       3       2       1       0
+------  ------  ------  ------  ------  ------  ------  ------
+[ MB ]  [ ME ]  [ CF ]  [ SR ]  [ IL ]  [        TNF         ]
+[                         TYPE LENGTH  (may be 0)            ]
+[                       PAYLOAD LENGTH (1B or 4B, see SR)    ]
+[                          ID LENGTH   (if IL)               ]
+[                         RECORD TYPE  (if TYPE LENGTH > 0)  ]
+[                              ID      (if IL)               ]
+[                           PAYLOAD    (payload length bytes)]
+
+
+

+

The first byte (Flags) has these bits:

    +
  • Bits 0-3: TNF - Type Name Format - describes record type (see TNF class)

  • +
  • Bit 3: IL - ID Length - indicates if the ID Length Field is present or not

  • +
  • Bit 4: SR - Short Record - set to 1 if the payload length field is 1 byte (8 bits / 0-255) or less, otherwise the payload length is 4 bytes

  • +
  • Bit 5: CF - Chunk Flag - indicates if this is the first record chunk or a middle record chunk, set to 0 for the first record of the message and for subsequent records set to 1.

  • +
  • Bit 6: ME - Message End - 1 indicates if this is the last record in the message

  • +
  • Bit 7: MB - Message Begin - 1 indicates if this is the first record in the message

  • +
+

+ +
+

Public Types

+
+
+enum class TNF : uint8_t
+

Type Name Format (TNF) field is a 3-bit value that describes the record type.

+

Some Common TNF::WELL_KNOWN record type strings:

    +
  • Text (T)

  • +
  • URI (U)

  • +
  • Smart Poster (Sp)

  • +
  • Alternative Carrier (ac)

  • +
  • Handover Carrier (Hc)

  • +
  • Handover Request (Hr)

  • +
  • Handover Select (Hs)

  • +
+

+

Values:

+
+
+enumerator EMPTY
+

Record is empty.

+
+ +
+
+enumerator WELL_KNOWN
+

Type field contains a well-known RTD type name.

+
+ +
+
+enumerator MIME_MEDIA
+

Type field contains a media type (RFC 2046)

+
+ +
+
+enumerator ABSOLUTE_URI
+

Type field contains an absolute URI (RFC 3986)

+
+ +
+
+enumerator EXTERNAL_TYPE
+

Type field Contains an external type name.

+
+ +
+
+enumerator UNKNOWN
+

Payload type is unknown, type length must be 0.

+
+ +
+
+enumerator UNCHANGED
+

Indicates the payload is an intermediate or final chunk of a chunked NDEF record, type length must be 0.

+
+ +
+
+enumerator RESERVED
+

Reserved by the NFC forum for future use.

+
+ +
+ +
+
+enum class Uic
+

URI Identifier Codes (UIC), See Table A-3 at https://www.oreilly.com/library/view/beginning-nfc/9781449324094/apa.html and https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef

+

Values:

+
+
+enumerator NONE
+

Exactly as written.

+
+ +
+
+enumerator HTTP_WWW
+

http://www.

+
+ +
+
+enumerator HTTPS_WWW
+

https://www.

+
+ +
+
+enumerator HTTP
+

http://

+
+ +
+
+enumerator HTTPS
+

https://

+
+ +
+
+enumerator TEL
+

tel:

+
+ +
+
+enumerator MAILTO
+

mailto:

+
+ +
+
+enumerator FTP_ANON
+

ftp://anonymous:anonymous@

+
+ +
+
+enumerator FTP_FTP
+

ftp://ftp.

+
+ +
+
+enumerator FTPS
+

ftps://

+
+ +
+
+enumerator SFTP
+

sftp://

+
+ +
+
+enumerator SMB
+

smb://

+
+ +
+
+enumerator NFS
+

nfs://

+
+ +
+
+enumerator FTP
+

ftp://

+
+ +
+
+enumerator DAV
+

dav://

+
+ +
+
+enumerator NEWS
+

news:

+
+ +
+
+enumerator TELNET
+

telnet://

+
+ +
+
+enumerator IMAP
+

imap:

+
+ +
+
+enumerator RSTP
+

rtsp://

+
+ +
+
+enumerator URN
+

urn:

+
+ +
+
+enumerator POP
+

pop:

+
+ +
+
+enumerator SIP
+

sip:

+
+ +
+
+enumerator SIPS
+

sips:

+
+ +
+
+enumerator TFTP
+

tftp:

+
+ +
+
+enumerator BTSPP
+

btspp://

+
+ +
+
+enumerator BTL2CAP
+

btl2cap://

+
+ +
+
+enumerator BTGOEP
+

btgoep://

+
+ +
+
+enumerator TCPOBEX
+

tcpobex://

+
+ +
+
+enumerator IRDAOBEX
+

irdaobex://

+
+ +
+
+enumerator FILE
+

file://

+
+ +
+
+enumerator URN_EPC_ID
+

urn:epc:id:

+
+ +
+
+enumerator URN_EPC_TAG
+

urn:epc:tag:

+
+ +
+
+enumerator URN_EPC_PAT
+

urn:epc:pat:

+
+ +
+
+enumerator URN_EPC_RAW
+

urn:epc:raw:

+
+ +
+
+enumerator URN_EPC
+

urn:epc:

+
+ +
+
+enumerator URN_NFC
+

urn:nfc:

+
+ +
+ +
+
+enum class BtType
+

Type of Bluetooth radios.

+

Values:

+
+
+enumerator BREDR
+

BT Classic.

+
+ +
+
+enumerator BLE
+

BT Low Energy.

+
+ +
+ +
+
+enum class BtAppearance : uint16_t
+

Some appearance codes for BLE radios.

+

Values:

+
+
+enumerator UNKNOWN
+

Generic Unknown.

+
+ +
+
+enumerator PHONE
+

Generic Phone.

+
+ +
+
+enumerator COMPUTER
+

Generic Computer.

+
+ +
+
+enumerator WATCH
+

Generic Watch.

+
+ +
+
+enumerator CLOCK
+

Generic Clock.

+
+ +
+
+enumerator DISPLAY
+

Generic Display.

+
+ +
+
+enumerator REMOTE_CONTROL
+

Generic Remote Control.

+
+ +
+
+enumerator GENERIC_HID
+

Generic HID.

+
+ +
+
+enumerator KEYBOARD
+

HID Keyboard.

+
+ +
+
+enumerator MOUSE
+

HID Mouse.

+
+ +
+
+enumerator JOYSTICK
+

HID Joystick.

+
+ +
+
+enumerator GAMEPAD
+

HID Gamepad.

+
+ +
+
+enumerator TOUCHPAD
+

HID Touchpad.

+
+ +
+
+enumerator GAMING
+

Generic Gaming group.

+
+ +
+ +
+
+enum class CarrierPowerState
+

Power state of a BLE radio.

+

Representation of the carrier power state in a Handover Select message.

+

Values:

+
+
+enumerator INACTIVE
+

Carrier power is off.

+
+ +
+
+enumerator ACTIVE
+

Carrier power is on.

+
+ +
+
+enumerator ACTIVATING
+

Carrier power is turning on.

+
+ +
+
+enumerator UNKNOWN
+

Carrier power state is unknown.

+
+ +
+ +
+
+enum class BtEir
+

Extended Inquiry Response (EIR) codes for data types in BT and BLE out of band (OOB) pairing NDEF records.

+

Values:

+
+
+enumerator FLAGS
+

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

+
+ +
+
+enumerator UUIDS_16_BIT_PARTIAL
+

Incomplete list of 16 bit service class UUIDs.

+
+ +
+
+enumerator UUIDS_16_BIT_COMPLETE
+

Complete list of 16 bit service class UUIDs.

+
+ +
+
+enumerator UUIDS_32_BIT_PARTIAL
+

Incomplete list of 32 bit service class UUIDs.

+
+ +
+
+enumerator UUIDS_32_BIT_COMPLETE
+

Complete list of 32 bit service class UUIDs.

+
+ +
+
+enumerator UUIDS_128_BIT_PARTIAL
+

Incomplete list of 128 bit service class UUIDs.

+
+ +
+
+enumerator UUIDS_128_BIT_COMPLETE
+

Complete list of 128 bit service class UUIDs.

+
+ +
+
+enumerator SHORT_LOCAL_NAME
+

Shortened Bluetooth Local Name.

+
+ +
+
+enumerator LONG_LOCAL_NAME
+

Complete Bluetooth Local Name.

+
+ +
+
+enumerator TX_POWER_LEVEL
+

TX Power level (1 byte), -127 dBm to +127 dBm.

+
+ +
+
+enumerator CLASS_OF_DEVICE
+

Class of Device.

+
+ +
+
+enumerator SP_HASH_C192
+

Simple Pairing Hash C-192.

+
+ +
+
+enumerator SP_RANDOM_R192
+

Simple Pairing Randomizer R-192.

+
+ +
+
+enumerator SECURITY_MANAGER_TK
+

Security Manager TK Value (LE Legacy Pairing)

+
+ +
+
+enumerator SECURITY_MANAGER_FLAGS
+

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)

+
+ +
+
+enumerator APPEARANCE
+

Appearance.

+
+ +
+
+enumerator MAC
+

Bluetooth Device Address.

+
+ +
+
+enumerator LE_ROLE
+

LE Role.

+
+ +
+
+enumerator SP_HASH_C256
+

Simple Pairing Hash C-256.

+
+ +
+
+enumerator SP_HASH_R256
+

Simple Pairing Randomizer R-256.

+
+ +
+
+enumerator LE_SC_CONFIRMATION
+

LE Secure Connections Confirmation Value.

+
+ +
+
+enumerator LE_SC_RANDOM
+

LE Secure Connections Random Value.

+
+ +
+ +
+
+enum class BleRole : uint8_t
+

Possible roles for BLE records to indicate support for.

+

Values:

+
+
+enumerator PERIPHERAL_ONLY
+

Radio can only act as a peripheral.

+
+ +
+
+enumerator CENTRAL_ONLY
+

Radio can only act as a central.

+
+ +
+
+enumerator PERIPHERAL_CENTRAL
+

Radio can act as both a peripheral and a central, but prefers peripheral.

+
+ +
+
+enumerator CENTRAL_PERIPHERAL
+

Radio can act as both a peripheral and a central, but prefers central.

+
+ +
+ +
+
+enum class WifiEncryptionType
+

Types of configurable encryption for WiFi networks.

+

Values:

+
+
+enumerator NONE
+

No encryption.

+
+ +
+
+enumerator WEP
+

WEP.

+
+ +
+
+enumerator TKIP
+

TKIP.

+
+ +
+
+enumerator AES
+

AES.

+
+ +
+ +
+
+enum class WifiAuthenticationType
+

WiFi network authentication.

+

Values:

+
+
+enumerator OPEN
+

Open / no security.

+
+ +
+
+enumerator WPA_PERSONAL
+

WPA personal.

+
+ +
+
+enumerator SHARED
+

Shared key.

+
+ +
+
+enumerator WPA_ENTERPRISE
+

WPA enterprise.

+
+ +
+
+enumerator WPA2_ENTERPRISE
+

WPA2 Enterprise.

+
+ +
+
+enumerator WPA2_PERSONAL
+

WPA2 personal.

+
+ +
+
+enumerator WPA_WPA2_PERSONAL
+

Both WPA and WPA2 personal.

+
+ +
+ +
+
+

Public Functions

+
+
+inline explicit Ndef(espp::Ndef::TNF tnf, std::string_view type, std::string_view payload)
+

Makes an NDEF record with header and payload.

+
+
Parameters
+
    +
  • tnf – The TNF for this packet.

  • +
  • type – String view for the type of this packet

  • +
  • payload – The payload data for the packet

  • +
+
+
+
+ +
+
+inline std::vector<uint8_t> serialize(bool message_begin = true, bool message_end = true)
+

Serialize the NDEF record into a sequence of bytes.

+
+
Parameters
+
    +
  • message_begin – True if this is the first record in the message.

  • +
  • message_end – True if this is the last record in the message.

  • +
+
+
Returns
+

The vector<uint8_t> of bytes representing the NDEF record.

+
+
+
+ +
+
+inline std::vector<uint8_t> payload()
+

Return just the payload as a vector of bytes.

+
+
Returns
+

Payload of the NDEF record as a vector of bytes.

+
+
+
+ +
+
+inline void set_id(int id)
+

Set the payload ID of the NDEF record.

+
+
Parameters
+

id – ID of the NDEF record.

+
+
+
+ +
+
+inline int get_id() const
+

Get the ID of the NDEF record.

+
+
Returns
+

ID of the NDEF record.

+
+
+
+ +
+
+inline int get_size() const
+

Get the number of bytes needed for the NDEF record.

+
+
Returns
+

Size of the NDEF record (bytes), for serialization.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline Ndef make_text(std::string_view text)
+

Static function to make an NDEF record for transmitting english text.

+
+
Parameters
+

text – The text that the NDEF record will hold.

+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_uri(std::string_view uri, espp::Ndef::Uic uic = espp::Ndef::Uic::NONE)
+

Static function to make an NDEF record for loading a URI.

+
+
Parameters
+
    +
  • uri – URI for the record to point to.

  • +
  • uic – UIC for the uri - helps shorten the uri text / NDEF record.

  • +
+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_android_launcher(std::string_view uri)
+

Static function to make an NDEF record for launching an Android App.

+
+
Parameters
+

uri – URI for the android package / app to launch.

+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_wifi_config(const espp::Ndef::WifiConfig &config)
+

Create a WiFi credential tag.

+
+
Parameters
+

configWifiConfig describing the WiFi network.

+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_handover_select(int carrier_data_ref)
+

Create a Handover Select record for a Bluetooth device.

+

+

+
+
Parameters
+

carrier_data_ref – Reference to the carrier data record, which is the record that contains the actual bluetooth data. This should be the same as the id of the carrier data record, such as ‘0’.

+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_handover_request(int carrier_data_ref)
+

Create a Handover request record for a Bluetooth device.

+

+

+
+
Parameters
+

carrier_data_ref – Reference to the carrier data record, which is the record that contains the actual bluetooth data. This should be the same as the id of the carrier data record, such as ‘0’.

+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_alternative_carrier(const CarrierPowerState &power_state, int carrier_data_ref)
+

Create a Handover Request record for a Bluetooth device.

+

See page 18 of https://core.ac.uk/download/pdf/250136576.pdf for more details.

+
+
Parameters
+
    +
  • power_state – Power state of the alternative carrier.

  • +
  • carrier_data_ref – Reference to the carrier data record, which is the record that contains the actual bluetooth data. This should be the same as the id of the carrier data record, such as ‘0’.

  • +
+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_oob_pairing(uint64_t mac_addr, uint32_t device_class, std::string_view name, std::string_view random_value = "", std::string_view confirm_value = "")
+

Static function to make an NDEF record for BT classic OOB Pairing (Android).

+
+

Note

+

If the address is e.g. f4:12:fa:42:fe:9e then the mac_addr should be 0xf412fa42fe9e.

+
+
+
Parameters
+
    +
  • mac_addr – 48 bit MAC Address of the BT radio

  • +
  • device_class – The bluetooth device class for this radio.

  • +
  • name – Name of the BT device.

  • +
  • random_value – The Simple pairing randomizer R for the pairing.

  • +
  • confirm_value – The Simple pairing hash C (confirm value) for the pairing.

  • +
+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+static inline Ndef make_le_oob_pairing(uint64_t mac_addr, espp::Ndef::BleRole role, std::string_view name = "", espp::Ndef::BtAppearance appearance = espp::Ndef::BtAppearance::UNKNOWN, std::string_view random_value = "", std::string_view confirm_value = "", std::string_view tk = "")
+

Static function to make an NDEF record for BLE OOB Pairing (Android).

+
+

Note

+

If the address is e.g. f4:12:fa:42:fe:9e then the mac_addr should be 0xf412fa42fe9e.

+
+
+
Parameters
+
    +
  • mac_addr – 48 bit MAC Address of the BLE radio.

  • +
  • role – The BLE role of the device (central / peripheral / dual)

  • +
  • name – Name of the BLE device. Optional.

  • +
  • appearance – BtAppearance of the device. Optional.

  • +
  • random_value – The Simple pairing randomizer R for the pairing. (16 bytes, optional)

  • +
  • confirm_value – The Simple pairing hash C (confirm value) for the pairing. (16 bytes, optional)

  • +
  • tk – Temporary key for the pairing (16 bytes, optional)

  • +
+
+
Returns
+

NDEF record object.

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t HANDOVER_VERSION = 0x13
+

Connection Handover version 1.3.

+
+ +
+
+
+Flags.__unnamed7__
+
+ +
+
+Flags.__unnamed7__.__unnamed9__
+
+ +
+
+struct WifiConfig
+

Configuration structure for wifi configuration ndef structure.

+
+

Public Members

+
+
+std::string_view ssid
+

SSID for the network.

+
+ +
+
+std::string_view key
+

Security key / password for the network.

+
+ +
+
+espp::Ndef::WifiAuthenticationType authentication = espp::Ndef::WifiAuthenticationType::WPA2_PERSONAL
+

Authentication type the network uses.

+
+ +
+
+espp::Ndef::WifiEncryptionType encryption = espp::Ndef::WifiEncryptionType::AES
+

Encryption type the network uses.

+
+ +
+
+uint64_t mac_address = 0xFFFFFFFFFFFF
+

Broadcast MAC address FF:FF:FF:FF:FF:FF.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/nfc/st25dv.html b/nfc/st25dv.html new file mode 100644 index 000000000..081c3df52 --- /dev/null +++ b/nfc/st25dv.html @@ -0,0 +1,1119 @@ + + + + + + + ST25DV - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ST25DV

+

The St25dv provides a utility class for NFC communications using the ST25DV +Dynamic NFC / RFID tag. The tag includes 4Kb, 16Kb, or 64Kb EEPROM along with +support for fast transfer mode - which enables bi-directional communications +with other NFC/RFID enabled devices such as phones. This chip stores in its +EEPROM NFC T5T tag records - which include a CC header (that this class +maintains) followed by serialized NDEF records.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Functions

+
+

Warning

+

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. +Potential matches: +

+
- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
+- bool operator==(const Config &rhs) const = default
+- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
+- bool operator==(const Hsv &rhs) const = default
+- bool operator==(const PinConfig &rhs) const = default
+- bool operator==(const PointerData &rhs) const = default
+- bool operator==(const Rgb &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const Vector2d &other) const
+- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
+- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
+- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
+- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
+- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)
+
+
+
+
+
+

Unions

+
+
+espp::St25dv::IT_STS.__unnamed15__
+
+

Public Members

+
+
+struct espp::St25dv::IT_STS
+
+ +
+
+uint8_t raw
+
+ +
+
+ +
+
+

Classes

+
+
+class St25dv : public espp::BasePeripheral<uint16_t>
+

Class for wireless communications using a ST25DV Dynamic NFC/RFID tag. The datasheet for the ST25DV can be found here: https://www.st.com/resource/en/datasheet/st25dv04k.pdf.

+
+

St25dv Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .clk_speed = 1000 * 1000,
+    });
+
+    // now make the st25dv which decodes the data
+    espp::St25dv st25dv({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+                                            std::placeholders::_2, std::placeholders::_3),
+                         .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+                                           std::placeholders::_2, std::placeholders::_3),
+                         .log_level = espp::Logger::Verbosity::INFO});
+
+    std::array<uint8_t, 50> programmed_data;
+    std::error_code ec;
+    st25dv.read(programmed_data.data(), programmed_data.size(), ec);
+    if (ec) {
+      fmt::print("Failed to read st25dv: {}\n", ec.message());
+      return;
+    }
+    fmt::print("Read: {}\n", programmed_data);
+
+    std::vector<espp::Ndef> records;
+
+    // create some sample records
+    int payload_id = '0';
+
+    records.emplace_back(espp::Ndef::make_handover_select(payload_id));
+    records.emplace_back(espp::Ndef::make_text("hello!"));
+    records.emplace_back(espp::Ndef::make_uri("github.com/esp-cpp/espp", espp::Ndef::Uic::HTTPS));
+    records.emplace_back(espp::Ndef::make_android_launcher("com.google.android.apps.photos"));
+    records.emplace_back(espp::Ndef::make_wifi_config({
+        .ssid = CONFIG_ESP_WIFI_SSID,
+        .key = CONFIG_ESP_WIFI_PASSWORD,
+    }));
+
+    // create BLE OOB pairing record
+    uint64_t radio_mac_addr = 0x060504030201; // 48b, example address 06:05:04:03:02:01
+#if CONFIG_BT_BLE_ENABLED
+    // get the mac address of the radio
+    init_low_level(HID_DEV_MODE);
+    const uint8_t *point = esp_bt_dev_get_address();
+    if (point == nullptr) {
+      fmt::print("Failed to get radio mac address!\n");
+      return;
+    } else {
+      // convert the 6 byte mac address to a 48 bit integer
+      for (int i = 0; i < 6; i++) {
+        radio_mac_addr |= (uint64_t)point[5 - i] << (i * 8);
+      }
+    }
+    fmt::print("radio mac addr: {:#x}\n", radio_mac_addr);
+#endif
+    auto ble_role = espp::Ndef::BleRole::PERIPHERAL_ONLY;
+    auto ble_appearance = espp::Ndef::BtAppearance::GAMEPAD;
+    std::string_view ble_radio_name = "BLE Radio";
+    records.emplace_back(
+        espp::Ndef::make_le_oob_pairing(radio_mac_addr, ble_role, ble_radio_name, ble_appearance));
+    records.back().set_id(payload_id);
+
+    // set one of the records we made to be the active tag
+    st25dv.set_records(records, ec);
+
+    // and finally, make the task to periodically poll the st25dv and print the
+    // state. The task will trigger sample quit when the phone reads the tag.
+    auto task_fn = [&quit_test, &st25dv](std::mutex &m, std::condition_variable &cv) {
+      {
+        std::unique_lock<std::mutex> lock(m);
+        cv.wait_for(lock, 30ms);
+      }
+      std::error_code ec;
+      auto it_sts = st25dv.get_interrupt_status(ec);
+      if (ec) {
+        fmt::print("Failed to get interrupt status: {}\n", ec.message());
+        // wait a bit before trying again
+        std::unique_lock<std::mutex> lock(m);
+        cv.wait_for(lock, 300ms);
+        return false;
+      }
+      static auto last_it_sts = it_sts;
+      if (it_sts != last_it_sts) {
+        fmt::print("[{:.3f}] IT STS: {}\n", elapsed(), it_sts);
+      }
+      last_it_sts = it_sts;
+      // we don't want to stop the task, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "St25dv Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Note

+

See https://stackoverflow.com/questions/61622309/base-address-requirement-for-ndef-messages-on-type-5-tags for some discussion about the Capability Container (CC) header that must be the first data in the EEPROM.

+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit St25dv(const Config &config)
+

Construct the St25dv with the provided configuration.

+
+ +
+
+inline void initialize(std::error_code &ec)
+

Initialize the St25dv.

+
+
Parameters
+

&ec – Error code to be filled with any errors that occur during initialization.

+
+
+
+ +
+
+inline IT_STS get_interrupt_status(std::error_code &ec)
+

Get the interrupt status register (dynamic IT_STS).

+
+

Note

+

Reading the interrupt status register clears it.

+
+
+

Note

+

The available states / flags in the register are available in St25dv::IT_STS.

+
+
+
Parameters
+

&ec – Error code to be filled with any errors that occur during reading.

+
+
Returns
+

The interrupt status register.

+
+
+
+ +
+
+inline void set_record(Ndef &record, std::error_code &ec)
+

Writes the provided record (along with CC header) to the EEPROM.

+
+

Note

+

Right now this only supports 4 B CC headers (for memory less than 16 Kbit).

+
+
+
Parameters
+
    +
  • record – The new NDEF record to serialize to the NFC EEPROM.

  • +
  • &ec – Error code to be filled with any errors that occur during writing.

  • +
+
+
+
+ +
+
+inline void set_record(const std::vector<uint8_t> &record_data, std::error_code &ec)
+

Writes the provided record (along with CC header) to the EEPROM.

+
+
Parameters
+
    +
  • &record_data – The serialized NDEF record to write to the NFC EEPROM.

  • +
  • &ec – Error code to be filled with any errors that occur during writing.

  • +
+
+
+
+ +
+
+inline void set_records(std::vector<Ndef> &records, std::error_code &ec)
+

Writes the provided records (along with CC header) to the EEPROM.

+
+
Parameters
+
    +
  • &records – Vector of NDEF records to serialize to the NFC EEPROM.

  • +
  • &ec – Error code to be filled with any errors that occur during writing.

  • +
+
+
+
+ +
+
+inline void write(std::string_view payload, std::error_code &ec)
+

Write a raw sequence of bytes to the EEPROM.

+
+
Parameters
+
    +
  • payload – Sequence of bytes to write.

  • +
  • &ec – Error code to be filled with any errors that occur during writing.

  • +
+
+
+
+ +
+
+inline void read(uint8_t *data, uint8_t length, std::error_code &ec)
+

Read a sequence of bytes from the EEPROM starting at offset 0.

+
+

Note

+

This may contain raw NDEF bytes as well as the CC header.

+
+
+
Parameters
+
    +
  • *data – Pointer to memory to be filled with bytes read.

  • +
  • length – Number of bytes to read.

  • +
  • &ec – Error code to be filled with any errors that occur during reading.

  • +
+
+
+
+ +
+
+inline void read(uint8_t *data, uint8_t length, uint16_t offset, std::error_code &ec)
+

Read a sequence of bytes from the EEPROM starting at the provided offset.

+
+

Note

+

This may contain raw NDEF bytes as well as the CC header.

+
+
+
Parameters
+
    +
  • *data – Pointer to memory to be filled with bytes read.

  • +
  • length – Number of bytes to read.

  • +
  • offset – Offset to start reading from.

  • +
  • &ec – Error code to be filled with any errors that occur during reading.

  • +
+
+
+
+ +
+
+inline void start_fast_transfer_mode(std::error_code &ec)
+

Enable fast transfer mode (using up to 255 bytes at a time) between RF and I2C. After calling this, you can call transfer(), receive(), and get_ftm_length() for fast bi-directional communications between RF and I2C.

+
+

Note

+

You must call stop_fast_transfer_mode() before calling any other functions on this class.

+
+
+
Parameters
+

&ec – Error code to be filled with any errors that occur during writing.

+
+
+
+ +
+
+inline void stop_fast_transfer_mode(std::error_code &ec)
+

Disable fast transfer mode (using up to 255 bytes at a time) between RF and I2C. After calling this, you cannot call transfer() or receive() without again calling start_fast_transfer_mode() first.

+
+
Parameters
+

&ec – Error code to be filled with any errors that occur during writing.

+
+
+
+ +
+
+inline uint8_t get_ftm_length(std::error_code &ec)
+

Returns the available message length in the FTM message box.

+

Will return non-zero if the RF received data into the FTM.

+
+
Parameters
+

&ec – Error code to be filled with any errors that occur during reading.

+
+
Returns
+

Number of bytes (up to 255) available in the FTM message box.

+
+
+
+ +
+
+inline void transfer(const uint8_t *data, uint8_t length, std::error_code &ec)
+

Write data to the FTM message box to send.

+
+

Note

+

Must call start_fast_transfer_mode() prior to use.

+
+
+
Parameters
+
    +
  • data – Data to be written.

  • +
  • length – Number of bytes to write.

  • +
  • &ec – Error code to be filled with any errors that occur during

  • +
+
+
+
+ +
+
+inline void receive(uint8_t *data, uint8_t length, std::error_code &ec)
+

Read data from the FTM message box.

+
+

Note

+

Must call start_fast_transfer_mode() prior to use.

+
+
+

Note

+

The length available to be read can be found by calling get_ftm_length().

+
+
+
Parameters
+
    +
  • data – Pointer to memory to be filled with data.

  • +
  • length – Number of bytes to read.

  • +
  • &ec – Error code to be filled with any errors that occur during

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DATA_ADDRESS = (0xA6 >> 1)
+

I2C Address for writing / reading data.

+
+ +
+
+static constexpr uint8_t SYST_ADDRESS = (0xAE >> 1)
+

I2C Address for writing / reading system config.

+
+ +
+
+
+struct Config
+

Configuration information for the St25dv.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

Function to write to the device.

+
+ +
+
+BasePeripheral::read_fn read
+

Function to read from the device.

+
+ +
+
+bool auto_init = {true}
+

Automatically initialize the device.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Log verbosity for the component.

+
+ +
+
+ +
+
+struct IT_STS
+

Encapsulates the different flags / bit fields that the IT_STS dynamic register holds for the different states it represents. Reading this register clears it to 0x00.

+
+

Note

+

RF events are reported in the IT_STS register even if GPO output is disabled.

+
+
+ +
+
+IT_STS.__unnamed15__
+
+ +
+
+IT_STS.__unnamed15__.__unnamed17__
+
+

Public Members

+
+
+uint8_t RF_USER
+

Manage GPO (set / reset GPO)

+
+ +
+
+uint8_t RF_ACTIVITY
+

Indicates RF Access.

+
+ +
+
+uint8_t RF_INTTERUPT
+

GPO Interrupt request.

+
+ +
+
+uint8_t FIELD_FALLING
+

RF field is falling.

+
+ +
+
+uint8_t FIELD_RISING
+

RF field is rising.

+
+ +
+
+uint8_t RF_PUT_MSG
+

Message put by RF into FTM mailbox.

+
+ +
+
+uint8_t RF_GET_MSG
+

reached.

+

Message read by RF from FTM mailbox, and end of message has been

+
+ +
+
+uint8_t RF_WRITE
+

Write in eeprom.

+
+ +
+
+ +
+ +
+
+class GPO
+
+ +
+
+class EH_CTRL
+
+ +
+
+class MB_CTRL
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/nfc/st25dv_example.html b/nfc/st25dv_example.html new file mode 100644 index 000000000..4eb693fc2 --- /dev/null +++ b/nfc/st25dv_example.html @@ -0,0 +1,244 @@ + + + + + + + St25dv Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

St25dv Example

+

This example shows how to configure a espp::St25dv class to communicate with +an ST25DV reprogrammable NFC tag.

+

image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be used with an Adafruit ST26DV16K +breakout, connected via I2C.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

Writing multiple records: +CleanShot 2023-07-25 at 11 44 01

+

Multiple records read: +image

+

Reading tag containing text: +phone 1 +Open web link: +phone 2 +Bluetooth pairing: +phone 3

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/nvs.html b/nvs.html new file mode 100644 index 000000000..804bcec79 --- /dev/null +++ b/nvs.html @@ -0,0 +1,1337 @@ + + + + + + + NVS APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

NVS APIs

+
+

NVS

+

The NVS component provides a simple class representing an NVS controller.

+
+
+

NVSHandle

+

The NVSHandle class manages individual NVS storage handles, allowing for scoped +control over specific NVS namespaces. It simplifies operations like reading, +writing, and committing key-value pairs within these namespaces.

+

Code examples for the NVS and NVSHandle API are provided in the nvs example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Nvs : public espp::BaseComponent
+

Class to interface with the NVS.

+

This class is used to interface with the ESP NVS system. It is used to init and erase the partition, or get and set variables

+
+

NVS Example

+
    std::error_code ec;
+    uint8_t counter = 0;
+    espp::Nvs nvs;
+    nvs.init(ec);
+    ec.clear();
+    // note that the namespace and key strings must be <= 15 characters
+    nvs.get_or_set_var("system", "reset_counter", counter, counter, ec);
+    ec.clear();
+    fmt::print("Reset Counter = {}\n", counter);
+
+    bool flag = false;
+    nvs.get_or_set_var("other-namespace", "flag", flag, flag, ec);
+    ec.clear();
+    fmt::print("Got / Set Flag = {}\n", flag);
+    // now toggle the flag
+    flag = !flag;
+    nvs.set_var("other-namespace", "flag", flag, ec);
+    ec.clear();
+    fmt::print("Toggled Flag = {}\n", flag);
+
+    // test protection against really long namespace names (length > 15)
+    std::string long_ns(16, 'a');
+    nvs.get_or_set_var(long_ns, "flag", flag, flag, ec);
+    if (ec) {
+      fmt::print("Expected error: {}\n", ec.message());
+    } else {
+      fmt::print("Unexpected success\n");
+    }
+    ec.clear();
+
+    // test getting a non-existent key
+    nvs.get_var("system", "not-here", counter, ec);
+    if (ec) {
+      fmt::print("Expected error: {}\n", ec.message());
+    } else {
+      fmt::print("Unexpected success\n");
+    }
+    ec.clear();
+
+    // test getting a string value
+    std::string str;
+    nvs.get_or_set_var("system", "string", str, std::string("default"), ec);
+    if (ec) {
+      fmt::print("Error: {}\n", ec.message());
+    } else {
+      fmt::print("String = '{}'\n", str);
+    }
+    ec.clear();
+
+    // test setting a string value
+    str = "hello";
+    nvs.set_var("system", "string", str, ec);
+    if (ec) {
+      fmt::print("Error: {}\n", ec.message());
+    } else {
+      fmt::print("String set to '{}'\n", str);
+    }
+    ec.clear();
+
+    // test getting the string value again
+    nvs.get_var("system", "string", str, ec);
+    if (ec) {
+      fmt::print("Error: {}\n", ec.message());
+    } else {
+      fmt::print("String = '{}'\n", str);
+    }
+    ec.clear();
+
+    // test erasing the string value
+    nvs.erase("system", "string", ec);
+    if (ec) {
+      fmt::print("Error: {}\n", ec.message());
+    } else {
+      fmt::print("String erased\n");
+    }
+    ec.clear();
+
+    // now test getting it again to ensure it was erased
+    nvs.get_var("system", "string", str, ec);
+    if (ec) {
+      fmt::print("Sucess, got expected error when reading erased value: {}\n", ec.message());
+    } else {
+      fmt::print("Failure, got unexpected success when reading erased value\n");
+    }
+    ec.clear();
+
+    counter++;
+
+    if (counter > 10) {
+      // test erasing the whole namespace
+      nvs.erase("system", ec);
+      if (ec) {
+        fmt::print("Error: {}\n", ec.message());
+      } else {
+        fmt::print("Namespace erased\n");
+      }
+      ec.clear();
+
+      // now erase the wole nvs partition
+      nvs.erase(ec);
+      nvs.init(ec);
+      counter = 0;
+      fmt::print("NVS erased, Reset Counter set to 0\n");
+      ec.clear();
+    }
+
+    nvs.set_var("system", "reset_counter", counter, ec);
+    fmt::print("Next Reset Counter will be = {}\n", counter);
+    fmt::print("NVS example complete!\n");
+
+
+
+
+

Public Functions

+
+
+inline explicit Nvs()
+

Construct a new NVS object.

+
+ +
+
+inline void init(std::error_code &ec)
+

Initialize the NVS.

+

+If the flash init fails because of no free pages or new version, it erases the NVS and re-initializes

+
+
Parameters
+

ec[out] Saves a std::error_code representing success or failure

+
+
+
+ +
+
+inline void erase(std::error_code &ec)
+

Erase the NVS.

+
+
Parameters
+

ec[out] Saves a std::error_code representing success or failure

+
+
+
+ +
+
+inline bool erase(std::string_view ns_name, std::error_code &ec)
+

Erase a namespace from the NVS.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to erase

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline bool erase(std::string_view ns_name, std::string_view key, std::error_code &ec)
+

Erase a key from the NVS.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to erase

  • +
  • key[in] NVS Key of the variable to erase

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void set_var(std::string_view ns_name, std::string_view key, T value, std::error_code &ec)
+

Save a variable in the NVS and commit.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to save

  • +
  • key[in] NVS Key of the variable to save

  • +
  • value[in] Variable to save

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get_var(std::string_view ns_name, std::string_view key, T &value, std::error_code &ec)
+

Reads a variable from the NVS.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to read

  • +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get_or_set_var(std::string_view ns_name, std::string_view key, T &value, T default_value, std::error_code &ec)
+

Reads a variable from the NVS.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to read

  • +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • default_value[in] If the key isn’t found in the NVS, this value is saved to NVS

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void set_var(const char *ns_name, const char *key, T value, std::error_code &ec)
+

Save a variable in the NVS and commit.

+

+Saves the key/variable pair, and commits the NVS.

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to save

  • +
  • key[in] NVS Key of the variable to save

  • +
  • value[in] Variable to save

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get_var(const char *ns_name, const char *key, T &value, std::error_code &ec)
+

Reads a variable from the NVS.

+

+Read the key/variable pair

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to read

  • +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get_or_set_var(const char *ns_name, const char *key, T &value, T default_value, std::error_code &ec)
+

Reads a variable from the NVS.

+

+Read the key/variable pair, If the key isn’t found in the NVS, default_value is saved to NVS

+
+
Parameters
+
    +
  • ns_name[in] Namespace of the variable to read

  • +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • default_value[in] If the key isn’t found in the NVS, this value is saved to NVS

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class NvsHandle : public espp::BaseComponent
+

Class to manage NVS handles.

+

This class provides an interface for managing specific ESP NVS namespaces, enabling operations like reading, writing, and committing key-value pairs. It encapsulates all direct interactions with the NVS to ensure proper error handling and namespace management.

+
+

NvsHandle Example

+
    // Init NVS
+    std::error_code ec;
+    espp::Nvs nvs;
+    nvs.init(ec);
+    ec.clear();
+
+    // Open
+    fmt::print("\nOpening Non-Volatile Storage (NVS) handle... ");
+    // Handle will automatically close when going out of scope or when it's reset.
+    espp::NvsHandle storage("storage", ec);
+    fmt::print("Done\n");
+    ec.clear();
+
+    // Read
+    fmt::print("Reading restart counter from NVS ... ");
+    int32_t restart_counter = 0;
+    storage.get("restart_counter", restart_counter, ec);
+    if (ec) {
+      if (ec.value() == static_cast<int>(NvsErrc::Key_Not_Found)) {
+        fmt::print("The value is not initialized yet!\n");
+      } else if (ec.value() == static_cast<int>(NvsErrc::Read_NVS_Failed)) {
+        fmt::print("Failed to read from NVS: {}\n", ec.message().c_str());
+      } else {
+        fmt::print("An error occurred: {}\n", ec.message().c_str());
+      }
+    } else {
+      fmt::print("Done\n");
+      fmt::print("Restart counter = {}\n", restart_counter);
+    }
+    ec.clear();
+
+    // Write
+    fmt::print("Updating restart counter in NVS ... ");
+    restart_counter++;
+    storage.set("restart_counter", restart_counter, ec);
+    fmt::print("Done\n");
+    ec.clear();
+
+    // Commit written value.
+    // After setting any values, nvs_commit() must be called to ensure changes are written
+    // to flash storage. Implementations may write to storage at other times,
+    // but this is not guaranteed.
+    fmt::print("Committing updates in NVS ... ");
+    storage.commit(ec);
+    fmt::print("Done\n");
+    ec.clear();
+
+    fmt::print("\n");
+    fflush(stdout);
+
+
+
+
+

Public Functions

+
+
+inline explicit NvsHandle(const char *ns_name, std::error_code &ec)
+

Construct a new NvsHandle object.

+

+Create an NvsHandle object for the key-value pairs in the ns_name namespace

+
+
Parameters
+
    +
  • ns_name[in] Namespace for NVS

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get(const char *key, T &value, std::error_code &ec)
+

Reads a variable from the NVS.

+

+Reads the value of key into value, if key exists

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get(std::string_view key, T &value, std::error_code &ec)
+

Reads a variable from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, bool &value, std::error_code &ec)
+

Reads a bool from the NVS.

+

+Read the key/variable pair

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to read

  • +
  • value[out] bool to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, bool &value, std::error_code &ec)
+

Reads a bool from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to read

  • +
  • value[out] bool to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, float &value, std::error_code &ec)
+

Reads a float from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Float variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, float &value, std::error_code &ec)
+

Reads a float from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Float variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, std::string &value, std::error_code &ec)
+

Reads a string from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to read

  • +
  • value[inout] string to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, std::string &value, std::error_code &ec)
+

Reads a string from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to read

  • +
  • value[out] string to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get(const char *key, T &value, const T default_value, std::error_code &ec)
+

Reads a variable from the NVS.

+

+Reads the value of key into value, if key exists

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void get(std::string_view key, T &value, const T default_value, std::error_code &ec)
+

Reads a variable from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[out] Variable to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, bool &value, const bool default_value, std::error_code &ec)
+

Reads a bool from the NVS.

+

+Read the key/variable pair

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to read

  • +
  • value[out] bool to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, bool &value, const bool default_value, std::error_code &ec)
+

Reads a bool from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to read

  • +
  • value[out] bool to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, float &value, const float default_value, std::error_code &ec)
+

Reads a float from the NVS.

+

+Read the key/variable pair

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to read

  • +
  • value[out] float to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, float &value, const float default_value, std::error_code &ec)
+

Reads a float from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the float to read

  • +
  • value[out] float to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(std::string_view key, std::string &value, const std::string &default_value, std::error_code &ec)
+

Reads a string from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to read

  • +
  • value[out] string to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void get(const char *key, std::string &value, const std::string &default_value, std::error_code &ec)
+

Reads a string from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to read

  • +
  • value[out] string to read

  • +
  • default_value[in] Default value to return if key is not found

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void set(const char *key, T value, std::error_code &ec)
+

Save a variable in the NVS.

+

+Saves the key/variable pair without committing the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to read

  • +
  • value[in] Variable to read

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+template<typename T>
inline void set(std::string_view key, T value, std::error_code &ec)
+

Save a variable in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the variable to save

  • +
  • value[in] Variable to save

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(std::string_view key, bool value, std::error_code &ec)
+

Set a bool in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to set

  • +
  • value[in] bool to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(const char *key, bool value, std::error_code &ec)
+

Set a bool in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the bool to set

  • +
  • value[in] bool to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(std::string_view key, float value, std::error_code &ec)
+

Set a float in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the float to set

  • +
  • value[in] float to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(const char *key, float value, std::error_code &ec)
+

Set a float in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the float to set

  • +
  • value[in] float to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(std::string_view key, const std::string &value, std::error_code &ec)
+

Set a string in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to set

  • +
  • value[in] string to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void set(const char *key, const std::string &value, std::error_code &ec)
+

Set a string in the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key of the string to set

  • +
  • value[in] string to set

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
+
+ +
+
+inline void commit(std::error_code &ec)
+

Commit changes.

+

+Commits changes to the NVS

+
+
Parameters
+

ec[out] Saves a std::error_code representing success or failure

+
+
+
+ +
+
+inline bool erase(std::string_view key, std::error_code &ec)
+

Erase a key from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key to erase

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
Returns
+

true if successful, false otherwise

+
+
+
+ +
+
+inline bool erase(const char *key, std::error_code &ec)
+

Erase a key from the NVS.

+
+
Parameters
+
    +
  • key[in] NVS Key to erase

  • +
  • ec[out] Saves a std::error_code representing success or failure

  • +
+
+
Returns
+

true if successful, false otherwise

+
+
+
+ +
+
+inline bool erase(std::error_code &ec)
+

Erase all keys from the NVS associated with the namespace / handle.

+
+
Parameters
+

ec[out] Saves a std::error_code representing success or failure

+
+
Returns
+

true if successful, false otherwise

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/nvs_example.html b/nvs_example.html new file mode 100644 index 000000000..39984284b --- /dev/null +++ b/nvs_example.html @@ -0,0 +1,280 @@ + + + + + + + NVS Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

NVS Example

+

This example shows the use of the NVS component to save a variable to the NVS and load +it after reset.

+
+

How to use example

+

The example outputs a log that counts up the number of times the system has been reset +since the NVS was last cleared.

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

NVS Example Output

+

CleanShot 2024-05-18 at 12 54 46 +CleanShot 2024-05-18 at 12 54 54 +CleanShot 2024-05-18 at 12 55 02

+
+
+

NVSHandle Example Output

+

First run:

+
Opening Non-Volatile Storage (NVS) handle... Done
+Reading restart counter from NVS ... [NVSHandle/E][0.061]: The value is not initialized in NVS, key = 'restart_counter'
+The value is not initialized yet!
+Updating restart counter in NVS ... Done
+Committing updates in NVS ... Done
+
+Restarting in 10 seconds...
+Restarting in 9 seconds...
+Restarting in 8 seconds...
+Restarting in 7 seconds...
+Restarting in 6 seconds...
+Restarting in 5 seconds...
+Restarting in 4 seconds...
+Restarting in 3 seconds...
+Restarting in 2 seconds...
+Restarting in 1 seconds...
+Restarting in 0 seconds...
+Restarting now.
+
+
+

Subsequent runs:

+
Opening Non-Volatile Storage (NVS) handle... Done
+Reading restart counter from NVS ... Done
+Restart counter = 1
+Updating restart counter in NVS ... Done
+Committing updates in NVS ... Done
+
+Restarting in 10 seconds...
+Restarting in 9 seconds...
+Restarting in 8 seconds...
+Restarting in 7 seconds...
+Restarting in 6 seconds...
+Restarting in 5 seconds...
+Restarting in 4 seconds...
+Restarting in 3 seconds...
+Restarting in 2 seconds...
+Restarting in 1 seconds...
+Restarting in 0 seconds...
+Restarting now.
+
+
+

Restart counter will increment on each run.

+

To reset the counter, erase the contents of flash memory using idf.py erase-flash, then upload the program again as described above.

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 000000000..f65832e8c Binary files /dev/null and b/objects.inv differ diff --git a/pid.html b/pid.html new file mode 100644 index 000000000..622647967 --- /dev/null +++ b/pid.html @@ -0,0 +1,623 @@ + + + + + + + PID APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PID APIs

+
+

PID

+

The PID component provides a simple, thread-safe class representing a PID +controller. It tracks how frequently its update() method is called and can +have its gains change dynamically.

+

Code examples for the task API are provided in the pid example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Pid : public espp::BaseComponent
+

Simple PID (proportional, integral, derivative) controller class with integrator clamping, output clamping, and prevention of integrator windup during output saturation. This class is thread-safe, so you can update(), clear(), and change_gains() from multiple threads if needed.

+
+

Basic PID Example

+
    espp::Pid pid({.kp = 1.0f,
+                   .ki = 0.1f,
+                   .kd = 0.0f,
+                   .integrator_min = -1000.0f,
+                   .integrator_max = 1000.0f,
+                   .output_min = -100.0f,
+                   .output_max = 100.0f});
+    for (int i = 0; i < num_seconds_to_run; i++) {
+      float error = (float)num_seconds_to_run / (float)(i + 1);
+      float output = pid.update(error);
+      fmt::print("PID: ({}) -> {:0.3f}\n", pid, output);
+      // std::this_thread::sleep_for(5ms);
+    }
+
+
+
+
+

Complex PID Example

+
    espp::Pid::Config pid_config{.kp = 1.0f,
+                                 .ki = 0.1f,
+                                 .kd = 0.0f,
+                                 .integrator_min = -1000.0f,
+                                 .integrator_max = 1000.0f,
+                                 .output_min = -100.0f,
+                                 .output_max = 100.0f,
+                                 .log_level = espp::Logger::Verbosity::INFO};
+    espp::Pid pid(pid_config);
+    auto task_fn = [&pid](std::mutex &m, std::condition_variable &cv) {
+      auto now = std::chrono::high_resolution_clock::now();
+      float elapsed = std::chrono::duration<float>(now - start).count();
+      float error = 2.0f / elapsed;
+      float output = pid.update(error);
+      fmt::print("PID: ({}) -> {:0.3f}\n", pid, output);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 100ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "PID Update"},
+                            .log_level = espp::Logger::Verbosity::INFO});
+    task.start();
+    for (int i = 0; i < num_seconds_to_run; i++) {
+      // change PID gains here
+      fmt::print("Increasing p-gain\n");
+      pid_config.kp = (float)i / (float)num_seconds_to_run;
+      pid.change_gains(pid_config);
+      std::this_thread::sleep_for(1s);
+    }
+
+
+
+
+

Public Functions

+
+
+inline explicit Pid(const Config &config)
+

Create the PID controller.

+
+ +
+
+inline void change_gains(const Config &config, bool reset_state = true)
+

Change the gains and other configuration for the PID controller.

+
+
Parameters
+
    +
  • config – Configuration struct with new gains and sampling time.

  • +
  • reset_state – Reset / clear the PID controller state.

  • +
+
+
+
+ +
+
+inline void set_config(const Config &config, bool reset_state = true)
+

Change the gains and other configuration for the PID controller.

+
+
Parameters
+
    +
  • config – Configuration struct with new gains and sampling time.

  • +
  • reset_state – Reset / clear the PID controller state.

  • +
+
+
+
+ +
+
+inline void clear()
+

Clear the PID controller state.

+
+ +
+
+inline float update(float error)
+

Update the PID controller with the latest error measurement, getting the output control signal in return.

+
+

Note

+

Tracks invocation timing to better compute time-accurate integral/derivative signals.

+
+
+
Parameters
+

error – Latest error signal.

+
+
Returns
+

The output control signal based on the PID state and error.

+
+
+
+ +
+
+inline float operator()(float error)
+

Update the PID controller with the latest error measurement, getting the output control signal in return.

+
+

Note

+

Tracks invocation timing to better compute time-accurate integral/derivative signals.

+
+
+
Parameters
+

error – Latest error signal.

+
+
Returns
+

The output control signal based on the PID state and error.

+
+
+
+ +
+
+inline float get_error() const
+

Get the current error (as of the last time update() or operator() were called)

+
+
Returns
+

Most recent error.

+
+
+
+ +
+
+inline float get_integrator() const
+

Get the current integrator (as of the last time update() or operator() were called)

+
+
Returns
+

Most recent integrator value.

+
+
+
+ +
+
+inline Config get_config() const
+

Get the configuration for the PID (gains, etc.).

+
+
Returns
+

Config structure containing gains, etc.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+
+

Public Members

+
+
+float kp
+

Proportional gain.

+
+ +
+
+float ki
+

Integral gain.

+
+

Note

+

should not be pre-multiplied by the time constant.

+
+
+ +
+
+float kd
+

Derivative gain.

+
+

Note

+

should not be pre-divided by the time-constant.

+
+
+ +
+
+float integrator_min
+

Minimum value the integrator can wind down to.

+
+

Note

+

Operates at the same scale as output_min and output_max. Could be 0 or negative. Can have different magnitude from integrator_max for asymmetric response.

+
+
+ +
+
+float integrator_max
+

Maximum value the integrator can wind up to.

+
+

Note

+

Operates at the same scale as output_min and output_max.

+
+
+ +
+
+float output_min
+

Limit the minimum output value. Can be a different magnitude from output max for asymmetric output behavior.

+
+ +
+
+float output_max
+

Limit the maximum output value.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Verbosity for the adc logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/pid_example.html b/pid_example.html new file mode 100644 index 000000000..3b88a6477 --- /dev/null +++ b/pid_example.html @@ -0,0 +1,229 @@ + + + + + + + PID Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PID Example

+

This example shows how to use the espp::Pid class to perform closed-loop +feedback control using proportional-integral-derivative (PID) control.

+

The example does not operate on real hardware, but simply runs the PID algorithm +on fake data.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

output

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/qwiicnes.html b/qwiicnes.html new file mode 100644 index 000000000..7a84f6106 --- /dev/null +++ b/qwiicnes.html @@ -0,0 +1,924 @@ + + + + + + + QwiicNES - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

QwiicNES

+

The Qwiicnes component provides a driver for the SparkFun Qwiic NES Controller.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Functions

+
+

Warning

+

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. +Potential matches: +

+
- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
+- bool operator==(const Config &rhs) const = default
+- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
+- bool operator==(const Hsv &rhs) const = default
+- bool operator==(const PinConfig &rhs) const = default
+- bool operator==(const PointerData &rhs) const = default
+- bool operator==(const Rgb &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const Vector2d &other) const
+- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
+- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
+- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
+- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
+- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)
+
+
+
+
+
+

Unions

+
+
+espp::QwiicNes::ButtonState.__unnamed11__
+
+

Public Members

+
+
+struct espp::QwiicNes::ButtonState
+
+ +
+
+uint8_t raw
+
+ +
+
+ +
+
+

Classes

+
+
+class QwiicNes : public espp::BasePeripheral<>
+

A class to interface with the Qwiic NES controller.

+

This class is used to interface with the Qwiic NES controller. The Qwiic NES controller is a breakout board for the NES controller. The Qwiic NES controller uses the I2C bus to communicate.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+    });
+    // now make the qwiicnes which decodes the data
+    espp::QwiicNes qwiicnes(
+        {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                            std::placeholders::_3),
+         .read_register =
+             std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+                       std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+         .log_level = espp::Logger::Verbosity::WARN});
+    // and finally, make the task to periodically poll the qwiicnes and print
+    // the state
+    auto task_fn = [&quit_test, &qwiicnes](std::mutex &m, std::condition_variable &cv) {
+      static espp::QwiicNes::ButtonState last_button_state;
+      std::error_code ec;
+      qwiicnes.update(ec);
+      if (ec) {
+        fmt::print("QwiicNes update failed: {}\n", ec.message());
+        return true; // stop the task
+      }
+      auto button_state = qwiicnes.get_button_state();
+      if (button_state != last_button_state) {
+        fmt::print("Button state: {}\n", button_state);
+        quit_test = button_state.select && button_state.start;
+        last_button_state = button_state;
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Qwiicnes Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+enum class Button : int
+

The buttons on the NES controller. @deftails The values in this enum match the button’s corresponding bit field in the byte returned by read_current_state() and read_button_accumulator().

+

Values:

+
+
+enumerator A
+
+ +
+
+enumerator B
+
+ +
+
+enumerator SELECT
+
+ +
+
+enumerator START
+
+ +
+
+enumerator UP
+
+ +
+
+enumerator DOWN
+
+ +
+
+enumerator LEFT
+
+ +
+
+enumerator RIGHT
+
+ +
+ +
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit QwiicNes(const Config &config)
+

Construct a new QwiicNes object.

+
+
Parameters
+

config – The configuration for the QwiicNes class.

+
+
+
+ +
+
+inline bool is_pressed(Button button) const
+

Return true if the given button is pressed.

+

+This function uses the accumulated button states which are updated by the update() function.

+
+
Parameters
+

button – The button to check.

+
+
Returns
+

true if the given button is pressed.

+
+
+
+ +
+
+inline ButtonState get_button_state() const
+

Return the current state of the buttons.

+

+This function uses the accumulated button states which are updated by the update() function.

+
+
Returns
+

The current state of the buttons.

+
+
+
+ +
+
+inline void update(std::error_code &ec)
+

Update the state of the buttons.

+

+This function reads the current state of the buttons and updates the accumulated button states. This function should be called periodically to ensure the accumulated button states are up to date. This function will log an error if it fails to read the current state of the buttons. The accumulated states represent all buttons which have been pressed since the last time this function was called.

+

See also

+

get_button_state()

+
+
+

See also

+

is_pressed()

+
+

+
+
Parameters
+

ec – The error code if the function fails.

+
+
+
+ +
+
+inline uint8_t read_current_state(std::error_code &ec)
+

Read the current state of the buttons.

+

+This function will log an error if it fails to read the current state of the buttons. This function does not update the accumulated button states. To update the accumulated button states, call the update() function. The current state represents the buttons which are currently pressed.

+
+
Parameters
+

ec – The error code if the function fails.

+
+
Returns
+

The current state of the buttons.

+
+
+
+ +
+
+inline uint8_t read_address(std::error_code &ec)
+

Read the current I2C address of the device.

+

+This function will log an error if it fails to read the current I2C address of the device. The I2C address is a 7-bit value. The 7-bit I2C address is shifted left by 1 bit and the least significant bit is set to 0. For example, if the I2C address is 0x54, then the value returned by this function will be 0xA8.

+
+
Parameters
+

ec – The error code if the function fails.

+
+
Returns
+

The current I2C address of the device.

+
+
+
+ +
+
+inline void update_address(uint8_t new_address, std::error_code &ec)
+

Update the I2C address of the device.

+

+This function will log an error if it fails to update the I2C address of the device. The I2C address is a 7-bit value. The 7-bit I2C address is shifted left by 1 bit and the least significant bit is set to 0.

+
+
Parameters
+
    +
  • new_address – The new I2C address of the device.

  • +
  • ec – The error code if the function fails.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline bool is_pressed(uint8_t state, Button button)
+

Return true if the given button is pressed.

+
+
Parameters
+
+
+
Returns
+

true if the given button is pressed.

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x54)
+

The default I2C address of the device.

+
+ +
+
+
+struct ButtonState
+

The state of the buttons on the NES controller.

+

Contains the state of each button on the NES controller.

+
+ +
+
+ButtonState.__unnamed11__
+
+ +
+
+ButtonState.__unnamed11__.__unnamed13__
+
+ +
+
+struct Config
+

The configuration for the QwiicNes class.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

The function to write data to the I2C bus.

+
+ +
+
+BasePeripheral::read_register_fn read_register
+

The function to write then read data from the I2C bus.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

The log level for the class.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/qwiicnes_example.html b/qwiicnes_example.html new file mode 100644 index 000000000..7e6a8c1e0 --- /dev/null +++ b/qwiicnes_example.html @@ -0,0 +1,233 @@ + + + + + + + QwiicNES Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

QwiicNES Example

+

This example demonstrates the use of the QwiicNES component to read the state of +a NES controller and print it to the serial console.

+
+

How to use example

+
+

Hardware Required

+

This example requires a connection (via I2C) to a QwiicNES board and a NES +controller.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+CleanShot 2023-11-05 at 11 07 00@2x +
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rmt.html b/rmt.html new file mode 100644 index 000000000..f2f2c0769 --- /dev/null +++ b/rmt.html @@ -0,0 +1,805 @@ + + + + + + + Remote Control Transceiver (RMT) - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Remote Control Transceiver (RMT)

+

The Rmt class provides a wrapper around the ESP32 RMT peripheral. It allows +you to send infrared signals with the ESP32. See the esp-idf documentation for +more information about the RMT peripheral. +(https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html)

+

The RmtEncoder class provides a wrapper around the ESP32 rmt encoder +functionality. It allows you to encode infrared signals with the ESP32. See the +esp-idf documentation for more information about the RMT encoder +(https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html#rmt-encoder)

+

The main functionality of the Rmt / RmtEncoder classes beyond what is +provided by the esp-idf is to allow the use of the RMT peripheral with c++ +functions (such as with bound functions, functionals, etc.). It also provides a +simpler wrapper / interface to the user.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Rmt : public espp::BaseComponent
+

Class wrapping the RMT peripheral on the ESP32.

+

The RMT (Remote Control Transceiver) peripheral is used to generate precise timing pulses on a GPIO pin. It can be used to drive a WS2812B or similar LED strip which uses a 1-wire protocol such as the WS2812B. The RMT peripheral is also used by the ESP32 to drive the IR transmitter.

+

+

+
+

Example 1: Transmitting data

+
    // create the rmt object
+    espp::Rmt rmt(espp::Rmt::Config{
+        .gpio_num = 18, // WS2812B data pin on the TinyS3
+        .resolution_hz = WS2812_FREQ_HZ,
+        .log_level = espp::Logger::Verbosity::INFO,
+    });
+
+    // tell the RMT object to use the led_encoder (espp::RmtEncoder) that's
+    // defined above
+    rmt.set_encoder(std::move(led_encoder));
+
+    // create a task to cycle through rainbow colors and send them to the
+    // WS2812B LED using the RMT peripheral
+    auto task_fn = [&rmt](std::mutex &m, std::condition_variable &cv) {
+      static auto start = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      float t = std::chrono::duration<float>(now - start).count();
+      // rotate through rainbow colors in hsv based on time, hue is 0-360
+      float hue = (cos(t) * 0.5f + 0.5f) * 360.0f;
+      espp::Hsv hsv(hue, 1.0f, 1.0f);
+      espp::Rgb rgb = hsv.rgb();
+      uint8_t green = std::clamp(int(rgb.g * 255), 0, 255);
+      uint8_t blue = std::clamp(int(rgb.b * 255), 0, 255);
+      uint8_t red = std::clamp(int(rgb.r * 255), 0, 255);
+      // NOTE: we only have one LED so we only need to send one set of RGB data
+      uint8_t data[3] = {green, blue, red};
+      // now we can send the data to the WS2812B LED
+      rmt.transmit(data, sizeof(data));
+      fmt::print("hsv->rgb->uint: {} -> {} -> {} {} {}\n", hsv, rgb, green, blue, red);
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 50ms);
+      }
+      // don't want to stop the task
+      return false;
+    };
+
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config =
+                                {
+                                    .name = "Rmt Task",
+                                    .stack_size_bytes = 5 * 1024,
+                                },
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Functions

+
+
+inline explicit Rmt(const Config &config)
+

Constructor.

+
+
Parameters
+

config – Configuration for this class

+
+
+
+ +
+
+inline ~Rmt()
+

Destructor.

+

This function disables the RMT peripheral and frees the RMT channel.

+
+ +
+
+inline bool transmit(const uint8_t *data, size_t length)
+

Transmit a buffer of data using the RMT peripheral.

+
+

Note

+

This function blocks until the data has been transmitted.

+
+
+
Parameters
+
    +
  • data – Pointer to the data to transmit

  • +
  • length – Length of the data to transmit

  • +
+
+
Returns
+

True if the data was successfully transmitted, false otherwise

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the RMT class.

+
+

Public Members

+
+
+int gpio_num
+

GPIO pin to use for the RMT peripheral.

+
+ +
+
+rmt_clock_source_t clock_src = RMT_CLK_SRC_DEFAULT
+

Clock source for the RMT peripheral.

+
+ +
+
+bool dma_enabled = false
+

Whether to use DMA for the RMT peripheral.

+
+ +
+
+int block_size = 64
+

Memory block size (e.g. 64 * 4 = 256 bytes) for the RMT peripheral. Note: this has different meaning depending on whether DMA is configured or not. Suggested size without DMA is >= 64, with DMA is >= 1024.

+
+ +
+
+size_t resolution_hz = 10000000
+

Resolution of the RMT peripheral.

+
+ +
+
+int transaction_queue_depth = 1
+

Depth of the RMT transaction queue (number of transactions that can be queued)

+
+ +
+
+Logger::Verbosity log_level = Logger::Verbosity::WARN
+

Log level for this class.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RmtEncoder
+

Class representing an RMT encoder.

+

This class is used to encode data for the RMT peripheral. It is used by the Rmt class to encode data for transmission.

+

+
+

Example 1: WS2812 encoder

+
    //
+    // The RmtEncoder provides a way to encode data into the RMT peripheral.
+    // This code is a custom encoder that encodes WS2812B data. It uses two
+    // encoders, a bytes encoder and a copy encoder. The bytes encoder encodes
+    // the RGB data into the RMT peripheral and the copy encoder encodes the
+    // reset code. The reset code is a special code that is sent after the RGB
+    // data to reset the WS2812B LEDs. The reset code is a 50us low pulse
+    // followed by a 50us high pulse. The reset code is sent after the RGB data
+    // to ensure that the WS2812B LEDs latch the RGB data. The reset code is
+    // sent after the RGB data because the WS2812B LEDs latch the RGB data on
+    // the rising edge of the reset code.
+    //
+    // This code is copied from the led_stip example in the esp-idf
+    // (https://github.com/espressif/esp-idf/tree/master/examples/peripherals/rmt/led_strip/main)
+    int led_encoder_state = 0;
+    static constexpr int WS2812_FREQ_HZ = 10000000;
+    static constexpr int MICROS_PER_SEC = 1000000;
+    auto led_encoder = std::make_unique<espp::RmtEncoder>(espp::RmtEncoder::Config{
+        // NOTE: since we're using the 10MHz RMT clock, we can use the pre-defined
+        //       ws2812_10mhz_bytes_encoder_config
+        .bytes_encoder_config = espp::RmtEncoder::ws2812_10mhz_bytes_encoder_config,
+        .encode = [&led_encoder_state](auto channel, auto *copy_encoder, auto *bytes_encoder,
+                                       const void *data, size_t data_size,
+                                       rmt_encode_state_t *ret_state) -> size_t {
+          // divide by 2 since we have both duration0 and duration1 in the reset code
+          static uint16_t reset_ticks =
+              WS2812_FREQ_HZ / MICROS_PER_SEC * 50 / 2; // reset code duration defaults to 50us
+          static rmt_symbol_word_t led_reset_code = (rmt_symbol_word_t){
+              .duration0 = reset_ticks,
+              .level0 = 0,
+              .duration1 = reset_ticks,
+              .level1 = 0,
+          };
+          rmt_encode_state_t session_state = RMT_ENCODING_RESET;
+          int state = RMT_ENCODING_RESET;
+          size_t encoded_symbols = 0;
+          switch (led_encoder_state) {
+          case 0: // send RGB data
+            encoded_symbols +=
+                bytes_encoder->encode(bytes_encoder, channel, data, data_size, &session_state);
+            if (session_state & RMT_ENCODING_COMPLETE) {
+              led_encoder_state = 1; // switch to next state when current encoding session finished
+            }
+            if (session_state & RMT_ENCODING_MEM_FULL) {
+              state |= RMT_ENCODING_MEM_FULL;
+              goto out; // yield if there's no free space for encoding artifacts
+            }
+            // fall-through
+          case 1: // send reset code
+            encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_reset_code,
+                                                    sizeof(led_reset_code), &session_state);
+            if (session_state & RMT_ENCODING_COMPLETE) {
+              led_encoder_state = RMT_ENCODING_RESET; // back to the initial encoding session
+              state |= RMT_ENCODING_COMPLETE;
+            }
+            if (session_state & RMT_ENCODING_MEM_FULL) {
+              state |= RMT_ENCODING_MEM_FULL;
+              goto out; // yield if there's no free space for encoding artifacts
+            }
+          }
+        out:
+          *ret_state = static_cast<rmt_encode_state_t>(state);
+          return encoded_symbols;
+        },
+        .del = [](auto *base_encoder) -> esp_err_t {
+          // we don't have any extra resources to free, so just return ESP_OK
+          return ESP_OK;
+        },
+        .reset = [&led_encoder_state](auto *base_encoder) -> esp_err_t {
+          // all we have is some extra state to reset
+          led_encoder_state = 0;
+          return ESP_OK;
+        },
+    });
+
+
+
+
+

Public Types

+
+
+typedef std::function<size_t(rmt_channel_handle_t channel, rmt_encoder_t *copy_encoder, rmt_encoder_t *bytes_encoder, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)> encode_fn
+

Function to encode data for the RMT peripheral.

+
+

Note

+

This function is called by the Rmt class to encode data for transmission. It is called repeatedly until all data has been encoded.

+
+
+

Note

+

This function should return the number of bytes encoded.

+
+
+

Note

+

This function should set the RMT encoder state to the next state to be used for encoding.

+
+
+
Param channel
+

RMT channel to use for encoding

+
+
Param copy_encoder
+

RMT encoder to use for copying data

+
+
Param bytes_encoder
+

RMT encoder to use for encoding bytes

+
+
Param primary_data
+

Pointer to the primary data to encode

+
+
Param data_size
+

Size of the primary data to encode

+
+
Param ret_state
+

Pointer to the RMT encoder state to return

+
+
Return
+

Number of bytes encoded

+
+
+
+ +
+
+typedef std::function<esp_err_t(rmt_encoder_t*)> delete_fn
+

Function to delete an RMT encoder.

+
+
Param encoder
+

RMT encoder to delete

+
+
Return
+

ESP_OK if the encoder was successfully deleted, an error code

+
+
+
+ +
+
+typedef std::function<esp_err_t(rmt_encoder_t*)> reset_fn
+

Function to reset an RMT encoder.

+
+
Param encoder
+

RMT encoder to reset

+
+
Return
+

ESP_OK if the encoder was successfully reset, an error code

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit RmtEncoder(const Config &config)
+

Constructor.

+
+
Parameters
+

config – Configuration for this class

+
+
+
+ +
+
+inline ~RmtEncoder()
+

Destructor.

+
+ +
+
+inline rmt_encoder_handle_t handle() const
+

Get the RMT encoder handle.

+
+
Returns
+

RMT encoder handle

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr rmt_bytes_encoder_config_t sk6805_10mhz_bytes_encoder_config  = {.bit0 ={.duration0 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level1 = 0,},.bit1 ={.duration0 = static_cast<uint16_t>(0.6 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.6 * 10000000 / 1000000),.level1 = 0,},.flags ={.msb_first = 1},}
+

Configuration for the byte encoding for SK6805 LEDs.

+

This configuration is used to encode bytes for SK6085 LEDs.

+

See also

+

Config

+
+

+
+

Note

+

This configuration can be provided to the configuration for this class. These values are based on the timing values provided in the SK6805 datasheet (https://cdn-shop.adafruit.com/product-files/3484/3484_Datasheet.pdf)

+
+
+ +
+
+static constexpr rmt_bytes_encoder_config_t ws2812_10mhz_bytes_encoder_config  = {.bit0 ={.duration0 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level1 = 0,},.bit1 ={.duration0 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level1 = 0,},.flags ={.msb_first = 1},}
+

Configuration for the byte encoding for WS2812 LEDs.

+

This configuration is used to encode bytes for WS2812 LEDs.

+

See also

+

Config

+
+

+
+

Note

+

This configuration can be provided to the configuration for this class.

+
+
+ +
+
+
+struct Config
+

Configuration for this class.

+
+

Public Members

+
+
+rmt_bytes_encoder_config_t bytes_encoder_config
+

Configuration for the RMT bytes encoder.

+
+ +
+
+encode_fn encode
+

Function to encode data for the RMT peripheral.

+
+ +
+
+delete_fn del
+

Function to delete an RMT encoder.

+
+ +
+
+reset_fn reset
+

Function to reset an RMT encoder.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rmt_example.html b/rmt_example.html new file mode 100644 index 000000000..8a6c8a21d --- /dev/null +++ b/rmt_example.html @@ -0,0 +1,235 @@ + + + + + + + RMT Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

RMT Example

+

This example shows the use of the espp::Rmt and espp::RmtEncoder classes of +the rmt component for driving an LED.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on a +TinyS3 to control its WS2812 LED using the +ESP RMT peripheral.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

image

+

https://github.com/esp-cpp/espp/assets/213467/321cb604-8ecb-40d6-9489-8e995c43f5b9

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rtc/bm8563.html b/rtc/bm8563.html new file mode 100644 index 000000000..849f8b425 --- /dev/null +++ b/rtc/bm8563.html @@ -0,0 +1,982 @@ + + + + + + + BM8563 - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BM8563

+

The Bm8563 component provides a driver for the Bm8563 RTC chip.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Functions

+
+

Warning

+

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. +Potential matches: +

+
- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
+- bool operator==(const Config &rhs) const = default
+- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
+- bool operator==(const Hsv &rhs) const = default
+- bool operator==(const PinConfig &rhs) const = default
+- bool operator==(const PointerData &rhs) const = default
+- bool operator==(const Rgb &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const Vector2d &other) const
+- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
+- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
+- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
+- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
+- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)
+
+
+
+
+

Warning

+

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. +Potential matches: +

+
- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
+- bool operator==(const Config &rhs) const = default
+- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
+- bool operator==(const Hsv &rhs) const = default
+- bool operator==(const PinConfig &rhs) const = default
+- bool operator==(const PointerData &rhs) const = default
+- bool operator==(const Rgb &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const Vector2d &other) const
+- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
+- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
+- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
+- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
+- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)
+
+
+
+
+

Warning

+

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. +Potential matches: +

+
- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
+- bool operator==(const Config &rhs) const = default
+- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
+- bool operator==(const Hsv &rhs) const = default
+- bool operator==(const PinConfig &rhs) const = default
+- bool operator==(const PointerData &rhs) const = default
+- bool operator==(const Rgb &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const TouchpadData &rhs) const = default
+- bool operator==(const Vector2d &other) const
+- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
+- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
+- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
+- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
+- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)
+
+
+
+
+
+

Classes

+
+
+class Bm8563 : public espp::BasePeripheral<>
+

The BM8563 RTC driver.

+

This driver is for the BM8563 RTC chip.

+
+

Example

+
    // make the I2C that we'll use to communicate
+    espp::I2c i2c({
+        .port = I2C_NUM_0,
+        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
+        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
+        .sda_pullup_en = GPIO_PULLUP_ENABLE,
+        .scl_pullup_en = GPIO_PULLUP_ENABLE,
+    });
+    // now make the bm8563
+    auto bm8563 = espp::Bm8563({
+        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+                           std::placeholders::_3),
+        .write_then_read =
+            std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+                      std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
+    });
+
+    std::error_code ec;
+
+    // set the time
+    espp::Bm8563::DateTime date_time = {.date =
+                                            {
+                                                .year = 2023,
+                                                .month = 11,
+                                                .weekday = 4,
+                                                .day = 23,
+                                            },
+                                        .time = {.hour = 8, .minute = 15, .second = 30}};
+    bm8563.set_date_time(date_time, ec);
+    if (ec) {
+      fmt::print("Error setting date time: {}\n", ec.message());
+    } else {
+      fmt::print("Date time set to {}\n", date_time);
+    }
+
+    // and finally, make the task to periodically poll the bm8563 and print
+    // the state
+    auto task_fn = [&bm8563](std::mutex &m, std::condition_variable &cv) {
+      std::error_code ec;
+      // Get the date time and print it
+      auto date_time = bm8563.get_date_time(ec);
+      if (ec) {
+        fmt::print("Error getting date time: {}\n", ec.message());
+      } else {
+        fmt::print("Date time is {}\n", date_time);
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 1s);
+      }
+      return false; // don't stop the task
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "BM8563 Task"},
+                            .log_level = espp::Logger::Verbosity::WARN});
+    task.start();
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(uint8_t)> probe_fn
+

Function to probe the peripheral

+
+
Param address
+

The address to probe

+
+
Return
+

True if the peripheral is found at the given address

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Bm8563(const Config &config)
+

Constructor.

+
+
Parameters
+

config – The configuration.

+
+
+
+ +
+
+inline DateTime get_date_time(std::error_code &ec)
+

Get the date and time.

+
+
Parameters
+

ec – The error code.

+
+
Returns
+

The date and time.

+
+
+
+ +
+
+inline void set_date_time(const DateTime &dt, std::error_code &ec)
+

Set the date and time.

+
+
Parameters
+
    +
  • dt – The date and time.

  • +
  • ec – The error code.

  • +
+
+
+
+ +
+
+inline Date get_date(std::error_code &ec)
+

Get the date.

+
+
Parameters
+

ec – The error code.

+
+
Returns
+

The date.

+
+
+
+ +
+
+inline void set_date(const Date &d, std::error_code &ec)
+

Set the date.

+
+
Parameters
+
    +
  • d – The date.

  • +
  • ec – The error code.

  • +
+
+
+
+ +
+
+inline Time get_time(std::error_code &ec)
+

Get the time.

+
+
Parameters
+

ec – The error code.

+
+
Returns
+

The time.

+
+
+
+ +
+
+inline void set_time(const Time &t, std::error_code &ec)
+

Set the time.

+
+
Parameters
+
    +
  • t – The time.

  • +
  • ec – The error code.

  • +
+
+
+
+ +
+
+inline bool probe(std::error_code &ec)
+

Probe the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

If the probe function is not set, this function will return false and set the error code to operation_not_supported

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

ec – The error code to set if there is an error

+
+
Returns
+

True if the peripheral is found

+
+
+
+ +
+
+inline void set_address(uint8_t address)
+

Set the address of the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

address – The address of the peripheral

+
+
+
+ +
+
+inline void set_probe(const probe_fn &probe)
+

Set the probe function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

+
+
+

Note

+

This function is only available if UseAddress is true

+
+
+
Parameters
+

probe – The probe function

+
+
+
+ +
+
+inline void set_write(const write_fn &write)
+

Set the write function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

+
+
+
Parameters
+

write – The write function

+
+
+
+ +
+
+inline void set_read(const read_fn &read)
+

Set the read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

+
+
+
Parameters
+

read – The read function

+
+
+
+ +
+
+inline void set_read_register(const read_register_fn &read_register)
+

Set the read register function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

+
+
+
Parameters
+

read_register – The read register function

+
+
+
+ +
+
+inline void set_write_then_read(const write_then_read_fn &write_then_read)
+

Set the write then read function

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

+
+
+
Parameters
+

write_then_read – The write then read function

+
+
+
+ +
+
+inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
+

Set the delay between the write and read operations in write_then_read

+
+

Note

+

This function is thread safe

+
+
+

Note

+

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

+
+
+

Note

+

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

+
+
+
Parameters
+

delay – The delay between the write and read operations in write_then_read

+
+
+
+ +
+
+inline void set_config(const Config &config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline void set_config(Config &&config)
+

Set the configuration for the peripheral

+
+

Note

+

This function is thread safe

+
+
+

Note

+

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

+
+
+
Parameters
+

config – The configuration for the peripheral

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline uint8_t bcd2byte(uint8_t value)
+

Convert a BCD value to a byte.

+
+
Parameters
+

value – The BCD value.

+
+
Returns
+

The byte value.

+
+
+
+ +
+
+static inline uint8_t byte2bcd(uint8_t value)
+

Convert a byte value to BCD.

+
+
Parameters
+

value – The byte value.

+
+
Returns
+

The BCD value.

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr uint8_t DEFAULT_ADDRESS = (0x51)
+

The default I2C address for the BM8563.

+
+ +
+
+
+struct Config
+

The configuration structure.

+
+

Public Members

+
+
+BasePeripheral::write_fn write
+

The I2C write function.

+
+ +
+
+BasePeripheral::write_then_read_fn write_then_read
+

The I2C write then read function.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the input driver.

+
+ +
+
+ +
+
+struct Date
+

The date structure.

+
+

Public Members

+
+
+uint16_t year
+

The year.

+
+ +
+
+uint8_t month
+

The month.

+
+ +
+
+uint8_t weekday
+

The day of the week.

+
+ +
+
+uint8_t day
+

The day of the month.

+
+ +
+
+ +
+
+struct DateTime
+

The date and time structure.

+
+

Public Members

+
+
+Date date
+

The date.

+
+ +
+
+Time time
+

The time.

+
+ +
+
+ +
+
+struct Time
+

The time structure.

+
+

Public Members

+
+
+uint8_t hour
+

The hour.

+
+ +
+
+uint8_t minute
+

The minute.

+
+ +
+
+uint8_t second
+

The second.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rtc/bm8563_example.html b/rtc/bm8563_example.html new file mode 100644 index 000000000..e3bf8d27b --- /dev/null +++ b/rtc/bm8563_example.html @@ -0,0 +1,239 @@ + + + + + + + BM8563 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BM8563 Example

+

This example shows how to use the BM8563 RTC driver to set and get the time.

+
+

How to use example

+
+

Hardware Required

+

This example can be run on any ESP32 board, the BM8563 is connected to the ESP32 +via I2C. This example uses the following I2C configuration:

+
    +
  • SDA GPIO 21

  • +
  • SCL GPIO 22

  • +
  • Frequency 400KHz

  • +
+

Which is a working configuration on the ESP32 TimerCam.

+

Note: on the ESP32 TimerCam, you’ll need to use a flash baudrate <= 1500000.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2023-11-06 at 08 26 00

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rtc/index.html b/rtc/index.html new file mode 100644 index 000000000..27533f5ee --- /dev/null +++ b/rtc/index.html @@ -0,0 +1,204 @@ + + + + + + + RTC APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rtsp.html b/rtsp.html new file mode 100644 index 000000000..6ba494138 --- /dev/null +++ b/rtsp.html @@ -0,0 +1,2344 @@ + + + + + + + RTSP APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

RTSP APIs

+
+

RTSP Client

+

The RtspClient class provides an interface to an RTSP server. It is used to +send RTSP requests and receive RTSP responses. It also provides an interface +to the RTP and RTCP sessions that are created as a result of the RTSP +interactions.

+

The RtspClient currently only supports MJPEG streams, since the ESP32 does +not have a hardware decoder for H.264 or H.265.

+

Additionally the client currently only supports UDP transport for RTP and RTCP +packets. TCP transport is not supported.

+

The user can register a callback function to be notified when new, complete JPEG +frames are received. The callback function is called with a pointer to the JPEG +frame.

+
+
+

RTSP Server

+

The RtspServer class provides an implementation of an RTSP server. It is used +to receive RTSP requests and send RTSP responses. It is designed to allow the +user to send JPEG frames to the server, which will then send them to the client +over RTP/UDP.

+

The server currently only supports MJPEG streams, since the ESP32 does not have +a hardware encoder for H.264 or H.265.

+

Additionally, the server currently only supports UDP transport for RTP and RTCP +packets. TCP transport is not supported.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class RtspClient : public espp::BaseComponent
+

A class for interacting with an RTSP server using RTP and RTCP over UDP

+

This class is used to connect to an RTSP server and receive JPEG frames over RTP. It uses the TCP socket to send RTSP requests and receive RTSP responses. It uses the UDP socket to receive RTP and RTCP packets.

+

The RTSP client is designed to be used with the RTSP server in the [camera-streamer]https://github.com/esp-cpp/camera-streamer) project, but it should work with any RTSP server that sends JPEG frames over RTP.

+
+

Example

+
  espp::RtspClient rtsp_client({
+      .server_address = ip_address, // string of the form {}.{}.{}.{}
+      .rtsp_port = CONFIG_RTSP_SERVER_PORT,
+      .path = "/mjpeg/1",
+      .on_jpeg_frame =
+          [](std::unique_ptr<espp::JpegFrame> jpeg_frame) {
+            fmt::print("Got JPEG frame of size {}x{}\n", jpeg_frame->get_width(),
+                       jpeg_frame->get_height());
+          },
+      .log_level = espp::Logger::Verbosity::ERROR,
+  });
+
+  std::error_code ec;
+
+  do {
+    // clear the error code
+    ec.clear();
+    rtsp_client.connect(ec);
+    if (ec) {
+      logger.error("Error connecting to server: {}", ec.message());
+      logger.info("Retrying in 1s...");
+      std::this_thread::sleep_for(1s);
+    }
+  } while (ec);
+
+  rtsp_client.describe(ec);
+  if (ec) {
+    logger.error("Error describing server: {}", ec.message());
+  }
+
+  rtsp_client.setup(ec);
+  if (ec) {
+    logger.error("Error setting up server: {}", ec.message());
+  }
+
+  rtsp_client.play(ec);
+  if (ec) {
+    logger.error("Error playing server: {}", ec.message());
+  }
+
+
+
+
+

Public Types

+
+
+using jpeg_frame_callback_t = std::function<void(std::unique_ptr<JpegFrame> jpeg_frame)>
+

Function type for the callback to call when a JPEG frame is received.

+
+ +
+
+

Public Functions

+
+
+explicit RtspClient(const Config &config)
+

Constructor

+
+
Parameters
+

config – The configuration for the RTSP client

+
+
+
+ +
+
+~RtspClient()
+

Destructor Disconnects from the RTSP server

+
+ +
+
+std::string send_request(const std::string &method, const std::string &path, const std::unordered_map<std::string, std::string> &extra_headers, std::error_code &ec)
+

Send an RTSP request to the server

+
+

Note

+

This is a blocking call

+
+
+

Note

+

This will parse the response and set the session ID if it is present in the response. If the response is not a 200 OK, then an error code will be set and the response will be returned. If the response is a 200 OK, then the response will be returned and the error code will be set to success.

+
+
+
Parameters
+
    +
  • method – The method to use for connecting. Options are “OPTIONS”, “DESCRIBE”, “SETUP”, “PLAY”, and “TEARDOWN”

  • +
  • path – The path to the RTSP stream on the server.

  • +
  • extra_headers – Any extra headers to send with the request. These will be added to the request after the CSeq and Session headers. The key is the header name and the value is the header value. For example, {“Accept”: “application/sdp”} will add “Accept: application/sdp” to the request. The “User-Agent” header will be added automatically. The “CSeq” and “Session” headers will be added automatically. The “Accept” header will be added automatically. The “Transport” header will be added automatically for the “SETUP” method. Defaults to an empty map.

  • +
  • ec – The error code to set if an error occurs

  • +
+
+
Returns
+

The response from the server

+
+
+
+ +
+
+void connect(std::error_code &ec)
+

Connect to the RTSP server Connects to the RTSP server and sends the OPTIONS request.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void disconnect(std::error_code &ec)
+

Disconnect from the RTSP server Disconnects from the RTSP server and sends the TEARDOWN request.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void describe(std::error_code &ec)
+

Describe the RTSP stream Sends the DESCRIBE request to the RTSP server and parses the response.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void setup(std::error_code &ec)
+

Setup the RTSP stream

+
+

Note

+

Starts the RTP and RTCP threads. Sends the SETUP request to the RTSP server and parses the response.

+
+
+

Note

+

The default ports are 5000 and 5001 for RTP and RTCP respectively.

+
+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void setup(size_t rtp_port, size_t rtcp_port, std::error_code &ec)
+

Setup the RTSP stream Sends the SETUP request to the RTSP server and parses the response.

+
+

Note

+

Starts the RTP and RTCP threads.

+
+
+
Parameters
+
    +
  • rtp_port – The RTP client port

  • +
  • rtcp_port – The RTCP client port

  • +
  • ec – The error code to set if an error occurs

  • +
+
+
+
+ +
+
+void play(std::error_code &ec)
+

Play the RTSP stream Sends the PLAY request to the RTSP server and parses the response.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void pause(std::error_code &ec)
+

Pause the RTSP stream Sends the PAUSE request to the RTSP server and parses the response.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+void teardown(std::error_code &ec)
+

Teardown the RTSP stream Sends the TEARDOWN request to the RTSP server and parses the response.

+
+
Parameters
+

ec – The error code to set if an error occurs

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the RTSP client.

+
+

Public Members

+
+
+std::string server_address
+

The server IP Address to connect to.

+
+ +
+
+int rtsp_port = {8554}
+

The port of the RTSP server.

+
+ +
+
+std::string path = {"/mjpeg/1"}
+

The path to the RTSP stream on the server. Will be appended to the server address and port to form the full path of the form “rtsp://<server_address>:<rtsp_port><path>”

+
+ +
+
+espp::RtspClient::jpeg_frame_callback_t on_jpeg_frame
+

The callback to call when a JPEG frame is received.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::INFO
+

The verbosity of the logger.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RtspServer : public espp::BaseComponent
+

Class for streaming MJPEG data from a camera using RTSP + RTP Starts a TCP socket to listen for RTSP connections, and then spawns off a new RTSP session for each connection.

+

See also

+

RtspSession

+
+

+
+

example

+
  const int server_port = CONFIG_RTSP_SERVER_PORT;
+  const std::string server_uri = fmt::format("rtsp://{}:{}/mjpeg/1", ip_address, server_port);
+
+  logger.info("Starting RTSP Server on port {}", server_port);
+  logger.info("RTSP URI: {}", server_uri);
+
+  espp::RtspServer rtsp_server({
+      .server_address = ip_address,
+      .port = server_port,
+      .path = "/mjpeg/1",
+      .log_level = espp::Logger::Verbosity::INFO,
+  });
+  rtsp_server.start();
+
+  espp::JpegFrame jpeg_frame(jpeg_data, sizeof(jpeg_data));
+
+  logger.info("Parsed JPEG image, num bytes: {}", jpeg_frame.get_data().size());
+  logger.info("Created frame of size {}x{}", jpeg_frame.get_width(), jpeg_frame.get_height());
+  rtsp_server.send_frame(jpeg_frame);
+
+
+
+
+

Note

+

This class does not currently send RTCP packets

+
+
+

Public Functions

+
+
+explicit RtspServer(const Config &config)
+

Construct an RTSP server.

+
+
Parameters
+

config – The configuration for the RTSP server

+
+
+
+ +
+
+~RtspServer()
+

Destroy the RTSP server.

+
+ +
+
+void set_session_log_level(espp::Logger::Verbosity log_level)
+

Sets the log level for the RTSP sessions created by this server.

+
+

Note

+

This does not affect the log level of the RTSP server itself

+
+
+

Note

+

This does not change the log level of any sessions that have already been created

+
+
+
Parameters
+

log_level – The log level to set

+
+
+
+ +
+
+bool start()
+

Start the RTSP server Starts the accept task, session task, and binds the RTSP socket.

+
+
Returns
+

True if the server was started successfully, false otherwise

+
+
+
+ +
+
+void stop()
+

Stop the FTP server Stops the accept task, session task, and closes the RTSP socket.

+
+ +
+
+void send_frame(const espp::JpegFrame &frame)
+

Send a frame over the RTSP connection Converts the full JPEG frame into a series of simplified RTP/JPEG packets and stores it to be sent over the RTP socket, but does not actually send it.

+
+

Note

+

Overwrites any existing frame that has not been sent

+
+
+
Parameters
+

frame – The frame to send

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the RTSP server.

+
+

Public Members

+
+
+std::string server_address
+

The ip address of the server.

+
+ +
+
+int port
+

The port to listen on.

+
+ +
+
+std::string path
+

The path to the RTSP stream.

+
+ +
+
+size_t max_data_size = 1000
+

The maximum size of RTP packet data for the MJPEG stream. Frames will be broken up into multiple packets if they are larger than this. It seems that 1500 works well for sending, but is too large for the esp32 (camera-display) to receive properly.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The log level for the RTSP server.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RtspSession : public espp::BaseComponent
+

Class that reepresents an RTSP session, which is uniquely identified by a session id and sends frame data over RTP and RTCP to the client

+
+

Public Functions

+
+
+explicit RtspSession(std::unique_ptr<espp::TcpSocket> control_socket, const Config &config)
+

Construct a new RtspSession object.

+
+
Parameters
+
    +
  • control_socket – The control socket of the session

  • +
  • config – The configuration of the session

  • +
+
+
+
+ +
+
+~RtspSession()
+

Destroy the RtspSession object Stop the session task.

+
+ +
+
+uint32_t get_session_id() const
+

Get the session id.

+
+
Returns
+

The session id

+
+
+
+ +
+
+bool is_closed() const
+

Check if the session is closed.

+
+
Returns
+

True if the session is closed, false otherwise

+
+
+
+ +
+
+bool is_connected() const
+

Get whether the session is connected

+
+
Returns
+

True if the session is connected, false otherwise

+
+
+
+ +
+
+bool is_active() const
+

Get whether the session is active

+
+
Returns
+

True if the session is active, false otherwise

+
+
+
+ +
+
+void play()
+

Mark the session as active This will cause the server to start sending frames to the client

+
+ +
+
+void pause()
+

Pause the session This will cause the server to stop sending frames to the client

+
+

Note

+

This does not stop the session, it just pauses it

+
+
+

Note

+

This is useful for when the client is buffering

+
+
+ +
+
+void teardown()
+

Teardown the session This will cause the server to stop sending frames to the client and close the connection

+
+ +
+
+bool send_rtp_packet(const espp::RtpPacket &packet)
+

Send an RTP packet to the client

+
+
Parameters
+

packet – The RTP packet to send

+
+
Returns
+

True if the packet was sent successfully, false otherwise

+
+
+
+ +
+
+bool send_rtcp_packet(const espp::RtcpPacket &packet)
+

Send an RTCP packet to the client

+
+
Parameters
+

packet – The RTCP packet to send

+
+
Returns
+

True if the packet was sent successfully, false otherwise

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration for the RTSP session.

+
+

Public Members

+
+
+std::string server_address
+

The address of the server.

+
+ +
+
+std::string rtsp_path
+

The RTSP path of the session.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The log level of the session.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RtpPacket
+

RtpPacket is a class to parse RTP packet. It can be used to parse and serialize RTP packets. The RTP header fields are stored in the class and can be modified. The payload is stored in the packet_ vector and can be modified.

+

Subclassed by espp::RtpJpegPacket

+
+

Public Functions

+
+
+RtpPacket()
+

Construct an empty RtpPacket. The packet_ vector is empty and the header fields are set to 0.

+
+ +
+
+explicit RtpPacket(size_t payload_size)
+

Construct an RtpPacket with a payload of size payload_size. The packet_ vector is resized to RTP_HEADER_SIZE + payload_size.

+
+ +
+
+explicit RtpPacket(std::string_view data)
+

Construct an RtpPacket from a string_view. Store the string_view in the packet_ vector and parses the header.

+
+
Parameters
+

data – The string_view to parse.

+
+
+
+ +
+
+~RtpPacket()
+

Destructor.

+
+ +
+
+int get_version() const
+

Get the RTP version.

+
+
Returns
+

The RTP version.

+
+
+
+ +
+
+bool get_padding() const
+

Get the padding flag.

+
+
Returns
+

The padding flag.

+
+
+
+ +
+
+bool get_extension() const
+

Get the extension flag.

+
+
Returns
+

The extension flag.

+
+
+
+ +
+
+int get_csrc_count() const
+

Get the CSRC count.

+
+
Returns
+

The CSRC count.

+
+
+
+ +
+
+bool get_marker() const
+

Get the marker flag.

+
+
Returns
+

The marker flag.

+
+
+
+ +
+
+int get_payload_type() const
+

Get the payload type.

+
+
Returns
+

The payload type.

+
+
+
+ +
+
+int get_sequence_number() const
+

Get the sequence number.

+
+
Returns
+

The sequence number.

+
+
+
+ +
+
+int get_timestamp() const
+

Get the timestamp.

+
+
Returns
+

The timestamp.

+
+
+
+ +
+
+int get_ssrc() const
+

Get the SSRC.

+
+
Returns
+

The SSRC.

+
+
+
+ +
+
+void set_version(int version)
+

Set the RTP version.

+
+
Parameters
+

version – The RTP version to set.

+
+
+
+ +
+
+void set_padding(bool padding)
+

Set the padding flag.

+
+
Parameters
+

padding – The padding flag to set.

+
+
+
+ +
+
+void set_extension(bool extension)
+

Set the extension flag.

+
+
Parameters
+

extension – The extension flag to set.

+
+
+
+ +
+
+void set_csrc_count(int csrc_count)
+

Set the CSRC count.

+
+
Parameters
+

csrc_count – The CSRC count to set.

+
+
+
+ +
+
+void set_marker(bool marker)
+

Set the marker flag.

+
+
Parameters
+

marker – The marker flag to set.

+
+
+
+ +
+
+void set_payload_type(int payload_type)
+

Set the payload type.

+
+
Parameters
+

payload_type – The payload type to set.

+
+
+
+ +
+
+void set_sequence_number(int sequence_number)
+

Set the sequence number.

+
+
Parameters
+

sequence_number – The sequence number to set.

+
+
+
+ +
+
+void set_timestamp(int timestamp)
+

Set the timestamp.

+
+
Parameters
+

timestamp – The timestamp to set.

+
+
+
+ +
+
+void set_ssrc(int ssrc)
+

Set the SSRC.

+
+
Parameters
+

ssrc – The SSRC to set.

+
+
+
+ +
+
+void serialize()
+

Serialize the RTP header.

+
+

Note

+

This method should be called after modifying the RTP header fields.

+
+
+

Note

+

This method does not serialize the payload. To set the payload, use set_payload(). To get the payload, use get_payload().

+
+
+ +
+
+std::string_view get_data() const
+

Get a string_view of the whole packet.

+
+

Note

+

The string_view is valid as long as the packet_ vector is not modified.

+
+
+

Note

+

If you manually build the packet_ vector, you should make sure that you call serialize() before calling this method.

+
+
+
Returns
+

A string_view of the whole packet.

+
+
+
+ +
+
+size_t get_rtp_header_size() const
+

Get the size of the RTP header.

+
+
Returns
+

The size of the RTP header.

+
+
+
+ +
+
+std::string_view get_rpt_header() const
+

Get a string_view of the RTP header.

+
+
Returns
+

A string_view of the RTP header.

+
+
+
+ +
+
+std::vector<uint8_t> &get_packet()
+

Get a reference to the packet_ vector.

+
+
Returns
+

A reference to the packet_ vector.

+
+
+
+ +
+
+std::string_view get_payload() const
+

Get a string_view of the payload.

+
+
Returns
+

A string_view of the payload.

+
+
+
+ +
+
+void set_payload(std::string_view payload)
+

Set the payload.

+
+
Parameters
+

payload – The payload to set.

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RtpJpegPacket : public espp::RtpPacket
+

RTP packet for JPEG video. The RTP payload for JPEG is defined in RFC 2435.

+
+

Public Functions

+
+
+inline explicit RtpJpegPacket(std::string_view data)
+

Construct an RTP packet from a buffer.

+
+
Parameters
+

data – The buffer containing the RTP packet.

+
+
+
+ +
+
+inline explicit RtpJpegPacket(const int type_specific, const int frag_type, const int q, const int width, const int height, std::string_view q0, std::string_view q1, std::string_view scan_data)
+

Construct an RTP packet from fields

+

This will construct a packet with quantization tables, so it can only be used for the first packet in a frame.

+
+
Parameters
+
    +
  • type_specific – The type-specific field.

  • +
  • frag_type – The fragment type field.

  • +
  • q – The q field.

  • +
  • width – The width field.

  • +
  • height – The height field.

  • +
  • q0 – The first quantization table.

  • +
  • q1 – The second quantization table.

  • +
  • scan_data – The scan data.

  • +
+
+
+
+ +
+
+inline explicit RtpJpegPacket(const int type_specific, const int offset, const int frag_type, const int q, const int width, const int height, std::string_view scan_data)
+

Construct an RTP packet from fields

+

This will construct a packet without quantization tables, so it cannot be used for the first packet in a frame.

+
+
Parameters
+
    +
  • type_specific – The type-specific field.

  • +
  • offset – The offset field.

  • +
  • frag_type – The fragment type field.

  • +
  • q – The q field.

  • +
  • width – The width field.

  • +
  • height – The height field.

  • +
  • scan_data – The scan data.

  • +
+
+
+
+ +
+
+inline int get_type_specific() const
+

Get the type-specific field.

+
+
Returns
+

The type-specific field.

+
+
+
+ +
+
+inline int get_offset() const
+

Get the offset field.

+
+
Returns
+

The offset field.

+
+
+
+ +
+
+inline int get_q() const
+

Get the fragment type field.

+
+
Returns
+

The fragment type field.

+
+
+
+ +
+
+inline int get_width() const
+

Get the fragment type field.

+
+
Returns
+

The fragment type field.

+
+
+
+ +
+
+inline int get_height() const
+

Get the fragment type field.

+
+
Returns
+

The fragment type field.

+
+
+
+ +
+
+inline std::string_view get_mjpeg_header() const
+

Get the mjepg header.

+
+
Returns
+

The mjepg header.

+
+
+
+ +
+
+inline bool has_q_tables() const
+

Get whether the packet contains quantization tables.

+
+

Note

+

The quantization tables are optional. If they are present, the number of quantization tables is always 2.

+
+
+

Note

+

This check is based on the value of the q field. If the q field is 128-256, the packet contains quantization tables.

+
+
+
Returns
+

Whether the packet contains quantization tables.

+
+
+
+ +
+
+inline int get_num_q_tables() const
+

Get the number of quantization tables.

+
+

Note

+

The quantization tables are optional. If they are present, the number of quantization tables is always 2.

+
+
+

Note

+

Only the first packet in a frame contains quantization tables.

+
+
+
Returns
+

The number of quantization tables.

+
+
+
+ +
+
+inline std::string_view get_q_table(int index) const
+

Get the quantization table at the specified index.

+
+
Parameters
+

index – The index of the quantization table.

+
+
Returns
+

The quantization table at the specified index.

+
+
+
+ +
+
+inline std::string_view get_jpeg_data() const
+

Get the JPEG data. The jpeg data is the payload minus the mjpeg header and quantization tables.

+
+
Returns
+

The JPEG data.

+
+
+
+ +
+
+int get_version() const
+

Get the RTP version.

+
+
Returns
+

The RTP version.

+
+
+
+ +
+
+bool get_padding() const
+

Get the padding flag.

+
+
Returns
+

The padding flag.

+
+
+
+ +
+
+bool get_extension() const
+

Get the extension flag.

+
+
Returns
+

The extension flag.

+
+
+
+ +
+
+int get_csrc_count() const
+

Get the CSRC count.

+
+
Returns
+

The CSRC count.

+
+
+
+ +
+
+bool get_marker() const
+

Get the marker flag.

+
+
Returns
+

The marker flag.

+
+
+
+ +
+
+int get_payload_type() const
+

Get the payload type.

+
+
Returns
+

The payload type.

+
+
+
+ +
+
+int get_sequence_number() const
+

Get the sequence number.

+
+
Returns
+

The sequence number.

+
+
+
+ +
+
+int get_timestamp() const
+

Get the timestamp.

+
+
Returns
+

The timestamp.

+
+
+
+ +
+
+int get_ssrc() const
+

Get the SSRC.

+
+
Returns
+

The SSRC.

+
+
+
+ +
+
+void set_version(int version)
+

Set the RTP version.

+
+
Parameters
+

version – The RTP version to set.

+
+
+
+ +
+
+void set_padding(bool padding)
+

Set the padding flag.

+
+
Parameters
+

padding – The padding flag to set.

+
+
+
+ +
+
+void set_extension(bool extension)
+

Set the extension flag.

+
+
Parameters
+

extension – The extension flag to set.

+
+
+
+ +
+
+void set_csrc_count(int csrc_count)
+

Set the CSRC count.

+
+
Parameters
+

csrc_count – The CSRC count to set.

+
+
+
+ +
+
+void set_marker(bool marker)
+

Set the marker flag.

+
+
Parameters
+

marker – The marker flag to set.

+
+
+
+ +
+
+void set_payload_type(int payload_type)
+

Set the payload type.

+
+
Parameters
+

payload_type – The payload type to set.

+
+
+
+ +
+
+void set_sequence_number(int sequence_number)
+

Set the sequence number.

+
+
Parameters
+

sequence_number – The sequence number to set.

+
+
+
+ +
+
+void set_timestamp(int timestamp)
+

Set the timestamp.

+
+
Parameters
+

timestamp – The timestamp to set.

+
+
+
+ +
+
+void set_ssrc(int ssrc)
+

Set the SSRC.

+
+
Parameters
+

ssrc – The SSRC to set.

+
+
+
+ +
+
+void serialize()
+

Serialize the RTP header.

+
+

Note

+

This method should be called after modifying the RTP header fields.

+
+
+

Note

+

This method does not serialize the payload. To set the payload, use set_payload(). To get the payload, use get_payload().

+
+
+ +
+
+std::string_view get_data() const
+

Get a string_view of the whole packet.

+
+

Note

+

The string_view is valid as long as the packet_ vector is not modified.

+
+
+

Note

+

If you manually build the packet_ vector, you should make sure that you call serialize() before calling this method.

+
+
+
Returns
+

A string_view of the whole packet.

+
+
+
+ +
+
+size_t get_rtp_header_size() const
+

Get the size of the RTP header.

+
+
Returns
+

The size of the RTP header.

+
+
+
+ +
+
+std::string_view get_rpt_header() const
+

Get a string_view of the RTP header.

+
+
Returns
+

A string_view of the RTP header.

+
+
+
+ +
+
+std::vector<uint8_t> &get_packet()
+

Get a reference to the packet_ vector.

+
+
Returns
+

A reference to the packet_ vector.

+
+
+
+ +
+
+std::string_view get_payload() const
+

Get a string_view of the payload.

+
+
Returns
+

A string_view of the payload.

+
+
+
+ +
+
+void set_payload(std::string_view payload)
+

Set the payload.

+
+
Parameters
+

payload – The payload to set.

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class RtcpPacket
+

A class to represent a RTCP packet.

+

This class is used to represent a RTCP packet. It is used as a base class for all RTCP packet types.

+
+

Note

+

At the moment, this class is not used.

+
+
+

Public Functions

+
+
+RtcpPacket() = default
+

Constructor, default.

+
+ +
+
+virtual ~RtcpPacket() = default
+

Destructor, default.

+
+ +
+
+std::string_view get_data() const
+

Get the buffer of the packet.

+
+
Returns
+

The buffer of the packet

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class JpegHeader
+

A class to generate a JPEG header for a given image size and quantization tables. The header is generated once and then cached for future use. The header is generated according to the JPEG standard and is compatible with the ESP32 camera driver.

+
+

Public Functions

+
+
+inline explicit JpegHeader(int width, int height, std::string_view q0_table, std::string_view q1_table)
+

Create a JPEG header for a given image size and quantization tables.

+
+
Parameters
+
    +
  • width – The image width in pixels.

  • +
  • height – The image height in pixels.

  • +
  • q0_table – The quantization table for the Y channel.

  • +
  • q1_table – The quantization table for the Cb and Cr channels.

  • +
+
+
+
+ +
+
+inline explicit JpegHeader(std::string_view data)
+

Create a JPEG header from a given JPEG header data.

+
+ +
+
+inline int get_width() const
+

Get the image width.

+
+
Returns
+

The image width in pixels.

+
+
+
+ +
+
+inline int get_height() const
+

Get the image height.

+
+
Returns
+

The image height in pixels.

+
+
+
+ +
+
+inline std::string_view get_data() const
+

Get the JPEG header data.

+
+
Returns
+

The JPEG header data.

+
+
+
+ +
+
+inline std::string_view get_quantization_table(int index) const
+

Get the Quantization table at the index.

+
+
Parameters
+

index – The index of the quantization table.

+
+
Returns
+

The quantization table.

+
+
+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class JpegFrame
+

A class that represents a complete JPEG frame.

+

This class is used to collect the JPEG scans that are received in RTP packets and to serialize them into a complete JPEG frame.

+
+

Public Functions

+
+
+inline explicit JpegFrame(const RtpJpegPacket &packet)
+

Construct a JpegFrame from a RtpJpegPacket.

+

This constructor will parse the header of the packet and add the JPEG data to the frame.

+
+
Parameters
+

packet – The packet to parse.

+
+
+
+ +
+
+inline explicit JpegFrame(const char *data, size_t size)
+

Construct a JpegFrame from buffer of jpeg data

+
+
Parameters
+
    +
  • data – The buffer containing the jpeg data.

  • +
  • size – The size of the buffer.

  • +
+
+
+
+ +
+
+inline const JpegHeader &get_header() const
+

Get a reference to the header.

+
+
Returns
+

A reference to the header.

+
+
+
+ +
+
+inline int get_width() const
+

Get the width of the frame.

+
+
Returns
+

The width of the frame.

+
+
+
+ +
+
+inline int get_height() const
+

Get the height of the frame.

+
+
Returns
+

The height of the frame.

+
+
+
+ +
+
+inline bool is_complete() const
+

Check if the frame is complete.

+
+
Returns
+

True if the frame is complete, false otherwise.

+
+
+
+ +
+
+inline void append(const RtpJpegPacket &packet)
+

Append a RtpJpegPacket to the frame. This will add the JPEG data to the frame.

+
+
Parameters
+

packet – The packet containing the scan to append.

+
+
+
+ +
+
+inline void add_scan(const RtpJpegPacket &packet)
+

Append a JPEG scan to the frame. This will add the JPEG data to the frame.

+
+

Note

+

If the packet contains the EOI marker, the frame will be finalized, and no further scans can be added.

+
+
+
Parameters
+

packet – The packet containing the scan to append.

+
+
+
+ +
+
+inline std::string_view get_data() const
+

Get the serialized data. This will return the serialized data.

+
+
Returns
+

The serialized data.

+
+
+
+ +
+
+inline std::string_view get_scan_data() const
+

Get the scan data. This will return the scan data.

+
+
Returns
+

The scan data.

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/rtsp_example.html b/rtsp_example.html new file mode 100644 index 000000000..0affeb5f1 --- /dev/null +++ b/rtsp_example.html @@ -0,0 +1,255 @@ + + + + + + + RTSP Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

RTSP Example

+

This example shows the use of the espp::RtspServer and espp::RtspClient +classes provided by the rtsp component for performing streaming of JPEG images +(espp::JpegFrame) using the MJPEG format over the Real Time Streaming +Protocol (RTSP) / Real Time Protocol (RTP) packets.

+

For more complete example use, see the +camera-streamer and +camera-display repositories.

+
+

How to use example

+
+

Hardware Required

+

This example is designed to be run on an M5Stack ESP32 Timer Cam module (server) or a +ESP32-S3-Box (client).

+
+
+

Configure the project

+
idf.py menuconfig
+
+
+

You need to configure the WiFi network in the RTSP Example Configuration +menuconfig and you can optionally configure the RTSP Server Port (default +8554).

+
+
+

Build and Flash

+

NOTE: this example is designed to be modified into client only or server-only operation depending on the hardware it is deployed to.

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

Example showing the server (camera), the client (handheld display), and the python client, with both clients connected simultaneously:

+

https://user-images.githubusercontent.com/213467/236601258-c334e1ba-5e18-4452-b48d-e792ec2ed4fb.mp4

+

Screenshot showing the server running for a very long time (all day, see timestamp in log > 33,000 seconds): +all_day_test

+

Screenshot showing the received framerate on the camera-display: +CleanShot 2023-05-06 at 10 27 21@2x

+

Screenshot of main code for camera-streamer output: +CleanShot 2023-05-06 at 10 29 31@2x

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 000000000..714b8fce6 --- /dev/null +++ b/search.html @@ -0,0 +1,207 @@ + + + + + + Search - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..9d512e42e --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["adc/adc_example","adc/adc_types","adc/ads1x15","adc/ads1x15_example","adc/ads7138","adc/ads7138_example","adc/continuous_adc","adc/index","adc/oneshot_adc","adc/tla2528","adc/tla2528_example","base_component","base_peripheral","battery/index","battery/max1704x","battery/max1704x_example","bldc/bldc_driver","bldc/bldc_motor","bldc/bldc_motor_example","bldc/index","ble/battery_service","ble/ble_gatt_server","ble/ble_gatt_server_example","ble/device_info_service","ble/gfps_service","ble/gfps_service_example","ble/hid_service","ble/hid_service_example","ble/index","button","button_example","cli","cli_example","color","color_example","controller","controller_example","csv","csv_example","display/display","display/display_drivers","display/display_drivers_example","display/index","encoder/abi_encoder","encoder/as5600","encoder/as5600_example","encoder/encoder_example","encoder/encoder_types","encoder/index","encoder/mt6701","encoder/mt6701_example","esp32_timer_cam","esp32_timer_cam_example","esp_box","esp_box_example","event_manager","event_manager_example","file_system","file_system_example","filters/biquad","filters/butterworth","filters/filters_example","filters/index","filters/lowpass","filters/simple_lowpass","filters/sos","filters/transfer_function","ftp/ftp_server","ftp/ftp_server_example","ftp/index","haptics/bldc_haptics","haptics/bldc_haptics_example","haptics/drv2605","haptics/drv2605_example","haptics/index","hid/hid-rp","hid/hid-rp_example","hid/index","i2c","i2c_example","index","input/chsc6x","input/chsc6x_example","input/cst816","input/cst816_example","input/encoder_input","input/ft5x06","input/ft5x06_example","input/gt911","input/gt911_example","input/index","input/keypad_input","input/pointer_input","input/t_keyboard","input/t_keyboard_example","input/touchpad_input","input/tt21100","input/tt21100_example","interrupt","interrupt_example","io_expander/aw9523","io_expander/aw9523_example","io_expander/index","io_expander/kts1622","io_expander/kts1622_example","io_expander/mcp23x17","io_expander/mcp23x17_example","joystick","joystick_example","led","led_example","led_strip","led_strip_example","logger","logger_example","math/bezier","math/fast_math","math/gaussian","math/index","math/math_example","math/range_mapper","math/vector2d","matouch_rotary_display","matouch_rotary_display_example","monitor","monitor_example","motorgo_mini","motorgo_mini_example","network/index","network/socket","network/socket_example","network/tcp_socket","network/udp_socket","nfc/index","nfc/ndef","nfc/st25dv","nfc/st25dv_example","nvs","nvs_example","pid","pid_example","qwiicnes","qwiicnes_example","rmt","rmt_example","rtc/bm8563","rtc/bm8563_example","rtc/index","rtsp","rtsp_example","seeed_studio_round_display","seeed_studio_round_display_example","serialization","serialization_example","state_machine","state_machine_example","t_deck","t_deck_example","t_dongle_s3","t_dongle_s3_example","tabulate","tabulate_example","task","task_example","thermistor","thermistor_example","timer","timer_example","wifi/index","wifi/wifi_ap","wifi/wifi_example","wifi/wifi_sta","wrover_kit","wrover_kit_example"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":5,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.todo":2,sphinx:56},filenames:["adc/adc_example.md","adc/adc_types.rst","adc/ads1x15.rst","adc/ads1x15_example.md","adc/ads7138.rst","adc/ads7138_example.md","adc/continuous_adc.rst","adc/index.rst","adc/oneshot_adc.rst","adc/tla2528.rst","adc/tla2528_example.md","base_component.rst","base_peripheral.rst","battery/index.rst","battery/max1704x.rst","battery/max1704x_example.md","bldc/bldc_driver.rst","bldc/bldc_motor.rst","bldc/bldc_motor_example.md","bldc/index.rst","ble/battery_service.rst","ble/ble_gatt_server.rst","ble/ble_gatt_server_example.md","ble/device_info_service.rst","ble/gfps_service.rst","ble/gfps_service_example.md","ble/hid_service.rst","ble/hid_service_example.md","ble/index.rst","button.rst","button_example.md","cli.rst","cli_example.md","color.rst","color_example.md","controller.rst","controller_example.md","csv.rst","csv_example.md","display/display.rst","display/display_drivers.rst","display/display_drivers_example.md","display/index.rst","encoder/abi_encoder.rst","encoder/as5600.rst","encoder/as5600_example.md","encoder/encoder_example.md","encoder/encoder_types.rst","encoder/index.rst","encoder/mt6701.rst","encoder/mt6701_example.md","esp32_timer_cam.rst","esp32_timer_cam_example.md","esp_box.rst","esp_box_example.md","event_manager.rst","event_manager_example.md","file_system.rst","file_system_example.md","filters/biquad.rst","filters/butterworth.rst","filters/filters_example.md","filters/index.rst","filters/lowpass.rst","filters/simple_lowpass.rst","filters/sos.rst","filters/transfer_function.rst","ftp/ftp_server.rst","ftp/ftp_server_example.md","ftp/index.rst","haptics/bldc_haptics.rst","haptics/bldc_haptics_example.md","haptics/drv2605.rst","haptics/drv2605_example.md","haptics/index.rst","hid/hid-rp.rst","hid/hid-rp_example.md","hid/index.rst","i2c.rst","i2c_example.md","index.rst","input/chsc6x.rst","input/chsc6x_example.md","input/cst816.rst","input/cst816_example.md","input/encoder_input.rst","input/ft5x06.rst","input/ft5x06_example.md","input/gt911.rst","input/gt911_example.md","input/index.rst","input/keypad_input.rst","input/pointer_input.rst","input/t_keyboard.rst","input/t_keyboard_example.md","input/touchpad_input.rst","input/tt21100.rst","input/tt21100_example.md","interrupt.rst","interrupt_example.md","io_expander/aw9523.rst","io_expander/aw9523_example.md","io_expander/index.rst","io_expander/kts1622.rst","io_expander/kts1622_example.md","io_expander/mcp23x17.rst","io_expander/mcp23x17_example.md","joystick.rst","joystick_example.md","led.rst","led_example.md","led_strip.rst","led_strip_example.md","logger.rst","logger_example.md","math/bezier.rst","math/fast_math.rst","math/gaussian.rst","math/index.rst","math/math_example.md","math/range_mapper.rst","math/vector2d.rst","matouch_rotary_display.rst","matouch_rotary_display_example.md","monitor.rst","monitor_example.md","motorgo_mini.rst","motorgo_mini_example.md","network/index.rst","network/socket.rst","network/socket_example.md","network/tcp_socket.rst","network/udp_socket.rst","nfc/index.rst","nfc/ndef.rst","nfc/st25dv.rst","nfc/st25dv_example.md","nvs.rst","nvs_example.md","pid.rst","pid_example.md","qwiicnes.rst","qwiicnes_example.md","rmt.rst","rmt_example.md","rtc/bm8563.rst","rtc/bm8563_example.md","rtc/index.rst","rtsp.rst","rtsp_example.md","seeed_studio_round_display.rst","seeed_studio_round_display_example.md","serialization.rst","serialization_example.md","state_machine.rst","state_machine_example.md","t_deck.rst","t_deck_example.md","t_dongle_s3.rst","t_dongle_s3_example.md","tabulate.rst","tabulate_example.md","task.rst","task_example.md","thermistor.rst","thermistor_example.md","timer.rst","timer_example.md","wifi/index.rst","wifi/wifi_ap.rst","wifi/wifi_example.md","wifi/wifi_sta.rst","wrover_kit.rst","wrover_kit_example.md"],objects:{"":[[113,0,1,"c.CONFIG_ESPP_LOGGER_LOG_LEVEL","CONFIG_ESPP_LOGGER_LOG_LEVEL"],[113,0,1,"c.ESPP_LOGGER_CURSOR_COMMANDS_ENABLED","ESPP_LOGGER_CURSOR_COMMANDS_ENABLED"],[113,0,1,"c.ESPP_LOGGER_DEBUG_ENABLED","ESPP_LOGGER_DEBUG_ENABLED"],[113,0,1,"c.ESPP_LOGGER_ERROR_ENABLED","ESPP_LOGGER_ERROR_ENABLED"],[113,0,1,"c.ESPP_LOGGER_INFO_ENABLED","ESPP_LOGGER_INFO_ENABLED"],[113,0,1,"c.ESPP_LOGGER_LOG_LEVEL_DEBUG","ESPP_LOGGER_LOG_LEVEL_DEBUG"],[113,0,1,"c.ESPP_LOGGER_LOG_LEVEL_ERROR","ESPP_LOGGER_LOG_LEVEL_ERROR"],[113,0,1,"c.ESPP_LOGGER_LOG_LEVEL_INFO","ESPP_LOGGER_LOG_LEVEL_INFO"],[113,0,1,"c.ESPP_LOGGER_LOG_LEVEL_NONE","ESPP_LOGGER_LOG_LEVEL_NONE"],[113,0,1,"c.ESPP_LOGGER_LOG_LEVEL_WARN","ESPP_LOGGER_LOG_LEVEL_WARN"],[113,0,1,"c.ESPP_LOGGER_WARN_ENABLED","ESPP_LOGGER_WARN_ENABLED"],[154,0,1,"c.MAGIC_ENUM_NO_CHECK_SUPPORT","MAGIC_ENUM_NO_CHECK_SUPPORT"],[37,0,1,"c.__gnu_linux__","__gnu_linux__"],[152,0,1,"c.__gnu_linux__","__gnu_linux__"],[160,0,1,"c.__unix__","__unix__"],[134,1,1,"_CPPv4N19PhonyNameDueToError3rawE","PhonyNameDueToError::raw"],[135,1,1,"_CPPv4N19PhonyNameDueToError3rawE","PhonyNameDueToError::raw"],[141,1,1,"_CPPv4N19PhonyNameDueToError3rawE","PhonyNameDueToError::raw"],[43,2,1,"_CPPv4I_11EncoderTypeEN4espp10AbiEncoderE","espp::AbiEncoder"],[43,3,1,"_CPPv4I_11EncoderTypeEN4espp10AbiEncoder10AbiEncoderERK6Config","espp::AbiEncoder::AbiEncoder"],[43,4,1,"_CPPv4I_11EncoderTypeEN4espp10AbiEncoder10AbiEncoderERK6Config","espp::AbiEncoder::AbiEncoder::config"],[43,5,1,"_CPPv4I_11EncoderTypeEN4espp10AbiEncoder10AbiEncoderERK6Config","espp::AbiEncoder::AbiEncoder::type"],[43,2,1,"_CPPv4N4espp10AbiEncoder6ConfigE","espp::AbiEncoder::Config"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config6a_gpioE","espp::AbiEncoder::Config::a_gpio"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config6b_gpioE","espp::AbiEncoder::Config::b_gpio"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config21counts_per_revolutionE","espp::AbiEncoder::Config::counts_per_revolution"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config10high_limitE","espp::AbiEncoder::Config::high_limit"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config6i_gpioE","espp::AbiEncoder::Config::i_gpio"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config9log_levelE","espp::AbiEncoder::Config::log_level"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config9low_limitE","espp::AbiEncoder::Config::low_limit"],[43,1,1,"_CPPv4N4espp10AbiEncoder6Config13max_glitch_nsE","espp::AbiEncoder::Config::max_glitch_ns"],[43,5,1,"_CPPv4I_11EncoderTypeEN4espp10AbiEncoderE","espp::AbiEncoder::T"],[43,3,1,"_CPPv4N4espp10AbiEncoder5clearEv","espp::AbiEncoder::clear"],[43,3,1,"_CPPv4N4espp10AbiEncoder9get_countEv","espp::AbiEncoder::get_count"],[43,3,1,"_CPPv4N4espp10AbiEncoder11get_degreesEv","espp::AbiEncoder::get_degrees"],[43,3,1,"_CPPv4NK4espp10AbiEncoder13get_log_levelEv","espp::AbiEncoder::get_log_level"],[43,3,1,"_CPPv4NK4espp10AbiEncoder17get_log_verbosityEv","espp::AbiEncoder::get_log_verbosity"],[43,3,1,"_CPPv4NK4espp10AbiEncoder8get_nameEv","espp::AbiEncoder::get_name"],[43,3,1,"_CPPv4N4espp10AbiEncoder11get_radiansEv","espp::AbiEncoder::get_radians"],[43,3,1,"_CPPv4N4espp10AbiEncoder15get_revolutionsEv","espp::AbiEncoder::get_revolutions"],[43,3,1,"_CPPv4N4espp10AbiEncoder13set_log_levelEN4espp6Logger9VerbosityE","espp::AbiEncoder::set_log_level"],[43,4,1,"_CPPv4N4espp10AbiEncoder13set_log_levelEN4espp6Logger9VerbosityE","espp::AbiEncoder::set_log_level::level"],[43,3,1,"_CPPv4N4espp10AbiEncoder18set_log_rate_limitENSt6chrono8durationIfEE","espp::AbiEncoder::set_log_rate_limit"],[43,4,1,"_CPPv4N4espp10AbiEncoder18set_log_rate_limitENSt6chrono8durationIfEE","espp::AbiEncoder::set_log_rate_limit::rate_limit"],[43,3,1,"_CPPv4N4espp10AbiEncoder11set_log_tagERKNSt11string_viewE","espp::AbiEncoder::set_log_tag"],[43,4,1,"_CPPv4N4espp10AbiEncoder11set_log_tagERKNSt11string_viewE","espp::AbiEncoder::set_log_tag::tag"],[43,3,1,"_CPPv4N4espp10AbiEncoder17set_log_verbosityEN4espp6Logger9VerbosityE","espp::AbiEncoder::set_log_verbosity"],[43,4,1,"_CPPv4N4espp10AbiEncoder17set_log_verbosityEN4espp6Logger9VerbosityE","espp::AbiEncoder::set_log_verbosity::level"],[43,3,1,"_CPPv4N4espp10AbiEncoder5startEv","espp::AbiEncoder::start"],[43,3,1,"_CPPv4N4espp10AbiEncoder4stopEv","espp::AbiEncoder::stop"],[43,3,1,"_CPPv4N4espp10AbiEncoderD0Ev","espp::AbiEncoder::~AbiEncoder"],[2,2,1,"_CPPv4N4espp7Ads1x15E","espp::Ads1x15"],[2,2,1,"_CPPv4N4espp7Ads1x1513Ads1015ConfigE","espp::Ads1x15::Ads1015Config"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config14device_addressE","espp::Ads1x15::Ads1015Config::device_address"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config4gainE","espp::Ads1x15::Ads1015Config::gain"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config9log_levelE","espp::Ads1x15::Ads1015Config::log_level"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config4readE","espp::Ads1x15::Ads1015Config::read"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config11sample_rateE","espp::Ads1x15::Ads1015Config::sample_rate"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1015Config5writeE","espp::Ads1x15::Ads1015Config::write"],[2,6,1,"_CPPv4N4espp7Ads1x1511Ads1015RateE","espp::Ads1x15::Ads1015Rate"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate6SPS128E","espp::Ads1x15::Ads1015Rate::SPS128"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate7SPS1600E","espp::Ads1x15::Ads1015Rate::SPS1600"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate7SPS2400E","espp::Ads1x15::Ads1015Rate::SPS2400"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate6SPS250E","espp::Ads1x15::Ads1015Rate::SPS250"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate7SPS3300E","espp::Ads1x15::Ads1015Rate::SPS3300"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate6SPS490E","espp::Ads1x15::Ads1015Rate::SPS490"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1015Rate6SPS920E","espp::Ads1x15::Ads1015Rate::SPS920"],[2,2,1,"_CPPv4N4espp7Ads1x1513Ads1115ConfigE","espp::Ads1x15::Ads1115Config"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config14device_addressE","espp::Ads1x15::Ads1115Config::device_address"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config4gainE","espp::Ads1x15::Ads1115Config::gain"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config9log_levelE","espp::Ads1x15::Ads1115Config::log_level"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config4readE","espp::Ads1x15::Ads1115Config::read"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config11sample_rateE","espp::Ads1x15::Ads1115Config::sample_rate"],[2,1,1,"_CPPv4N4espp7Ads1x1513Ads1115Config5writeE","espp::Ads1x15::Ads1115Config::write"],[2,6,1,"_CPPv4N4espp7Ads1x1511Ads1115RateE","espp::Ads1x15::Ads1115Rate"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate6SPS128E","espp::Ads1x15::Ads1115Rate::SPS128"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate5SPS16E","espp::Ads1x15::Ads1115Rate::SPS16"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate6SPS250E","espp::Ads1x15::Ads1115Rate::SPS250"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate5SPS32E","espp::Ads1x15::Ads1115Rate::SPS32"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate6SPS475E","espp::Ads1x15::Ads1115Rate::SPS475"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate5SPS64E","espp::Ads1x15::Ads1115Rate::SPS64"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate4SPS8E","espp::Ads1x15::Ads1115Rate::SPS8"],[2,7,1,"_CPPv4N4espp7Ads1x1511Ads1115Rate6SPS860E","espp::Ads1x15::Ads1115Rate::SPS860"],[2,3,1,"_CPPv4N4espp7Ads1x157Ads1x15ERK13Ads1015Config","espp::Ads1x15::Ads1x15"],[2,3,1,"_CPPv4N4espp7Ads1x157Ads1x15ERK13Ads1115Config","espp::Ads1x15::Ads1x15"],[2,4,1,"_CPPv4N4espp7Ads1x157Ads1x15ERK13Ads1015Config","espp::Ads1x15::Ads1x15::config"],[2,4,1,"_CPPv4N4espp7Ads1x157Ads1x15ERK13Ads1115Config","espp::Ads1x15::Ads1x15::config"],[2,1,1,"_CPPv4N4espp7Ads1x1515DEFAULT_ADDRESSE","espp::Ads1x15::DEFAULT_ADDRESS"],[2,6,1,"_CPPv4N4espp7Ads1x154GainE","espp::Ads1x15::Gain"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain5EIGHTE","espp::Ads1x15::Gain::EIGHT"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain4FOURE","espp::Ads1x15::Gain::FOUR"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain3ONEE","espp::Ads1x15::Gain::ONE"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain7SIXTEENE","espp::Ads1x15::Gain::SIXTEEN"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain3TWOE","espp::Ads1x15::Gain::TWO"],[2,7,1,"_CPPv4N4espp7Ads1x154Gain9TWOTHIRDSE","espp::Ads1x15::Gain::TWOTHIRDS"],[2,3,1,"_CPPv4NK4espp7Ads1x1513get_log_levelEv","espp::Ads1x15::get_log_level"],[2,3,1,"_CPPv4NK4espp7Ads1x1517get_log_verbosityEv","espp::Ads1x15::get_log_verbosity"],[2,3,1,"_CPPv4NK4espp7Ads1x158get_nameEv","espp::Ads1x15::get_name"],[2,3,1,"_CPPv4N4espp7Ads1x155probeERNSt10error_codeE","espp::Ads1x15::probe"],[2,4,1,"_CPPv4N4espp7Ads1x155probeERNSt10error_codeE","espp::Ads1x15::probe::ec"],[2,8,1,"_CPPv4N4espp7Ads1x158probe_fnE","espp::Ads1x15::probe_fn"],[2,3,1,"_CPPv4N4espp7Ads1x159sample_mvEiRNSt10error_codeE","espp::Ads1x15::sample_mv"],[2,4,1,"_CPPv4N4espp7Ads1x159sample_mvEiRNSt10error_codeE","espp::Ads1x15::sample_mv::channel"],[2,4,1,"_CPPv4N4espp7Ads1x159sample_mvEiRNSt10error_codeE","espp::Ads1x15::sample_mv::ec"],[2,3,1,"_CPPv4N4espp7Ads1x1511set_addressE7uint8_t","espp::Ads1x15::set_address"],[2,4,1,"_CPPv4N4espp7Ads1x1511set_addressE7uint8_t","espp::Ads1x15::set_address::address"],[2,3,1,"_CPPv4N4espp7Ads1x1510set_configERK6Config","espp::Ads1x15::set_config"],[2,3,1,"_CPPv4N4espp7Ads1x1510set_configERR6Config","espp::Ads1x15::set_config"],[2,4,1,"_CPPv4N4espp7Ads1x1510set_configERK6Config","espp::Ads1x15::set_config::config"],[2,4,1,"_CPPv4N4espp7Ads1x1510set_configERR6Config","espp::Ads1x15::set_config::config"],[2,3,1,"_CPPv4N4espp7Ads1x1513set_log_levelEN4espp6Logger9VerbosityE","espp::Ads1x15::set_log_level"],[2,4,1,"_CPPv4N4espp7Ads1x1513set_log_levelEN4espp6Logger9VerbosityE","espp::Ads1x15::set_log_level::level"],[2,3,1,"_CPPv4N4espp7Ads1x1518set_log_rate_limitENSt6chrono8durationIfEE","espp::Ads1x15::set_log_rate_limit"],[2,4,1,"_CPPv4N4espp7Ads1x1518set_log_rate_limitENSt6chrono8durationIfEE","espp::Ads1x15::set_log_rate_limit::rate_limit"],[2,3,1,"_CPPv4N4espp7Ads1x1511set_log_tagERKNSt11string_viewE","espp::Ads1x15::set_log_tag"],[2,4,1,"_CPPv4N4espp7Ads1x1511set_log_tagERKNSt11string_viewE","espp::Ads1x15::set_log_tag::tag"],[2,3,1,"_CPPv4N4espp7Ads1x1517set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ads1x15::set_log_verbosity"],[2,4,1,"_CPPv4N4espp7Ads1x1517set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ads1x15::set_log_verbosity::level"],[2,3,1,"_CPPv4N4espp7Ads1x159set_probeERK8probe_fn","espp::Ads1x15::set_probe"],[2,4,1,"_CPPv4N4espp7Ads1x159set_probeERK8probe_fn","espp::Ads1x15::set_probe::probe"],[2,3,1,"_CPPv4N4espp7Ads1x158set_readERK7read_fn","espp::Ads1x15::set_read"],[2,4,1,"_CPPv4N4espp7Ads1x158set_readERK7read_fn","espp::Ads1x15::set_read::read"],[2,3,1,"_CPPv4N4espp7Ads1x1517set_read_registerERK16read_register_fn","espp::Ads1x15::set_read_register"],[2,4,1,"_CPPv4N4espp7Ads1x1517set_read_registerERK16read_register_fn","espp::Ads1x15::set_read_register::read_register"],[2,3,1,"_CPPv4N4espp7Ads1x1534set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ads1x15::set_separate_write_then_read_delay"],[2,4,1,"_CPPv4N4espp7Ads1x1534set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ads1x15::set_separate_write_then_read_delay::delay"],[2,3,1,"_CPPv4N4espp7Ads1x159set_writeERK8write_fn","espp::Ads1x15::set_write"],[2,4,1,"_CPPv4N4espp7Ads1x159set_writeERK8write_fn","espp::Ads1x15::set_write::write"],[2,3,1,"_CPPv4N4espp7Ads1x1519set_write_then_readERK18write_then_read_fn","espp::Ads1x15::set_write_then_read"],[2,4,1,"_CPPv4N4espp7Ads1x1519set_write_then_readERK18write_then_read_fn","espp::Ads1x15::set_write_then_read::write_then_read"],[4,2,1,"_CPPv4N4espp7Ads7138E","espp::Ads7138"],[4,3,1,"_CPPv4N4espp7Ads71387Ads7138ERK6Config","espp::Ads7138::Ads7138"],[4,4,1,"_CPPv4N4espp7Ads71387Ads7138ERK6Config","espp::Ads7138::Ads7138::config"],[4,6,1,"_CPPv4N4espp7Ads713810AlertLogicE","espp::Ads7138::AlertLogic"],[4,7,1,"_CPPv4N4espp7Ads713810AlertLogic11ACTIVE_HIGHE","espp::Ads7138::AlertLogic::ACTIVE_HIGH"],[4,7,1,"_CPPv4N4espp7Ads713810AlertLogic10ACTIVE_LOWE","espp::Ads7138::AlertLogic::ACTIVE_LOW"],[4,7,1,"_CPPv4N4espp7Ads713810AlertLogic11PULSED_HIGHE","espp::Ads7138::AlertLogic::PULSED_HIGH"],[4,7,1,"_CPPv4N4espp7Ads713810AlertLogic10PULSED_LOWE","espp::Ads7138::AlertLogic::PULSED_LOW"],[4,6,1,"_CPPv4N4espp7Ads713811AnalogEventE","espp::Ads7138::AnalogEvent"],[4,7,1,"_CPPv4N4espp7Ads713811AnalogEvent6INSIDEE","espp::Ads7138::AnalogEvent::INSIDE"],[4,7,1,"_CPPv4N4espp7Ads713811AnalogEvent7OUTSIDEE","espp::Ads7138::AnalogEvent::OUTSIDE"],[4,6,1,"_CPPv4N4espp7Ads71386AppendE","espp::Ads7138::Append"],[4,7,1,"_CPPv4N4espp7Ads71386Append10CHANNEL_IDE","espp::Ads7138::Append::CHANNEL_ID"],[4,7,1,"_CPPv4N4espp7Ads71386Append4NONEE","espp::Ads7138::Append::NONE"],[4,7,1,"_CPPv4N4espp7Ads71386Append6STATUSE","espp::Ads7138::Append::STATUS"],[4,6,1,"_CPPv4N4espp7Ads71387ChannelE","espp::Ads7138::Channel"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH0E","espp::Ads7138::Channel::CH0"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH1E","espp::Ads7138::Channel::CH1"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH2E","espp::Ads7138::Channel::CH2"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH3E","espp::Ads7138::Channel::CH3"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH4E","espp::Ads7138::Channel::CH4"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH5E","espp::Ads7138::Channel::CH5"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH6E","espp::Ads7138::Channel::CH6"],[4,7,1,"_CPPv4N4espp7Ads71387Channel3CH7E","espp::Ads7138::Channel::CH7"],[4,2,1,"_CPPv4N4espp7Ads71386ConfigE","espp::Ads7138::Config"],[4,1,1,"_CPPv4N4espp7Ads71386Config13analog_inputsE","espp::Ads7138::Config::analog_inputs"],[4,1,1,"_CPPv4N4espp7Ads71386Config9auto_initE","espp::Ads7138::Config::auto_init"],[4,1,1,"_CPPv4N4espp7Ads71386Config10avdd_voltsE","espp::Ads7138::Config::avdd_volts"],[4,1,1,"_CPPv4N4espp7Ads71386Config14device_addressE","espp::Ads7138::Config::device_address"],[4,1,1,"_CPPv4N4espp7Ads71386Config14digital_inputsE","espp::Ads7138::Config::digital_inputs"],[4,1,1,"_CPPv4N4espp7Ads71386Config20digital_output_modesE","espp::Ads7138::Config::digital_output_modes"],[4,1,1,"_CPPv4N4espp7Ads71386Config21digital_output_valuesE","espp::Ads7138::Config::digital_output_values"],[4,1,1,"_CPPv4N4espp7Ads71386Config15digital_outputsE","espp::Ads7138::Config::digital_outputs"],[4,1,1,"_CPPv4N4espp7Ads71386Config9log_levelE","espp::Ads7138::Config::log_level"],[4,1,1,"_CPPv4N4espp7Ads71386Config4modeE","espp::Ads7138::Config::mode"],[4,1,1,"_CPPv4N4espp7Ads71386Config18oversampling_ratioE","espp::Ads7138::Config::oversampling_ratio"],[4,1,1,"_CPPv4N4espp7Ads71386Config4readE","espp::Ads7138::Config::read"],[4,1,1,"_CPPv4N4espp7Ads71386Config18statistics_enabledE","espp::Ads7138::Config::statistics_enabled"],[4,1,1,"_CPPv4N4espp7Ads71386Config5writeE","espp::Ads7138::Config::write"],[4,1,1,"_CPPv4N4espp7Ads713815DEFAULT_ADDRESSE","espp::Ads7138::DEFAULT_ADDRESS"],[4,6,1,"_CPPv4N4espp7Ads713810DataFormatE","espp::Ads7138::DataFormat"],[4,7,1,"_CPPv4N4espp7Ads713810DataFormat8AVERAGEDE","espp::Ads7138::DataFormat::AVERAGED"],[4,7,1,"_CPPv4N4espp7Ads713810DataFormat3RAWE","espp::Ads7138::DataFormat::RAW"],[4,6,1,"_CPPv4N4espp7Ads713812DigitalEventE","espp::Ads7138::DigitalEvent"],[4,7,1,"_CPPv4N4espp7Ads713812DigitalEvent4HIGHE","espp::Ads7138::DigitalEvent::HIGH"],[4,7,1,"_CPPv4N4espp7Ads713812DigitalEvent3LOWE","espp::Ads7138::DigitalEvent::LOW"],[4,6,1,"_CPPv4N4espp7Ads71384ModeE","espp::Ads7138::Mode"],[4,7,1,"_CPPv4N4espp7Ads71384Mode10AUTONOMOUSE","espp::Ads7138::Mode::AUTONOMOUS"],[4,7,1,"_CPPv4N4espp7Ads71384Mode8AUTO_SEQE","espp::Ads7138::Mode::AUTO_SEQ"],[4,7,1,"_CPPv4N4espp7Ads71384Mode6MANUALE","espp::Ads7138::Mode::MANUAL"],[4,6,1,"_CPPv4N4espp7Ads713810OutputModeE","espp::Ads7138::OutputMode"],[4,7,1,"_CPPv4N4espp7Ads713810OutputMode10OPEN_DRAINE","espp::Ads7138::OutputMode::OPEN_DRAIN"],[4,7,1,"_CPPv4N4espp7Ads713810OutputMode9PUSH_PULLE","espp::Ads7138::OutputMode::PUSH_PULL"],[4,6,1,"_CPPv4N4espp7Ads713817OversamplingRatioE","espp::Ads7138::OversamplingRatio"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio4NONEE","espp::Ads7138::OversamplingRatio::NONE"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio7OSR_128E","espp::Ads7138::OversamplingRatio::OSR_128"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio6OSR_16E","espp::Ads7138::OversamplingRatio::OSR_16"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio5OSR_2E","espp::Ads7138::OversamplingRatio::OSR_2"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio6OSR_32E","espp::Ads7138::OversamplingRatio::OSR_32"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio5OSR_4E","espp::Ads7138::OversamplingRatio::OSR_4"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio6OSR_64E","espp::Ads7138::OversamplingRatio::OSR_64"],[4,7,1,"_CPPv4N4espp7Ads713817OversamplingRatio5OSR_8E","espp::Ads7138::OversamplingRatio::OSR_8"],[4,3,1,"_CPPv4N4espp7Ads713821clear_event_high_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_high_flag"],[4,4,1,"_CPPv4N4espp7Ads713821clear_event_high_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_high_flag::ec"],[4,4,1,"_CPPv4N4espp7Ads713821clear_event_high_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_high_flag::flags"],[4,3,1,"_CPPv4N4espp7Ads713820clear_event_low_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_low_flag"],[4,4,1,"_CPPv4N4espp7Ads713820clear_event_low_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_low_flag::ec"],[4,4,1,"_CPPv4N4espp7Ads713820clear_event_low_flagE7uint8_tRNSt10error_codeE","espp::Ads7138::clear_event_low_flag::flags"],[4,3,1,"_CPPv4N4espp7Ads713815configure_alertE10OutputMode10AlertLogicRNSt10error_codeE","espp::Ads7138::configure_alert"],[4,4,1,"_CPPv4N4espp7Ads713815configure_alertE10OutputMode10AlertLogicRNSt10error_codeE","espp::Ads7138::configure_alert::alert_logic"],[4,4,1,"_CPPv4N4espp7Ads713815configure_alertE10OutputMode10AlertLogicRNSt10error_codeE","espp::Ads7138::configure_alert::ec"],[4,4,1,"_CPPv4N4espp7Ads713815configure_alertE10OutputMode10AlertLogicRNSt10error_codeE","espp::Ads7138::configure_alert::output_mode"],[4,3,1,"_CPPv4N4espp7Ads713810get_all_mvERNSt10error_codeE","espp::Ads7138::get_all_mv"],[4,4,1,"_CPPv4N4espp7Ads713810get_all_mvERNSt10error_codeE","espp::Ads7138::get_all_mv::ec"],[4,3,1,"_CPPv4N4espp7Ads713814get_all_mv_mapERNSt10error_codeE","espp::Ads7138::get_all_mv_map"],[4,4,1,"_CPPv4N4espp7Ads713814get_all_mv_mapERNSt10error_codeE","espp::Ads7138::get_all_mv_map::ec"],[4,3,1,"_CPPv4N4espp7Ads713823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Ads7138::get_digital_input_value"],[4,4,1,"_CPPv4N4espp7Ads713823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Ads7138::get_digital_input_value::channel"],[4,4,1,"_CPPv4N4espp7Ads713823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Ads7138::get_digital_input_value::ec"],[4,3,1,"_CPPv4N4espp7Ads713824get_digital_input_valuesERNSt10error_codeE","espp::Ads7138::get_digital_input_values"],[4,4,1,"_CPPv4N4espp7Ads713824get_digital_input_valuesERNSt10error_codeE","espp::Ads7138::get_digital_input_values::ec"],[4,3,1,"_CPPv4N4espp7Ads713814get_event_dataEP7uint8_tP7uint8_tP7uint8_tRNSt10error_codeE","espp::Ads7138::get_event_data"],[4,4,1,"_CPPv4N4espp7Ads713814get_event_dataEP7uint8_tP7uint8_tP7uint8_tRNSt10error_codeE","espp::Ads7138::get_event_data::ec"],[4,4,1,"_CPPv4N4espp7Ads713814get_event_dataEP7uint8_tP7uint8_tP7uint8_tRNSt10error_codeE","espp::Ads7138::get_event_data::event_flags"],[4,4,1,"_CPPv4N4espp7Ads713814get_event_dataEP7uint8_tP7uint8_tP7uint8_tRNSt10error_codeE","espp::Ads7138::get_event_data::event_high_flags"],[4,4,1,"_CPPv4N4espp7Ads713814get_event_dataEP7uint8_tP7uint8_tP7uint8_tRNSt10error_codeE","espp::Ads7138::get_event_data::event_low_flags"],[4,3,1,"_CPPv4N4espp7Ads713815get_event_flagsERNSt10error_codeE","espp::Ads7138::get_event_flags"],[4,4,1,"_CPPv4N4espp7Ads713815get_event_flagsERNSt10error_codeE","espp::Ads7138::get_event_flags::ec"],[4,3,1,"_CPPv4N4espp7Ads713819get_event_high_flagERNSt10error_codeE","espp::Ads7138::get_event_high_flag"],[4,4,1,"_CPPv4N4espp7Ads713819get_event_high_flagERNSt10error_codeE","espp::Ads7138::get_event_high_flag::ec"],[4,3,1,"_CPPv4N4espp7Ads713818get_event_low_flagERNSt10error_codeE","espp::Ads7138::get_event_low_flag"],[4,4,1,"_CPPv4N4espp7Ads713818get_event_low_flagERNSt10error_codeE","espp::Ads7138::get_event_low_flag::ec"],[4,3,1,"_CPPv4NK4espp7Ads713813get_log_levelEv","espp::Ads7138::get_log_level"],[4,3,1,"_CPPv4NK4espp7Ads713817get_log_verbosityEv","espp::Ads7138::get_log_verbosity"],[4,3,1,"_CPPv4N4espp7Ads71386get_mvE7ChannelRNSt10error_codeE","espp::Ads7138::get_mv"],[4,4,1,"_CPPv4N4espp7Ads71386get_mvE7ChannelRNSt10error_codeE","espp::Ads7138::get_mv::channel"],[4,4,1,"_CPPv4N4espp7Ads71386get_mvE7ChannelRNSt10error_codeE","espp::Ads7138::get_mv::ec"],[4,3,1,"_CPPv4NK4espp7Ads71388get_nameEv","espp::Ads7138::get_name"],[4,3,1,"_CPPv4N4espp7Ads713810initializeERNSt10error_codeE","espp::Ads7138::initialize"],[4,4,1,"_CPPv4N4espp7Ads713810initializeERNSt10error_codeE","espp::Ads7138::initialize::ec"],[4,3,1,"_CPPv4N4espp7Ads71385probeERNSt10error_codeE","espp::Ads7138::probe"],[4,4,1,"_CPPv4N4espp7Ads71385probeERNSt10error_codeE","espp::Ads7138::probe::ec"],[4,8,1,"_CPPv4N4espp7Ads71388probe_fnE","espp::Ads7138::probe_fn"],[4,3,1,"_CPPv4N4espp7Ads71385resetERNSt10error_codeE","espp::Ads7138::reset"],[4,4,1,"_CPPv4N4espp7Ads71385resetERNSt10error_codeE","espp::Ads7138::reset::ec"],[4,3,1,"_CPPv4N4espp7Ads713811set_addressE7uint8_t","espp::Ads7138::set_address"],[4,4,1,"_CPPv4N4espp7Ads713811set_addressE7uint8_t","espp::Ads7138::set_address::address"],[4,3,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::channel"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::ec"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::event"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::event_count"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::high_threshold_mv"],[4,4,1,"_CPPv4N4espp7Ads713816set_analog_alertE7Channelff11AnalogEventiRNSt10error_codeE","espp::Ads7138::set_analog_alert::low_threshold_mv"],[4,3,1,"_CPPv4N4espp7Ads713810set_configERK6Config","espp::Ads7138::set_config"],[4,3,1,"_CPPv4N4espp7Ads713810set_configERR6Config","espp::Ads7138::set_config"],[4,4,1,"_CPPv4N4espp7Ads713810set_configERK6Config","espp::Ads7138::set_config::config"],[4,4,1,"_CPPv4N4espp7Ads713810set_configERR6Config","espp::Ads7138::set_config::config"],[4,3,1,"_CPPv4N4espp7Ads713817set_digital_alertE7Channel12DigitalEventRNSt10error_codeE","espp::Ads7138::set_digital_alert"],[4,4,1,"_CPPv4N4espp7Ads713817set_digital_alertE7Channel12DigitalEventRNSt10error_codeE","espp::Ads7138::set_digital_alert::channel"],[4,4,1,"_CPPv4N4espp7Ads713817set_digital_alertE7Channel12DigitalEventRNSt10error_codeE","espp::Ads7138::set_digital_alert::ec"],[4,4,1,"_CPPv4N4espp7Ads713817set_digital_alertE7Channel12DigitalEventRNSt10error_codeE","espp::Ads7138::set_digital_alert::event"],[4,3,1,"_CPPv4N4espp7Ads713823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Ads7138::set_digital_output_mode"],[4,4,1,"_CPPv4N4espp7Ads713823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Ads7138::set_digital_output_mode::channel"],[4,4,1,"_CPPv4N4espp7Ads713823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Ads7138::set_digital_output_mode::ec"],[4,4,1,"_CPPv4N4espp7Ads713823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Ads7138::set_digital_output_mode::output_mode"],[4,3,1,"_CPPv4N4espp7Ads713824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Ads7138::set_digital_output_value"],[4,4,1,"_CPPv4N4espp7Ads713824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Ads7138::set_digital_output_value::channel"],[4,4,1,"_CPPv4N4espp7Ads713824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Ads7138::set_digital_output_value::ec"],[4,4,1,"_CPPv4N4espp7Ads713824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Ads7138::set_digital_output_value::value"],[4,3,1,"_CPPv4N4espp7Ads713813set_log_levelEN4espp6Logger9VerbosityE","espp::Ads7138::set_log_level"],[4,4,1,"_CPPv4N4espp7Ads713813set_log_levelEN4espp6Logger9VerbosityE","espp::Ads7138::set_log_level::level"],[4,3,1,"_CPPv4N4espp7Ads713818set_log_rate_limitENSt6chrono8durationIfEE","espp::Ads7138::set_log_rate_limit"],[4,4,1,"_CPPv4N4espp7Ads713818set_log_rate_limitENSt6chrono8durationIfEE","espp::Ads7138::set_log_rate_limit::rate_limit"],[4,3,1,"_CPPv4N4espp7Ads713811set_log_tagERKNSt11string_viewE","espp::Ads7138::set_log_tag"],[4,4,1,"_CPPv4N4espp7Ads713811set_log_tagERKNSt11string_viewE","espp::Ads7138::set_log_tag::tag"],[4,3,1,"_CPPv4N4espp7Ads713817set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ads7138::set_log_verbosity"],[4,4,1,"_CPPv4N4espp7Ads713817set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ads7138::set_log_verbosity::level"],[4,3,1,"_CPPv4N4espp7Ads71389set_probeERK8probe_fn","espp::Ads7138::set_probe"],[4,4,1,"_CPPv4N4espp7Ads71389set_probeERK8probe_fn","espp::Ads7138::set_probe::probe"],[4,3,1,"_CPPv4N4espp7Ads71388set_readERK7read_fn","espp::Ads7138::set_read"],[4,4,1,"_CPPv4N4espp7Ads71388set_readERK7read_fn","espp::Ads7138::set_read::read"],[4,3,1,"_CPPv4N4espp7Ads713817set_read_registerERK16read_register_fn","espp::Ads7138::set_read_register"],[4,4,1,"_CPPv4N4espp7Ads713817set_read_registerERK16read_register_fn","espp::Ads7138::set_read_register::read_register"],[4,3,1,"_CPPv4N4espp7Ads713834set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ads7138::set_separate_write_then_read_delay"],[4,4,1,"_CPPv4N4espp7Ads713834set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ads7138::set_separate_write_then_read_delay::delay"],[4,3,1,"_CPPv4N4espp7Ads71389set_writeERK8write_fn","espp::Ads7138::set_write"],[4,4,1,"_CPPv4N4espp7Ads71389set_writeERK8write_fn","espp::Ads7138::set_write::write"],[4,3,1,"_CPPv4N4espp7Ads713819set_write_then_readERK18write_then_read_fn","espp::Ads7138::set_write_then_read"],[4,4,1,"_CPPv4N4espp7Ads713819set_write_then_readERK18write_then_read_fn","espp::Ads7138::set_write_then_read::write_then_read"],[44,2,1,"_CPPv4N4espp6As5600E","espp::As5600"],[44,3,1,"_CPPv4N4espp6As56006As5600ERK6Config","espp::As5600::As5600"],[44,4,1,"_CPPv4N4espp6As56006As5600ERK6Config","espp::As5600::As5600::config"],[44,1,1,"_CPPv4N4espp6As560021COUNTS_PER_REVOLUTIONE","espp::As5600::COUNTS_PER_REVOLUTION"],[44,1,1,"_CPPv4N4espp6As560023COUNTS_PER_REVOLUTION_FE","espp::As5600::COUNTS_PER_REVOLUTION_F"],[44,1,1,"_CPPv4N4espp6As560017COUNTS_TO_DEGREESE","espp::As5600::COUNTS_TO_DEGREES"],[44,1,1,"_CPPv4N4espp6As560017COUNTS_TO_RADIANSE","espp::As5600::COUNTS_TO_RADIANS"],[44,2,1,"_CPPv4N4espp6As56006ConfigE","espp::As5600::Config"],[44,1,1,"_CPPv4N4espp6As56006Config9auto_initE","espp::As5600::Config::auto_init"],[44,1,1,"_CPPv4N4espp6As56006Config14device_addressE","espp::As5600::Config::device_address"],[44,1,1,"_CPPv4N4espp6As56006Config13update_periodE","espp::As5600::Config::update_period"],[44,1,1,"_CPPv4N4espp6As56006Config15velocity_filterE","espp::As5600::Config::velocity_filter"],[44,1,1,"_CPPv4N4espp6As56006Config15write_then_readE","espp::As5600::Config::write_then_read"],[44,1,1,"_CPPv4N4espp6As560015DEFAULT_ADDRESSE","espp::As5600::DEFAULT_ADDRESS"],[44,1,1,"_CPPv4N4espp6As560018SECONDS_PER_MINUTEE","espp::As5600::SECONDS_PER_MINUTE"],[44,3,1,"_CPPv4NK4espp6As560015get_accumulatorEv","espp::As5600::get_accumulator"],[44,3,1,"_CPPv4NK4espp6As56009get_countEv","espp::As5600::get_count"],[44,3,1,"_CPPv4NK4espp6As560011get_degreesEv","espp::As5600::get_degrees"],[44,3,1,"_CPPv4NK4espp6As560013get_log_levelEv","espp::As5600::get_log_level"],[44,3,1,"_CPPv4NK4espp6As560017get_log_verbosityEv","espp::As5600::get_log_verbosity"],[44,3,1,"_CPPv4NK4espp6As560022get_mechanical_degreesEv","espp::As5600::get_mechanical_degrees"],[44,3,1,"_CPPv4NK4espp6As560022get_mechanical_radiansEv","espp::As5600::get_mechanical_radians"],[44,3,1,"_CPPv4NK4espp6As56008get_nameEv","espp::As5600::get_name"],[44,3,1,"_CPPv4NK4espp6As560011get_radiansEv","espp::As5600::get_radians"],[44,3,1,"_CPPv4NK4espp6As56007get_rpmEv","espp::As5600::get_rpm"],[44,3,1,"_CPPv4N4espp6As560010initializeERNSt10error_codeE","espp::As5600::initialize"],[44,4,1,"_CPPv4N4espp6As560010initializeERNSt10error_codeE","espp::As5600::initialize::ec"],[44,3,1,"_CPPv4NK4espp6As560017needs_zero_searchEv","espp::As5600::needs_zero_search"],[44,3,1,"_CPPv4N4espp6As56005probeERNSt10error_codeE","espp::As5600::probe"],[44,4,1,"_CPPv4N4espp6As56005probeERNSt10error_codeE","espp::As5600::probe::ec"],[44,8,1,"_CPPv4N4espp6As56008probe_fnE","espp::As5600::probe_fn"],[44,3,1,"_CPPv4N4espp6As560011set_addressE7uint8_t","espp::As5600::set_address"],[44,4,1,"_CPPv4N4espp6As560011set_addressE7uint8_t","espp::As5600::set_address::address"],[44,3,1,"_CPPv4N4espp6As560010set_configERK6Config","espp::As5600::set_config"],[44,3,1,"_CPPv4N4espp6As560010set_configERR6Config","espp::As5600::set_config"],[44,4,1,"_CPPv4N4espp6As560010set_configERK6Config","espp::As5600::set_config::config"],[44,4,1,"_CPPv4N4espp6As560010set_configERR6Config","espp::As5600::set_config::config"],[44,3,1,"_CPPv4N4espp6As560013set_log_levelEN4espp6Logger9VerbosityE","espp::As5600::set_log_level"],[44,4,1,"_CPPv4N4espp6As560013set_log_levelEN4espp6Logger9VerbosityE","espp::As5600::set_log_level::level"],[44,3,1,"_CPPv4N4espp6As560018set_log_rate_limitENSt6chrono8durationIfEE","espp::As5600::set_log_rate_limit"],[44,4,1,"_CPPv4N4espp6As560018set_log_rate_limitENSt6chrono8durationIfEE","espp::As5600::set_log_rate_limit::rate_limit"],[44,3,1,"_CPPv4N4espp6As560011set_log_tagERKNSt11string_viewE","espp::As5600::set_log_tag"],[44,4,1,"_CPPv4N4espp6As560011set_log_tagERKNSt11string_viewE","espp::As5600::set_log_tag::tag"],[44,3,1,"_CPPv4N4espp6As560017set_log_verbosityEN4espp6Logger9VerbosityE","espp::As5600::set_log_verbosity"],[44,4,1,"_CPPv4N4espp6As560017set_log_verbosityEN4espp6Logger9VerbosityE","espp::As5600::set_log_verbosity::level"],[44,3,1,"_CPPv4N4espp6As56009set_probeERK8probe_fn","espp::As5600::set_probe"],[44,4,1,"_CPPv4N4espp6As56009set_probeERK8probe_fn","espp::As5600::set_probe::probe"],[44,3,1,"_CPPv4N4espp6As56008set_readERK7read_fn","espp::As5600::set_read"],[44,4,1,"_CPPv4N4espp6As56008set_readERK7read_fn","espp::As5600::set_read::read"],[44,3,1,"_CPPv4N4espp6As560017set_read_registerERK16read_register_fn","espp::As5600::set_read_register"],[44,4,1,"_CPPv4N4espp6As560017set_read_registerERK16read_register_fn","espp::As5600::set_read_register::read_register"],[44,3,1,"_CPPv4N4espp6As560034set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::As5600::set_separate_write_then_read_delay"],[44,4,1,"_CPPv4N4espp6As560034set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::As5600::set_separate_write_then_read_delay::delay"],[44,3,1,"_CPPv4N4espp6As56009set_writeERK8write_fn","espp::As5600::set_write"],[44,4,1,"_CPPv4N4espp6As56009set_writeERK8write_fn","espp::As5600::set_write::write"],[44,3,1,"_CPPv4N4espp6As560019set_write_then_readERK18write_then_read_fn","espp::As5600::set_write_then_read"],[44,4,1,"_CPPv4N4espp6As560019set_write_then_readERK18write_then_read_fn","espp::As5600::set_write_then_read::write_then_read"],[44,8,1,"_CPPv4N4espp6As560018velocity_filter_fnE","espp::As5600::velocity_filter_fn"],[100,2,1,"_CPPv4N4espp6Aw9523E","espp::Aw9523"],[100,3,1,"_CPPv4N4espp6Aw95236Aw9523ERK6Config","espp::Aw9523::Aw9523"],[100,4,1,"_CPPv4N4espp6Aw95236Aw9523ERK6Config","espp::Aw9523::Aw9523::config"],[100,2,1,"_CPPv4N4espp6Aw95236ConfigE","espp::Aw9523::Config"],[100,1,1,"_CPPv4N4espp6Aw95236Config9auto_initE","espp::Aw9523::Config::auto_init"],[100,1,1,"_CPPv4N4espp6Aw95236Config14device_addressE","espp::Aw9523::Config::device_address"],[100,1,1,"_CPPv4N4espp6Aw95236Config9log_levelE","espp::Aw9523::Config::log_level"],[100,1,1,"_CPPv4N4espp6Aw95236Config15max_led_currentE","espp::Aw9523::Config::max_led_current"],[100,1,1,"_CPPv4N4espp6Aw95236Config20output_drive_mode_p0E","espp::Aw9523::Config::output_drive_mode_p0"],[100,1,1,"_CPPv4N4espp6Aw95236Config21port_0_direction_maskE","espp::Aw9523::Config::port_0_direction_mask"],[100,1,1,"_CPPv4N4espp6Aw95236Config21port_0_interrupt_maskE","espp::Aw9523::Config::port_0_interrupt_mask"],[100,1,1,"_CPPv4N4espp6Aw95236Config21port_1_direction_maskE","espp::Aw9523::Config::port_1_direction_mask"],[100,1,1,"_CPPv4N4espp6Aw95236Config21port_1_interrupt_maskE","espp::Aw9523::Config::port_1_interrupt_mask"],[100,1,1,"_CPPv4N4espp6Aw95236Config5writeE","espp::Aw9523::Config::write"],[100,1,1,"_CPPv4N4espp6Aw95236Config15write_then_readE","espp::Aw9523::Config::write_then_read"],[100,1,1,"_CPPv4N4espp6Aw952315DEFAULT_ADDRESSE","espp::Aw9523::DEFAULT_ADDRESS"],[100,6,1,"_CPPv4N4espp6Aw952313MaxLedCurrentE","espp::Aw9523::MaxLedCurrent"],[100,7,1,"_CPPv4N4espp6Aw952313MaxLedCurrent4IMAXE","espp::Aw9523::MaxLedCurrent::IMAX"],[100,7,1,"_CPPv4N4espp6Aw952313MaxLedCurrent7IMAX_25E","espp::Aw9523::MaxLedCurrent::IMAX_25"],[100,7,1,"_CPPv4N4espp6Aw952313MaxLedCurrent7IMAX_50E","espp::Aw9523::MaxLedCurrent::IMAX_50"],[100,7,1,"_CPPv4N4espp6Aw952313MaxLedCurrent7IMAX_75E","espp::Aw9523::MaxLedCurrent::IMAX_75"],[100,6,1,"_CPPv4N4espp6Aw952317OutputDriveModeP0E","espp::Aw9523::OutputDriveModeP0"],[100,7,1,"_CPPv4N4espp6Aw952317OutputDriveModeP010OPEN_DRAINE","espp::Aw9523::OutputDriveModeP0::OPEN_DRAIN"],[100,7,1,"_CPPv4N4espp6Aw952317OutputDriveModeP09PUSH_PULLE","espp::Aw9523::OutputDriveModeP0::PUSH_PULL"],[100,6,1,"_CPPv4N4espp6Aw95234PortE","espp::Aw9523::Port"],[100,7,1,"_CPPv4N4espp6Aw95234Port5PORT0E","espp::Aw9523::Port::PORT0"],[100,7,1,"_CPPv4N4espp6Aw95234Port5PORT1E","espp::Aw9523::Port::PORT1"],[100,3,1,"_CPPv4N4espp6Aw952310clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins"],[100,3,1,"_CPPv4N4espp6Aw952310clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins"],[100,3,1,"_CPPv4N4espp6Aw952310clear_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::clear_pins"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::clear_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::mask"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::clear_pins::mask"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::p0"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::p1"],[100,4,1,"_CPPv4N4espp6Aw952310clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::clear_pins::port"],[100,3,1,"_CPPv4N4espp6Aw952324configure_global_controlE17OutputDriveModeP013MaxLedCurrentRNSt10error_codeE","espp::Aw9523::configure_global_control"],[100,4,1,"_CPPv4N4espp6Aw952324configure_global_controlE17OutputDriveModeP013MaxLedCurrentRNSt10error_codeE","espp::Aw9523::configure_global_control::ec"],[100,4,1,"_CPPv4N4espp6Aw952324configure_global_controlE17OutputDriveModeP013MaxLedCurrentRNSt10error_codeE","espp::Aw9523::configure_global_control::max_led_current"],[100,4,1,"_CPPv4N4espp6Aw952324configure_global_controlE17OutputDriveModeP013MaxLedCurrentRNSt10error_codeE","espp::Aw9523::configure_global_control::output_drive_mode_p0"],[100,3,1,"_CPPv4N4espp6Aw952313configure_ledE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led"],[100,3,1,"_CPPv4N4espp6Aw952313configure_ledE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led"],[100,3,1,"_CPPv4N4espp6Aw952313configure_ledE8uint16_tRNSt10error_codeE","espp::Aw9523::configure_led"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::ec"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::ec"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE8uint16_tRNSt10error_codeE","espp::Aw9523::configure_led::ec"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::mask"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE8uint16_tRNSt10error_codeE","espp::Aw9523::configure_led::mask"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::p0"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::p1"],[100,4,1,"_CPPv4N4espp6Aw952313configure_ledE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::configure_led::port"],[100,3,1,"_CPPv4NK4espp6Aw952313get_log_levelEv","espp::Aw9523::get_log_level"],[100,3,1,"_CPPv4NK4espp6Aw952317get_log_verbosityEv","espp::Aw9523::get_log_verbosity"],[100,3,1,"_CPPv4NK4espp6Aw95238get_nameEv","espp::Aw9523::get_name"],[100,3,1,"_CPPv4N4espp6Aw952310get_outputE4PortRNSt10error_codeE","espp::Aw9523::get_output"],[100,3,1,"_CPPv4N4espp6Aw952310get_outputERNSt10error_codeE","espp::Aw9523::get_output"],[100,4,1,"_CPPv4N4espp6Aw952310get_outputE4PortRNSt10error_codeE","espp::Aw9523::get_output::ec"],[100,4,1,"_CPPv4N4espp6Aw952310get_outputERNSt10error_codeE","espp::Aw9523::get_output::ec"],[100,4,1,"_CPPv4N4espp6Aw952310get_outputE4PortRNSt10error_codeE","espp::Aw9523::get_output::port"],[100,3,1,"_CPPv4N4espp6Aw95238get_pinsE4PortRNSt10error_codeE","espp::Aw9523::get_pins"],[100,3,1,"_CPPv4N4espp6Aw95238get_pinsERNSt10error_codeE","espp::Aw9523::get_pins"],[100,4,1,"_CPPv4N4espp6Aw95238get_pinsE4PortRNSt10error_codeE","espp::Aw9523::get_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw95238get_pinsERNSt10error_codeE","espp::Aw9523::get_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw95238get_pinsE4PortRNSt10error_codeE","espp::Aw9523::get_pins::port"],[100,3,1,"_CPPv4N4espp6Aw952310initializeERNSt10error_codeE","espp::Aw9523::initialize"],[100,4,1,"_CPPv4N4espp6Aw952310initializeERNSt10error_codeE","espp::Aw9523::initialize::ec"],[100,3,1,"_CPPv4N4espp6Aw95233ledE8uint16_t7uint8_tRNSt10error_codeE","espp::Aw9523::led"],[100,4,1,"_CPPv4N4espp6Aw95233ledE8uint16_t7uint8_tRNSt10error_codeE","espp::Aw9523::led::brightness"],[100,4,1,"_CPPv4N4espp6Aw95233ledE8uint16_t7uint8_tRNSt10error_codeE","espp::Aw9523::led::ec"],[100,4,1,"_CPPv4N4espp6Aw95233ledE8uint16_t7uint8_tRNSt10error_codeE","espp::Aw9523::led::pin"],[100,3,1,"_CPPv4N4espp6Aw95236outputE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::output"],[100,3,1,"_CPPv4N4espp6Aw95236outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::output"],[100,3,1,"_CPPv4N4espp6Aw95236outputE8uint16_tRNSt10error_codeE","espp::Aw9523::output"],[100,4,1,"_CPPv4N4espp6Aw95236outputE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::output::ec"],[100,4,1,"_CPPv4N4espp6Aw95236outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::output::ec"],[100,4,1,"_CPPv4N4espp6Aw95236outputE8uint16_tRNSt10error_codeE","espp::Aw9523::output::ec"],[100,4,1,"_CPPv4N4espp6Aw95236outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::output::p0"],[100,4,1,"_CPPv4N4espp6Aw95236outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::output::p1"],[100,4,1,"_CPPv4N4espp6Aw95236outputE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::output::port"],[100,4,1,"_CPPv4N4espp6Aw95236outputE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::output::value"],[100,4,1,"_CPPv4N4espp6Aw95236outputE8uint16_tRNSt10error_codeE","espp::Aw9523::output::value"],[100,3,1,"_CPPv4N4espp6Aw95235probeERNSt10error_codeE","espp::Aw9523::probe"],[100,4,1,"_CPPv4N4espp6Aw95235probeERNSt10error_codeE","espp::Aw9523::probe::ec"],[100,8,1,"_CPPv4N4espp6Aw95238probe_fnE","espp::Aw9523::probe_fn"],[100,3,1,"_CPPv4N4espp6Aw952311set_addressE7uint8_t","espp::Aw9523::set_address"],[100,4,1,"_CPPv4N4espp6Aw952311set_addressE7uint8_t","espp::Aw9523::set_address::address"],[100,3,1,"_CPPv4N4espp6Aw952310set_configERK6Config","espp::Aw9523::set_config"],[100,3,1,"_CPPv4N4espp6Aw952310set_configERR6Config","espp::Aw9523::set_config"],[100,4,1,"_CPPv4N4espp6Aw952310set_configERK6Config","espp::Aw9523::set_config::config"],[100,4,1,"_CPPv4N4espp6Aw952310set_configERR6Config","espp::Aw9523::set_config::config"],[100,3,1,"_CPPv4N4espp6Aw952313set_directionE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction"],[100,3,1,"_CPPv4N4espp6Aw952313set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::ec"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::ec"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::mask"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::p0"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::p1"],[100,4,1,"_CPPv4N4espp6Aw952313set_directionE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_direction::port"],[100,3,1,"_CPPv4N4espp6Aw952313set_interruptE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt"],[100,3,1,"_CPPv4N4espp6Aw952313set_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::ec"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::ec"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::mask"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::p0"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::p1"],[100,4,1,"_CPPv4N4espp6Aw952313set_interruptE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_interrupt::port"],[100,3,1,"_CPPv4N4espp6Aw952313set_log_levelEN4espp6Logger9VerbosityE","espp::Aw9523::set_log_level"],[100,4,1,"_CPPv4N4espp6Aw952313set_log_levelEN4espp6Logger9VerbosityE","espp::Aw9523::set_log_level::level"],[100,3,1,"_CPPv4N4espp6Aw952318set_log_rate_limitENSt6chrono8durationIfEE","espp::Aw9523::set_log_rate_limit"],[100,4,1,"_CPPv4N4espp6Aw952318set_log_rate_limitENSt6chrono8durationIfEE","espp::Aw9523::set_log_rate_limit::rate_limit"],[100,3,1,"_CPPv4N4espp6Aw952311set_log_tagERKNSt11string_viewE","espp::Aw9523::set_log_tag"],[100,4,1,"_CPPv4N4espp6Aw952311set_log_tagERKNSt11string_viewE","espp::Aw9523::set_log_tag::tag"],[100,3,1,"_CPPv4N4espp6Aw952317set_log_verbosityEN4espp6Logger9VerbosityE","espp::Aw9523::set_log_verbosity"],[100,4,1,"_CPPv4N4espp6Aw952317set_log_verbosityEN4espp6Logger9VerbosityE","espp::Aw9523::set_log_verbosity::level"],[100,3,1,"_CPPv4N4espp6Aw95238set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins"],[100,3,1,"_CPPv4N4espp6Aw95238set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins"],[100,3,1,"_CPPv4N4espp6Aw95238set_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::set_pins"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::set_pins::ec"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::mask"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE8uint16_tRNSt10error_codeE","espp::Aw9523::set_pins::mask"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::p0"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::p1"],[100,4,1,"_CPPv4N4espp6Aw95238set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Aw9523::set_pins::port"],[100,3,1,"_CPPv4N4espp6Aw95239set_probeERK8probe_fn","espp::Aw9523::set_probe"],[100,4,1,"_CPPv4N4espp6Aw95239set_probeERK8probe_fn","espp::Aw9523::set_probe::probe"],[100,3,1,"_CPPv4N4espp6Aw95238set_readERK7read_fn","espp::Aw9523::set_read"],[100,4,1,"_CPPv4N4espp6Aw95238set_readERK7read_fn","espp::Aw9523::set_read::read"],[100,3,1,"_CPPv4N4espp6Aw952317set_read_registerERK16read_register_fn","espp::Aw9523::set_read_register"],[100,4,1,"_CPPv4N4espp6Aw952317set_read_registerERK16read_register_fn","espp::Aw9523::set_read_register::read_register"],[100,3,1,"_CPPv4N4espp6Aw952334set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Aw9523::set_separate_write_then_read_delay"],[100,4,1,"_CPPv4N4espp6Aw952334set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Aw9523::set_separate_write_then_read_delay::delay"],[100,3,1,"_CPPv4N4espp6Aw95239set_writeERK8write_fn","espp::Aw9523::set_write"],[100,4,1,"_CPPv4N4espp6Aw95239set_writeERK8write_fn","espp::Aw9523::set_write::write"],[100,3,1,"_CPPv4N4espp6Aw952319set_write_then_readERK18write_then_read_fn","espp::Aw9523::set_write_then_read"],[100,4,1,"_CPPv4N4espp6Aw952319set_write_then_readERK18write_then_read_fn","espp::Aw9523::set_write_then_read::write_then_read"],[11,2,1,"_CPPv4N4espp13BaseComponentE","espp::BaseComponent"],[11,3,1,"_CPPv4NK4espp13BaseComponent13get_log_levelEv","espp::BaseComponent::get_log_level"],[11,3,1,"_CPPv4NK4espp13BaseComponent17get_log_verbosityEv","espp::BaseComponent::get_log_verbosity"],[11,3,1,"_CPPv4NK4espp13BaseComponent8get_nameEv","espp::BaseComponent::get_name"],[11,3,1,"_CPPv4N4espp13BaseComponent13set_log_levelEN4espp6Logger9VerbosityE","espp::BaseComponent::set_log_level"],[11,4,1,"_CPPv4N4espp13BaseComponent13set_log_levelEN4espp6Logger9VerbosityE","espp::BaseComponent::set_log_level::level"],[11,3,1,"_CPPv4N4espp13BaseComponent18set_log_rate_limitENSt6chrono8durationIfEE","espp::BaseComponent::set_log_rate_limit"],[11,4,1,"_CPPv4N4espp13BaseComponent18set_log_rate_limitENSt6chrono8durationIfEE","espp::BaseComponent::set_log_rate_limit::rate_limit"],[11,3,1,"_CPPv4N4espp13BaseComponent11set_log_tagERKNSt11string_viewE","espp::BaseComponent::set_log_tag"],[11,4,1,"_CPPv4N4espp13BaseComponent11set_log_tagERKNSt11string_viewE","espp::BaseComponent::set_log_tag::tag"],[11,3,1,"_CPPv4N4espp13BaseComponent17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BaseComponent::set_log_verbosity"],[11,4,1,"_CPPv4N4espp13BaseComponent17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BaseComponent::set_log_verbosity::level"],[12,2,1,"_CPPv4I_NSt8integralE_bEN4espp14BasePeripheralE","espp::BasePeripheral"],[12,2,1,"_CPPv4N4espp14BasePeripheral6ConfigE","espp::BasePeripheral::Config"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config7addressE","espp::BasePeripheral::Config::address"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config5probeE","espp::BasePeripheral::Config::probe"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config4readE","espp::BasePeripheral::Config::read"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config13read_registerE","espp::BasePeripheral::Config::read_register"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config30separate_write_then_read_delayE","espp::BasePeripheral::Config::separate_write_then_read_delay"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config5writeE","espp::BasePeripheral::Config::write"],[12,1,1,"_CPPv4N4espp14BasePeripheral6Config15write_then_readE","espp::BasePeripheral::Config::write_then_read"],[12,5,1,"_CPPv4I_NSt8integralE_bEN4espp14BasePeripheralE","espp::BasePeripheral::RegisterAddressType"],[12,5,1,"_CPPv4I_NSt8integralE_bEN4espp14BasePeripheralE","espp::BasePeripheral::UseAddress"],[12,3,1,"_CPPv4NK4espp14BasePeripheral13get_log_levelEv","espp::BasePeripheral::get_log_level"],[12,3,1,"_CPPv4NK4espp14BasePeripheral17get_log_verbosityEv","espp::BasePeripheral::get_log_verbosity"],[12,3,1,"_CPPv4NK4espp14BasePeripheral8get_nameEv","espp::BasePeripheral::get_name"],[12,3,1,"_CPPv4N4espp14BasePeripheral5probeERNSt10error_codeE","espp::BasePeripheral::probe"],[12,4,1,"_CPPv4N4espp14BasePeripheral5probeERNSt10error_codeE","espp::BasePeripheral::probe::ec"],[12,8,1,"_CPPv4N4espp14BasePeripheral8probe_fnE","espp::BasePeripheral::probe_fn"],[12,3,1,"_CPPv4N4espp14BasePeripheral11set_addressE7uint8_t","espp::BasePeripheral::set_address"],[12,4,1,"_CPPv4N4espp14BasePeripheral11set_addressE7uint8_t","espp::BasePeripheral::set_address::address"],[12,3,1,"_CPPv4N4espp14BasePeripheral10set_configERK6Config","espp::BasePeripheral::set_config"],[12,3,1,"_CPPv4N4espp14BasePeripheral10set_configERR6Config","espp::BasePeripheral::set_config"],[12,4,1,"_CPPv4N4espp14BasePeripheral10set_configERK6Config","espp::BasePeripheral::set_config::config"],[12,4,1,"_CPPv4N4espp14BasePeripheral10set_configERR6Config","espp::BasePeripheral::set_config::config"],[12,3,1,"_CPPv4N4espp14BasePeripheral13set_log_levelEN4espp6Logger9VerbosityE","espp::BasePeripheral::set_log_level"],[12,4,1,"_CPPv4N4espp14BasePeripheral13set_log_levelEN4espp6Logger9VerbosityE","espp::BasePeripheral::set_log_level::level"],[12,3,1,"_CPPv4N4espp14BasePeripheral18set_log_rate_limitENSt6chrono8durationIfEE","espp::BasePeripheral::set_log_rate_limit"],[12,4,1,"_CPPv4N4espp14BasePeripheral18set_log_rate_limitENSt6chrono8durationIfEE","espp::BasePeripheral::set_log_rate_limit::rate_limit"],[12,3,1,"_CPPv4N4espp14BasePeripheral11set_log_tagERKNSt11string_viewE","espp::BasePeripheral::set_log_tag"],[12,4,1,"_CPPv4N4espp14BasePeripheral11set_log_tagERKNSt11string_viewE","espp::BasePeripheral::set_log_tag::tag"],[12,3,1,"_CPPv4N4espp14BasePeripheral17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BasePeripheral::set_log_verbosity"],[12,4,1,"_CPPv4N4espp14BasePeripheral17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BasePeripheral::set_log_verbosity::level"],[12,3,1,"_CPPv4N4espp14BasePeripheral9set_probeERK8probe_fn","espp::BasePeripheral::set_probe"],[12,4,1,"_CPPv4N4espp14BasePeripheral9set_probeERK8probe_fn","espp::BasePeripheral::set_probe::probe"],[12,3,1,"_CPPv4N4espp14BasePeripheral8set_readERK7read_fn","espp::BasePeripheral::set_read"],[12,4,1,"_CPPv4N4espp14BasePeripheral8set_readERK7read_fn","espp::BasePeripheral::set_read::read"],[12,3,1,"_CPPv4N4espp14BasePeripheral17set_read_registerERK16read_register_fn","espp::BasePeripheral::set_read_register"],[12,4,1,"_CPPv4N4espp14BasePeripheral17set_read_registerERK16read_register_fn","espp::BasePeripheral::set_read_register::read_register"],[12,3,1,"_CPPv4N4espp14BasePeripheral34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::BasePeripheral::set_separate_write_then_read_delay"],[12,4,1,"_CPPv4N4espp14BasePeripheral34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::BasePeripheral::set_separate_write_then_read_delay::delay"],[12,3,1,"_CPPv4N4espp14BasePeripheral9set_writeERK8write_fn","espp::BasePeripheral::set_write"],[12,4,1,"_CPPv4N4espp14BasePeripheral9set_writeERK8write_fn","espp::BasePeripheral::set_write::write"],[12,3,1,"_CPPv4N4espp14BasePeripheral19set_write_then_readERK18write_then_read_fn","espp::BasePeripheral::set_write_then_read"],[12,4,1,"_CPPv4N4espp14BasePeripheral19set_write_then_readERK18write_then_read_fn","espp::BasePeripheral::set_write_then_read::write_then_read"],[20,2,1,"_CPPv4N4espp14BatteryServiceE","espp::BatteryService"],[20,3,1,"_CPPv4N4espp14BatteryService14BatteryServiceEN4espp6Logger9VerbosityE","espp::BatteryService::BatteryService"],[20,4,1,"_CPPv4N4espp14BatteryService14BatteryServiceEN4espp6Logger9VerbosityE","espp::BatteryService::BatteryService::log_level"],[20,3,1,"_CPPv4N4espp14BatteryService6deinitEv","espp::BatteryService::deinit"],[20,3,1,"_CPPv4N4espp14BatteryService17get_battery_levelEv","espp::BatteryService::get_battery_level"],[20,3,1,"_CPPv4NK4espp14BatteryService13get_log_levelEv","espp::BatteryService::get_log_level"],[20,3,1,"_CPPv4NK4espp14BatteryService17get_log_verbosityEv","espp::BatteryService::get_log_verbosity"],[20,3,1,"_CPPv4NK4espp14BatteryService8get_nameEv","espp::BatteryService::get_name"],[20,3,1,"_CPPv4N4espp14BatteryService11get_serviceEv","espp::BatteryService::get_service"],[20,3,1,"_CPPv4N4espp14BatteryService4initEP12NimBLEServer","espp::BatteryService::init"],[20,4,1,"_CPPv4N4espp14BatteryService4initEP12NimBLEServer","espp::BatteryService::init::server"],[20,3,1,"_CPPv4N4espp14BatteryService17set_battery_levelE7uint8_t","espp::BatteryService::set_battery_level"],[20,4,1,"_CPPv4N4espp14BatteryService17set_battery_levelE7uint8_t","espp::BatteryService::set_battery_level::level"],[20,3,1,"_CPPv4N4espp14BatteryService13set_log_levelEN4espp6Logger9VerbosityE","espp::BatteryService::set_log_level"],[20,4,1,"_CPPv4N4espp14BatteryService13set_log_levelEN4espp6Logger9VerbosityE","espp::BatteryService::set_log_level::level"],[20,3,1,"_CPPv4N4espp14BatteryService18set_log_rate_limitENSt6chrono8durationIfEE","espp::BatteryService::set_log_rate_limit"],[20,4,1,"_CPPv4N4espp14BatteryService18set_log_rate_limitENSt6chrono8durationIfEE","espp::BatteryService::set_log_rate_limit::rate_limit"],[20,3,1,"_CPPv4N4espp14BatteryService11set_log_tagERKNSt11string_viewE","espp::BatteryService::set_log_tag"],[20,4,1,"_CPPv4N4espp14BatteryService11set_log_tagERKNSt11string_viewE","espp::BatteryService::set_log_tag::tag"],[20,3,1,"_CPPv4N4espp14BatteryService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BatteryService::set_log_verbosity"],[20,4,1,"_CPPv4N4espp14BatteryService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BatteryService::set_log_verbosity::level"],[20,3,1,"_CPPv4N4espp14BatteryService5startEv","espp::BatteryService::start"],[20,3,1,"_CPPv4N4espp14BatteryService4uuidEv","espp::BatteryService::uuid"],[115,2,1,"_CPPv4I0EN4espp6BezierE","espp::Bezier"],[115,3,1,"_CPPv4N4espp6Bezier6BezierERK14WeightedConfig","espp::Bezier::Bezier"],[115,3,1,"_CPPv4N4espp6Bezier6BezierERK6Config","espp::Bezier::Bezier"],[115,4,1,"_CPPv4N4espp6Bezier6BezierERK14WeightedConfig","espp::Bezier::Bezier::config"],[115,4,1,"_CPPv4N4espp6Bezier6BezierERK6Config","espp::Bezier::Bezier::config"],[115,2,1,"_CPPv4N4espp6Bezier6ConfigE","espp::Bezier::Config"],[115,1,1,"_CPPv4N4espp6Bezier6Config14control_pointsE","espp::Bezier::Config::control_points"],[115,5,1,"_CPPv4I0EN4espp6BezierE","espp::Bezier::T"],[115,2,1,"_CPPv4N4espp6Bezier14WeightedConfigE","espp::Bezier::WeightedConfig"],[115,1,1,"_CPPv4N4espp6Bezier14WeightedConfig14control_pointsE","espp::Bezier::WeightedConfig::control_points"],[115,1,1,"_CPPv4N4espp6Bezier14WeightedConfig7weightsE","espp::Bezier::WeightedConfig::weights"],[115,3,1,"_CPPv4NK4espp6Bezier2atEf","espp::Bezier::at"],[115,4,1,"_CPPv4NK4espp6Bezier2atEf","espp::Bezier::at::t"],[115,3,1,"_CPPv4NK4espp6BezierclEf","espp::Bezier::operator()"],[115,4,1,"_CPPv4NK4espp6BezierclEf","espp::Bezier::operator()::t"],[59,2,1,"_CPPv4N4espp15BiquadFilterDf1E","espp::BiquadFilterDf1"],[59,3,1,"_CPPv4N4espp15BiquadFilterDf16updateEf","espp::BiquadFilterDf1::update"],[59,4,1,"_CPPv4N4espp15BiquadFilterDf16updateEf","espp::BiquadFilterDf1::update::input"],[59,2,1,"_CPPv4N4espp15BiquadFilterDf2E","espp::BiquadFilterDf2"],[59,3,1,"_CPPv4N4espp15BiquadFilterDf26updateEKf","espp::BiquadFilterDf2::update"],[59,3,1,"_CPPv4N4espp15BiquadFilterDf26updateEPKfPf6size_t","espp::BiquadFilterDf2::update"],[59,4,1,"_CPPv4N4espp15BiquadFilterDf26updateEKf","espp::BiquadFilterDf2::update::input"],[59,4,1,"_CPPv4N4espp15BiquadFilterDf26updateEPKfPf6size_t","espp::BiquadFilterDf2::update::input"],[59,4,1,"_CPPv4N4espp15BiquadFilterDf26updateEPKfPf6size_t","espp::BiquadFilterDf2::update::length"],[59,4,1,"_CPPv4N4espp15BiquadFilterDf26updateEPKfPf6size_t","espp::BiquadFilterDf2::update::output"],[16,2,1,"_CPPv4N4espp10BldcDriverE","espp::BldcDriver"],[16,3,1,"_CPPv4N4espp10BldcDriver10BldcDriverERK6Config","espp::BldcDriver::BldcDriver"],[16,4,1,"_CPPv4N4espp10BldcDriver10BldcDriverERK6Config","espp::BldcDriver::BldcDriver::config"],[16,2,1,"_CPPv4N4espp10BldcDriver6ConfigE","espp::BldcDriver::Config"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config12dead_zone_nsE","espp::BldcDriver::Config::dead_zone_ns"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_a_hE","espp::BldcDriver::Config::gpio_a_h"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_a_lE","espp::BldcDriver::Config::gpio_a_l"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_b_hE","espp::BldcDriver::Config::gpio_b_h"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_b_lE","espp::BldcDriver::Config::gpio_b_l"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_c_hE","espp::BldcDriver::Config::gpio_c_h"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config8gpio_c_lE","espp::BldcDriver::Config::gpio_c_l"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config11gpio_enableE","espp::BldcDriver::Config::gpio_enable"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config10gpio_faultE","espp::BldcDriver::Config::gpio_fault"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config13limit_voltageE","espp::BldcDriver::Config::limit_voltage"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config9log_levelE","espp::BldcDriver::Config::log_level"],[16,1,1,"_CPPv4N4espp10BldcDriver6Config20power_supply_voltageE","espp::BldcDriver::Config::power_supply_voltage"],[16,3,1,"_CPPv4N4espp10BldcDriver15configure_powerEff","espp::BldcDriver::configure_power"],[16,4,1,"_CPPv4N4espp10BldcDriver15configure_powerEff","espp::BldcDriver::configure_power::power_supply_voltage"],[16,4,1,"_CPPv4N4espp10BldcDriver15configure_powerEff","espp::BldcDriver::configure_power::voltage_limit"],[16,3,1,"_CPPv4N4espp10BldcDriver7disableEv","espp::BldcDriver::disable"],[16,3,1,"_CPPv4N4espp10BldcDriver6enableEv","espp::BldcDriver::enable"],[16,3,1,"_CPPv4NK4espp10BldcDriver13get_log_levelEv","espp::BldcDriver::get_log_level"],[16,3,1,"_CPPv4NK4espp10BldcDriver17get_log_verbosityEv","espp::BldcDriver::get_log_verbosity"],[16,3,1,"_CPPv4NK4espp10BldcDriver8get_nameEv","espp::BldcDriver::get_name"],[16,3,1,"_CPPv4NK4espp10BldcDriver22get_power_supply_limitEv","espp::BldcDriver::get_power_supply_limit"],[16,3,1,"_CPPv4NK4espp10BldcDriver17get_voltage_limitEv","espp::BldcDriver::get_voltage_limit"],[16,3,1,"_CPPv4NK4espp10BldcDriver10is_enabledEv","espp::BldcDriver::is_enabled"],[16,3,1,"_CPPv4N4espp10BldcDriver10is_faultedEv","espp::BldcDriver::is_faulted"],[16,3,1,"_CPPv4N4espp10BldcDriver13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcDriver::set_log_level"],[16,4,1,"_CPPv4N4espp10BldcDriver13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcDriver::set_log_level::level"],[16,3,1,"_CPPv4N4espp10BldcDriver18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcDriver::set_log_rate_limit"],[16,4,1,"_CPPv4N4espp10BldcDriver18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcDriver::set_log_rate_limit::rate_limit"],[16,3,1,"_CPPv4N4espp10BldcDriver11set_log_tagERKNSt11string_viewE","espp::BldcDriver::set_log_tag"],[16,4,1,"_CPPv4N4espp10BldcDriver11set_log_tagERKNSt11string_viewE","espp::BldcDriver::set_log_tag::tag"],[16,3,1,"_CPPv4N4espp10BldcDriver17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcDriver::set_log_verbosity"],[16,4,1,"_CPPv4N4espp10BldcDriver17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcDriver::set_log_verbosity::level"],[16,3,1,"_CPPv4N4espp10BldcDriver15set_phase_stateEiii","espp::BldcDriver::set_phase_state"],[16,4,1,"_CPPv4N4espp10BldcDriver15set_phase_stateEiii","espp::BldcDriver::set_phase_state::state_a"],[16,4,1,"_CPPv4N4espp10BldcDriver15set_phase_stateEiii","espp::BldcDriver::set_phase_state::state_b"],[16,4,1,"_CPPv4N4espp10BldcDriver15set_phase_stateEiii","espp::BldcDriver::set_phase_state::state_c"],[16,3,1,"_CPPv4N4espp10BldcDriver7set_pwmEfff","espp::BldcDriver::set_pwm"],[16,4,1,"_CPPv4N4espp10BldcDriver7set_pwmEfff","espp::BldcDriver::set_pwm::duty_a"],[16,4,1,"_CPPv4N4espp10BldcDriver7set_pwmEfff","espp::BldcDriver::set_pwm::duty_b"],[16,4,1,"_CPPv4N4espp10BldcDriver7set_pwmEfff","espp::BldcDriver::set_pwm::duty_c"],[16,3,1,"_CPPv4N4espp10BldcDriver11set_voltageEfff","espp::BldcDriver::set_voltage"],[16,4,1,"_CPPv4N4espp10BldcDriver11set_voltageEfff","espp::BldcDriver::set_voltage::ua"],[16,4,1,"_CPPv4N4espp10BldcDriver11set_voltageEfff","espp::BldcDriver::set_voltage::ub"],[16,4,1,"_CPPv4N4espp10BldcDriver11set_voltageEfff","espp::BldcDriver::set_voltage::uc"],[16,3,1,"_CPPv4N4espp10BldcDriverD0Ev","espp::BldcDriver::~BldcDriver"],[70,2,1,"_CPPv4I_12MotorConceptEN4espp11BldcHapticsE","espp::BldcHaptics"],[70,3,1,"_CPPv4N4espp11BldcHaptics11BldcHapticsERK6Config","espp::BldcHaptics::BldcHaptics"],[70,4,1,"_CPPv4N4espp11BldcHaptics11BldcHapticsERK6Config","espp::BldcHaptics::BldcHaptics::config"],[70,2,1,"_CPPv4N4espp11BldcHaptics6ConfigE","espp::BldcHaptics::Config"],[70,1,1,"_CPPv4N4espp11BldcHaptics6Config13kd_factor_maxE","espp::BldcHaptics::Config::kd_factor_max"],[70,1,1,"_CPPv4N4espp11BldcHaptics6Config13kd_factor_minE","espp::BldcHaptics::Config::kd_factor_min"],[70,1,1,"_CPPv4N4espp11BldcHaptics6Config9kp_factorE","espp::BldcHaptics::Config::kp_factor"],[70,1,1,"_CPPv4N4espp11BldcHaptics6Config9log_levelE","espp::BldcHaptics::Config::log_level"],[70,1,1,"_CPPv4N4espp11BldcHaptics6Config5motorE","espp::BldcHaptics::Config::motor"],[70,5,1,"_CPPv4I_12MotorConceptEN4espp11BldcHapticsE","espp::BldcHaptics::M"],[70,3,1,"_CPPv4NK4espp11BldcHaptics13get_log_levelEv","espp::BldcHaptics::get_log_level"],[70,3,1,"_CPPv4NK4espp11BldcHaptics17get_log_verbosityEv","espp::BldcHaptics::get_log_verbosity"],[70,3,1,"_CPPv4NK4espp11BldcHaptics8get_nameEv","espp::BldcHaptics::get_name"],[70,3,1,"_CPPv4NK4espp11BldcHaptics12get_positionEv","espp::BldcHaptics::get_position"],[70,3,1,"_CPPv4NK4espp11BldcHaptics10is_runningEv","espp::BldcHaptics::is_running"],[70,3,1,"_CPPv4N4espp11BldcHaptics11play_hapticERKN6detail12HapticConfigE","espp::BldcHaptics::play_haptic"],[70,4,1,"_CPPv4N4espp11BldcHaptics11play_hapticERKN6detail12HapticConfigE","espp::BldcHaptics::play_haptic::config"],[70,3,1,"_CPPv4N4espp11BldcHaptics13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcHaptics::set_log_level"],[70,4,1,"_CPPv4N4espp11BldcHaptics13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcHaptics::set_log_level::level"],[70,3,1,"_CPPv4N4espp11BldcHaptics18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcHaptics::set_log_rate_limit"],[70,4,1,"_CPPv4N4espp11BldcHaptics18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcHaptics::set_log_rate_limit::rate_limit"],[70,3,1,"_CPPv4N4espp11BldcHaptics11set_log_tagERKNSt11string_viewE","espp::BldcHaptics::set_log_tag"],[70,4,1,"_CPPv4N4espp11BldcHaptics11set_log_tagERKNSt11string_viewE","espp::BldcHaptics::set_log_tag::tag"],[70,3,1,"_CPPv4N4espp11BldcHaptics17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcHaptics::set_log_verbosity"],[70,4,1,"_CPPv4N4espp11BldcHaptics17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcHaptics::set_log_verbosity::level"],[70,3,1,"_CPPv4N4espp11BldcHaptics5startEv","espp::BldcHaptics::start"],[70,3,1,"_CPPv4N4espp11BldcHaptics4stopEv","espp::BldcHaptics::stop"],[70,3,1,"_CPPv4N4espp11BldcHaptics20update_detent_configERKN6detail12DetentConfigE","espp::BldcHaptics::update_detent_config"],[70,4,1,"_CPPv4N4espp11BldcHaptics20update_detent_configERKN6detail12DetentConfigE","espp::BldcHaptics::update_detent_config::config"],[70,3,1,"_CPPv4N4espp11BldcHapticsD0Ev","espp::BldcHaptics::~BldcHaptics"],[17,2,1,"_CPPv4I_13DriverConcept_13SensorConcept_20CurrentSensorConceptEN4espp9BldcMotorE","espp::BldcMotor"],[17,3,1,"_CPPv4N4espp9BldcMotor9BldcMotorERK6Config","espp::BldcMotor::BldcMotor"],[17,4,1,"_CPPv4N4espp9BldcMotor9BldcMotorERK6Config","espp::BldcMotor::BldcMotor::config"],[17,5,1,"_CPPv4I_13DriverConcept_13SensorConcept_20CurrentSensorConceptEN4espp9BldcMotorE","espp::BldcMotor::CS"],[17,2,1,"_CPPv4N4espp9BldcMotor6ConfigE","espp::BldcMotor::Config"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config12angle_filterE","espp::BldcMotor::Config::angle_filter"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config9auto_initE","espp::BldcMotor::Config::auto_init"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config13current_limitE","espp::BldcMotor::Config::current_limit"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config13current_senseE","espp::BldcMotor::Config::current_sense"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config16d_current_filterE","espp::BldcMotor::Config::d_current_filter"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config6driverE","espp::BldcMotor::Config::driver"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config8foc_typeE","espp::BldcMotor::Config::foc_type"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config9kv_ratingE","espp::BldcMotor::Config::kv_rating"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config9log_levelE","espp::BldcMotor::Config::log_level"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config14num_pole_pairsE","espp::BldcMotor::Config::num_pole_pairs"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config16phase_inductanceE","espp::BldcMotor::Config::phase_inductance"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config16phase_resistanceE","espp::BldcMotor::Config::phase_resistance"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config16q_current_filterE","espp::BldcMotor::Config::q_current_filter"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config17run_sensor_updateE","espp::BldcMotor::Config::run_sensor_update"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config6sensorE","espp::BldcMotor::Config::sensor"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config17torque_controllerE","espp::BldcMotor::Config::torque_controller"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config15velocity_filterE","espp::BldcMotor::Config::velocity_filter"],[17,1,1,"_CPPv4N4espp9BldcMotor6Config14velocity_limitE","espp::BldcMotor::Config::velocity_limit"],[17,5,1,"_CPPv4I_13DriverConcept_13SensorConcept_20CurrentSensorConceptEN4espp9BldcMotorE","espp::BldcMotor::D"],[17,5,1,"_CPPv4I_13DriverConcept_13SensorConcept_20CurrentSensorConceptEN4espp9BldcMotorE","espp::BldcMotor::S"],[17,3,1,"_CPPv4N4espp9BldcMotor7disableEv","espp::BldcMotor::disable"],[17,3,1,"_CPPv4N4espp9BldcMotor6enableEv","espp::BldcMotor::enable"],[17,8,1,"_CPPv4N4espp9BldcMotor9filter_fnE","espp::BldcMotor::filter_fn"],[17,3,1,"_CPPv4N4espp9BldcMotor20get_electrical_angleEv","espp::BldcMotor::get_electrical_angle"],[17,3,1,"_CPPv4NK4espp9BldcMotor13get_log_levelEv","espp::BldcMotor::get_log_level"],[17,3,1,"_CPPv4NK4espp9BldcMotor17get_log_verbosityEv","espp::BldcMotor::get_log_verbosity"],[17,3,1,"_CPPv4NK4espp9BldcMotor8get_nameEv","espp::BldcMotor::get_name"],[17,3,1,"_CPPv4N4espp9BldcMotor15get_shaft_angleEv","espp::BldcMotor::get_shaft_angle"],[17,3,1,"_CPPv4N4espp9BldcMotor18get_shaft_velocityEv","espp::BldcMotor::get_shaft_velocity"],[17,3,1,"_CPPv4N4espp9BldcMotor10initializeEfN6detail15SensorDirectionE","espp::BldcMotor::initialize"],[17,4,1,"_CPPv4N4espp9BldcMotor10initializeEfN6detail15SensorDirectionE","espp::BldcMotor::initialize::sensor_direction"],[17,4,1,"_CPPv4N4espp9BldcMotor10initializeEfN6detail15SensorDirectionE","espp::BldcMotor::initialize::zero_electric_offset"],[17,3,1,"_CPPv4NK4espp9BldcMotor10is_enabledEv","espp::BldcMotor::is_enabled"],[17,3,1,"_CPPv4N4espp9BldcMotor8loop_focEv","espp::BldcMotor::loop_foc"],[17,3,1,"_CPPv4N4espp9BldcMotor4moveEf","espp::BldcMotor::move"],[17,4,1,"_CPPv4N4espp9BldcMotor4moveEf","espp::BldcMotor::move::new_target"],[17,3,1,"_CPPv4N4espp9BldcMotor13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcMotor::set_log_level"],[17,4,1,"_CPPv4N4espp9BldcMotor13set_log_levelEN4espp6Logger9VerbosityE","espp::BldcMotor::set_log_level::level"],[17,3,1,"_CPPv4N4espp9BldcMotor18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcMotor::set_log_rate_limit"],[17,4,1,"_CPPv4N4espp9BldcMotor18set_log_rate_limitENSt6chrono8durationIfEE","espp::BldcMotor::set_log_rate_limit::rate_limit"],[17,3,1,"_CPPv4N4espp9BldcMotor11set_log_tagERKNSt11string_viewE","espp::BldcMotor::set_log_tag"],[17,4,1,"_CPPv4N4espp9BldcMotor11set_log_tagERKNSt11string_viewE","espp::BldcMotor::set_log_tag::tag"],[17,3,1,"_CPPv4N4espp9BldcMotor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcMotor::set_log_verbosity"],[17,4,1,"_CPPv4N4espp9BldcMotor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BldcMotor::set_log_verbosity::level"],[17,3,1,"_CPPv4N4espp9BldcMotor23set_motion_control_typeEN6detail17MotionControlTypeE","espp::BldcMotor::set_motion_control_type"],[17,4,1,"_CPPv4N4espp9BldcMotor23set_motion_control_typeEN6detail17MotionControlTypeE","espp::BldcMotor::set_motion_control_type::motion_control_type"],[17,3,1,"_CPPv4N4espp9BldcMotor17set_phase_voltageEfff","espp::BldcMotor::set_phase_voltage"],[17,4,1,"_CPPv4N4espp9BldcMotor17set_phase_voltageEfff","espp::BldcMotor::set_phase_voltage::el_angle"],[17,4,1,"_CPPv4N4espp9BldcMotor17set_phase_voltageEfff","espp::BldcMotor::set_phase_voltage::ud"],[17,4,1,"_CPPv4N4espp9BldcMotor17set_phase_voltageEfff","espp::BldcMotor::set_phase_voltage::uq"],[17,3,1,"_CPPv4N4espp9BldcMotorD0Ev","espp::BldcMotor::~BldcMotor"],[21,2,1,"_CPPv4N4espp13BleGattServerE","espp::BleGattServer"],[21,2,1,"_CPPv4N4espp13BleGattServer21AdvertisingParametersE","espp::BleGattServer::AdvertisingParameters"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters17connect_whitelistE","espp::BleGattServer::AdvertisingParameters::connect_whitelist"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters11connectableE","espp::BleGattServer::AdvertisingParameters::connectable"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters16directed_addressE","espp::BleGattServer::AdvertisingParameters::directed_address"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters11duration_msE","espp::BleGattServer::AdvertisingParameters::duration_ms"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters16include_tx_powerE","espp::BleGattServer::AdvertisingParameters::include_tx_power"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters15max_interval_msE","espp::BleGattServer::AdvertisingParameters::max_interval_ms"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters15min_interval_msE","espp::BleGattServer::AdvertisingParameters::min_interval_ms"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters22scan_request_whitelistE","espp::BleGattServer::AdvertisingParameters::scan_request_whitelist"],[21,1,1,"_CPPv4N4espp13BleGattServer21AdvertisingParameters13scan_responseE","espp::BleGattServer::AdvertisingParameters::scan_response"],[21,3,1,"_CPPv4N4espp13BleGattServer13BleGattServerERK6Config","espp::BleGattServer::BleGattServer"],[21,3,1,"_CPPv4N4espp13BleGattServer13BleGattServerEv","espp::BleGattServer::BleGattServer"],[21,4,1,"_CPPv4N4espp13BleGattServer13BleGattServerERK6Config","espp::BleGattServer::BleGattServer::config"],[21,2,1,"_CPPv4N4espp13BleGattServer9CallbacksE","espp::BleGattServer::Callbacks"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks31advertisement_complete_callbackE","espp::BleGattServer::Callbacks::advertisement_complete_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks30advertisement_stopped_callbackE","espp::BleGattServer::Callbacks::advertisement_stopped_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks32authentication_complete_callbackE","espp::BleGattServer::Callbacks::authentication_complete_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks24confirm_passkey_callbackE","espp::BleGattServer::Callbacks::confirm_passkey_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks16connect_callbackE","espp::BleGattServer::Callbacks::connect_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks19disconnect_callbackE","espp::BleGattServer::Callbacks::disconnect_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks20get_passkey_callbackE","espp::BleGattServer::Callbacks::get_passkey_callback"],[21,1,1,"_CPPv4N4espp13BleGattServer9Callbacks21scan_request_callbackE","espp::BleGattServer::Callbacks::scan_request_callback"],[21,2,1,"_CPPv4N4espp13BleGattServer6ConfigE","espp::BleGattServer::Config"],[21,1,1,"_CPPv4N4espp13BleGattServer6Config9callbacksE","espp::BleGattServer::Config::callbacks"],[21,1,1,"_CPPv4N4espp13BleGattServer6Config9log_levelE","espp::BleGattServer::Config::log_level"],[21,6,1,"_CPPv4N4espp13BleGattServer16DisconnectReasonE","espp::BleGattServer::DisconnectReason"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason22AUTHENTICATION_FAILUREE","espp::BleGattServer::DisconnectReason::AUTHENTICATION_FAILURE"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason21CONNECTION_TERMINATEDE","espp::BleGattServer::DisconnectReason::CONNECTION_TERMINATED"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason21LOCAL_USER_TERMINATEDE","espp::BleGattServer::DisconnectReason::LOCAL_USER_TERMINATED"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason24REMOTE_DEVICE_TERMINATEDE","espp::BleGattServer::DisconnectReason::REMOTE_DEVICE_TERMINATED"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason22REMOTE_USER_TERMINATEDE","espp::BleGattServer::DisconnectReason::REMOTE_USER_TERMINATED"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason7TIMEOUTE","espp::BleGattServer::DisconnectReason::TIMEOUT"],[21,7,1,"_CPPv4N4espp13BleGattServer16DisconnectReason7UNKNOWNE","espp::BleGattServer::DisconnectReason::UNKNOWN"],[21,8,1,"_CPPv4N4espp13BleGattServer33advertisement_complete_callback_tE","espp::BleGattServer::advertisement_complete_callback_t"],[21,8,1,"_CPPv4N4espp13BleGattServer32advertisement_stopped_callback_tE","espp::BleGattServer::advertisement_stopped_callback_t"],[21,8,1,"_CPPv4N4espp13BleGattServer34authentication_complete_callback_tE","espp::BleGattServer::authentication_complete_callback_t"],[21,3,1,"_CPPv4N4espp13BleGattServer15battery_serviceEv","espp::BleGattServer::battery_service"],[21,8,1,"_CPPv4N4espp13BleGattServer26confirm_passkey_callback_tE","espp::BleGattServer::confirm_passkey_callback_t"],[21,8,1,"_CPPv4N4espp13BleGattServer18connect_callback_tE","espp::BleGattServer::connect_callback_t"],[21,3,1,"_CPPv4N4espp13BleGattServer6deinitEv","espp::BleGattServer::deinit"],[21,3,1,"_CPPv4N4espp13BleGattServer19device_info_serviceEv","espp::BleGattServer::device_info_service"],[21,3,1,"_CPPv4N4espp13BleGattServer14disconnect_allEv","espp::BleGattServer::disconnect_all"],[21,8,1,"_CPPv4N4espp13BleGattServer21disconnect_callback_tE","espp::BleGattServer::disconnect_callback_t"],[21,3,1,"_CPPv4N4espp13BleGattServer30get_connected_device_addressesEv","espp::BleGattServer::get_connected_device_addresses"],[21,3,1,"_CPPv4N4espp13BleGattServer26get_connected_device_infosEv","espp::BleGattServer::get_connected_device_infos"],[21,3,1,"_CPPv4N4espp13BleGattServer25get_connected_device_nameER14NimBLEConnInfo","espp::BleGattServer::get_connected_device_name"],[21,4,1,"_CPPv4N4espp13BleGattServer25get_connected_device_nameER14NimBLEConnInfo","espp::BleGattServer::get_connected_device_name::conn_info"],[21,3,1,"_CPPv4N4espp13BleGattServer26get_connected_device_namesEv","espp::BleGattServer::get_connected_device_names"],[21,3,1,"_CPPv4N4espp13BleGattServer25get_connected_device_rssiER14NimBLEConnInfo","espp::BleGattServer::get_connected_device_rssi"],[21,4,1,"_CPPv4N4espp13BleGattServer25get_connected_device_rssiER14NimBLEConnInfo","espp::BleGattServer::get_connected_device_rssi::conn_info"],[21,3,1,"_CPPv4N4espp13BleGattServer33get_connected_devices_rssi_valuesEv","espp::BleGattServer::get_connected_devices_rssi_values"],[21,3,1,"_CPPv4NK4espp13BleGattServer13get_log_levelEv","espp::BleGattServer::get_log_level"],[21,3,1,"_CPPv4NK4espp13BleGattServer17get_log_verbosityEv","espp::BleGattServer::get_log_verbosity"],[21,3,1,"_CPPv4NK4espp13BleGattServer8get_nameEv","espp::BleGattServer::get_name"],[21,3,1,"_CPPv4N4espp13BleGattServer18get_paired_devicesEv","espp::BleGattServer::get_paired_devices"],[21,8,1,"_CPPv4N4espp13BleGattServer22get_passkey_callback_tE","espp::BleGattServer::get_passkey_callback_t"],[21,3,1,"_CPPv4N4espp13BleGattServer4initERKNSt6stringE","espp::BleGattServer::init"],[21,4,1,"_CPPv4N4espp13BleGattServer4initERKNSt6stringE","espp::BleGattServer::init::device_name"],[21,3,1,"_CPPv4N4espp13BleGattServer20interval_ms_to_unitsE8uint16_t","espp::BleGattServer::interval_ms_to_units"],[21,4,1,"_CPPv4N4espp13BleGattServer20interval_ms_to_unitsE8uint16_t","espp::BleGattServer::interval_ms_to_units::interval_ms"],[21,3,1,"_CPPv4N4espp13BleGattServer20interval_units_to_msE8uint16_t","espp::BleGattServer::interval_units_to_ms"],[21,4,1,"_CPPv4N4espp13BleGattServer20interval_units_to_msE8uint16_t","espp::BleGattServer::interval_units_to_ms::interval_units"],[21,3,1,"_CPPv4NK4espp13BleGattServer12is_connectedEv","espp::BleGattServer::is_connected"],[21,8,1,"_CPPv4N4espp13BleGattServer23scan_request_callback_tE","espp::BleGattServer::scan_request_callback_t"],[21,3,1,"_CPPv4NK4espp13BleGattServer6serverEv","espp::BleGattServer::server"],[21,3,1,"_CPPv4N4espp13BleGattServer27set_advertise_on_disconnectEb","espp::BleGattServer::set_advertise_on_disconnect"],[21,4,1,"_CPPv4N4espp13BleGattServer27set_advertise_on_disconnectEb","espp::BleGattServer::set_advertise_on_disconnect::advertise_on_disconnect"],[21,3,1,"_CPPv4N4espp13BleGattServer22set_advertisement_dataERK14AdvertisedData","espp::BleGattServer::set_advertisement_data"],[21,3,1,"_CPPv4N4espp13BleGattServer22set_advertisement_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_advertisement_data"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_advertisement_dataERK14AdvertisedData","espp::BleGattServer::set_advertisement_data::advertising_data"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_advertisement_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_advertisement_data::advertising_data"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_advertisement_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_advertisement_data::instance"],[21,3,1,"_CPPv4N4espp13BleGattServer13set_callbacksERK9Callbacks","espp::BleGattServer::set_callbacks"],[21,4,1,"_CPPv4N4espp13BleGattServer13set_callbacksERK9Callbacks","espp::BleGattServer::set_callbacks::callbacks"],[21,3,1,"_CPPv4N4espp13BleGattServer15set_device_nameERKNSt6stringE","espp::BleGattServer::set_device_name"],[21,4,1,"_CPPv4N4espp13BleGattServer15set_device_nameERKNSt6stringE","espp::BleGattServer::set_device_name::device_name"],[21,3,1,"_CPPv4N4espp13BleGattServer25set_init_key_distributionE7uint8_t","espp::BleGattServer::set_init_key_distribution"],[21,4,1,"_CPPv4N4espp13BleGattServer25set_init_key_distributionE7uint8_t","espp::BleGattServer::set_init_key_distribution::key_distribution"],[21,3,1,"_CPPv4N4espp13BleGattServer19set_io_capabilitiesE7uint8_t","espp::BleGattServer::set_io_capabilities"],[21,4,1,"_CPPv4N4espp13BleGattServer19set_io_capabilitiesE7uint8_t","espp::BleGattServer::set_io_capabilities::io_capabilities"],[21,3,1,"_CPPv4N4espp13BleGattServer13set_log_levelEN4espp6Logger9VerbosityE","espp::BleGattServer::set_log_level"],[21,4,1,"_CPPv4N4espp13BleGattServer13set_log_levelEN4espp6Logger9VerbosityE","espp::BleGattServer::set_log_level::level"],[21,3,1,"_CPPv4N4espp13BleGattServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::BleGattServer::set_log_rate_limit"],[21,4,1,"_CPPv4N4espp13BleGattServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::BleGattServer::set_log_rate_limit::rate_limit"],[21,3,1,"_CPPv4N4espp13BleGattServer11set_log_tagERKNSt11string_viewE","espp::BleGattServer::set_log_tag"],[21,4,1,"_CPPv4N4espp13BleGattServer11set_log_tagERKNSt11string_viewE","espp::BleGattServer::set_log_tag::tag"],[21,3,1,"_CPPv4N4espp13BleGattServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BleGattServer::set_log_verbosity"],[21,4,1,"_CPPv4N4espp13BleGattServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::BleGattServer::set_log_verbosity::level"],[21,3,1,"_CPPv4N4espp13BleGattServer11set_passkeyE8uint32_t","espp::BleGattServer::set_passkey"],[21,4,1,"_CPPv4N4espp13BleGattServer11set_passkeyE8uint32_t","espp::BleGattServer::set_passkey::passkey"],[21,3,1,"_CPPv4N4espp13BleGattServer25set_resp_key_distributionE7uint8_t","espp::BleGattServer::set_resp_key_distribution"],[21,4,1,"_CPPv4N4espp13BleGattServer25set_resp_key_distributionE7uint8_t","espp::BleGattServer::set_resp_key_distribution::key_distribution"],[21,3,1,"_CPPv4N4espp13BleGattServer22set_scan_response_dataERK14AdvertisedData","espp::BleGattServer::set_scan_response_data"],[21,3,1,"_CPPv4N4espp13BleGattServer22set_scan_response_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_scan_response_data"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_scan_response_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_scan_response_data::instance"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_scan_response_dataERK14AdvertisedData","espp::BleGattServer::set_scan_response_data::scan_response_data"],[21,4,1,"_CPPv4N4espp13BleGattServer22set_scan_response_dataERK14AdvertisedData7uint8_t","espp::BleGattServer::set_scan_response_data::scan_response_data"],[21,3,1,"_CPPv4N4espp13BleGattServer12set_securityEbbb","espp::BleGattServer::set_security"],[21,4,1,"_CPPv4N4espp13BleGattServer12set_securityEbbb","espp::BleGattServer::set_security::bonding"],[21,4,1,"_CPPv4N4espp13BleGattServer12set_securityEbbb","espp::BleGattServer::set_security::mitm"],[21,4,1,"_CPPv4N4espp13BleGattServer12set_securityEbbb","espp::BleGattServer::set_security::secure"],[21,3,1,"_CPPv4N4espp13BleGattServer5startEv","espp::BleGattServer::start"],[21,3,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_t7uint8_t","espp::BleGattServer::start_advertising"],[21,3,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_tP13NimBLEAddress","espp::BleGattServer::start_advertising"],[21,3,1,"_CPPv4N4espp13BleGattServer17start_advertisingERK21AdvertisingParameters","espp::BleGattServer::start_advertising"],[21,4,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_tP13NimBLEAddress","espp::BleGattServer::start_advertising::directed_address"],[21,4,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_t7uint8_t","espp::BleGattServer::start_advertising::duration_ms"],[21,4,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_tP13NimBLEAddress","espp::BleGattServer::start_advertising::duration_ms"],[21,4,1,"_CPPv4N4espp13BleGattServer17start_advertisingE8uint32_t7uint8_t","espp::BleGattServer::start_advertising::instance"],[21,4,1,"_CPPv4N4espp13BleGattServer17start_advertisingERK21AdvertisingParameters","espp::BleGattServer::start_advertising::params"],[21,3,1,"_CPPv4N4espp13BleGattServer14start_servicesEv","espp::BleGattServer::start_services"],[21,3,1,"_CPPv4N4espp13BleGattServer16stop_advertisingE7uint8_t","espp::BleGattServer::stop_advertising"],[21,3,1,"_CPPv4N4espp13BleGattServer16stop_advertisingEv","espp::BleGattServer::stop_advertising"],[21,4,1,"_CPPv4N4espp13BleGattServer16stop_advertisingE7uint8_t","espp::BleGattServer::stop_advertising::instance"],[21,3,1,"_CPPv4N4espp13BleGattServer10unpair_allEv","espp::BleGattServer::unpair_all"],[21,3,1,"_CPPv4N4espp13BleGattServerD0Ev","espp::BleGattServer::~BleGattServer"],[21,2,1,"_CPPv4N4espp33BleGattServerAdvertisingCallbacksE","espp::BleGattServerAdvertisingCallbacks"],[21,2,1,"_CPPv4N4espp22BleGattServerCallbacksE","espp::BleGattServerCallbacks"],[21,2,1,"_CPPv4N4espp17BleGattServerMenuE","espp::BleGattServerMenu"],[21,3,1,"_CPPv4N4espp17BleGattServerMenu17BleGattServerMenuENSt17reference_wrapperIN4espp13BleGattServerEEE","espp::BleGattServerMenu::BleGattServerMenu"],[21,4,1,"_CPPv4N4espp17BleGattServerMenu17BleGattServerMenuENSt17reference_wrapperIN4espp13BleGattServerEEE","espp::BleGattServerMenu::BleGattServerMenu::server"],[21,3,1,"_CPPv4N4espp17BleGattServerMenu3getENSt11string_viewENSt11string_viewE","espp::BleGattServerMenu::get"],[21,4,1,"_CPPv4N4espp17BleGattServerMenu3getENSt11string_viewENSt11string_viewE","espp::BleGattServerMenu::get::description"],[21,4,1,"_CPPv4N4espp17BleGattServerMenu3getENSt11string_viewENSt11string_viewE","espp::BleGattServerMenu::get::name"],[145,2,1,"_CPPv4N4espp6Bm8563E","espp::Bm8563"],[145,3,1,"_CPPv4N4espp6Bm85636Bm8563ERK6Config","espp::Bm8563::Bm8563"],[145,4,1,"_CPPv4N4espp6Bm85636Bm8563ERK6Config","espp::Bm8563::Bm8563::config"],[145,2,1,"_CPPv4N4espp6Bm85636ConfigE","espp::Bm8563::Config"],[145,1,1,"_CPPv4N4espp6Bm85636Config9log_levelE","espp::Bm8563::Config::log_level"],[145,1,1,"_CPPv4N4espp6Bm85636Config5writeE","espp::Bm8563::Config::write"],[145,1,1,"_CPPv4N4espp6Bm85636Config15write_then_readE","espp::Bm8563::Config::write_then_read"],[145,1,1,"_CPPv4N4espp6Bm856315DEFAULT_ADDRESSE","espp::Bm8563::DEFAULT_ADDRESS"],[145,2,1,"_CPPv4N4espp6Bm85634DateE","espp::Bm8563::Date"],[145,1,1,"_CPPv4N4espp6Bm85634Date3dayE","espp::Bm8563::Date::day"],[145,1,1,"_CPPv4N4espp6Bm85634Date5monthE","espp::Bm8563::Date::month"],[145,1,1,"_CPPv4N4espp6Bm85634Date7weekdayE","espp::Bm8563::Date::weekday"],[145,1,1,"_CPPv4N4espp6Bm85634Date4yearE","espp::Bm8563::Date::year"],[145,2,1,"_CPPv4N4espp6Bm85638DateTimeE","espp::Bm8563::DateTime"],[145,1,1,"_CPPv4N4espp6Bm85638DateTime4dateE","espp::Bm8563::DateTime::date"],[145,1,1,"_CPPv4N4espp6Bm85638DateTime4timeE","espp::Bm8563::DateTime::time"],[145,2,1,"_CPPv4N4espp6Bm85634TimeE","espp::Bm8563::Time"],[145,1,1,"_CPPv4N4espp6Bm85634Time4hourE","espp::Bm8563::Time::hour"],[145,1,1,"_CPPv4N4espp6Bm85634Time6minuteE","espp::Bm8563::Time::minute"],[145,1,1,"_CPPv4N4espp6Bm85634Time6secondE","espp::Bm8563::Time::second"],[145,3,1,"_CPPv4N4espp6Bm85638bcd2byteE7uint8_t","espp::Bm8563::bcd2byte"],[145,4,1,"_CPPv4N4espp6Bm85638bcd2byteE7uint8_t","espp::Bm8563::bcd2byte::value"],[145,3,1,"_CPPv4N4espp6Bm85638byte2bcdE7uint8_t","espp::Bm8563::byte2bcd"],[145,4,1,"_CPPv4N4espp6Bm85638byte2bcdE7uint8_t","espp::Bm8563::byte2bcd::value"],[145,3,1,"_CPPv4N4espp6Bm85638get_dateERNSt10error_codeE","espp::Bm8563::get_date"],[145,4,1,"_CPPv4N4espp6Bm85638get_dateERNSt10error_codeE","espp::Bm8563::get_date::ec"],[145,3,1,"_CPPv4N4espp6Bm856313get_date_timeERNSt10error_codeE","espp::Bm8563::get_date_time"],[145,4,1,"_CPPv4N4espp6Bm856313get_date_timeERNSt10error_codeE","espp::Bm8563::get_date_time::ec"],[145,3,1,"_CPPv4NK4espp6Bm856313get_log_levelEv","espp::Bm8563::get_log_level"],[145,3,1,"_CPPv4NK4espp6Bm856317get_log_verbosityEv","espp::Bm8563::get_log_verbosity"],[145,3,1,"_CPPv4NK4espp6Bm85638get_nameEv","espp::Bm8563::get_name"],[145,3,1,"_CPPv4N4espp6Bm85638get_timeERNSt10error_codeE","espp::Bm8563::get_time"],[145,4,1,"_CPPv4N4espp6Bm85638get_timeERNSt10error_codeE","espp::Bm8563::get_time::ec"],[145,3,1,"_CPPv4N4espp6Bm85635probeERNSt10error_codeE","espp::Bm8563::probe"],[145,4,1,"_CPPv4N4espp6Bm85635probeERNSt10error_codeE","espp::Bm8563::probe::ec"],[145,8,1,"_CPPv4N4espp6Bm85638probe_fnE","espp::Bm8563::probe_fn"],[145,3,1,"_CPPv4N4espp6Bm856311set_addressE7uint8_t","espp::Bm8563::set_address"],[145,4,1,"_CPPv4N4espp6Bm856311set_addressE7uint8_t","espp::Bm8563::set_address::address"],[145,3,1,"_CPPv4N4espp6Bm856310set_configERK6Config","espp::Bm8563::set_config"],[145,3,1,"_CPPv4N4espp6Bm856310set_configERR6Config","espp::Bm8563::set_config"],[145,4,1,"_CPPv4N4espp6Bm856310set_configERK6Config","espp::Bm8563::set_config::config"],[145,4,1,"_CPPv4N4espp6Bm856310set_configERR6Config","espp::Bm8563::set_config::config"],[145,3,1,"_CPPv4N4espp6Bm85638set_dateERK4DateRNSt10error_codeE","espp::Bm8563::set_date"],[145,4,1,"_CPPv4N4espp6Bm85638set_dateERK4DateRNSt10error_codeE","espp::Bm8563::set_date::d"],[145,4,1,"_CPPv4N4espp6Bm85638set_dateERK4DateRNSt10error_codeE","espp::Bm8563::set_date::ec"],[145,3,1,"_CPPv4N4espp6Bm856313set_date_timeERK8DateTimeRNSt10error_codeE","espp::Bm8563::set_date_time"],[145,4,1,"_CPPv4N4espp6Bm856313set_date_timeERK8DateTimeRNSt10error_codeE","espp::Bm8563::set_date_time::dt"],[145,4,1,"_CPPv4N4espp6Bm856313set_date_timeERK8DateTimeRNSt10error_codeE","espp::Bm8563::set_date_time::ec"],[145,3,1,"_CPPv4N4espp6Bm856313set_log_levelEN4espp6Logger9VerbosityE","espp::Bm8563::set_log_level"],[145,4,1,"_CPPv4N4espp6Bm856313set_log_levelEN4espp6Logger9VerbosityE","espp::Bm8563::set_log_level::level"],[145,3,1,"_CPPv4N4espp6Bm856318set_log_rate_limitENSt6chrono8durationIfEE","espp::Bm8563::set_log_rate_limit"],[145,4,1,"_CPPv4N4espp6Bm856318set_log_rate_limitENSt6chrono8durationIfEE","espp::Bm8563::set_log_rate_limit::rate_limit"],[145,3,1,"_CPPv4N4espp6Bm856311set_log_tagERKNSt11string_viewE","espp::Bm8563::set_log_tag"],[145,4,1,"_CPPv4N4espp6Bm856311set_log_tagERKNSt11string_viewE","espp::Bm8563::set_log_tag::tag"],[145,3,1,"_CPPv4N4espp6Bm856317set_log_verbosityEN4espp6Logger9VerbosityE","espp::Bm8563::set_log_verbosity"],[145,4,1,"_CPPv4N4espp6Bm856317set_log_verbosityEN4espp6Logger9VerbosityE","espp::Bm8563::set_log_verbosity::level"],[145,3,1,"_CPPv4N4espp6Bm85639set_probeERK8probe_fn","espp::Bm8563::set_probe"],[145,4,1,"_CPPv4N4espp6Bm85639set_probeERK8probe_fn","espp::Bm8563::set_probe::probe"],[145,3,1,"_CPPv4N4espp6Bm85638set_readERK7read_fn","espp::Bm8563::set_read"],[145,4,1,"_CPPv4N4espp6Bm85638set_readERK7read_fn","espp::Bm8563::set_read::read"],[145,3,1,"_CPPv4N4espp6Bm856317set_read_registerERK16read_register_fn","espp::Bm8563::set_read_register"],[145,4,1,"_CPPv4N4espp6Bm856317set_read_registerERK16read_register_fn","espp::Bm8563::set_read_register::read_register"],[145,3,1,"_CPPv4N4espp6Bm856334set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Bm8563::set_separate_write_then_read_delay"],[145,4,1,"_CPPv4N4espp6Bm856334set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Bm8563::set_separate_write_then_read_delay::delay"],[145,3,1,"_CPPv4N4espp6Bm85638set_timeERK4TimeRNSt10error_codeE","espp::Bm8563::set_time"],[145,4,1,"_CPPv4N4espp6Bm85638set_timeERK4TimeRNSt10error_codeE","espp::Bm8563::set_time::ec"],[145,4,1,"_CPPv4N4espp6Bm85638set_timeERK4TimeRNSt10error_codeE","espp::Bm8563::set_time::t"],[145,3,1,"_CPPv4N4espp6Bm85639set_writeERK8write_fn","espp::Bm8563::set_write"],[145,4,1,"_CPPv4N4espp6Bm85639set_writeERK8write_fn","espp::Bm8563::set_write::write"],[145,3,1,"_CPPv4N4espp6Bm856319set_write_then_readERK18write_then_read_fn","espp::Bm8563::set_write_then_read"],[145,4,1,"_CPPv4N4espp6Bm856319set_write_then_readERK18write_then_read_fn","espp::Bm8563::set_write_then_read::write_then_read"],[60,2,1,"_CPPv4I_6size_t0EN4espp17ButterworthFilterE","espp::ButterworthFilter"],[60,3,1,"_CPPv4N4espp17ButterworthFilter17ButterworthFilterERK6Config","espp::ButterworthFilter::ButterworthFilter"],[60,4,1,"_CPPv4N4espp17ButterworthFilter17ButterworthFilterERK6Config","espp::ButterworthFilter::ButterworthFilter::config"],[60,2,1,"_CPPv4N4espp17ButterworthFilter6ConfigE","espp::ButterworthFilter::Config"],[60,1,1,"_CPPv4N4espp17ButterworthFilter6Config27normalized_cutoff_frequencyE","espp::ButterworthFilter::Config::normalized_cutoff_frequency"],[60,5,1,"_CPPv4I_6size_t0EN4espp17ButterworthFilterE","espp::ButterworthFilter::Impl"],[60,5,1,"_CPPv4I_6size_t0EN4espp17ButterworthFilterE","espp::ButterworthFilter::ORDER"],[60,3,1,"_CPPv4N4espp17ButterworthFilterclEf","espp::ButterworthFilter::operator()"],[60,4,1,"_CPPv4N4espp17ButterworthFilterclEf","espp::ButterworthFilter::operator()::input"],[60,3,1,"_CPPv4N4espp17ButterworthFilter6updateEf","espp::ButterworthFilter::update"],[60,4,1,"_CPPv4N4espp17ButterworthFilter6updateEf","espp::ButterworthFilter::update::input"],[29,2,1,"_CPPv4N4espp6ButtonE","espp::Button"],[29,8,1,"_CPPv4N4espp6Button11ActiveLevelE","espp::Button::ActiveLevel"],[29,3,1,"_CPPv4N4espp6Button6ButtonERK12SimpleConfig","espp::Button::Button"],[29,3,1,"_CPPv4N4espp6Button6ButtonERK6Config","espp::Button::Button"],[29,4,1,"_CPPv4N4espp6Button6ButtonERK12SimpleConfig","espp::Button::Button::config"],[29,4,1,"_CPPv4N4espp6Button6ButtonERK6Config","espp::Button::Button::config"],[29,2,1,"_CPPv4N4espp6Button6ConfigE","espp::Button::Config"],[29,1,1,"_CPPv4N4espp6Button6Config16interrupt_configE","espp::Button::Config::interrupt_config"],[29,1,1,"_CPPv4N4espp6Button6Config11isr_core_idE","espp::Button::Config::isr_core_id"],[29,1,1,"_CPPv4N4espp6Button6Config9log_levelE","espp::Button::Config::log_level"],[29,1,1,"_CPPv4N4espp6Button6Config4nameE","espp::Button::Config::name"],[29,1,1,"_CPPv4N4espp6Button6Config11task_configE","espp::Button::Config::task_config"],[29,8,1,"_CPPv4N4espp6Button5EventE","espp::Button::Event"],[29,8,1,"_CPPv4N4espp6Button13InterruptTypeE","espp::Button::InterruptType"],[29,2,1,"_CPPv4N4espp6Button12SimpleConfigE","espp::Button::SimpleConfig"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig12active_levelE","espp::Button::SimpleConfig::active_level"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig8gpio_numE","espp::Button::SimpleConfig::gpio_num"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig9log_levelE","espp::Button::SimpleConfig::log_level"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig4nameE","espp::Button::SimpleConfig::name"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig16pulldown_enabledE","espp::Button::SimpleConfig::pulldown_enabled"],[29,1,1,"_CPPv4N4espp6Button12SimpleConfig14pullup_enabledE","espp::Button::SimpleConfig::pullup_enabled"],[29,6,1,"_CPPv4N4espp6Button4TypeE","espp::Button::Type"],[29,7,1,"_CPPv4N4espp6Button4Type8ANY_EDGEE","espp::Button::Type::ANY_EDGE"],[29,7,1,"_CPPv4N4espp6Button4Type12FALLING_EDGEE","espp::Button::Type::FALLING_EDGE"],[29,7,1,"_CPPv4N4espp6Button4Type10HIGH_LEVELE","espp::Button::Type::HIGH_LEVEL"],[29,7,1,"_CPPv4N4espp6Button4Type9LOW_LEVELE","espp::Button::Type::LOW_LEVEL"],[29,7,1,"_CPPv4N4espp6Button4Type11RISING_EDGEE","espp::Button::Type::RISING_EDGE"],[29,3,1,"_CPPv4N4espp6Button13add_interruptERK9PinConfig","espp::Button::add_interrupt"],[29,4,1,"_CPPv4N4espp6Button13add_interruptERK9PinConfig","espp::Button::add_interrupt::interrupt"],[29,8,1,"_CPPv4N4espp6Button10callback_tE","espp::Button::callback_t"],[29,3,1,"_CPPv4N4espp6Button11disable_allEv","espp::Button::disable_all"],[29,3,1,"_CPPv4N4espp6Button17disable_interruptERK9PinConfig","espp::Button::disable_interrupt"],[29,3,1,"_CPPv4N4espp6Button17disable_interruptEi","espp::Button::disable_interrupt"],[29,4,1,"_CPPv4N4espp6Button17disable_interruptEi","espp::Button::disable_interrupt::gpio_num"],[29,4,1,"_CPPv4N4espp6Button17disable_interruptERK9PinConfig","espp::Button::disable_interrupt::interrupt"],[29,3,1,"_CPPv4N4espp6Button16enable_interruptERK9PinConfig","espp::Button::enable_interrupt"],[29,3,1,"_CPPv4N4espp6Button16enable_interruptEi","espp::Button::enable_interrupt"],[29,4,1,"_CPPv4N4espp6Button16enable_interruptEi","espp::Button::enable_interrupt::gpio_num"],[29,4,1,"_CPPv4N4espp6Button16enable_interruptERK9PinConfig","espp::Button::enable_interrupt::interrupt"],[29,8,1,"_CPPv4N4espp6Button17event_callback_fnE","espp::Button::event_callback_fn"],[29,3,1,"_CPPv4N4espp6Button17get_active_statesEv","espp::Button::get_active_states"],[29,3,1,"_CPPv4NK4espp6Button13get_log_levelEv","espp::Button::get_log_level"],[29,3,1,"_CPPv4NK4espp6Button17get_log_verbosityEv","espp::Button::get_log_verbosity"],[29,3,1,"_CPPv4NK4espp6Button18get_min_queue_sizeEv","espp::Button::get_min_queue_size"],[29,3,1,"_CPPv4NK4espp6Button8get_nameEv","espp::Button::get_name"],[29,3,1,"_CPPv4NK4espp6Button9is_activeERK9PinConfig","espp::Button::is_active"],[29,4,1,"_CPPv4NK4espp6Button9is_activeERK9PinConfig","espp::Button::is_active::interrupt"],[29,3,1,"_CPPv4NK4espp6Button10is_pressedEv","espp::Button::is_pressed"],[29,3,1,"_CPPv4N4espp6Button10remove_allEv","espp::Button::remove_all"],[29,3,1,"_CPPv4N4espp6Button16remove_interruptERK9PinConfig","espp::Button::remove_interrupt"],[29,3,1,"_CPPv4N4espp6Button16remove_interruptEi","espp::Button::remove_interrupt"],[29,4,1,"_CPPv4N4espp6Button16remove_interruptEi","espp::Button::remove_interrupt::gpio_num"],[29,4,1,"_CPPv4N4espp6Button16remove_interruptERK9PinConfig","espp::Button::remove_interrupt::interrupt"],[29,3,1,"_CPPv4N4espp6Button13set_log_levelEN4espp6Logger9VerbosityE","espp::Button::set_log_level"],[29,4,1,"_CPPv4N4espp6Button13set_log_levelEN4espp6Logger9VerbosityE","espp::Button::set_log_level::level"],[29,3,1,"_CPPv4N4espp6Button18set_log_rate_limitENSt6chrono8durationIfEE","espp::Button::set_log_rate_limit"],[29,4,1,"_CPPv4N4espp6Button18set_log_rate_limitENSt6chrono8durationIfEE","espp::Button::set_log_rate_limit::rate_limit"],[29,3,1,"_CPPv4N4espp6Button11set_log_tagERKNSt11string_viewE","espp::Button::set_log_tag"],[29,4,1,"_CPPv4N4espp6Button11set_log_tagERKNSt11string_viewE","espp::Button::set_log_tag::tag"],[29,3,1,"_CPPv4N4espp6Button17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Button::set_log_verbosity"],[29,4,1,"_CPPv4N4espp6Button17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Button::set_log_verbosity::level"],[81,2,1,"_CPPv4N4espp6Chsc6xE","espp::Chsc6x"],[81,3,1,"_CPPv4N4espp6Chsc6x6Chsc6xERK6Config","espp::Chsc6x::Chsc6x"],[81,4,1,"_CPPv4N4espp6Chsc6x6Chsc6xERK6Config","espp::Chsc6x::Chsc6x::config"],[81,2,1,"_CPPv4N4espp6Chsc6x6ConfigE","espp::Chsc6x::Config"],[81,1,1,"_CPPv4N4espp6Chsc6x6Config7addressE","espp::Chsc6x::Config::address"],[81,1,1,"_CPPv4N4espp6Chsc6x6Config9log_levelE","espp::Chsc6x::Config::log_level"],[81,1,1,"_CPPv4N4espp6Chsc6x6Config4readE","espp::Chsc6x::Config::read"],[81,1,1,"_CPPv4N4espp6Chsc6x6Config5writeE","espp::Chsc6x::Config::write"],[81,1,1,"_CPPv4N4espp6Chsc6x15DEFAULT_ADDRESSE","espp::Chsc6x::DEFAULT_ADDRESS"],[81,3,1,"_CPPv4NK4espp6Chsc6x13get_log_levelEv","espp::Chsc6x::get_log_level"],[81,3,1,"_CPPv4NK4espp6Chsc6x17get_log_verbosityEv","espp::Chsc6x::get_log_verbosity"],[81,3,1,"_CPPv4NK4espp6Chsc6x8get_nameEv","espp::Chsc6x::get_name"],[81,3,1,"_CPPv4NK4espp6Chsc6x20get_num_touch_pointsEv","espp::Chsc6x::get_num_touch_points"],[81,3,1,"_CPPv4NK4espp6Chsc6x15get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Chsc6x::get_touch_point"],[81,4,1,"_CPPv4NK4espp6Chsc6x15get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Chsc6x::get_touch_point::num_touch_points"],[81,4,1,"_CPPv4NK4espp6Chsc6x15get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Chsc6x::get_touch_point::x"],[81,4,1,"_CPPv4NK4espp6Chsc6x15get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Chsc6x::get_touch_point::y"],[81,3,1,"_CPPv4N4espp6Chsc6x5probeERNSt10error_codeE","espp::Chsc6x::probe"],[81,4,1,"_CPPv4N4espp6Chsc6x5probeERNSt10error_codeE","espp::Chsc6x::probe::ec"],[81,8,1,"_CPPv4N4espp6Chsc6x8probe_fnE","espp::Chsc6x::probe_fn"],[81,3,1,"_CPPv4N4espp6Chsc6x11set_addressE7uint8_t","espp::Chsc6x::set_address"],[81,4,1,"_CPPv4N4espp6Chsc6x11set_addressE7uint8_t","espp::Chsc6x::set_address::address"],[81,3,1,"_CPPv4N4espp6Chsc6x10set_configERK6Config","espp::Chsc6x::set_config"],[81,3,1,"_CPPv4N4espp6Chsc6x10set_configERR6Config","espp::Chsc6x::set_config"],[81,4,1,"_CPPv4N4espp6Chsc6x10set_configERK6Config","espp::Chsc6x::set_config::config"],[81,4,1,"_CPPv4N4espp6Chsc6x10set_configERR6Config","espp::Chsc6x::set_config::config"],[81,3,1,"_CPPv4N4espp6Chsc6x13set_log_levelEN4espp6Logger9VerbosityE","espp::Chsc6x::set_log_level"],[81,4,1,"_CPPv4N4espp6Chsc6x13set_log_levelEN4espp6Logger9VerbosityE","espp::Chsc6x::set_log_level::level"],[81,3,1,"_CPPv4N4espp6Chsc6x18set_log_rate_limitENSt6chrono8durationIfEE","espp::Chsc6x::set_log_rate_limit"],[81,4,1,"_CPPv4N4espp6Chsc6x18set_log_rate_limitENSt6chrono8durationIfEE","espp::Chsc6x::set_log_rate_limit::rate_limit"],[81,3,1,"_CPPv4N4espp6Chsc6x11set_log_tagERKNSt11string_viewE","espp::Chsc6x::set_log_tag"],[81,4,1,"_CPPv4N4espp6Chsc6x11set_log_tagERKNSt11string_viewE","espp::Chsc6x::set_log_tag::tag"],[81,3,1,"_CPPv4N4espp6Chsc6x17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Chsc6x::set_log_verbosity"],[81,4,1,"_CPPv4N4espp6Chsc6x17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Chsc6x::set_log_verbosity::level"],[81,3,1,"_CPPv4N4espp6Chsc6x9set_probeERK8probe_fn","espp::Chsc6x::set_probe"],[81,4,1,"_CPPv4N4espp6Chsc6x9set_probeERK8probe_fn","espp::Chsc6x::set_probe::probe"],[81,3,1,"_CPPv4N4espp6Chsc6x8set_readERK7read_fn","espp::Chsc6x::set_read"],[81,4,1,"_CPPv4N4espp6Chsc6x8set_readERK7read_fn","espp::Chsc6x::set_read::read"],[81,3,1,"_CPPv4N4espp6Chsc6x17set_read_registerERK16read_register_fn","espp::Chsc6x::set_read_register"],[81,4,1,"_CPPv4N4espp6Chsc6x17set_read_registerERK16read_register_fn","espp::Chsc6x::set_read_register::read_register"],[81,3,1,"_CPPv4N4espp6Chsc6x34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Chsc6x::set_separate_write_then_read_delay"],[81,4,1,"_CPPv4N4espp6Chsc6x34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Chsc6x::set_separate_write_then_read_delay::delay"],[81,3,1,"_CPPv4N4espp6Chsc6x9set_writeERK8write_fn","espp::Chsc6x::set_write"],[81,4,1,"_CPPv4N4espp6Chsc6x9set_writeERK8write_fn","espp::Chsc6x::set_write::write"],[81,3,1,"_CPPv4N4espp6Chsc6x19set_write_then_readERK18write_then_read_fn","espp::Chsc6x::set_write_then_read"],[81,4,1,"_CPPv4N4espp6Chsc6x19set_write_then_readERK18write_then_read_fn","espp::Chsc6x::set_write_then_read::write_then_read"],[81,3,1,"_CPPv4N4espp6Chsc6x6updateERNSt10error_codeE","espp::Chsc6x::update"],[81,4,1,"_CPPv4N4espp6Chsc6x6updateERNSt10error_codeE","espp::Chsc6x::update::ec"],[6,2,1,"_CPPv4N4espp13ContinuousAdcE","espp::ContinuousAdc"],[6,2,1,"_CPPv4N4espp13ContinuousAdc6ConfigE","espp::ContinuousAdc::Config"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config8channelsE","espp::ContinuousAdc::Config::channels"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config12convert_modeE","espp::ContinuousAdc::Config::convert_mode"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config9log_levelE","espp::ContinuousAdc::Config::log_level"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config14sample_rate_hzE","espp::ContinuousAdc::Config::sample_rate_hz"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config13task_priorityE","espp::ContinuousAdc::Config::task_priority"],[6,1,1,"_CPPv4N4espp13ContinuousAdc6Config17window_size_bytesE","espp::ContinuousAdc::Config::window_size_bytes"],[6,3,1,"_CPPv4N4espp13ContinuousAdc13ContinuousAdcERK6Config","espp::ContinuousAdc::ContinuousAdc"],[6,4,1,"_CPPv4N4espp13ContinuousAdc13ContinuousAdcERK6Config","espp::ContinuousAdc::ContinuousAdc::config"],[6,3,1,"_CPPv4NK4espp13ContinuousAdc13get_log_levelEv","espp::ContinuousAdc::get_log_level"],[6,3,1,"_CPPv4NK4espp13ContinuousAdc17get_log_verbosityEv","espp::ContinuousAdc::get_log_verbosity"],[6,3,1,"_CPPv4N4espp13ContinuousAdc6get_mvERK9AdcConfig","espp::ContinuousAdc::get_mv"],[6,4,1,"_CPPv4N4espp13ContinuousAdc6get_mvERK9AdcConfig","espp::ContinuousAdc::get_mv::config"],[6,3,1,"_CPPv4NK4espp13ContinuousAdc8get_nameEv","espp::ContinuousAdc::get_name"],[6,3,1,"_CPPv4N4espp13ContinuousAdc8get_rateERK9AdcConfig","espp::ContinuousAdc::get_rate"],[6,4,1,"_CPPv4N4espp13ContinuousAdc8get_rateERK9AdcConfig","espp::ContinuousAdc::get_rate::config"],[6,3,1,"_CPPv4N4espp13ContinuousAdc13set_log_levelEN4espp6Logger9VerbosityE","espp::ContinuousAdc::set_log_level"],[6,4,1,"_CPPv4N4espp13ContinuousAdc13set_log_levelEN4espp6Logger9VerbosityE","espp::ContinuousAdc::set_log_level::level"],[6,3,1,"_CPPv4N4espp13ContinuousAdc18set_log_rate_limitENSt6chrono8durationIfEE","espp::ContinuousAdc::set_log_rate_limit"],[6,4,1,"_CPPv4N4espp13ContinuousAdc18set_log_rate_limitENSt6chrono8durationIfEE","espp::ContinuousAdc::set_log_rate_limit::rate_limit"],[6,3,1,"_CPPv4N4espp13ContinuousAdc11set_log_tagERKNSt11string_viewE","espp::ContinuousAdc::set_log_tag"],[6,4,1,"_CPPv4N4espp13ContinuousAdc11set_log_tagERKNSt11string_viewE","espp::ContinuousAdc::set_log_tag::tag"],[6,3,1,"_CPPv4N4espp13ContinuousAdc17set_log_verbosityEN4espp6Logger9VerbosityE","espp::ContinuousAdc::set_log_verbosity"],[6,4,1,"_CPPv4N4espp13ContinuousAdc17set_log_verbosityEN4espp6Logger9VerbosityE","espp::ContinuousAdc::set_log_verbosity::level"],[6,3,1,"_CPPv4N4espp13ContinuousAdc5startEv","espp::ContinuousAdc::start"],[6,3,1,"_CPPv4N4espp13ContinuousAdc4stopEv","espp::ContinuousAdc::stop"],[6,3,1,"_CPPv4N4espp13ContinuousAdcD0Ev","espp::ContinuousAdc::~ContinuousAdc"],[35,2,1,"_CPPv4N4espp10ControllerE","espp::Controller"],[35,2,1,"_CPPv4N4espp10Controller20AnalogJoystickConfigE","espp::Controller::AnalogJoystickConfig"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig10active_lowE","espp::Controller::AnalogJoystickConfig::active_low"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig6gpio_aE","espp::Controller::AnalogJoystickConfig::gpio_a"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig6gpio_bE","espp::Controller::AnalogJoystickConfig::gpio_b"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig20gpio_joystick_selectE","espp::Controller::AnalogJoystickConfig::gpio_joystick_select"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig11gpio_selectE","espp::Controller::AnalogJoystickConfig::gpio_select"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig10gpio_startE","espp::Controller::AnalogJoystickConfig::gpio_start"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig6gpio_xE","espp::Controller::AnalogJoystickConfig::gpio_x"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig6gpio_yE","espp::Controller::AnalogJoystickConfig::gpio_y"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig15joystick_configE","espp::Controller::AnalogJoystickConfig::joystick_config"],[35,1,1,"_CPPv4N4espp10Controller20AnalogJoystickConfig9log_levelE","espp::Controller::AnalogJoystickConfig::log_level"],[35,6,1,"_CPPv4N4espp10Controller6ButtonE","espp::Controller::Button"],[35,7,1,"_CPPv4N4espp10Controller6Button1AE","espp::Controller::Button::A"],[35,7,1,"_CPPv4N4espp10Controller6Button1BE","espp::Controller::Button::B"],[35,7,1,"_CPPv4N4espp10Controller6Button4DOWNE","espp::Controller::Button::DOWN"],[35,7,1,"_CPPv4N4espp10Controller6Button15JOYSTICK_SELECTE","espp::Controller::Button::JOYSTICK_SELECT"],[35,7,1,"_CPPv4N4espp10Controller6Button11LAST_UNUSEDE","espp::Controller::Button::LAST_UNUSED"],[35,7,1,"_CPPv4N4espp10Controller6Button4LEFTE","espp::Controller::Button::LEFT"],[35,7,1,"_CPPv4N4espp10Controller6Button5RIGHTE","espp::Controller::Button::RIGHT"],[35,7,1,"_CPPv4N4espp10Controller6Button6SELECTE","espp::Controller::Button::SELECT"],[35,7,1,"_CPPv4N4espp10Controller6Button5STARTE","espp::Controller::Button::START"],[35,7,1,"_CPPv4N4espp10Controller6Button2UPE","espp::Controller::Button::UP"],[35,7,1,"_CPPv4N4espp10Controller6Button1XE","espp::Controller::Button::X"],[35,7,1,"_CPPv4N4espp10Controller6Button1YE","espp::Controller::Button::Y"],[35,3,1,"_CPPv4N4espp10Controller10ControllerERK10DualConfig","espp::Controller::Controller"],[35,3,1,"_CPPv4N4espp10Controller10ControllerERK13DigitalConfig","espp::Controller::Controller"],[35,3,1,"_CPPv4N4espp10Controller10ControllerERK20AnalogJoystickConfig","espp::Controller::Controller"],[35,4,1,"_CPPv4N4espp10Controller10ControllerERK10DualConfig","espp::Controller::Controller::config"],[35,4,1,"_CPPv4N4espp10Controller10ControllerERK13DigitalConfig","espp::Controller::Controller::config"],[35,4,1,"_CPPv4N4espp10Controller10ControllerERK20AnalogJoystickConfig","espp::Controller::Controller::config"],[35,2,1,"_CPPv4N4espp10Controller13DigitalConfigE","espp::Controller::DigitalConfig"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig10active_lowE","espp::Controller::DigitalConfig::active_low"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig6gpio_aE","espp::Controller::DigitalConfig::gpio_a"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig6gpio_bE","espp::Controller::DigitalConfig::gpio_b"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig9gpio_downE","espp::Controller::DigitalConfig::gpio_down"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig9gpio_leftE","espp::Controller::DigitalConfig::gpio_left"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig10gpio_rightE","espp::Controller::DigitalConfig::gpio_right"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig11gpio_selectE","espp::Controller::DigitalConfig::gpio_select"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig10gpio_startE","espp::Controller::DigitalConfig::gpio_start"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig7gpio_upE","espp::Controller::DigitalConfig::gpio_up"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig6gpio_xE","espp::Controller::DigitalConfig::gpio_x"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig6gpio_yE","espp::Controller::DigitalConfig::gpio_y"],[35,1,1,"_CPPv4N4espp10Controller13DigitalConfig9log_levelE","espp::Controller::DigitalConfig::log_level"],[35,2,1,"_CPPv4N4espp10Controller10DualConfigE","espp::Controller::DualConfig"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig10active_lowE","espp::Controller::DualConfig::active_low"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig6gpio_aE","espp::Controller::DualConfig::gpio_a"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig6gpio_bE","espp::Controller::DualConfig::gpio_b"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig9gpio_downE","espp::Controller::DualConfig::gpio_down"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig20gpio_joystick_selectE","espp::Controller::DualConfig::gpio_joystick_select"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig9gpio_leftE","espp::Controller::DualConfig::gpio_left"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig10gpio_rightE","espp::Controller::DualConfig::gpio_right"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig11gpio_selectE","espp::Controller::DualConfig::gpio_select"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig10gpio_startE","espp::Controller::DualConfig::gpio_start"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig7gpio_upE","espp::Controller::DualConfig::gpio_up"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig6gpio_xE","espp::Controller::DualConfig::gpio_x"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig6gpio_yE","espp::Controller::DualConfig::gpio_y"],[35,1,1,"_CPPv4N4espp10Controller10DualConfig9log_levelE","espp::Controller::DualConfig::log_level"],[35,2,1,"_CPPv4N4espp10Controller5StateE","espp::Controller::State"],[35,1,1,"_CPPv4N4espp10Controller5State1aE","espp::Controller::State::a"],[35,1,1,"_CPPv4N4espp10Controller5State1bE","espp::Controller::State::b"],[35,1,1,"_CPPv4N4espp10Controller5State4downE","espp::Controller::State::down"],[35,1,1,"_CPPv4N4espp10Controller5State15joystick_selectE","espp::Controller::State::joystick_select"],[35,1,1,"_CPPv4N4espp10Controller5State4leftE","espp::Controller::State::left"],[35,1,1,"_CPPv4N4espp10Controller5State5rightE","espp::Controller::State::right"],[35,1,1,"_CPPv4N4espp10Controller5State6selectE","espp::Controller::State::select"],[35,1,1,"_CPPv4N4espp10Controller5State5startE","espp::Controller::State::start"],[35,1,1,"_CPPv4N4espp10Controller5State2upE","espp::Controller::State::up"],[35,1,1,"_CPPv4N4espp10Controller5State1xE","espp::Controller::State::x"],[35,1,1,"_CPPv4N4espp10Controller5State1yE","espp::Controller::State::y"],[35,3,1,"_CPPv4NK4espp10Controller13get_log_levelEv","espp::Controller::get_log_level"],[35,3,1,"_CPPv4NK4espp10Controller17get_log_verbosityEv","espp::Controller::get_log_verbosity"],[35,3,1,"_CPPv4NK4espp10Controller8get_nameEv","espp::Controller::get_name"],[35,3,1,"_CPPv4N4espp10Controller9get_stateEv","espp::Controller::get_state"],[35,3,1,"_CPPv4N4espp10Controller10is_pressedEK6Button","espp::Controller::is_pressed"],[35,4,1,"_CPPv4N4espp10Controller10is_pressedEK6Button","espp::Controller::is_pressed::input"],[35,3,1,"_CPPv4N4espp10Controller13set_log_levelEN4espp6Logger9VerbosityE","espp::Controller::set_log_level"],[35,4,1,"_CPPv4N4espp10Controller13set_log_levelEN4espp6Logger9VerbosityE","espp::Controller::set_log_level::level"],[35,3,1,"_CPPv4N4espp10Controller18set_log_rate_limitENSt6chrono8durationIfEE","espp::Controller::set_log_rate_limit"],[35,4,1,"_CPPv4N4espp10Controller18set_log_rate_limitENSt6chrono8durationIfEE","espp::Controller::set_log_rate_limit::rate_limit"],[35,3,1,"_CPPv4N4espp10Controller11set_log_tagERKNSt11string_viewE","espp::Controller::set_log_tag"],[35,4,1,"_CPPv4N4espp10Controller11set_log_tagERKNSt11string_viewE","espp::Controller::set_log_tag::tag"],[35,3,1,"_CPPv4N4espp10Controller17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Controller::set_log_verbosity"],[35,4,1,"_CPPv4N4espp10Controller17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Controller::set_log_verbosity::level"],[35,3,1,"_CPPv4N4espp10Controller6updateEv","espp::Controller::update"],[35,3,1,"_CPPv4N4espp10ControllerD0Ev","espp::Controller::~Controller"],[83,2,1,"_CPPv4N4espp6Cst816E","espp::Cst816"],[83,2,1,"_CPPv4N4espp6Cst8166ConfigE","espp::Cst816::Config"],[83,1,1,"_CPPv4N4espp6Cst8166Config7addressE","espp::Cst816::Config::address"],[83,1,1,"_CPPv4N4espp6Cst8166Config9log_levelE","espp::Cst816::Config::log_level"],[83,1,1,"_CPPv4N4espp6Cst8166Config4readE","espp::Cst816::Config::read"],[83,1,1,"_CPPv4N4espp6Cst8166Config5writeE","espp::Cst816::Config::write"],[83,3,1,"_CPPv4N4espp6Cst8166Cst816ERK6Config","espp::Cst816::Cst816"],[83,4,1,"_CPPv4N4espp6Cst8166Cst816ERK6Config","espp::Cst816::Cst816::config"],[83,1,1,"_CPPv4N4espp6Cst81615DEFAULT_ADDRESSE","espp::Cst816::DEFAULT_ADDRESS"],[83,3,1,"_CPPv4NK4espp6Cst81621get_home_button_stateEv","espp::Cst816::get_home_button_state"],[83,3,1,"_CPPv4NK4espp6Cst81613get_log_levelEv","espp::Cst816::get_log_level"],[83,3,1,"_CPPv4NK4espp6Cst81617get_log_verbosityEv","espp::Cst816::get_log_verbosity"],[83,3,1,"_CPPv4NK4espp6Cst8168get_nameEv","espp::Cst816::get_name"],[83,3,1,"_CPPv4NK4espp6Cst81620get_num_touch_pointsEv","espp::Cst816::get_num_touch_points"],[83,3,1,"_CPPv4NK4espp6Cst81615get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Cst816::get_touch_point"],[83,4,1,"_CPPv4NK4espp6Cst81615get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Cst816::get_touch_point::num_touch_points"],[83,4,1,"_CPPv4NK4espp6Cst81615get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Cst816::get_touch_point::x"],[83,4,1,"_CPPv4NK4espp6Cst81615get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Cst816::get_touch_point::y"],[83,3,1,"_CPPv4N4espp6Cst8165probeERNSt10error_codeE","espp::Cst816::probe"],[83,4,1,"_CPPv4N4espp6Cst8165probeERNSt10error_codeE","espp::Cst816::probe::ec"],[83,8,1,"_CPPv4N4espp6Cst8168probe_fnE","espp::Cst816::probe_fn"],[83,3,1,"_CPPv4N4espp6Cst81611set_addressE7uint8_t","espp::Cst816::set_address"],[83,4,1,"_CPPv4N4espp6Cst81611set_addressE7uint8_t","espp::Cst816::set_address::address"],[83,3,1,"_CPPv4N4espp6Cst81610set_configERK6Config","espp::Cst816::set_config"],[83,3,1,"_CPPv4N4espp6Cst81610set_configERR6Config","espp::Cst816::set_config"],[83,4,1,"_CPPv4N4espp6Cst81610set_configERK6Config","espp::Cst816::set_config::config"],[83,4,1,"_CPPv4N4espp6Cst81610set_configERR6Config","espp::Cst816::set_config::config"],[83,3,1,"_CPPv4N4espp6Cst81613set_log_levelEN4espp6Logger9VerbosityE","espp::Cst816::set_log_level"],[83,4,1,"_CPPv4N4espp6Cst81613set_log_levelEN4espp6Logger9VerbosityE","espp::Cst816::set_log_level::level"],[83,3,1,"_CPPv4N4espp6Cst81618set_log_rate_limitENSt6chrono8durationIfEE","espp::Cst816::set_log_rate_limit"],[83,4,1,"_CPPv4N4espp6Cst81618set_log_rate_limitENSt6chrono8durationIfEE","espp::Cst816::set_log_rate_limit::rate_limit"],[83,3,1,"_CPPv4N4espp6Cst81611set_log_tagERKNSt11string_viewE","espp::Cst816::set_log_tag"],[83,4,1,"_CPPv4N4espp6Cst81611set_log_tagERKNSt11string_viewE","espp::Cst816::set_log_tag::tag"],[83,3,1,"_CPPv4N4espp6Cst81617set_log_verbosityEN4espp6Logger9VerbosityE","espp::Cst816::set_log_verbosity"],[83,4,1,"_CPPv4N4espp6Cst81617set_log_verbosityEN4espp6Logger9VerbosityE","espp::Cst816::set_log_verbosity::level"],[83,3,1,"_CPPv4N4espp6Cst8169set_probeERK8probe_fn","espp::Cst816::set_probe"],[83,4,1,"_CPPv4N4espp6Cst8169set_probeERK8probe_fn","espp::Cst816::set_probe::probe"],[83,3,1,"_CPPv4N4espp6Cst8168set_readERK7read_fn","espp::Cst816::set_read"],[83,4,1,"_CPPv4N4espp6Cst8168set_readERK7read_fn","espp::Cst816::set_read::read"],[83,3,1,"_CPPv4N4espp6Cst81617set_read_registerERK16read_register_fn","espp::Cst816::set_read_register"],[83,4,1,"_CPPv4N4espp6Cst81617set_read_registerERK16read_register_fn","espp::Cst816::set_read_register::read_register"],[83,3,1,"_CPPv4N4espp6Cst81634set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Cst816::set_separate_write_then_read_delay"],[83,4,1,"_CPPv4N4espp6Cst81634set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Cst816::set_separate_write_then_read_delay::delay"],[83,3,1,"_CPPv4N4espp6Cst8169set_writeERK8write_fn","espp::Cst816::set_write"],[83,4,1,"_CPPv4N4espp6Cst8169set_writeERK8write_fn","espp::Cst816::set_write::write"],[83,3,1,"_CPPv4N4espp6Cst81619set_write_then_readERK18write_then_read_fn","espp::Cst816::set_write_then_read"],[83,4,1,"_CPPv4N4espp6Cst81619set_write_then_readERK18write_then_read_fn","espp::Cst816::set_write_then_read::write_then_read"],[83,3,1,"_CPPv4N4espp6Cst8166updateERNSt10error_codeE","espp::Cst816::update"],[83,4,1,"_CPPv4N4espp6Cst8166updateERNSt10error_codeE","espp::Cst816::update::ec"],[23,2,1,"_CPPv4N4espp17DeviceInfoServiceE","espp::DeviceInfoService"],[23,2,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfoE","espp::DeviceInfoService::DeviceInfo"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo16firmware_versionE","espp::DeviceInfoService::DeviceInfo::firmware_version"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo16hardware_versionE","espp::DeviceInfoService::DeviceInfo::hardware_version"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo17manufacturer_nameE","espp::DeviceInfoService::DeviceInfo::manufacturer_name"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo12model_numberE","espp::DeviceInfoService::DeviceInfo::model_number"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo6pnp_idE","espp::DeviceInfoService::DeviceInfo::pnp_id"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo13serial_numberE","espp::DeviceInfoService::DeviceInfo::serial_number"],[23,1,1,"_CPPv4N4espp17DeviceInfoService10DeviceInfo16software_versionE","espp::DeviceInfoService::DeviceInfo::software_version"],[23,3,1,"_CPPv4N4espp17DeviceInfoService17DeviceInfoServiceEN4espp6Logger9VerbosityE","espp::DeviceInfoService::DeviceInfoService"],[23,4,1,"_CPPv4N4espp17DeviceInfoService17DeviceInfoServiceEN4espp6Logger9VerbosityE","espp::DeviceInfoService::DeviceInfoService::log_level"],[23,2,1,"_CPPv4N4espp17DeviceInfoService5PnpIdE","espp::DeviceInfoService::PnpId"],[23,1,1,"_CPPv4N4espp17DeviceInfoService5PnpId10product_idE","espp::DeviceInfoService::PnpId::product_id"],[23,1,1,"_CPPv4N4espp17DeviceInfoService5PnpId15product_versionE","espp::DeviceInfoService::PnpId::product_version"],[23,1,1,"_CPPv4N4espp17DeviceInfoService5PnpId9vendor_idE","espp::DeviceInfoService::PnpId::vendor_id"],[23,1,1,"_CPPv4N4espp17DeviceInfoService5PnpId16vendor_id_sourceE","espp::DeviceInfoService::PnpId::vendor_id_source"],[23,3,1,"_CPPv4N4espp17DeviceInfoService6deinitEv","espp::DeviceInfoService::deinit"],[23,3,1,"_CPPv4NK4espp17DeviceInfoService13get_log_levelEv","espp::DeviceInfoService::get_log_level"],[23,3,1,"_CPPv4NK4espp17DeviceInfoService17get_log_verbosityEv","espp::DeviceInfoService::get_log_verbosity"],[23,3,1,"_CPPv4NK4espp17DeviceInfoService8get_nameEv","espp::DeviceInfoService::get_name"],[23,3,1,"_CPPv4N4espp17DeviceInfoService11get_serviceEv","espp::DeviceInfoService::get_service"],[23,3,1,"_CPPv4N4espp17DeviceInfoService4initEP12NimBLEServer","espp::DeviceInfoService::init"],[23,4,1,"_CPPv4N4espp17DeviceInfoService4initEP12NimBLEServer","espp::DeviceInfoService::init::server"],[23,3,1,"_CPPv4N4espp17DeviceInfoService15set_device_infoERK10DeviceInfo","espp::DeviceInfoService::set_device_info"],[23,4,1,"_CPPv4N4espp17DeviceInfoService15set_device_infoERK10DeviceInfo","espp::DeviceInfoService::set_device_info::info"],[23,3,1,"_CPPv4N4espp17DeviceInfoService20set_firmware_versionERKNSt6stringE","espp::DeviceInfoService::set_firmware_version"],[23,4,1,"_CPPv4N4espp17DeviceInfoService20set_firmware_versionERKNSt6stringE","espp::DeviceInfoService::set_firmware_version::version"],[23,3,1,"_CPPv4N4espp17DeviceInfoService20set_hardware_versionERKNSt6stringE","espp::DeviceInfoService::set_hardware_version"],[23,4,1,"_CPPv4N4espp17DeviceInfoService20set_hardware_versionERKNSt6stringE","espp::DeviceInfoService::set_hardware_version::version"],[23,3,1,"_CPPv4N4espp17DeviceInfoService13set_log_levelEN4espp6Logger9VerbosityE","espp::DeviceInfoService::set_log_level"],[23,4,1,"_CPPv4N4espp17DeviceInfoService13set_log_levelEN4espp6Logger9VerbosityE","espp::DeviceInfoService::set_log_level::level"],[23,3,1,"_CPPv4N4espp17DeviceInfoService18set_log_rate_limitENSt6chrono8durationIfEE","espp::DeviceInfoService::set_log_rate_limit"],[23,4,1,"_CPPv4N4espp17DeviceInfoService18set_log_rate_limitENSt6chrono8durationIfEE","espp::DeviceInfoService::set_log_rate_limit::rate_limit"],[23,3,1,"_CPPv4N4espp17DeviceInfoService11set_log_tagERKNSt11string_viewE","espp::DeviceInfoService::set_log_tag"],[23,4,1,"_CPPv4N4espp17DeviceInfoService11set_log_tagERKNSt11string_viewE","espp::DeviceInfoService::set_log_tag::tag"],[23,3,1,"_CPPv4N4espp17DeviceInfoService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::DeviceInfoService::set_log_verbosity"],[23,4,1,"_CPPv4N4espp17DeviceInfoService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::DeviceInfoService::set_log_verbosity::level"],[23,3,1,"_CPPv4N4espp17DeviceInfoService21set_manufacturer_nameERKNSt6stringE","espp::DeviceInfoService::set_manufacturer_name"],[23,4,1,"_CPPv4N4espp17DeviceInfoService21set_manufacturer_nameERKNSt6stringE","espp::DeviceInfoService::set_manufacturer_name::name"],[23,3,1,"_CPPv4N4espp17DeviceInfoService16set_model_numberERKNSt6stringE","espp::DeviceInfoService::set_model_number"],[23,4,1,"_CPPv4N4espp17DeviceInfoService16set_model_numberERKNSt6stringE","espp::DeviceInfoService::set_model_number::number"],[23,3,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idE7uint8_t8uint16_t8uint16_t8uint16_t","espp::DeviceInfoService::set_pnp_id"],[23,3,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idERK5PnpId","espp::DeviceInfoService::set_pnp_id"],[23,4,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idERK5PnpId","espp::DeviceInfoService::set_pnp_id::pnp_id"],[23,4,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idE7uint8_t8uint16_t8uint16_t8uint16_t","espp::DeviceInfoService::set_pnp_id::product_id"],[23,4,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idE7uint8_t8uint16_t8uint16_t8uint16_t","espp::DeviceInfoService::set_pnp_id::product_version"],[23,4,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idE7uint8_t8uint16_t8uint16_t8uint16_t","espp::DeviceInfoService::set_pnp_id::vendor_id"],[23,4,1,"_CPPv4N4espp17DeviceInfoService10set_pnp_idE7uint8_t8uint16_t8uint16_t8uint16_t","espp::DeviceInfoService::set_pnp_id::vendor_id_source"],[23,3,1,"_CPPv4N4espp17DeviceInfoService17set_serial_numberERKNSt6stringE","espp::DeviceInfoService::set_serial_number"],[23,4,1,"_CPPv4N4espp17DeviceInfoService17set_serial_numberERKNSt6stringE","espp::DeviceInfoService::set_serial_number::number"],[23,3,1,"_CPPv4N4espp17DeviceInfoService20set_software_versionERKNSt6stringE","espp::DeviceInfoService::set_software_version"],[23,4,1,"_CPPv4N4espp17DeviceInfoService20set_software_versionERKNSt6stringE","espp::DeviceInfoService::set_software_version::version"],[23,3,1,"_CPPv4N4espp17DeviceInfoService5startEv","espp::DeviceInfoService::start"],[23,3,1,"_CPPv4N4espp17DeviceInfoService4uuidEv","espp::DeviceInfoService::uuid"],[39,2,1,"_CPPv4I0EN4espp7DisplayE","espp::Display"],[39,2,1,"_CPPv4N4espp7Display16AllocatingConfigE","espp::Display::AllocatingConfig"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig16allocation_flagsE","espp::Display::AllocatingConfig::allocation_flags"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig18backlight_on_valueE","espp::Display::AllocatingConfig::backlight_on_value"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig13backlight_pinE","espp::Display::AllocatingConfig::backlight_pin"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig15double_bufferedE","espp::Display::AllocatingConfig::double_buffered"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig14flush_callbackE","espp::Display::AllocatingConfig::flush_callback"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig6heightE","espp::Display::AllocatingConfig::height"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig9log_levelE","espp::Display::AllocatingConfig::log_level"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig17pixel_buffer_sizeE","espp::Display::AllocatingConfig::pixel_buffer_size"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig8rotationE","espp::Display::AllocatingConfig::rotation"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig17rotation_callbackE","espp::Display::AllocatingConfig::rotation_callback"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig25software_rotation_enabledE","espp::Display::AllocatingConfig::software_rotation_enabled"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig13update_periodE","espp::Display::AllocatingConfig::update_period"],[39,1,1,"_CPPv4N4espp7Display16AllocatingConfig5widthE","espp::Display::AllocatingConfig::width"],[39,3,1,"_CPPv4N4espp7Display7DisplayERK16AllocatingConfig","espp::Display::Display"],[39,3,1,"_CPPv4N4espp7Display7DisplayERK19NonAllocatingConfig","espp::Display::Display"],[39,4,1,"_CPPv4N4espp7Display7DisplayERK16AllocatingConfig","espp::Display::Display::config"],[39,4,1,"_CPPv4N4espp7Display7DisplayERK19NonAllocatingConfig","espp::Display::Display::config"],[39,2,1,"_CPPv4N4espp7Display19NonAllocatingConfigE","espp::Display::NonAllocatingConfig"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig18backlight_on_valueE","espp::Display::NonAllocatingConfig::backlight_on_value"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig13backlight_pinE","espp::Display::NonAllocatingConfig::backlight_pin"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig14flush_callbackE","espp::Display::NonAllocatingConfig::flush_callback"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig6heightE","espp::Display::NonAllocatingConfig::height"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig9log_levelE","espp::Display::NonAllocatingConfig::log_level"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig17pixel_buffer_sizeE","espp::Display::NonAllocatingConfig::pixel_buffer_size"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig8rotationE","espp::Display::NonAllocatingConfig::rotation"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig17rotation_callbackE","espp::Display::NonAllocatingConfig::rotation_callback"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig25software_rotation_enabledE","espp::Display::NonAllocatingConfig::software_rotation_enabled"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig13update_periodE","espp::Display::NonAllocatingConfig::update_period"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig5vram0E","espp::Display::NonAllocatingConfig::vram0"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig5vram1E","espp::Display::NonAllocatingConfig::vram1"],[39,1,1,"_CPPv4N4espp7Display19NonAllocatingConfig5widthE","espp::Display::NonAllocatingConfig::width"],[39,5,1,"_CPPv4I0EN4espp7DisplayE","espp::Display::Pixel"],[39,8,1,"_CPPv4N4espp7Display8flush_fnE","espp::Display::flush_fn"],[39,3,1,"_CPPv4NK4espp7Display13force_refreshEv","espp::Display::force_refresh"],[39,3,1,"_CPPv4NK4espp7Display14get_brightnessEv","espp::Display::get_brightness"],[39,3,1,"_CPPv4NK4espp7Display13get_log_levelEv","espp::Display::get_log_level"],[39,3,1,"_CPPv4NK4espp7Display17get_log_verbosityEv","espp::Display::get_log_verbosity"],[39,3,1,"_CPPv4NK4espp7Display8get_nameEv","espp::Display::get_name"],[39,3,1,"_CPPv4NK4espp7Display6heightEv","espp::Display::height"],[39,3,1,"_CPPv4N4espp7Display5pauseEv","espp::Display::pause"],[39,3,1,"_CPPv4N4espp7Display6resumeEv","espp::Display::resume"],[39,8,1,"_CPPv4N4espp7Display11rotation_fnE","espp::Display::rotation_fn"],[39,3,1,"_CPPv4N4espp7Display14set_brightnessEf","espp::Display::set_brightness"],[39,4,1,"_CPPv4N4espp7Display14set_brightnessEf","espp::Display::set_brightness::brightness"],[39,3,1,"_CPPv4N4espp7Display13set_log_levelEN4espp6Logger9VerbosityE","espp::Display::set_log_level"],[39,4,1,"_CPPv4N4espp7Display13set_log_levelEN4espp6Logger9VerbosityE","espp::Display::set_log_level::level"],[39,3,1,"_CPPv4N4espp7Display18set_log_rate_limitENSt6chrono8durationIfEE","espp::Display::set_log_rate_limit"],[39,4,1,"_CPPv4N4espp7Display18set_log_rate_limitENSt6chrono8durationIfEE","espp::Display::set_log_rate_limit::rate_limit"],[39,3,1,"_CPPv4N4espp7Display11set_log_tagERKNSt11string_viewE","espp::Display::set_log_tag"],[39,4,1,"_CPPv4N4espp7Display11set_log_tagERKNSt11string_viewE","espp::Display::set_log_tag::tag"],[39,3,1,"_CPPv4N4espp7Display17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Display::set_log_verbosity"],[39,4,1,"_CPPv4N4espp7Display17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Display::set_log_verbosity::level"],[39,3,1,"_CPPv4N4espp7Display5vram0Ev","espp::Display::vram0"],[39,3,1,"_CPPv4N4espp7Display5vram1Ev","espp::Display::vram1"],[39,3,1,"_CPPv4NK4espp7Display15vram_size_bytesEv","espp::Display::vram_size_bytes"],[39,3,1,"_CPPv4NK4espp7Display12vram_size_pxEv","espp::Display::vram_size_px"],[39,3,1,"_CPPv4NK4espp7Display5widthEv","espp::Display::width"],[39,3,1,"_CPPv4N4espp7DisplayD0Ev","espp::Display::~Display"],[72,2,1,"_CPPv4N4espp7Drv2605E","espp::Drv2605"],[72,2,1,"_CPPv4N4espp7Drv26056ConfigE","espp::Drv2605::Config"],[72,1,1,"_CPPv4N4espp7Drv26056Config9auto_initE","espp::Drv2605::Config::auto_init"],[72,1,1,"_CPPv4N4espp7Drv26056Config14device_addressE","espp::Drv2605::Config::device_address"],[72,1,1,"_CPPv4N4espp7Drv26056Config9log_levelE","espp::Drv2605::Config::log_level"],[72,1,1,"_CPPv4N4espp7Drv26056Config10motor_typeE","espp::Drv2605::Config::motor_type"],[72,1,1,"_CPPv4N4espp7Drv26056Config13read_registerE","espp::Drv2605::Config::read_register"],[72,1,1,"_CPPv4N4espp7Drv26056Config5writeE","espp::Drv2605::Config::write"],[72,3,1,"_CPPv4N4espp7Drv26057Drv2605ERK6Config","espp::Drv2605::Drv2605"],[72,4,1,"_CPPv4N4espp7Drv26057Drv2605ERK6Config","espp::Drv2605::Drv2605::config"],[72,6,1,"_CPPv4N4espp7Drv26057LibraryE","espp::Drv2605::Library"],[72,7,1,"_CPPv4N4espp7Drv26057Library5EMPTYE","espp::Drv2605::Library::EMPTY"],[72,7,1,"_CPPv4N4espp7Drv26057Library5ERM_0E","espp::Drv2605::Library::ERM_0"],[72,7,1,"_CPPv4N4espp7Drv26057Library5ERM_1E","espp::Drv2605::Library::ERM_1"],[72,7,1,"_CPPv4N4espp7Drv26057Library5ERM_2E","espp::Drv2605::Library::ERM_2"],[72,7,1,"_CPPv4N4espp7Drv26057Library5ERM_3E","espp::Drv2605::Library::ERM_3"],[72,7,1,"_CPPv4N4espp7Drv26057Library5ERM_4E","espp::Drv2605::Library::ERM_4"],[72,7,1,"_CPPv4N4espp7Drv26057Library3LRAE","espp::Drv2605::Library::LRA"],[72,6,1,"_CPPv4N4espp7Drv26054ModeE","espp::Drv2605::Mode"],[72,7,1,"_CPPv4N4espp7Drv26054Mode9AUDIOVIBEE","espp::Drv2605::Mode::AUDIOVIBE"],[72,7,1,"_CPPv4N4espp7Drv26054Mode7AUTOCALE","espp::Drv2605::Mode::AUTOCAL"],[72,7,1,"_CPPv4N4espp7Drv26054Mode7DIAGNOSE","espp::Drv2605::Mode::DIAGNOS"],[72,7,1,"_CPPv4N4espp7Drv26054Mode11EXTTRIGEDGEE","espp::Drv2605::Mode::EXTTRIGEDGE"],[72,7,1,"_CPPv4N4espp7Drv26054Mode10EXTTRIGLVLE","espp::Drv2605::Mode::EXTTRIGLVL"],[72,7,1,"_CPPv4N4espp7Drv26054Mode7INTTRIGE","espp::Drv2605::Mode::INTTRIG"],[72,7,1,"_CPPv4N4espp7Drv26054Mode9PWMANALOGE","espp::Drv2605::Mode::PWMANALOG"],[72,7,1,"_CPPv4N4espp7Drv26054Mode8REALTIMEE","espp::Drv2605::Mode::REALTIME"],[72,6,1,"_CPPv4N4espp7Drv26059MotorTypeE","espp::Drv2605::MotorType"],[72,7,1,"_CPPv4N4espp7Drv26059MotorType3ERME","espp::Drv2605::MotorType::ERM"],[72,7,1,"_CPPv4N4espp7Drv26059MotorType3LRAE","espp::Drv2605::MotorType::LRA"],[72,6,1,"_CPPv4N4espp7Drv26058WaveformE","espp::Drv2605::Waveform"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform12ALERT_1000MSE","espp::Drv2605::Waveform::ALERT_1000MS"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform11ALERT_750MSE","espp::Drv2605::Waveform::ALERT_750MS"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform5BUZZ1E","espp::Drv2605::Waveform::BUZZ1"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform5BUZZ2E","espp::Drv2605::Waveform::BUZZ2"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform5BUZZ3E","espp::Drv2605::Waveform::BUZZ3"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform5BUZZ4E","espp::Drv2605::Waveform::BUZZ4"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform5BUZZ5E","espp::Drv2605::Waveform::BUZZ5"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform12DOUBLE_CLICKE","espp::Drv2605::Waveform::DOUBLE_CLICK"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform3ENDE","espp::Drv2605::Waveform::END"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform3MAXE","espp::Drv2605::Waveform::MAX"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform16PULSING_STRONG_1E","espp::Drv2605::Waveform::PULSING_STRONG_1"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform16PULSING_STRONG_2E","espp::Drv2605::Waveform::PULSING_STRONG_2"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform11SHARP_CLICKE","espp::Drv2605::Waveform::SHARP_CLICK"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform9SOFT_BUMPE","espp::Drv2605::Waveform::SOFT_BUMP"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform9SOFT_FUZZE","espp::Drv2605::Waveform::SOFT_FUZZ"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform11STRONG_BUZZE","espp::Drv2605::Waveform::STRONG_BUZZ"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform12STRONG_CLICKE","espp::Drv2605::Waveform::STRONG_CLICK"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform18TRANSITION_CLICK_1E","espp::Drv2605::Waveform::TRANSITION_CLICK_1"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform16TRANSITION_HUM_1E","espp::Drv2605::Waveform::TRANSITION_HUM_1"],[72,7,1,"_CPPv4N4espp7Drv26058Waveform12TRIPLE_CLICKE","espp::Drv2605::Waveform::TRIPLE_CLICK"],[72,3,1,"_CPPv4NK4espp7Drv260513get_log_levelEv","espp::Drv2605::get_log_level"],[72,3,1,"_CPPv4NK4espp7Drv260517get_log_verbosityEv","espp::Drv2605::get_log_verbosity"],[72,3,1,"_CPPv4NK4espp7Drv26058get_nameEv","espp::Drv2605::get_name"],[72,3,1,"_CPPv4N4espp7Drv260510initializeERNSt10error_codeE","espp::Drv2605::initialize"],[72,4,1,"_CPPv4N4espp7Drv260510initializeERNSt10error_codeE","espp::Drv2605::initialize::ec"],[72,3,1,"_CPPv4N4espp7Drv26055probeERNSt10error_codeE","espp::Drv2605::probe"],[72,4,1,"_CPPv4N4espp7Drv26055probeERNSt10error_codeE","espp::Drv2605::probe::ec"],[72,8,1,"_CPPv4N4espp7Drv26058probe_fnE","espp::Drv2605::probe_fn"],[72,3,1,"_CPPv4N4espp7Drv260514select_libraryE7LibraryRNSt10error_codeE","espp::Drv2605::select_library"],[72,4,1,"_CPPv4N4espp7Drv260514select_libraryE7LibraryRNSt10error_codeE","espp::Drv2605::select_library::ec"],[72,4,1,"_CPPv4N4espp7Drv260514select_libraryE7LibraryRNSt10error_codeE","espp::Drv2605::select_library::lib"],[72,3,1,"_CPPv4N4espp7Drv260511set_addressE7uint8_t","espp::Drv2605::set_address"],[72,4,1,"_CPPv4N4espp7Drv260511set_addressE7uint8_t","espp::Drv2605::set_address::address"],[72,3,1,"_CPPv4N4espp7Drv260510set_configERK6Config","espp::Drv2605::set_config"],[72,3,1,"_CPPv4N4espp7Drv260510set_configERR6Config","espp::Drv2605::set_config"],[72,4,1,"_CPPv4N4espp7Drv260510set_configERK6Config","espp::Drv2605::set_config::config"],[72,4,1,"_CPPv4N4espp7Drv260510set_configERR6Config","espp::Drv2605::set_config::config"],[72,3,1,"_CPPv4N4espp7Drv260513set_log_levelEN4espp6Logger9VerbosityE","espp::Drv2605::set_log_level"],[72,4,1,"_CPPv4N4espp7Drv260513set_log_levelEN4espp6Logger9VerbosityE","espp::Drv2605::set_log_level::level"],[72,3,1,"_CPPv4N4espp7Drv260518set_log_rate_limitENSt6chrono8durationIfEE","espp::Drv2605::set_log_rate_limit"],[72,4,1,"_CPPv4N4espp7Drv260518set_log_rate_limitENSt6chrono8durationIfEE","espp::Drv2605::set_log_rate_limit::rate_limit"],[72,3,1,"_CPPv4N4espp7Drv260511set_log_tagERKNSt11string_viewE","espp::Drv2605::set_log_tag"],[72,4,1,"_CPPv4N4espp7Drv260511set_log_tagERKNSt11string_viewE","espp::Drv2605::set_log_tag::tag"],[72,3,1,"_CPPv4N4espp7Drv260517set_log_verbosityEN4espp6Logger9VerbosityE","espp::Drv2605::set_log_verbosity"],[72,4,1,"_CPPv4N4espp7Drv260517set_log_verbosityEN4espp6Logger9VerbosityE","espp::Drv2605::set_log_verbosity::level"],[72,3,1,"_CPPv4N4espp7Drv26058set_modeE4ModeRNSt10error_codeE","espp::Drv2605::set_mode"],[72,4,1,"_CPPv4N4espp7Drv26058set_modeE4ModeRNSt10error_codeE","espp::Drv2605::set_mode::ec"],[72,4,1,"_CPPv4N4espp7Drv26058set_modeE4ModeRNSt10error_codeE","espp::Drv2605::set_mode::mode"],[72,3,1,"_CPPv4N4espp7Drv26059set_probeERK8probe_fn","espp::Drv2605::set_probe"],[72,4,1,"_CPPv4N4espp7Drv26059set_probeERK8probe_fn","espp::Drv2605::set_probe::probe"],[72,3,1,"_CPPv4N4espp7Drv26058set_readERK7read_fn","espp::Drv2605::set_read"],[72,4,1,"_CPPv4N4espp7Drv26058set_readERK7read_fn","espp::Drv2605::set_read::read"],[72,3,1,"_CPPv4N4espp7Drv260517set_read_registerERK16read_register_fn","espp::Drv2605::set_read_register"],[72,4,1,"_CPPv4N4espp7Drv260517set_read_registerERK16read_register_fn","espp::Drv2605::set_read_register::read_register"],[72,3,1,"_CPPv4N4espp7Drv260534set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Drv2605::set_separate_write_then_read_delay"],[72,4,1,"_CPPv4N4espp7Drv260534set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Drv2605::set_separate_write_then_read_delay::delay"],[72,3,1,"_CPPv4N4espp7Drv260512set_waveformE7uint8_t8WaveformRNSt10error_codeE","espp::Drv2605::set_waveform"],[72,4,1,"_CPPv4N4espp7Drv260512set_waveformE7uint8_t8WaveformRNSt10error_codeE","espp::Drv2605::set_waveform::ec"],[72,4,1,"_CPPv4N4espp7Drv260512set_waveformE7uint8_t8WaveformRNSt10error_codeE","espp::Drv2605::set_waveform::slot"],[72,4,1,"_CPPv4N4espp7Drv260512set_waveformE7uint8_t8WaveformRNSt10error_codeE","espp::Drv2605::set_waveform::w"],[72,3,1,"_CPPv4N4espp7Drv26059set_writeERK8write_fn","espp::Drv2605::set_write"],[72,4,1,"_CPPv4N4espp7Drv26059set_writeERK8write_fn","espp::Drv2605::set_write::write"],[72,3,1,"_CPPv4N4espp7Drv260519set_write_then_readERK18write_then_read_fn","espp::Drv2605::set_write_then_read"],[72,4,1,"_CPPv4N4espp7Drv260519set_write_then_readERK18write_then_read_fn","espp::Drv2605::set_write_then_read::write_then_read"],[72,3,1,"_CPPv4N4espp7Drv26055startERNSt10error_codeE","espp::Drv2605::start"],[72,4,1,"_CPPv4N4espp7Drv26055startERNSt10error_codeE","espp::Drv2605::start::ec"],[72,3,1,"_CPPv4N4espp7Drv26054stopERNSt10error_codeE","espp::Drv2605::stop"],[72,4,1,"_CPPv4N4espp7Drv26054stopERNSt10error_codeE","espp::Drv2605::stop::ec"],[85,2,1,"_CPPv4N4espp12EncoderInputE","espp::EncoderInput"],[85,2,1,"_CPPv4N4espp12EncoderInput6ConfigE","espp::EncoderInput::Config"],[85,1,1,"_CPPv4N4espp12EncoderInput6Config9log_levelE","espp::EncoderInput::Config::log_level"],[85,1,1,"_CPPv4N4espp12EncoderInput6Config4readE","espp::EncoderInput::Config::read"],[85,3,1,"_CPPv4N4espp12EncoderInput12EncoderInputERK6Config","espp::EncoderInput::EncoderInput"],[85,4,1,"_CPPv4N4espp12EncoderInput12EncoderInputERK6Config","espp::EncoderInput::EncoderInput::config"],[85,3,1,"_CPPv4N4espp12EncoderInput23get_button_input_deviceEv","espp::EncoderInput::get_button_input_device"],[85,3,1,"_CPPv4N4espp12EncoderInput24get_encoder_input_deviceEv","espp::EncoderInput::get_encoder_input_device"],[85,3,1,"_CPPv4NK4espp12EncoderInput13get_log_levelEv","espp::EncoderInput::get_log_level"],[85,3,1,"_CPPv4NK4espp12EncoderInput17get_log_verbosityEv","espp::EncoderInput::get_log_verbosity"],[85,3,1,"_CPPv4NK4espp12EncoderInput8get_nameEv","espp::EncoderInput::get_name"],[85,3,1,"_CPPv4N4espp12EncoderInput13set_log_levelEN4espp6Logger9VerbosityE","espp::EncoderInput::set_log_level"],[85,4,1,"_CPPv4N4espp12EncoderInput13set_log_levelEN4espp6Logger9VerbosityE","espp::EncoderInput::set_log_level::level"],[85,3,1,"_CPPv4N4espp12EncoderInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::EncoderInput::set_log_rate_limit"],[85,4,1,"_CPPv4N4espp12EncoderInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::EncoderInput::set_log_rate_limit::rate_limit"],[85,3,1,"_CPPv4N4espp12EncoderInput11set_log_tagERKNSt11string_viewE","espp::EncoderInput::set_log_tag"],[85,4,1,"_CPPv4N4espp12EncoderInput11set_log_tagERKNSt11string_viewE","espp::EncoderInput::set_log_tag::tag"],[85,3,1,"_CPPv4N4espp12EncoderInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EncoderInput::set_log_verbosity"],[85,4,1,"_CPPv4N4espp12EncoderInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EncoderInput::set_log_verbosity::level"],[85,3,1,"_CPPv4N4espp12EncoderInputD0Ev","espp::EncoderInput::~EncoderInput"],[53,2,1,"_CPPv4N4espp6EspBoxE","espp::EspBox"],[53,6,1,"_CPPv4N4espp6EspBox7BoxTypeE","espp::EspBox::BoxType"],[53,7,1,"_CPPv4N4espp6EspBox7BoxType3BOXE","espp::EspBox::BoxType::BOX"],[53,7,1,"_CPPv4N4espp6EspBox7BoxType4BOX3E","espp::EspBox::BoxType::BOX3"],[53,7,1,"_CPPv4N4espp6EspBox7BoxType7UNKNOWNE","espp::EspBox::BoxType::UNKNOWN"],[53,8,1,"_CPPv4N4espp6EspBox13DisplayDriverE","espp::EspBox::DisplayDriver"],[53,8,1,"_CPPv4N4espp6EspBox5PixelE","espp::EspBox::Pixel"],[53,3,1,"_CPPv4NK4espp6EspBox17audio_buffer_sizeEv","espp::EspBox::audio_buffer_size"],[53,3,1,"_CPPv4N4espp6EspBox17audio_sample_rateE8uint32_t","espp::EspBox::audio_sample_rate"],[53,3,1,"_CPPv4NK4espp6EspBox17audio_sample_rateEv","espp::EspBox::audio_sample_rate"],[53,4,1,"_CPPv4N4espp6EspBox17audio_sample_rateE8uint32_t","espp::EspBox::audio_sample_rate::sample_rate"],[53,3,1,"_CPPv4NK4espp6EspBox8box_typeEv","espp::EspBox::box_type"],[53,3,1,"_CPPv4N4espp6EspBox10brightnessEf","espp::EspBox::brightness"],[53,3,1,"_CPPv4NK4espp6EspBox10brightnessEv","espp::EspBox::brightness"],[53,4,1,"_CPPv4N4espp6EspBox10brightnessEf","espp::EspBox::brightness::brightness"],[53,3,1,"_CPPv4NK4espp6EspBox7displayEv","espp::EspBox::display"],[53,3,1,"_CPPv4N4espp6EspBox12enable_soundEb","espp::EspBox::enable_sound"],[53,4,1,"_CPPv4N4espp6EspBox12enable_soundEb","espp::EspBox::enable_sound::enable"],[53,3,1,"_CPPv4NK4espp6EspBox13frame_buffer0Ev","espp::EspBox::frame_buffer0"],[53,3,1,"_CPPv4NK4espp6EspBox13frame_buffer1Ev","espp::EspBox::frame_buffer1"],[53,3,1,"_CPPv4N4espp6EspBox3getEv","espp::EspBox::get"],[53,3,1,"_CPPv4N4espp6EspBox15get_lcd_dc_gpioEv","espp::EspBox::get_lcd_dc_gpio"],[53,3,1,"_CPPv4NK4espp6EspBox13get_log_levelEv","espp::EspBox::get_log_level"],[53,3,1,"_CPPv4NK4espp6EspBox17get_log_verbosityEv","espp::EspBox::get_log_verbosity"],[53,3,1,"_CPPv4N4espp6EspBox12get_mute_pinEv","espp::EspBox::get_mute_pin"],[53,3,1,"_CPPv4NK4espp6EspBox8get_nameEv","espp::EspBox::get_name"],[53,3,1,"_CPPv4N4espp6EspBox14initialize_lcdEv","espp::EspBox::initialize_lcd"],[53,3,1,"_CPPv4N4espp6EspBox16initialize_touchERK16touch_callback_t","espp::EspBox::initialize_touch"],[53,4,1,"_CPPv4N4espp6EspBox16initialize_touchERK16touch_callback_t","espp::EspBox::initialize_touch::callback"],[53,3,1,"_CPPv4N4espp6EspBox12internal_i2cEv","espp::EspBox::internal_i2c"],[53,3,1,"_CPPv4N4espp6EspBox10interruptsEv","espp::EspBox::interrupts"],[53,3,1,"_CPPv4NK4espp6EspBox8is_mutedEv","espp::EspBox::is_muted"],[53,3,1,"_CPPv4N4espp6EspBox10lcd_heightEv","espp::EspBox::lcd_height"],[53,3,1,"_CPPv4N4espp6EspBox9lcd_widthEv","espp::EspBox::lcd_width"],[53,3,1,"_CPPv4N4espp6EspBox4muteEb","espp::EspBox::mute"],[53,4,1,"_CPPv4N4espp6EspBox4muteEb","espp::EspBox::mute::mute"],[53,3,1,"_CPPv4N4espp6EspBox10play_audioEPK7uint8_t8uint32_t","espp::EspBox::play_audio"],[53,3,1,"_CPPv4N4espp6EspBox10play_audioERKNSt6vectorI7uint8_tEE","espp::EspBox::play_audio"],[53,4,1,"_CPPv4N4espp6EspBox10play_audioEPK7uint8_t8uint32_t","espp::EspBox::play_audio::data"],[53,4,1,"_CPPv4N4espp6EspBox10play_audioERKNSt6vectorI7uint8_tEE","espp::EspBox::play_audio::data"],[53,4,1,"_CPPv4N4espp6EspBox10play_audioEPK7uint8_t8uint32_t","espp::EspBox::play_audio::num_bytes"],[53,3,1,"_CPPv4N4espp6EspBox13set_log_levelEN4espp6Logger9VerbosityE","espp::EspBox::set_log_level"],[53,4,1,"_CPPv4N4espp6EspBox13set_log_levelEN4espp6Logger9VerbosityE","espp::EspBox::set_log_level::level"],[53,3,1,"_CPPv4N4espp6EspBox18set_log_rate_limitENSt6chrono8durationIfEE","espp::EspBox::set_log_rate_limit"],[53,4,1,"_CPPv4N4espp6EspBox18set_log_rate_limitENSt6chrono8durationIfEE","espp::EspBox::set_log_rate_limit::rate_limit"],[53,3,1,"_CPPv4N4espp6EspBox11set_log_tagERKNSt11string_viewE","espp::EspBox::set_log_tag"],[53,4,1,"_CPPv4N4espp6EspBox11set_log_tagERKNSt11string_viewE","espp::EspBox::set_log_tag::tag"],[53,3,1,"_CPPv4N4espp6EspBox17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EspBox::set_log_verbosity"],[53,4,1,"_CPPv4N4espp6EspBox17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EspBox::set_log_verbosity::level"],[53,3,1,"_CPPv4NK4espp6EspBox16touchpad_convertERK12TouchpadData","espp::EspBox::touchpad_convert"],[53,4,1,"_CPPv4NK4espp6EspBox16touchpad_convertERK12TouchpadData","espp::EspBox::touchpad_convert::data"],[53,3,1,"_CPPv4NK4espp6EspBox13touchpad_dataEv","espp::EspBox::touchpad_data"],[53,3,1,"_CPPv4NK4espp6EspBox14touchpad_inputEv","espp::EspBox::touchpad_input"],[53,3,1,"_CPPv4N4espp6EspBox13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::EspBox::touchpad_read"],[53,4,1,"_CPPv4N4espp6EspBox13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::EspBox::touchpad_read::btn_state"],[53,4,1,"_CPPv4N4espp6EspBox13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::EspBox::touchpad_read::num_touch_points"],[53,4,1,"_CPPv4N4espp6EspBox13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::EspBox::touchpad_read::x"],[53,4,1,"_CPPv4N4espp6EspBox13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::EspBox::touchpad_read::y"],[53,3,1,"_CPPv4N4espp6EspBox6volumeEf","espp::EspBox::volume"],[53,3,1,"_CPPv4NK4espp6EspBox6volumeEv","espp::EspBox::volume"],[53,4,1,"_CPPv4N4espp6EspBox6volumeEf","espp::EspBox::volume::volume"],[53,3,1,"_CPPv4NK4espp6EspBox5vram0Ev","espp::EspBox::vram0"],[53,3,1,"_CPPv4NK4espp6EspBox5vram1Ev","espp::EspBox::vram1"],[53,3,1,"_CPPv4N4espp6EspBox9write_lcdEPK7uint8_t6size_t8uint32_t","espp::EspBox::write_lcd"],[53,4,1,"_CPPv4N4espp6EspBox9write_lcdEPK7uint8_t6size_t8uint32_t","espp::EspBox::write_lcd::data"],[53,4,1,"_CPPv4N4espp6EspBox9write_lcdEPK7uint8_t6size_t8uint32_t","espp::EspBox::write_lcd::length"],[53,4,1,"_CPPv4N4espp6EspBox9write_lcdEPK7uint8_t6size_t8uint32_t","espp::EspBox::write_lcd::user_data"],[53,3,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame::data"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame::height"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame::width"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame::x"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::EspBox::write_lcd_frame::y"],[53,3,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::data"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::user_data"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::xe"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::xs"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::ye"],[53,4,1,"_CPPv4N4espp6EspBox15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::EspBox::write_lcd_lines::ys"],[51,2,1,"_CPPv4N4espp11EspTimerCamE","espp::EspTimerCam"],[51,3,1,"_CPPv4N4espp11EspTimerCam8gaussianEv","espp::EspTimerCam::gaussian"],[51,3,1,"_CPPv4N4espp11EspTimerCam3getEv","espp::EspTimerCam::get"],[51,3,1,"_CPPv4N4espp11EspTimerCam19get_battery_voltageEv","espp::EspTimerCam::get_battery_voltage"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d0_pinEv","espp::EspTimerCam::get_camera_d0_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d1_pinEv","espp::EspTimerCam::get_camera_d1_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d2_pinEv","espp::EspTimerCam::get_camera_d2_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d3_pinEv","espp::EspTimerCam::get_camera_d3_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d4_pinEv","espp::EspTimerCam::get_camera_d4_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d5_pinEv","espp::EspTimerCam::get_camera_d5_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d6_pinEv","espp::EspTimerCam::get_camera_d6_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam17get_camera_d7_pinEv","espp::EspTimerCam::get_camera_d7_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam19get_camera_href_pinEv","espp::EspTimerCam::get_camera_href_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam19get_camera_pclk_pinEv","espp::EspTimerCam::get_camera_pclk_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam20get_camera_reset_pinEv","espp::EspTimerCam::get_camera_reset_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam18get_camera_scl_pinEv","espp::EspTimerCam::get_camera_scl_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam18get_camera_sda_pinEv","espp::EspTimerCam::get_camera_sda_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam20get_camera_vsync_pinEv","espp::EspTimerCam::get_camera_vsync_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam23get_camera_xclk_freq_hzEv","espp::EspTimerCam::get_camera_xclk_freq_hz"],[51,3,1,"_CPPv4N4espp11EspTimerCam19get_camera_xclk_pinEv","espp::EspTimerCam::get_camera_xclk_pin"],[51,3,1,"_CPPv4N4espp11EspTimerCam24get_led_breathing_periodEv","espp::EspTimerCam::get_led_breathing_period"],[51,3,1,"_CPPv4N4espp11EspTimerCam18get_led_brightnessEv","espp::EspTimerCam::get_led_brightness"],[51,3,1,"_CPPv4NK4espp11EspTimerCam13get_log_levelEv","espp::EspTimerCam::get_log_level"],[51,3,1,"_CPPv4NK4espp11EspTimerCam17get_log_verbosityEv","espp::EspTimerCam::get_log_verbosity"],[51,3,1,"_CPPv4NK4espp11EspTimerCam8get_nameEv","espp::EspTimerCam::get_name"],[51,3,1,"_CPPv4N4espp11EspTimerCam14initialize_ledEf","espp::EspTimerCam::initialize_led"],[51,4,1,"_CPPv4N4espp11EspTimerCam14initialize_ledEf","espp::EspTimerCam::initialize_led::breathing_period"],[51,3,1,"_CPPv4N4espp11EspTimerCam14initialize_rtcEv","espp::EspTimerCam::initialize_rtc"],[51,3,1,"_CPPv4N4espp11EspTimerCam12internal_i2cEv","espp::EspTimerCam::internal_i2c"],[51,3,1,"_CPPv4N4espp11EspTimerCam10interruptsEv","espp::EspTimerCam::interrupts"],[51,3,1,"_CPPv4N4espp11EspTimerCam3ledEv","espp::EspTimerCam::led"],[51,3,1,"_CPPv4N4espp11EspTimerCam3rtcEv","espp::EspTimerCam::rtc"],[51,3,1,"_CPPv4N4espp11EspTimerCam24set_led_breathing_periodEf","espp::EspTimerCam::set_led_breathing_period"],[51,4,1,"_CPPv4N4espp11EspTimerCam24set_led_breathing_periodEf","espp::EspTimerCam::set_led_breathing_period::period"],[51,3,1,"_CPPv4N4espp11EspTimerCam18set_led_brightnessEf","espp::EspTimerCam::set_led_brightness"],[51,4,1,"_CPPv4N4espp11EspTimerCam18set_led_brightnessEf","espp::EspTimerCam::set_led_brightness::brightness"],[51,3,1,"_CPPv4N4espp11EspTimerCam13set_log_levelEN4espp6Logger9VerbosityE","espp::EspTimerCam::set_log_level"],[51,4,1,"_CPPv4N4espp11EspTimerCam13set_log_levelEN4espp6Logger9VerbosityE","espp::EspTimerCam::set_log_level::level"],[51,3,1,"_CPPv4N4espp11EspTimerCam18set_log_rate_limitENSt6chrono8durationIfEE","espp::EspTimerCam::set_log_rate_limit"],[51,4,1,"_CPPv4N4espp11EspTimerCam18set_log_rate_limitENSt6chrono8durationIfEE","espp::EspTimerCam::set_log_rate_limit::rate_limit"],[51,3,1,"_CPPv4N4espp11EspTimerCam11set_log_tagERKNSt11string_viewE","espp::EspTimerCam::set_log_tag"],[51,4,1,"_CPPv4N4espp11EspTimerCam11set_log_tagERKNSt11string_viewE","espp::EspTimerCam::set_log_tag::tag"],[51,3,1,"_CPPv4N4espp11EspTimerCam17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EspTimerCam::set_log_verbosity"],[51,4,1,"_CPPv4N4espp11EspTimerCam17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EspTimerCam::set_log_verbosity::level"],[51,3,1,"_CPPv4N4espp11EspTimerCam19start_led_breathingEv","espp::EspTimerCam::start_led_breathing"],[51,3,1,"_CPPv4N4espp11EspTimerCam18stop_led_breathingEv","espp::EspTimerCam::stop_led_breathing"],[55,2,1,"_CPPv4N4espp12EventManagerE","espp::EventManager"],[55,3,1,"_CPPv4N4espp12EventManager13add_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::add_publisher"],[55,4,1,"_CPPv4N4espp12EventManager13add_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::add_publisher::component"],[55,4,1,"_CPPv4N4espp12EventManager13add_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::add_publisher::topic"],[55,3,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnEK6size_t","espp::EventManager::add_subscriber"],[55,3,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnERKN4espp4Task10BaseConfigE","espp::EventManager::add_subscriber"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnEK6size_t","espp::EventManager::add_subscriber::callback"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnERKN4espp4Task10BaseConfigE","espp::EventManager::add_subscriber::callback"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnEK6size_t","espp::EventManager::add_subscriber::component"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnERKN4espp4Task10BaseConfigE","espp::EventManager::add_subscriber::component"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnEK6size_t","espp::EventManager::add_subscriber::stack_size_bytes"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnERKN4espp4Task10BaseConfigE","espp::EventManager::add_subscriber::task_config"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnEK6size_t","espp::EventManager::add_subscriber::topic"],[55,4,1,"_CPPv4N4espp12EventManager14add_subscriberERKNSt6stringERKNSt6stringERKN4espp12EventManager17event_callback_fnERKN4espp4Task10BaseConfigE","espp::EventManager::add_subscriber::topic"],[55,8,1,"_CPPv4N4espp12EventManager17event_callback_fnE","espp::EventManager::event_callback_fn"],[55,3,1,"_CPPv4N4espp12EventManager3getEv","espp::EventManager::get"],[55,3,1,"_CPPv4NK4espp12EventManager13get_log_levelEv","espp::EventManager::get_log_level"],[55,3,1,"_CPPv4NK4espp12EventManager17get_log_verbosityEv","espp::EventManager::get_log_verbosity"],[55,3,1,"_CPPv4NK4espp12EventManager8get_nameEv","espp::EventManager::get_name"],[55,3,1,"_CPPv4N4espp12EventManager7publishERKNSt6stringERKNSt6vectorI7uint8_tEE","espp::EventManager::publish"],[55,4,1,"_CPPv4N4espp12EventManager7publishERKNSt6stringERKNSt6vectorI7uint8_tEE","espp::EventManager::publish::data"],[55,4,1,"_CPPv4N4espp12EventManager7publishERKNSt6stringERKNSt6vectorI7uint8_tEE","espp::EventManager::publish::topic"],[55,3,1,"_CPPv4N4espp12EventManager16remove_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::remove_publisher"],[55,4,1,"_CPPv4N4espp12EventManager16remove_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::remove_publisher::component"],[55,4,1,"_CPPv4N4espp12EventManager16remove_publisherERKNSt6stringERKNSt6stringE","espp::EventManager::remove_publisher::topic"],[55,3,1,"_CPPv4N4espp12EventManager17remove_subscriberERKNSt6stringERKNSt6stringE","espp::EventManager::remove_subscriber"],[55,4,1,"_CPPv4N4espp12EventManager17remove_subscriberERKNSt6stringERKNSt6stringE","espp::EventManager::remove_subscriber::component"],[55,4,1,"_CPPv4N4espp12EventManager17remove_subscriberERKNSt6stringERKNSt6stringE","espp::EventManager::remove_subscriber::topic"],[55,3,1,"_CPPv4N4espp12EventManager13set_log_levelEN4espp6Logger9VerbosityE","espp::EventManager::set_log_level"],[55,4,1,"_CPPv4N4espp12EventManager13set_log_levelEN4espp6Logger9VerbosityE","espp::EventManager::set_log_level::level"],[55,3,1,"_CPPv4N4espp12EventManager18set_log_rate_limitENSt6chrono8durationIfEE","espp::EventManager::set_log_rate_limit"],[55,4,1,"_CPPv4N4espp12EventManager18set_log_rate_limitENSt6chrono8durationIfEE","espp::EventManager::set_log_rate_limit::rate_limit"],[55,3,1,"_CPPv4N4espp12EventManager11set_log_tagERKNSt11string_viewE","espp::EventManager::set_log_tag"],[55,4,1,"_CPPv4N4espp12EventManager11set_log_tagERKNSt11string_viewE","espp::EventManager::set_log_tag::tag"],[55,3,1,"_CPPv4N4espp12EventManager17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EventManager::set_log_verbosity"],[55,4,1,"_CPPv4N4espp12EventManager17set_log_verbosityEN4espp6Logger9VerbosityE","espp::EventManager::set_log_verbosity::level"],[57,2,1,"_CPPv4N4espp10FileSystemE","espp::FileSystem"],[57,2,1,"_CPPv4N4espp10FileSystem10ListConfigE","espp::FileSystem::ListConfig"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig9date_timeE","espp::FileSystem::ListConfig::date_time"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig5groupE","espp::FileSystem::ListConfig::group"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig15number_of_linksE","espp::FileSystem::ListConfig::number_of_links"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig5ownerE","espp::FileSystem::ListConfig::owner"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig11permissionsE","espp::FileSystem::ListConfig::permissions"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig9recursiveE","espp::FileSystem::ListConfig::recursive"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig4sizeE","espp::FileSystem::ListConfig::size"],[57,1,1,"_CPPv4N4espp10FileSystem10ListConfig4typeE","espp::FileSystem::ListConfig::type"],[57,3,1,"_CPPv4N4espp10FileSystem17file_entry_stringERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::file_entry_string"],[57,4,1,"_CPPv4N4espp10FileSystem17file_entry_stringERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::file_entry_string::config"],[57,4,1,"_CPPv4N4espp10FileSystem17file_entry_stringERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::file_entry_string::path"],[57,4,1,"_CPPv4N4espp10FileSystem17file_entry_stringERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::file_entry_string::prefix"],[57,3,1,"_CPPv4N4espp10FileSystem3getEv","espp::FileSystem::get"],[57,3,1,"_CPPv4NK4espp10FileSystem23get_file_time_as_stringERKNSt10filesystem4pathE","espp::FileSystem::get_file_time_as_string"],[57,4,1,"_CPPv4NK4espp10FileSystem23get_file_time_as_stringERKNSt10filesystem4pathE","espp::FileSystem::get_file_time_as_string::path"],[57,3,1,"_CPPv4N4espp10FileSystem17get_files_in_pathERKNSt10filesystem4pathEbb","espp::FileSystem::get_files_in_path"],[57,4,1,"_CPPv4N4espp10FileSystem17get_files_in_pathERKNSt10filesystem4pathEbb","espp::FileSystem::get_files_in_path::include_directories"],[57,4,1,"_CPPv4N4espp10FileSystem17get_files_in_pathERKNSt10filesystem4pathEbb","espp::FileSystem::get_files_in_path::path"],[57,4,1,"_CPPv4N4espp10FileSystem17get_files_in_pathERKNSt10filesystem4pathEbb","espp::FileSystem::get_files_in_path::recursive"],[57,3,1,"_CPPv4NK4espp10FileSystem14get_free_spaceEv","espp::FileSystem::get_free_space"],[57,3,1,"_CPPv4NK4espp10FileSystem13get_log_levelEv","espp::FileSystem::get_log_level"],[57,3,1,"_CPPv4NK4espp10FileSystem17get_log_verbosityEv","espp::FileSystem::get_log_verbosity"],[57,3,1,"_CPPv4N4espp10FileSystem15get_mount_pointEv","espp::FileSystem::get_mount_point"],[57,3,1,"_CPPv4NK4espp10FileSystem8get_nameEv","espp::FileSystem::get_name"],[57,3,1,"_CPPv4N4espp10FileSystem19get_partition_labelEv","espp::FileSystem::get_partition_label"],[57,3,1,"_CPPv4N4espp10FileSystem13get_root_pathEv","espp::FileSystem::get_root_path"],[57,3,1,"_CPPv4NK4espp10FileSystem15get_total_spaceEv","espp::FileSystem::get_total_space"],[57,3,1,"_CPPv4NK4espp10FileSystem14get_used_spaceEv","espp::FileSystem::get_used_space"],[57,3,1,"_CPPv4N4espp10FileSystem14human_readableE6size_t","espp::FileSystem::human_readable"],[57,4,1,"_CPPv4N4espp10FileSystem14human_readableE6size_t","espp::FileSystem::human_readable::bytes"],[57,3,1,"_CPPv4N4espp10FileSystem16is_grow_on_mountEv","espp::FileSystem::is_grow_on_mount"],[57,3,1,"_CPPv4N4espp10FileSystem21is_mount_as_read_onlyEv","espp::FileSystem::is_mount_as_read_only"],[57,3,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory"],[57,3,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt6stringERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::config"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt6stringERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::config"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::path"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt6stringERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::path"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt10filesystem4pathERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::prefix"],[57,4,1,"_CPPv4N4espp10FileSystem14list_directoryERKNSt6stringERK10ListConfigRKNSt6stringE","espp::FileSystem::list_directory::prefix"],[57,3,1,"_CPPv4N4espp10FileSystem6removeERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove"],[57,4,1,"_CPPv4N4espp10FileSystem6removeERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove::ec"],[57,4,1,"_CPPv4N4espp10FileSystem6removeERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove::path"],[57,3,1,"_CPPv4N4espp10FileSystem15remove_contentsERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove_contents"],[57,4,1,"_CPPv4N4espp10FileSystem15remove_contentsERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove_contents::ec"],[57,4,1,"_CPPv4N4espp10FileSystem15remove_contentsERKNSt10filesystem4pathERNSt10error_codeE","espp::FileSystem::remove_contents::path"],[57,3,1,"_CPPv4N4espp10FileSystem17set_grow_on_mountEb","espp::FileSystem::set_grow_on_mount"],[57,4,1,"_CPPv4N4espp10FileSystem17set_grow_on_mountEb","espp::FileSystem::set_grow_on_mount::grow_on_mount"],[57,3,1,"_CPPv4N4espp10FileSystem13set_log_levelEN4espp6Logger9VerbosityE","espp::FileSystem::set_log_level"],[57,4,1,"_CPPv4N4espp10FileSystem13set_log_levelEN4espp6Logger9VerbosityE","espp::FileSystem::set_log_level::level"],[57,3,1,"_CPPv4N4espp10FileSystem18set_log_rate_limitENSt6chrono8durationIfEE","espp::FileSystem::set_log_rate_limit"],[57,4,1,"_CPPv4N4espp10FileSystem18set_log_rate_limitENSt6chrono8durationIfEE","espp::FileSystem::set_log_rate_limit::rate_limit"],[57,3,1,"_CPPv4N4espp10FileSystem11set_log_tagERKNSt11string_viewE","espp::FileSystem::set_log_tag"],[57,4,1,"_CPPv4N4espp10FileSystem11set_log_tagERKNSt11string_viewE","espp::FileSystem::set_log_tag::tag"],[57,3,1,"_CPPv4N4espp10FileSystem17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FileSystem::set_log_verbosity"],[57,4,1,"_CPPv4N4espp10FileSystem17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FileSystem::set_log_verbosity::level"],[57,3,1,"_CPPv4N4espp10FileSystem22set_mount_as_read_onlyEb","espp::FileSystem::set_mount_as_read_only"],[57,4,1,"_CPPv4N4espp10FileSystem22set_mount_as_read_onlyEb","espp::FileSystem::set_mount_as_read_only::read_only"],[57,3,1,"_CPPv4N4espp10FileSystem9to_stringE6time_t","espp::FileSystem::to_string"],[57,3,1,"_CPPv4N4espp10FileSystem9to_stringERKNSt10filesystem5permsE","espp::FileSystem::to_string"],[57,4,1,"_CPPv4N4espp10FileSystem9to_stringERKNSt10filesystem5permsE","espp::FileSystem::to_string::permissions"],[57,4,1,"_CPPv4N4espp10FileSystem9to_stringE6time_t","espp::FileSystem::to_string::time"],[57,3,1,"_CPPv4I0EN4espp10FileSystem9to_time_tENSt6time_tE2TP","espp::FileSystem::to_time_t"],[57,5,1,"_CPPv4I0EN4espp10FileSystem9to_time_tENSt6time_tE2TP","espp::FileSystem::to_time_t::TP"],[57,4,1,"_CPPv4I0EN4espp10FileSystem9to_time_tENSt6time_tE2TP","espp::FileSystem::to_time_t::tp"],[86,2,1,"_CPPv4N4espp6Ft5x06E","espp::Ft5x06"],[86,2,1,"_CPPv4N4espp6Ft5x066ConfigE","espp::Ft5x06::Config"],[86,1,1,"_CPPv4N4espp6Ft5x066Config9log_levelE","espp::Ft5x06::Config::log_level"],[86,1,1,"_CPPv4N4espp6Ft5x066Config13read_registerE","espp::Ft5x06::Config::read_register"],[86,1,1,"_CPPv4N4espp6Ft5x066Config5writeE","espp::Ft5x06::Config::write"],[86,1,1,"_CPPv4N4espp6Ft5x0615DEFAULT_ADDRESSE","espp::Ft5x06::DEFAULT_ADDRESS"],[86,3,1,"_CPPv4N4espp6Ft5x066Ft5x06ERK6Config","espp::Ft5x06::Ft5x06"],[86,4,1,"_CPPv4N4espp6Ft5x066Ft5x06ERK6Config","espp::Ft5x06::Ft5x06::config"],[86,6,1,"_CPPv4N4espp6Ft5x067GestureE","espp::Ft5x06::Gesture"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture9MOVE_DOWNE","espp::Ft5x06::Gesture::MOVE_DOWN"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture9MOVE_LEFTE","espp::Ft5x06::Gesture::MOVE_LEFT"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture10MOVE_RIGHTE","espp::Ft5x06::Gesture::MOVE_RIGHT"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture7MOVE_UPE","espp::Ft5x06::Gesture::MOVE_UP"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture4NONEE","espp::Ft5x06::Gesture::NONE"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture7ZOOM_INE","espp::Ft5x06::Gesture::ZOOM_IN"],[86,7,1,"_CPPv4N4espp6Ft5x067Gesture8ZOOM_OUTE","espp::Ft5x06::Gesture::ZOOM_OUT"],[86,3,1,"_CPPv4NK4espp6Ft5x0613get_log_levelEv","espp::Ft5x06::get_log_level"],[86,3,1,"_CPPv4NK4espp6Ft5x0617get_log_verbosityEv","espp::Ft5x06::get_log_verbosity"],[86,3,1,"_CPPv4NK4espp6Ft5x068get_nameEv","espp::Ft5x06::get_name"],[86,3,1,"_CPPv4N4espp6Ft5x0620get_num_touch_pointsERNSt10error_codeE","espp::Ft5x06::get_num_touch_points"],[86,4,1,"_CPPv4N4espp6Ft5x0620get_num_touch_pointsERNSt10error_codeE","espp::Ft5x06::get_num_touch_points::ec"],[86,3,1,"_CPPv4N4espp6Ft5x0615get_touch_pointEP7uint8_tP8uint16_tP8uint16_tRNSt10error_codeE","espp::Ft5x06::get_touch_point"],[86,4,1,"_CPPv4N4espp6Ft5x0615get_touch_pointEP7uint8_tP8uint16_tP8uint16_tRNSt10error_codeE","espp::Ft5x06::get_touch_point::ec"],[86,4,1,"_CPPv4N4espp6Ft5x0615get_touch_pointEP7uint8_tP8uint16_tP8uint16_tRNSt10error_codeE","espp::Ft5x06::get_touch_point::num_touch_points"],[86,4,1,"_CPPv4N4espp6Ft5x0615get_touch_pointEP7uint8_tP8uint16_tP8uint16_tRNSt10error_codeE","espp::Ft5x06::get_touch_point::x"],[86,4,1,"_CPPv4N4espp6Ft5x0615get_touch_pointEP7uint8_tP8uint16_tP8uint16_tRNSt10error_codeE","espp::Ft5x06::get_touch_point::y"],[86,3,1,"_CPPv4N4espp6Ft5x065probeERNSt10error_codeE","espp::Ft5x06::probe"],[86,4,1,"_CPPv4N4espp6Ft5x065probeERNSt10error_codeE","espp::Ft5x06::probe::ec"],[86,8,1,"_CPPv4N4espp6Ft5x068probe_fnE","espp::Ft5x06::probe_fn"],[86,3,1,"_CPPv4N4espp6Ft5x0612read_gestureERNSt10error_codeE","espp::Ft5x06::read_gesture"],[86,4,1,"_CPPv4N4espp6Ft5x0612read_gestureERNSt10error_codeE","espp::Ft5x06::read_gesture::ec"],[86,3,1,"_CPPv4N4espp6Ft5x0611set_addressE7uint8_t","espp::Ft5x06::set_address"],[86,4,1,"_CPPv4N4espp6Ft5x0611set_addressE7uint8_t","espp::Ft5x06::set_address::address"],[86,3,1,"_CPPv4N4espp6Ft5x0610set_configERK6Config","espp::Ft5x06::set_config"],[86,3,1,"_CPPv4N4espp6Ft5x0610set_configERR6Config","espp::Ft5x06::set_config"],[86,4,1,"_CPPv4N4espp6Ft5x0610set_configERK6Config","espp::Ft5x06::set_config::config"],[86,4,1,"_CPPv4N4espp6Ft5x0610set_configERR6Config","espp::Ft5x06::set_config::config"],[86,3,1,"_CPPv4N4espp6Ft5x0613set_log_levelEN4espp6Logger9VerbosityE","espp::Ft5x06::set_log_level"],[86,4,1,"_CPPv4N4espp6Ft5x0613set_log_levelEN4espp6Logger9VerbosityE","espp::Ft5x06::set_log_level::level"],[86,3,1,"_CPPv4N4espp6Ft5x0618set_log_rate_limitENSt6chrono8durationIfEE","espp::Ft5x06::set_log_rate_limit"],[86,4,1,"_CPPv4N4espp6Ft5x0618set_log_rate_limitENSt6chrono8durationIfEE","espp::Ft5x06::set_log_rate_limit::rate_limit"],[86,3,1,"_CPPv4N4espp6Ft5x0611set_log_tagERKNSt11string_viewE","espp::Ft5x06::set_log_tag"],[86,4,1,"_CPPv4N4espp6Ft5x0611set_log_tagERKNSt11string_viewE","espp::Ft5x06::set_log_tag::tag"],[86,3,1,"_CPPv4N4espp6Ft5x0617set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ft5x06::set_log_verbosity"],[86,4,1,"_CPPv4N4espp6Ft5x0617set_log_verbosityEN4espp6Logger9VerbosityE","espp::Ft5x06::set_log_verbosity::level"],[86,3,1,"_CPPv4N4espp6Ft5x069set_probeERK8probe_fn","espp::Ft5x06::set_probe"],[86,4,1,"_CPPv4N4espp6Ft5x069set_probeERK8probe_fn","espp::Ft5x06::set_probe::probe"],[86,3,1,"_CPPv4N4espp6Ft5x068set_readERK7read_fn","espp::Ft5x06::set_read"],[86,4,1,"_CPPv4N4espp6Ft5x068set_readERK7read_fn","espp::Ft5x06::set_read::read"],[86,3,1,"_CPPv4N4espp6Ft5x0617set_read_registerERK16read_register_fn","espp::Ft5x06::set_read_register"],[86,4,1,"_CPPv4N4espp6Ft5x0617set_read_registerERK16read_register_fn","espp::Ft5x06::set_read_register::read_register"],[86,3,1,"_CPPv4N4espp6Ft5x0634set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ft5x06::set_separate_write_then_read_delay"],[86,4,1,"_CPPv4N4espp6Ft5x0634set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Ft5x06::set_separate_write_then_read_delay::delay"],[86,3,1,"_CPPv4N4espp6Ft5x069set_writeERK8write_fn","espp::Ft5x06::set_write"],[86,4,1,"_CPPv4N4espp6Ft5x069set_writeERK8write_fn","espp::Ft5x06::set_write::write"],[86,3,1,"_CPPv4N4espp6Ft5x0619set_write_then_readERK18write_then_read_fn","espp::Ft5x06::set_write_then_read"],[86,4,1,"_CPPv4N4espp6Ft5x0619set_write_then_readERK18write_then_read_fn","espp::Ft5x06::set_write_then_read::write_then_read"],[67,2,1,"_CPPv4N4espp16FtpClientSessionE","espp::FtpClientSession"],[67,3,1,"_CPPv4NK4espp16FtpClientSession17current_directoryEv","espp::FtpClientSession::current_directory"],[67,3,1,"_CPPv4NK4espp16FtpClientSession13get_log_levelEv","espp::FtpClientSession::get_log_level"],[67,3,1,"_CPPv4NK4espp16FtpClientSession17get_log_verbosityEv","espp::FtpClientSession::get_log_verbosity"],[67,3,1,"_CPPv4NK4espp16FtpClientSession8get_nameEv","espp::FtpClientSession::get_name"],[67,3,1,"_CPPv4NK4espp16FtpClientSession2idEv","espp::FtpClientSession::id"],[67,3,1,"_CPPv4NK4espp16FtpClientSession8is_aliveEv","espp::FtpClientSession::is_alive"],[67,3,1,"_CPPv4NK4espp16FtpClientSession12is_connectedEv","espp::FtpClientSession::is_connected"],[67,3,1,"_CPPv4NK4espp16FtpClientSession26is_passive_data_connectionEv","espp::FtpClientSession::is_passive_data_connection"],[67,3,1,"_CPPv4N4espp16FtpClientSession13set_log_levelEN4espp6Logger9VerbosityE","espp::FtpClientSession::set_log_level"],[67,4,1,"_CPPv4N4espp16FtpClientSession13set_log_levelEN4espp6Logger9VerbosityE","espp::FtpClientSession::set_log_level::level"],[67,3,1,"_CPPv4N4espp16FtpClientSession18set_log_rate_limitENSt6chrono8durationIfEE","espp::FtpClientSession::set_log_rate_limit"],[67,4,1,"_CPPv4N4espp16FtpClientSession18set_log_rate_limitENSt6chrono8durationIfEE","espp::FtpClientSession::set_log_rate_limit::rate_limit"],[67,3,1,"_CPPv4N4espp16FtpClientSession11set_log_tagERKNSt11string_viewE","espp::FtpClientSession::set_log_tag"],[67,4,1,"_CPPv4N4espp16FtpClientSession11set_log_tagERKNSt11string_viewE","espp::FtpClientSession::set_log_tag::tag"],[67,3,1,"_CPPv4N4espp16FtpClientSession17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FtpClientSession::set_log_verbosity"],[67,4,1,"_CPPv4N4espp16FtpClientSession17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FtpClientSession::set_log_verbosity::level"],[67,2,1,"_CPPv4N4espp9FtpServerE","espp::FtpServer"],[67,3,1,"_CPPv4N4espp9FtpServer9FtpServerENSt11string_viewE8uint16_tRKNSt10filesystem4pathE","espp::FtpServer::FtpServer"],[67,4,1,"_CPPv4N4espp9FtpServer9FtpServerENSt11string_viewE8uint16_tRKNSt10filesystem4pathE","espp::FtpServer::FtpServer::ip_address"],[67,4,1,"_CPPv4N4espp9FtpServer9FtpServerENSt11string_viewE8uint16_tRKNSt10filesystem4pathE","espp::FtpServer::FtpServer::port"],[67,4,1,"_CPPv4N4espp9FtpServer9FtpServerENSt11string_viewE8uint16_tRKNSt10filesystem4pathE","espp::FtpServer::FtpServer::root"],[67,3,1,"_CPPv4NK4espp9FtpServer13get_log_levelEv","espp::FtpServer::get_log_level"],[67,3,1,"_CPPv4NK4espp9FtpServer17get_log_verbosityEv","espp::FtpServer::get_log_verbosity"],[67,3,1,"_CPPv4NK4espp9FtpServer8get_nameEv","espp::FtpServer::get_name"],[67,3,1,"_CPPv4N4espp9FtpServer13set_log_levelEN4espp6Logger9VerbosityE","espp::FtpServer::set_log_level"],[67,4,1,"_CPPv4N4espp9FtpServer13set_log_levelEN4espp6Logger9VerbosityE","espp::FtpServer::set_log_level::level"],[67,3,1,"_CPPv4N4espp9FtpServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::FtpServer::set_log_rate_limit"],[67,4,1,"_CPPv4N4espp9FtpServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::FtpServer::set_log_rate_limit::rate_limit"],[67,3,1,"_CPPv4N4espp9FtpServer11set_log_tagERKNSt11string_viewE","espp::FtpServer::set_log_tag"],[67,4,1,"_CPPv4N4espp9FtpServer11set_log_tagERKNSt11string_viewE","espp::FtpServer::set_log_tag::tag"],[67,3,1,"_CPPv4N4espp9FtpServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FtpServer::set_log_verbosity"],[67,4,1,"_CPPv4N4espp9FtpServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::FtpServer::set_log_verbosity::level"],[67,3,1,"_CPPv4N4espp9FtpServer5startEv","espp::FtpServer::start"],[67,3,1,"_CPPv4N4espp9FtpServer4stopEv","espp::FtpServer::stop"],[67,3,1,"_CPPv4N4espp9FtpServerD0Ev","espp::FtpServer::~FtpServer"],[75,2,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::BUTTON_COUNT"],[75,6,1,"_CPPv4N4espp18GamepadInputReport3HatE","espp::GamepadInputReport::Hat"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat8CENTEREDE","espp::GamepadInputReport::Hat::CENTERED"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat4DOWNE","espp::GamepadInputReport::Hat::DOWN"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat9DOWN_LEFTE","espp::GamepadInputReport::Hat::DOWN_LEFT"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat10DOWN_RIGHTE","espp::GamepadInputReport::Hat::DOWN_RIGHT"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat4LEFTE","espp::GamepadInputReport::Hat::LEFT"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat5RIGHTE","espp::GamepadInputReport::Hat::RIGHT"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat2UPE","espp::GamepadInputReport::Hat::UP"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat7UP_LEFTE","espp::GamepadInputReport::Hat::UP_LEFT"],[75,7,1,"_CPPv4N4espp18GamepadInputReport3Hat8UP_RIGHTE","espp::GamepadInputReport::Hat::UP_RIGHT"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::JOYSTICK_MAX"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::JOYSTICK_MIN"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::JOYSTICK_TYPE"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::REPORT_ID"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::TRIGGER_MAX"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::TRIGGER_MIN"],[75,5,1,"_CPPv4I_6size_t00_13JOYSTICK_TYPE_13JOYSTICK_TYPE_12TRIGGER_TYPE_12TRIGGER_TYPE_7uint8_tEN4espp18GamepadInputReportE","espp::GamepadInputReport::TRIGGER_TYPE"],[75,3,1,"_CPPv4N4espp18GamepadInputReport14get_descriptorEv","espp::GamepadInputReport::get_descriptor"],[75,3,1,"_CPPv4N4espp18GamepadInputReport10get_reportEv","espp::GamepadInputReport::get_report"],[75,3,1,"_CPPv4N4espp18GamepadInputReport5resetEv","espp::GamepadInputReport::reset"],[75,3,1,"_CPPv4N4espp18GamepadInputReport15set_acceleratorEf","espp::GamepadInputReport::set_accelerator"],[75,4,1,"_CPPv4N4espp18GamepadInputReport15set_acceleratorEf","espp::GamepadInputReport::set_accelerator::value"],[75,3,1,"_CPPv4N4espp18GamepadInputReport9set_brakeEf","espp::GamepadInputReport::set_brake"],[75,4,1,"_CPPv4N4espp18GamepadInputReport9set_brakeEf","espp::GamepadInputReport::set_brake::value"],[75,3,1,"_CPPv4N4espp18GamepadInputReport10set_buttonEib","espp::GamepadInputReport::set_button"],[75,4,1,"_CPPv4N4espp18GamepadInputReport10set_buttonEib","espp::GamepadInputReport::set_button::button_index"],[75,4,1,"_CPPv4N4espp18GamepadInputReport10set_buttonEib","espp::GamepadInputReport::set_button::value"],[75,3,1,"_CPPv4N4espp18GamepadInputReport7set_hatE3Hat","espp::GamepadInputReport::set_hat"],[75,4,1,"_CPPv4N4espp18GamepadInputReport7set_hatE3Hat","espp::GamepadInputReport::set_hat::hat"],[75,3,1,"_CPPv4N4espp18GamepadInputReport17set_left_joystickEff","espp::GamepadInputReport::set_left_joystick"],[75,4,1,"_CPPv4N4espp18GamepadInputReport17set_left_joystickEff","espp::GamepadInputReport::set_left_joystick::lx"],[75,4,1,"_CPPv4N4espp18GamepadInputReport17set_left_joystickEff","espp::GamepadInputReport::set_left_joystick::ly"],[75,3,1,"_CPPv4N4espp18GamepadInputReport18set_right_joystickEff","espp::GamepadInputReport::set_right_joystick"],[75,4,1,"_CPPv4N4espp18GamepadInputReport18set_right_joystickEff","espp::GamepadInputReport::set_right_joystick::rx"],[75,4,1,"_CPPv4N4espp18GamepadInputReport18set_right_joystickEff","espp::GamepadInputReport::set_right_joystick::ry"],[75,2,1,"_CPPv4I_6size_t_7uint8_tEN4espp22GamepadLedOutputReportE","espp::GamepadLedOutputReport"],[75,5,1,"_CPPv4I_6size_t_7uint8_tEN4espp22GamepadLedOutputReportE","espp::GamepadLedOutputReport::LED_COUNT"],[75,5,1,"_CPPv4I_6size_t_7uint8_tEN4espp22GamepadLedOutputReportE","espp::GamepadLedOutputReport::REPORT_ID"],[75,3,1,"_CPPv4N4espp22GamepadLedOutputReport14get_descriptorEv","espp::GamepadLedOutputReport::get_descriptor"],[75,3,1,"_CPPv4N4espp22GamepadLedOutputReport10get_reportEv","espp::GamepadLedOutputReport::get_report"],[75,3,1,"_CPPv4N4espp22GamepadLedOutputReport7set_ledEib","espp::GamepadLedOutputReport::set_led"],[75,4,1,"_CPPv4N4espp22GamepadLedOutputReport7set_ledEib","espp::GamepadLedOutputReport::set_led::led_index"],[75,4,1,"_CPPv4N4espp22GamepadLedOutputReport7set_ledEib","espp::GamepadLedOutputReport::set_led::value"],[117,2,1,"_CPPv4N4espp8GaussianE","espp::Gaussian"],[117,2,1,"_CPPv4N4espp8Gaussian6ConfigE","espp::Gaussian::Config"],[117,1,1,"_CPPv4N4espp8Gaussian6Config5alphaE","espp::Gaussian::Config::alpha"],[117,1,1,"_CPPv4N4espp8Gaussian6Config4betaE","espp::Gaussian::Config::beta"],[117,1,1,"_CPPv4N4espp8Gaussian6Config5gammaE","espp::Gaussian::Config::gamma"],[117,3,1,"_CPPv4N4espp8Gaussian8GaussianERK6Config","espp::Gaussian::Gaussian"],[117,4,1,"_CPPv4N4espp8Gaussian8GaussianERK6Config","espp::Gaussian::Gaussian::config"],[117,3,1,"_CPPv4NK4espp8Gaussian2atEf","espp::Gaussian::at"],[117,4,1,"_CPPv4NK4espp8Gaussian2atEf","espp::Gaussian::at::t"],[117,3,1,"_CPPv4NK4espp8Gaussian9get_alphaEv","espp::Gaussian::get_alpha"],[117,3,1,"_CPPv4NK4espp8Gaussian8get_betaEv","espp::Gaussian::get_beta"],[117,3,1,"_CPPv4NK4espp8Gaussian10get_configEv","espp::Gaussian::get_config"],[117,3,1,"_CPPv4NK4espp8Gaussian9get_gammaEv","espp::Gaussian::get_gamma"],[117,3,1,"_CPPv4NK4espp8GaussianclEf","espp::Gaussian::operator()"],[117,4,1,"_CPPv4NK4espp8GaussianclEf","espp::Gaussian::operator()::t"],[117,3,1,"_CPPv4N4espp8Gaussian9set_alphaEf","espp::Gaussian::set_alpha"],[117,4,1,"_CPPv4N4espp8Gaussian9set_alphaEf","espp::Gaussian::set_alpha::alpha"],[117,3,1,"_CPPv4N4espp8Gaussian8set_betaEf","espp::Gaussian::set_beta"],[117,4,1,"_CPPv4N4espp8Gaussian8set_betaEf","espp::Gaussian::set_beta::beta"],[117,3,1,"_CPPv4N4espp8Gaussian10set_configERK6Config","espp::Gaussian::set_config"],[117,4,1,"_CPPv4N4espp8Gaussian10set_configERK6Config","espp::Gaussian::set_config::config"],[117,3,1,"_CPPv4N4espp8Gaussian9set_gammaEf","espp::Gaussian::set_gamma"],[117,4,1,"_CPPv4N4espp8Gaussian9set_gammaEf","espp::Gaussian::set_gamma::gamma"],[117,3,1,"_CPPv4N4espp8Gaussian6updateERK6Config","espp::Gaussian::update"],[117,4,1,"_CPPv4N4espp8Gaussian6updateERK6Config","espp::Gaussian::update::config"],[40,2,1,"_CPPv4N4espp6Gc9a01E","espp::Gc9a01"],[40,3,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear"],[40,4,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear::color"],[40,4,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear::height"],[40,4,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear::width"],[40,4,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear::x"],[40,4,1,"_CPPv4N4espp6Gc9a015clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Gc9a01::clear::y"],[40,3,1,"_CPPv4N4espp6Gc9a014fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Gc9a01::fill"],[40,4,1,"_CPPv4N4espp6Gc9a014fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Gc9a01::fill::area"],[40,4,1,"_CPPv4N4espp6Gc9a014fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Gc9a01::fill::color_map"],[40,4,1,"_CPPv4N4espp6Gc9a014fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Gc9a01::fill::disp"],[40,4,1,"_CPPv4N4espp6Gc9a014fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Gc9a01::fill::flags"],[40,3,1,"_CPPv4N4espp6Gc9a015flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Gc9a01::flush"],[40,4,1,"_CPPv4N4espp6Gc9a015flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Gc9a01::flush::area"],[40,4,1,"_CPPv4N4espp6Gc9a015flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Gc9a01::flush::color_map"],[40,4,1,"_CPPv4N4espp6Gc9a015flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Gc9a01::flush::disp"],[40,3,1,"_CPPv4N4espp6Gc9a0110get_offsetERiRi","espp::Gc9a01::get_offset"],[40,4,1,"_CPPv4N4espp6Gc9a0110get_offsetERiRi","espp::Gc9a01::get_offset::x"],[40,4,1,"_CPPv4N4espp6Gc9a0110get_offsetERiRi","espp::Gc9a01::get_offset::y"],[40,3,1,"_CPPv4N4espp6Gc9a0118get_offset_rotatedERiRi","espp::Gc9a01::get_offset_rotated"],[40,4,1,"_CPPv4N4espp6Gc9a0118get_offset_rotatedERiRi","espp::Gc9a01::get_offset_rotated::x"],[40,4,1,"_CPPv4N4espp6Gc9a0118get_offset_rotatedERiRi","espp::Gc9a01::get_offset_rotated::y"],[40,3,1,"_CPPv4N4espp6Gc9a0110initializeERKN15display_drivers6ConfigE","espp::Gc9a01::initialize"],[40,4,1,"_CPPv4N4espp6Gc9a0110initializeERKN15display_drivers6ConfigE","espp::Gc9a01::initialize::config"],[40,3,1,"_CPPv4N4espp6Gc9a016rotateERK15DisplayRotation","espp::Gc9a01::rotate"],[40,4,1,"_CPPv4N4espp6Gc9a016rotateERK15DisplayRotation","espp::Gc9a01::rotate::rotation"],[40,3,1,"_CPPv4N4espp6Gc9a0112send_commandE7Command","espp::Gc9a01::send_command"],[40,3,1,"_CPPv4N4espp6Gc9a0112send_commandE7uint8_t","espp::Gc9a01::send_command"],[40,4,1,"_CPPv4N4espp6Gc9a0112send_commandE7Command","espp::Gc9a01::send_command::command"],[40,4,1,"_CPPv4N4espp6Gc9a0112send_commandE7uint8_t","espp::Gc9a01::send_command::command"],[40,3,1,"_CPPv4N4espp6Gc9a019send_dataEPK7uint8_t6size_t8uint32_t","espp::Gc9a01::send_data"],[40,4,1,"_CPPv4N4espp6Gc9a019send_dataEPK7uint8_t6size_t8uint32_t","espp::Gc9a01::send_data::data"],[40,4,1,"_CPPv4N4espp6Gc9a019send_dataEPK7uint8_t6size_t8uint32_t","espp::Gc9a01::send_data::flags"],[40,4,1,"_CPPv4N4espp6Gc9a019send_dataEPK7uint8_t6size_t8uint32_t","espp::Gc9a01::send_data::length"],[40,3,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Gc9a01::set_drawing_area"],[40,3,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaEPK9lv_area_t","espp::Gc9a01::set_drawing_area"],[40,4,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaEPK9lv_area_t","espp::Gc9a01::set_drawing_area::area"],[40,4,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Gc9a01::set_drawing_area::xe"],[40,4,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Gc9a01::set_drawing_area::xs"],[40,4,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Gc9a01::set_drawing_area::ye"],[40,4,1,"_CPPv4N4espp6Gc9a0116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Gc9a01::set_drawing_area::ys"],[40,3,1,"_CPPv4N4espp6Gc9a0110set_offsetEii","espp::Gc9a01::set_offset"],[40,4,1,"_CPPv4N4espp6Gc9a0110set_offsetEii","espp::Gc9a01::set_offset::x"],[40,4,1,"_CPPv4N4espp6Gc9a0110set_offsetEii","espp::Gc9a01::set_offset::y"],[24,2,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacksE","espp::GfpsAccountKeyCharacteristicCallbacks"],[24,3,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onRead"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onRead::characteristic"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onRead::conn_info"],[24,3,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onWrite"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onWrite::characteristic"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsAccountKeyCharacteristicCallbacks::onWrite::conn_info"],[24,3,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_read"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_read::characteristic"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_read::conn_info"],[24,3,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_write"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_write::characteristic"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_write::conn_info"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_write::length"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsAccountKeyCharacteristicCallbacks::on_gfps_write::value"],[24,3,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsAccountKeyCharacteristicCallbacks::set_log_level"],[24,4,1,"_CPPv4N4espp37GfpsAccountKeyCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsAccountKeyCharacteristicCallbacks::set_log_level::log_level"],[24,2,1,"_CPPv4N4espp26GfpsCharacteristicCallbackE","espp::GfpsCharacteristicCallback"],[24,3,1,"_CPPv4N4espp26GfpsCharacteristicCallback12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsCharacteristicCallback::on_gfps_read"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsCharacteristicCallback::on_gfps_read::characteristic"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsCharacteristicCallback::on_gfps_read::conn_info"],[24,3,1,"_CPPv4N4espp26GfpsCharacteristicCallback13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsCharacteristicCallback::on_gfps_write"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsCharacteristicCallback::on_gfps_write::characteristic"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsCharacteristicCallback::on_gfps_write::conn_info"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsCharacteristicCallback::on_gfps_write::length"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsCharacteristicCallback::on_gfps_write::value"],[24,3,1,"_CPPv4N4espp26GfpsCharacteristicCallback13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsCharacteristicCallback::set_log_level"],[24,4,1,"_CPPv4N4espp26GfpsCharacteristicCallback13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsCharacteristicCallback::set_log_level::log_level"],[24,2,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacksE","espp::GfpsKbPairingCharacteristicCallbacks"],[24,3,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onRead"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onRead::characteristic"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onRead::conn_info"],[24,3,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onWrite"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onWrite::characteristic"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsKbPairingCharacteristicCallbacks::onWrite::conn_info"],[24,3,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_read"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_read::characteristic"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_read::conn_info"],[24,3,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_write"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_write::characteristic"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_write::conn_info"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_write::length"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsKbPairingCharacteristicCallbacks::on_gfps_write::value"],[24,3,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsKbPairingCharacteristicCallbacks::set_log_level"],[24,4,1,"_CPPv4N4espp36GfpsKbPairingCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsKbPairingCharacteristicCallbacks::set_log_level::log_level"],[24,2,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacksE","espp::GfpsModelIdCharacteristicCallbacks"],[24,3,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsModelIdCharacteristicCallbacks::onRead"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsModelIdCharacteristicCallbacks::onRead::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsModelIdCharacteristicCallbacks::onRead::conn_info"],[24,3,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_read"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_read::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_read::conn_info"],[24,3,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_write"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_write::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_write::conn_info"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_write::length"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsModelIdCharacteristicCallbacks::on_gfps_write::value"],[24,3,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsModelIdCharacteristicCallbacks::set_log_level"],[24,4,1,"_CPPv4N4espp34GfpsModelIdCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsModelIdCharacteristicCallbacks::set_log_level::log_level"],[24,2,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacksE","espp::GfpsPasskeyCharacteristicCallbacks"],[24,3,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onRead"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onRead::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks6onReadEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onRead::conn_info"],[24,3,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onWrite"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onWrite::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks7onWriteEP20NimBLECharacteristicR14NimBLEConnInfo","espp::GfpsPasskeyCharacteristicCallbacks::onWrite::conn_info"],[24,3,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_read"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_read::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks12on_gfps_readER14NimBLEConnInfo24nearby_fp_Characteristic","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_read::conn_info"],[24,3,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_write"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_write::characteristic"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_write::conn_info"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_write::length"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13on_gfps_writeER14NimBLEConnInfo24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsPasskeyCharacteristicCallbacks::on_gfps_write::value"],[24,3,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsPasskeyCharacteristicCallbacks::set_log_level"],[24,4,1,"_CPPv4N4espp34GfpsPasskeyCharacteristicCallbacks13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsPasskeyCharacteristicCallbacks::set_log_level::log_level"],[24,2,1,"_CPPv4N4espp11GfpsServiceE","espp::GfpsService"],[24,3,1,"_CPPv4N4espp11GfpsService11GfpsServiceEN4espp6Logger9VerbosityE","espp::GfpsService::GfpsService"],[24,3,1,"_CPPv4N4espp11GfpsService11GfpsServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::GfpsService::GfpsService"],[24,4,1,"_CPPv4N4espp11GfpsService11GfpsServiceEN4espp6Logger9VerbosityE","espp::GfpsService::GfpsService::log_level"],[24,4,1,"_CPPv4N4espp11GfpsService11GfpsServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::GfpsService::GfpsService::log_level"],[24,4,1,"_CPPv4N4espp11GfpsService11GfpsServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::GfpsService::GfpsService::server"],[24,3,1,"_CPPv4N4espp11GfpsService6deinitEv","espp::GfpsService::deinit"],[24,3,1,"_CPPv4NK4espp11GfpsService13get_log_levelEv","espp::GfpsService::get_log_level"],[24,3,1,"_CPPv4NK4espp11GfpsService17get_log_verbosityEv","espp::GfpsService::get_log_verbosity"],[24,3,1,"_CPPv4NK4espp11GfpsService8get_nameEv","espp::GfpsService::get_name"],[24,3,1,"_CPPv4NK4espp11GfpsService11get_passkeyEv","espp::GfpsService::get_passkey"],[24,3,1,"_CPPv4NK4espp11GfpsService16get_service_dataEv","espp::GfpsService::get_service_data"],[24,3,1,"_CPPv4N4espp11GfpsService4initEP12NimBLEServer","espp::GfpsService::init"],[24,4,1,"_CPPv4N4espp11GfpsService4initEP12NimBLEServer","espp::GfpsService::init::server"],[24,3,1,"_CPPv4N4espp11GfpsService6notifyE24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsService::notify"],[24,4,1,"_CPPv4N4espp11GfpsService6notifyE24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsService::notify::characteristic"],[24,4,1,"_CPPv4N4espp11GfpsService6notifyE24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsService::notify::length"],[24,4,1,"_CPPv4N4espp11GfpsService6notifyE24nearby_fp_CharacteristicPK7uint8_t6size_t","espp::GfpsService::notify::value"],[24,3,1,"_CPPv4N4espp11GfpsService18on_pairing_requestER14NimBLEConnInfo","espp::GfpsService::on_pairing_request"],[24,4,1,"_CPPv4N4espp11GfpsService18on_pairing_requestER14NimBLEConnInfo","espp::GfpsService::on_pairing_request::conn_info"],[24,3,1,"_CPPv4NK4espp11GfpsService7serviceEv","espp::GfpsService::service"],[24,3,1,"_CPPv4N4espp11GfpsService13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsService::set_log_level"],[24,4,1,"_CPPv4N4espp11GfpsService13set_log_levelEN4espp6Logger9VerbosityE","espp::GfpsService::set_log_level::level"],[24,3,1,"_CPPv4N4espp11GfpsService18set_log_rate_limitENSt6chrono8durationIfEE","espp::GfpsService::set_log_rate_limit"],[24,4,1,"_CPPv4N4espp11GfpsService18set_log_rate_limitENSt6chrono8durationIfEE","espp::GfpsService::set_log_rate_limit::rate_limit"],[24,3,1,"_CPPv4N4espp11GfpsService11set_log_tagERKNSt11string_viewE","espp::GfpsService::set_log_tag"],[24,4,1,"_CPPv4N4espp11GfpsService11set_log_tagERKNSt11string_viewE","espp::GfpsService::set_log_tag::tag"],[24,3,1,"_CPPv4N4espp11GfpsService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::GfpsService::set_log_verbosity"],[24,4,1,"_CPPv4N4espp11GfpsService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::GfpsService::set_log_verbosity::level"],[24,3,1,"_CPPv4N4espp11GfpsService11set_passkeyE8uint32_t","espp::GfpsService::set_passkey"],[24,4,1,"_CPPv4N4espp11GfpsService11set_passkeyE8uint32_t","espp::GfpsService::set_passkey::passkey"],[24,3,1,"_CPPv4N4espp11GfpsService5startEv","espp::GfpsService::start"],[24,3,1,"_CPPv4NK4espp11GfpsService4uuidEv","espp::GfpsService::uuid"],[88,2,1,"_CPPv4N4espp5Gt911E","espp::Gt911"],[88,2,1,"_CPPv4N4espp5Gt9116ConfigE","espp::Gt911::Config"],[88,1,1,"_CPPv4N4espp5Gt9116Config7addressE","espp::Gt911::Config::address"],[88,1,1,"_CPPv4N4espp5Gt9116Config9log_levelE","espp::Gt911::Config::log_level"],[88,1,1,"_CPPv4N4espp5Gt9116Config4readE","espp::Gt911::Config::read"],[88,1,1,"_CPPv4N4espp5Gt9116Config5writeE","espp::Gt911::Config::write"],[88,1,1,"_CPPv4N4espp5Gt91117DEFAULT_ADDRESS_1E","espp::Gt911::DEFAULT_ADDRESS_1"],[88,1,1,"_CPPv4N4espp5Gt91117DEFAULT_ADDRESS_2E","espp::Gt911::DEFAULT_ADDRESS_2"],[88,3,1,"_CPPv4N4espp5Gt9115Gt911ERK6Config","espp::Gt911::Gt911"],[88,4,1,"_CPPv4N4espp5Gt9115Gt911ERK6Config","espp::Gt911::Gt911::config"],[88,3,1,"_CPPv4NK4espp5Gt91121get_home_button_stateEv","espp::Gt911::get_home_button_state"],[88,3,1,"_CPPv4NK4espp5Gt91113get_log_levelEv","espp::Gt911::get_log_level"],[88,3,1,"_CPPv4NK4espp5Gt91117get_log_verbosityEv","espp::Gt911::get_log_verbosity"],[88,3,1,"_CPPv4NK4espp5Gt9118get_nameEv","espp::Gt911::get_name"],[88,3,1,"_CPPv4NK4espp5Gt91120get_num_touch_pointsEv","espp::Gt911::get_num_touch_points"],[88,3,1,"_CPPv4NK4espp5Gt91115get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Gt911::get_touch_point"],[88,4,1,"_CPPv4NK4espp5Gt91115get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Gt911::get_touch_point::num_touch_points"],[88,4,1,"_CPPv4NK4espp5Gt91115get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Gt911::get_touch_point::x"],[88,4,1,"_CPPv4NK4espp5Gt91115get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Gt911::get_touch_point::y"],[88,3,1,"_CPPv4N4espp5Gt9115probeERNSt10error_codeE","espp::Gt911::probe"],[88,4,1,"_CPPv4N4espp5Gt9115probeERNSt10error_codeE","espp::Gt911::probe::ec"],[88,8,1,"_CPPv4N4espp5Gt9118probe_fnE","espp::Gt911::probe_fn"],[88,3,1,"_CPPv4N4espp5Gt91111set_addressE7uint8_t","espp::Gt911::set_address"],[88,4,1,"_CPPv4N4espp5Gt91111set_addressE7uint8_t","espp::Gt911::set_address::address"],[88,3,1,"_CPPv4N4espp5Gt91110set_configERK6Config","espp::Gt911::set_config"],[88,3,1,"_CPPv4N4espp5Gt91110set_configERR6Config","espp::Gt911::set_config"],[88,4,1,"_CPPv4N4espp5Gt91110set_configERK6Config","espp::Gt911::set_config::config"],[88,4,1,"_CPPv4N4espp5Gt91110set_configERR6Config","espp::Gt911::set_config::config"],[88,3,1,"_CPPv4N4espp5Gt91113set_log_levelEN4espp6Logger9VerbosityE","espp::Gt911::set_log_level"],[88,4,1,"_CPPv4N4espp5Gt91113set_log_levelEN4espp6Logger9VerbosityE","espp::Gt911::set_log_level::level"],[88,3,1,"_CPPv4N4espp5Gt91118set_log_rate_limitENSt6chrono8durationIfEE","espp::Gt911::set_log_rate_limit"],[88,4,1,"_CPPv4N4espp5Gt91118set_log_rate_limitENSt6chrono8durationIfEE","espp::Gt911::set_log_rate_limit::rate_limit"],[88,3,1,"_CPPv4N4espp5Gt91111set_log_tagERKNSt11string_viewE","espp::Gt911::set_log_tag"],[88,4,1,"_CPPv4N4espp5Gt91111set_log_tagERKNSt11string_viewE","espp::Gt911::set_log_tag::tag"],[88,3,1,"_CPPv4N4espp5Gt91117set_log_verbosityEN4espp6Logger9VerbosityE","espp::Gt911::set_log_verbosity"],[88,4,1,"_CPPv4N4espp5Gt91117set_log_verbosityEN4espp6Logger9VerbosityE","espp::Gt911::set_log_verbosity::level"],[88,3,1,"_CPPv4N4espp5Gt9119set_probeERK8probe_fn","espp::Gt911::set_probe"],[88,4,1,"_CPPv4N4espp5Gt9119set_probeERK8probe_fn","espp::Gt911::set_probe::probe"],[88,3,1,"_CPPv4N4espp5Gt9118set_readERK7read_fn","espp::Gt911::set_read"],[88,4,1,"_CPPv4N4espp5Gt9118set_readERK7read_fn","espp::Gt911::set_read::read"],[88,3,1,"_CPPv4N4espp5Gt91117set_read_registerERK16read_register_fn","espp::Gt911::set_read_register"],[88,4,1,"_CPPv4N4espp5Gt91117set_read_registerERK16read_register_fn","espp::Gt911::set_read_register::read_register"],[88,3,1,"_CPPv4N4espp5Gt91134set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Gt911::set_separate_write_then_read_delay"],[88,4,1,"_CPPv4N4espp5Gt91134set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Gt911::set_separate_write_then_read_delay::delay"],[88,3,1,"_CPPv4N4espp5Gt9119set_writeERK8write_fn","espp::Gt911::set_write"],[88,4,1,"_CPPv4N4espp5Gt9119set_writeERK8write_fn","espp::Gt911::set_write::write"],[88,3,1,"_CPPv4N4espp5Gt91119set_write_then_readERK18write_then_read_fn","espp::Gt911::set_write_then_read"],[88,4,1,"_CPPv4N4espp5Gt91119set_write_then_readERK18write_then_read_fn","espp::Gt911::set_write_then_read::write_then_read"],[88,3,1,"_CPPv4N4espp5Gt9116updateERNSt10error_codeE","espp::Gt911::update"],[88,4,1,"_CPPv4N4espp5Gt9116updateERNSt10error_codeE","espp::Gt911::update::ec"],[26,2,1,"_CPPv4N4espp10HidServiceE","espp::HidService"],[26,3,1,"_CPPv4N4espp10HidService10HidServiceEN4espp6Logger9VerbosityE","espp::HidService::HidService"],[26,3,1,"_CPPv4N4espp10HidService10HidServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::HidService::HidService"],[26,4,1,"_CPPv4N4espp10HidService10HidServiceEN4espp6Logger9VerbosityE","espp::HidService::HidService::log_level"],[26,4,1,"_CPPv4N4espp10HidService10HidServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::HidService::HidService::log_level"],[26,4,1,"_CPPv4N4espp10HidService10HidServiceEP12NimBLEServerN4espp6Logger9VerbosityE","espp::HidService::HidService::server"],[26,3,1,"_CPPv4N4espp10HidService6deinitEv","espp::HidService::deinit"],[26,3,1,"_CPPv4N4espp10HidService14feature_reportE7uint8_t","espp::HidService::feature_report"],[26,4,1,"_CPPv4N4espp10HidService14feature_reportE7uint8_t","espp::HidService::feature_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService11get_controlEv","espp::HidService::get_control"],[26,3,1,"_CPPv4NK4espp10HidService13get_log_levelEv","espp::HidService::get_log_level"],[26,3,1,"_CPPv4NK4espp10HidService17get_log_verbosityEv","espp::HidService::get_log_verbosity"],[26,3,1,"_CPPv4NK4espp10HidService8get_nameEv","espp::HidService::get_name"],[26,3,1,"_CPPv4N4espp10HidService17get_protocol_modeEv","espp::HidService::get_protocol_mode"],[26,3,1,"_CPPv4N4espp10HidService4initEP12NimBLEServer","espp::HidService::init"],[26,4,1,"_CPPv4N4espp10HidService4initEP12NimBLEServer","espp::HidService::init::server"],[26,3,1,"_CPPv4N4espp10HidService12input_reportE7uint8_t","espp::HidService::input_report"],[26,4,1,"_CPPv4N4espp10HidService12input_reportE7uint8_t","espp::HidService::input_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService13output_reportE7uint8_t","espp::HidService::output_report"],[26,4,1,"_CPPv4N4espp10HidService13output_reportE7uint8_t","espp::HidService::output_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService21remove_feature_reportE7uint8_t","espp::HidService::remove_feature_report"],[26,4,1,"_CPPv4N4espp10HidService21remove_feature_reportE7uint8_t","espp::HidService::remove_feature_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService19remove_input_reportE7uint8_t","espp::HidService::remove_input_report"],[26,4,1,"_CPPv4N4espp10HidService19remove_input_reportE7uint8_t","espp::HidService::remove_input_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService20remove_output_reportE7uint8_t","espp::HidService::remove_output_report"],[26,4,1,"_CPPv4N4espp10HidService20remove_output_reportE7uint8_t","espp::HidService::remove_output_report::report_id"],[26,3,1,"_CPPv4N4espp10HidService7serviceEv","espp::HidService::service"],[26,3,1,"_CPPv4N4espp10HidService8set_infoE7uint8_t7uint8_t","espp::HidService::set_info"],[26,4,1,"_CPPv4N4espp10HidService8set_infoE7uint8_t7uint8_t","espp::HidService::set_info::country"],[26,4,1,"_CPPv4N4espp10HidService8set_infoE7uint8_t7uint8_t","espp::HidService::set_info::flags"],[26,3,1,"_CPPv4N4espp10HidService13set_log_levelEN4espp6Logger9VerbosityE","espp::HidService::set_log_level"],[26,4,1,"_CPPv4N4espp10HidService13set_log_levelEN4espp6Logger9VerbosityE","espp::HidService::set_log_level::level"],[26,3,1,"_CPPv4N4espp10HidService18set_log_rate_limitENSt6chrono8durationIfEE","espp::HidService::set_log_rate_limit"],[26,4,1,"_CPPv4N4espp10HidService18set_log_rate_limitENSt6chrono8durationIfEE","espp::HidService::set_log_rate_limit::rate_limit"],[26,3,1,"_CPPv4N4espp10HidService11set_log_tagERKNSt11string_viewE","espp::HidService::set_log_tag"],[26,4,1,"_CPPv4N4espp10HidService11set_log_tagERKNSt11string_viewE","espp::HidService::set_log_tag::tag"],[26,3,1,"_CPPv4N4espp10HidService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::HidService::set_log_verbosity"],[26,4,1,"_CPPv4N4espp10HidService17set_log_verbosityEN4espp6Logger9VerbosityE","espp::HidService::set_log_verbosity::level"],[26,3,1,"_CPPv4N4espp10HidService14set_report_mapENSt11string_viewE","espp::HidService::set_report_map"],[26,3,1,"_CPPv4N4espp10HidService14set_report_mapEPK7uint8_t6size_t","espp::HidService::set_report_map"],[26,3,1,"_CPPv4N4espp10HidService14set_report_mapERKNSt6vectorI7uint8_tEE","espp::HidService::set_report_map"],[26,4,1,"_CPPv4N4espp10HidService14set_report_mapENSt11string_viewE","espp::HidService::set_report_map::report_map"],[26,4,1,"_CPPv4N4espp10HidService14set_report_mapEPK7uint8_t6size_t","espp::HidService::set_report_map::report_map"],[26,4,1,"_CPPv4N4espp10HidService14set_report_mapERKNSt6vectorI7uint8_tEE","espp::HidService::set_report_map::report_map"],[26,4,1,"_CPPv4N4espp10HidService14set_report_mapEPK7uint8_t6size_t","espp::HidService::set_report_map::report_map_len"],[26,3,1,"_CPPv4N4espp10HidService5startEv","espp::HidService::start"],[26,3,1,"_CPPv4N4espp10HidService4uuidEv","espp::HidService::uuid"],[26,3,1,"_CPPv4N4espp10HidServiceD0Ev","espp::HidService::~HidService"],[166,2,1,"_CPPv4N4espp19HighResolutionTimerE","espp::HighResolutionTimer"],[166,8,1,"_CPPv4N4espp19HighResolutionTimer8CallbackE","espp::HighResolutionTimer::Callback"],[166,2,1,"_CPPv4N4espp19HighResolutionTimer6ConfigE","espp::HighResolutionTimer::Config"],[166,1,1,"_CPPv4N4espp19HighResolutionTimer6Config8callbackE","espp::HighResolutionTimer::Config::callback"],[166,1,1,"_CPPv4N4espp19HighResolutionTimer6Config15dispatch_methodE","espp::HighResolutionTimer::Config::dispatch_method"],[166,1,1,"_CPPv4N4espp19HighResolutionTimer6Config9log_levelE","espp::HighResolutionTimer::Config::log_level"],[166,1,1,"_CPPv4N4espp19HighResolutionTimer6Config4nameE","espp::HighResolutionTimer::Config::name"],[166,1,1,"_CPPv4N4espp19HighResolutionTimer6Config21skip_unhandled_eventsE","espp::HighResolutionTimer::Config::skip_unhandled_events"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer19HighResolutionTimerERK6Config","espp::HighResolutionTimer::HighResolutionTimer"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer19HighResolutionTimerERK6Config","espp::HighResolutionTimer::HighResolutionTimer::config"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer13get_log_levelEv","espp::HighResolutionTimer::get_log_level"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer17get_log_verbosityEv","espp::HighResolutionTimer::get_log_verbosity"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer8get_nameEv","espp::HighResolutionTimer::get_name"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer10get_periodEv","espp::HighResolutionTimer::get_period"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer10is_oneshotEv","espp::HighResolutionTimer::is_oneshot"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer11is_periodicEv","espp::HighResolutionTimer::is_periodic"],[166,3,1,"_CPPv4NK4espp19HighResolutionTimer10is_runningEv","espp::HighResolutionTimer::is_running"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer7oneshotE8uint64_t","espp::HighResolutionTimer::oneshot"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer7oneshotE8uint64_t","espp::HighResolutionTimer::oneshot::timeout_us"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer8periodicE8uint64_t","espp::HighResolutionTimer::periodic"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer8periodicE8uint64_t","espp::HighResolutionTimer::periodic::period_us"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer13set_log_levelEN4espp6Logger9VerbosityE","espp::HighResolutionTimer::set_log_level"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer13set_log_levelEN4espp6Logger9VerbosityE","espp::HighResolutionTimer::set_log_level::level"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer18set_log_rate_limitENSt6chrono8durationIfEE","espp::HighResolutionTimer::set_log_rate_limit"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer18set_log_rate_limitENSt6chrono8durationIfEE","espp::HighResolutionTimer::set_log_rate_limit::rate_limit"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer11set_log_tagERKNSt11string_viewE","espp::HighResolutionTimer::set_log_tag"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer11set_log_tagERKNSt11string_viewE","espp::HighResolutionTimer::set_log_tag::tag"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::HighResolutionTimer::set_log_verbosity"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::HighResolutionTimer::set_log_verbosity::level"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer10set_periodE8uint64_t","espp::HighResolutionTimer::set_period"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer10set_periodE8uint64_t","espp::HighResolutionTimer::set_period::period_us"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer5startE8uint64_tb","espp::HighResolutionTimer::start"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer5startE8uint64_tb","espp::HighResolutionTimer::start::oneshot"],[166,4,1,"_CPPv4N4espp19HighResolutionTimer5startE8uint64_tb","espp::HighResolutionTimer::start::period_us"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer14start_watchdogEv","espp::HighResolutionTimer::start_watchdog"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer4stopEv","espp::HighResolutionTimer::stop"],[166,3,1,"_CPPv4N4espp19HighResolutionTimer13stop_watchdogEv","espp::HighResolutionTimer::stop_watchdog"],[166,3,1,"_CPPv4N4espp19HighResolutionTimerD0Ev","espp::HighResolutionTimer::~HighResolutionTimer"],[33,2,1,"_CPPv4N4espp3HsvE","espp::Hsv"],[33,3,1,"_CPPv4N4espp3Hsv3HsvERK3Hsv","espp::Hsv::Hsv"],[33,3,1,"_CPPv4N4espp3Hsv3HsvERK3Rgb","espp::Hsv::Hsv"],[33,3,1,"_CPPv4N4espp3Hsv3HsvERKfRKfRKf","espp::Hsv::Hsv"],[33,4,1,"_CPPv4N4espp3Hsv3HsvERKfRKfRKf","espp::Hsv::Hsv::h"],[33,4,1,"_CPPv4N4espp3Hsv3HsvERK3Hsv","espp::Hsv::Hsv::hsv"],[33,4,1,"_CPPv4N4espp3Hsv3HsvERK3Rgb","espp::Hsv::Hsv::rgb"],[33,4,1,"_CPPv4N4espp3Hsv3HsvERKfRKfRKf","espp::Hsv::Hsv::s"],[33,4,1,"_CPPv4N4espp3Hsv3HsvERKfRKfRKf","espp::Hsv::Hsv::v"],[33,1,1,"_CPPv4N4espp3Hsv1hE","espp::Hsv::h"],[33,3,1,"_CPPv4N4espp3HsvaSERK3Hsv","espp::Hsv::operator="],[33,3,1,"_CPPv4N4espp3HsvaSERK3Rgb","espp::Hsv::operator="],[33,4,1,"_CPPv4N4espp3HsvaSERK3Hsv","espp::Hsv::operator=::other"],[33,4,1,"_CPPv4N4espp3HsvaSERK3Rgb","espp::Hsv::operator=::rgb"],[33,3,1,"_CPPv4NK4espp3Hsv3rgbEv","espp::Hsv::rgb"],[33,1,1,"_CPPv4N4espp3Hsv1sE","espp::Hsv::s"],[33,1,1,"_CPPv4N4espp3Hsv1vE","espp::Hsv::v"],[78,2,1,"_CPPv4N4espp3I2cE","espp::I2c"],[78,2,1,"_CPPv4N4espp3I2c6ConfigE","espp::I2c::Config"],[78,1,1,"_CPPv4N4espp3I2c6Config9auto_initE","espp::I2c::Config::auto_init"],[78,1,1,"_CPPv4N4espp3I2c6Config9clk_speedE","espp::I2c::Config::clk_speed"],[78,1,1,"_CPPv4N4espp3I2c6Config11isr_core_idE","espp::I2c::Config::isr_core_id"],[78,1,1,"_CPPv4N4espp3I2c6Config9log_levelE","espp::I2c::Config::log_level"],[78,1,1,"_CPPv4N4espp3I2c6Config4portE","espp::I2c::Config::port"],[78,1,1,"_CPPv4N4espp3I2c6Config10scl_io_numE","espp::I2c::Config::scl_io_num"],[78,1,1,"_CPPv4N4espp3I2c6Config13scl_pullup_enE","espp::I2c::Config::scl_pullup_en"],[78,1,1,"_CPPv4N4espp3I2c6Config10sda_io_numE","espp::I2c::Config::sda_io_num"],[78,1,1,"_CPPv4N4espp3I2c6Config13sda_pullup_enE","espp::I2c::Config::sda_pullup_en"],[78,1,1,"_CPPv4N4espp3I2c6Config10timeout_msE","espp::I2c::Config::timeout_ms"],[78,3,1,"_CPPv4N4espp3I2c3I2cERK6Config","espp::I2c::I2c"],[78,4,1,"_CPPv4N4espp3I2c3I2cERK6Config","espp::I2c::I2c::config"],[78,3,1,"_CPPv4N4espp3I2c6deinitERNSt10error_codeE","espp::I2c::deinit"],[78,4,1,"_CPPv4N4espp3I2c6deinitERNSt10error_codeE","espp::I2c::deinit::ec"],[78,3,1,"_CPPv4NK4espp3I2c13get_log_levelEv","espp::I2c::get_log_level"],[78,3,1,"_CPPv4NK4espp3I2c17get_log_verbosityEv","espp::I2c::get_log_verbosity"],[78,3,1,"_CPPv4NK4espp3I2c8get_nameEv","espp::I2c::get_name"],[78,3,1,"_CPPv4N4espp3I2c4initERNSt10error_codeE","espp::I2c::init"],[78,4,1,"_CPPv4N4espp3I2c4initERNSt10error_codeE","espp::I2c::init::ec"],[78,3,1,"_CPPv4N4espp3I2c12probe_deviceEK7uint8_t","espp::I2c::probe_device"],[78,4,1,"_CPPv4N4espp3I2c12probe_deviceEK7uint8_t","espp::I2c::probe_device::dev_addr"],[78,3,1,"_CPPv4N4espp3I2c4readEK7uint8_tP7uint8_t6size_t","espp::I2c::read"],[78,4,1,"_CPPv4N4espp3I2c4readEK7uint8_tP7uint8_t6size_t","espp::I2c::read::data"],[78,4,1,"_CPPv4N4espp3I2c4readEK7uint8_tP7uint8_t6size_t","espp::I2c::read::data_len"],[78,4,1,"_CPPv4N4espp3I2c4readEK7uint8_tP7uint8_t6size_t","espp::I2c::read::dev_addr"],[78,3,1,"_CPPv4N4espp3I2c16read_at_registerEK7uint8_tK7uint8_tP7uint8_t6size_t","espp::I2c::read_at_register"],[78,4,1,"_CPPv4N4espp3I2c16read_at_registerEK7uint8_tK7uint8_tP7uint8_t6size_t","espp::I2c::read_at_register::data"],[78,4,1,"_CPPv4N4espp3I2c16read_at_registerEK7uint8_tK7uint8_tP7uint8_t6size_t","espp::I2c::read_at_register::data_len"],[78,4,1,"_CPPv4N4espp3I2c16read_at_registerEK7uint8_tK7uint8_tP7uint8_t6size_t","espp::I2c::read_at_register::dev_addr"],[78,4,1,"_CPPv4N4espp3I2c16read_at_registerEK7uint8_tK7uint8_tP7uint8_t6size_t","espp::I2c::read_at_register::reg_addr"],[78,3,1,"_CPPv4N4espp3I2c23read_at_register_vectorEK7uint8_tK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_at_register_vector"],[78,4,1,"_CPPv4N4espp3I2c23read_at_register_vectorEK7uint8_tK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_at_register_vector::data"],[78,4,1,"_CPPv4N4espp3I2c23read_at_register_vectorEK7uint8_tK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_at_register_vector::dev_addr"],[78,4,1,"_CPPv4N4espp3I2c23read_at_register_vectorEK7uint8_tK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_at_register_vector::reg_addr"],[78,3,1,"_CPPv4N4espp3I2c11read_vectorEK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_vector"],[78,4,1,"_CPPv4N4espp3I2c11read_vectorEK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_vector::data"],[78,4,1,"_CPPv4N4espp3I2c11read_vectorEK7uint8_tRNSt6vectorI7uint8_tEE","espp::I2c::read_vector::dev_addr"],[78,3,1,"_CPPv4N4espp3I2c13set_log_levelEN4espp6Logger9VerbosityE","espp::I2c::set_log_level"],[78,4,1,"_CPPv4N4espp3I2c13set_log_levelEN4espp6Logger9VerbosityE","espp::I2c::set_log_level::level"],[78,3,1,"_CPPv4N4espp3I2c18set_log_rate_limitENSt6chrono8durationIfEE","espp::I2c::set_log_rate_limit"],[78,4,1,"_CPPv4N4espp3I2c18set_log_rate_limitENSt6chrono8durationIfEE","espp::I2c::set_log_rate_limit::rate_limit"],[78,3,1,"_CPPv4N4espp3I2c11set_log_tagERKNSt11string_viewE","espp::I2c::set_log_tag"],[78,4,1,"_CPPv4N4espp3I2c11set_log_tagERKNSt11string_viewE","espp::I2c::set_log_tag::tag"],[78,3,1,"_CPPv4N4espp3I2c17set_log_verbosityEN4espp6Logger9VerbosityE","espp::I2c::set_log_verbosity"],[78,4,1,"_CPPv4N4espp3I2c17set_log_verbosityEN4espp6Logger9VerbosityE","espp::I2c::set_log_verbosity::level"],[78,3,1,"_CPPv4N4espp3I2c5writeEK7uint8_tPK7uint8_tK6size_t","espp::I2c::write"],[78,4,1,"_CPPv4N4espp3I2c5writeEK7uint8_tPK7uint8_tK6size_t","espp::I2c::write::data"],[78,4,1,"_CPPv4N4espp3I2c5writeEK7uint8_tPK7uint8_tK6size_t","espp::I2c::write::data_len"],[78,4,1,"_CPPv4N4espp3I2c5writeEK7uint8_tPK7uint8_tK6size_t","espp::I2c::write::dev_addr"],[78,3,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read"],[78,4,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read::dev_addr"],[78,4,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read::read_data"],[78,4,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read::read_size"],[78,4,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read::write_data"],[78,4,1,"_CPPv4N4espp3I2c10write_readEK7uint8_tPK7uint8_tK6size_tP7uint8_t6size_t","espp::I2c::write_read::write_size"],[78,3,1,"_CPPv4N4espp3I2c17write_read_vectorEK7uint8_tRKNSt6vectorI7uint8_tEERNSt6vectorI7uint8_tEE","espp::I2c::write_read_vector"],[78,4,1,"_CPPv4N4espp3I2c17write_read_vectorEK7uint8_tRKNSt6vectorI7uint8_tEERNSt6vectorI7uint8_tEE","espp::I2c::write_read_vector::dev_addr"],[78,4,1,"_CPPv4N4espp3I2c17write_read_vectorEK7uint8_tRKNSt6vectorI7uint8_tEERNSt6vectorI7uint8_tEE","espp::I2c::write_read_vector::read_data"],[78,4,1,"_CPPv4N4espp3I2c17write_read_vectorEK7uint8_tRKNSt6vectorI7uint8_tEERNSt6vectorI7uint8_tEE","espp::I2c::write_read_vector::write_data"],[78,3,1,"_CPPv4N4espp3I2c12write_vectorEK7uint8_tRKNSt6vectorI7uint8_tEE","espp::I2c::write_vector"],[78,4,1,"_CPPv4N4espp3I2c12write_vectorEK7uint8_tRKNSt6vectorI7uint8_tEE","espp::I2c::write_vector::data"],[78,4,1,"_CPPv4N4espp3I2c12write_vectorEK7uint8_tRKNSt6vectorI7uint8_tEE","espp::I2c::write_vector::dev_addr"],[78,3,1,"_CPPv4N4espp3I2cD0Ev","espp::I2c::~I2c"],[78,2,1,"_CPPv4N4espp7I2cMenuE","espp::I2cMenu"],[78,3,1,"_CPPv4N4espp7I2cMenu7I2cMenuENSt17reference_wrapperIN4espp3I2cEEE","espp::I2cMenu::I2cMenu"],[78,4,1,"_CPPv4N4espp7I2cMenu7I2cMenuENSt17reference_wrapperIN4espp3I2cEEE","espp::I2cMenu::I2cMenu::i2c"],[78,3,1,"_CPPv4N4espp7I2cMenu3getENSt11string_viewENSt11string_viewE","espp::I2cMenu::get"],[78,4,1,"_CPPv4N4espp7I2cMenu3getENSt11string_viewENSt11string_viewE","espp::I2cMenu::get::description"],[78,4,1,"_CPPv4N4espp7I2cMenu3getENSt11string_viewENSt11string_viewE","espp::I2cMenu::get::name"],[40,2,1,"_CPPv4N4espp7Ili9341E","espp::Ili9341"],[40,3,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear"],[40,4,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear::color"],[40,4,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear::height"],[40,4,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear::width"],[40,4,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear::x"],[40,4,1,"_CPPv4N4espp7Ili93415clearE6size_t6size_t6size_t6size_t8uint16_t","espp::Ili9341::clear::y"],[40,3,1,"_CPPv4N4espp7Ili93414fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Ili9341::fill"],[40,4,1,"_CPPv4N4espp7Ili93414fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Ili9341::fill::area"],[40,4,1,"_CPPv4N4espp7Ili93414fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Ili9341::fill::color_map"],[40,4,1,"_CPPv4N4espp7Ili93414fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Ili9341::fill::disp"],[40,4,1,"_CPPv4N4espp7Ili93414fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::Ili9341::fill::flags"],[40,3,1,"_CPPv4N4espp7Ili93415flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Ili9341::flush"],[40,4,1,"_CPPv4N4espp7Ili93415flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Ili9341::flush::area"],[40,4,1,"_CPPv4N4espp7Ili93415flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Ili9341::flush::color_map"],[40,4,1,"_CPPv4N4espp7Ili93415flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::Ili9341::flush::disp"],[40,3,1,"_CPPv4N4espp7Ili934110get_offsetERiRi","espp::Ili9341::get_offset"],[40,4,1,"_CPPv4N4espp7Ili934110get_offsetERiRi","espp::Ili9341::get_offset::x"],[40,4,1,"_CPPv4N4espp7Ili934110get_offsetERiRi","espp::Ili9341::get_offset::y"],[40,3,1,"_CPPv4N4espp7Ili934118get_offset_rotatedERiRi","espp::Ili9341::get_offset_rotated"],[40,4,1,"_CPPv4N4espp7Ili934118get_offset_rotatedERiRi","espp::Ili9341::get_offset_rotated::x"],[40,4,1,"_CPPv4N4espp7Ili934118get_offset_rotatedERiRi","espp::Ili9341::get_offset_rotated::y"],[40,3,1,"_CPPv4N4espp7Ili934110initializeERKN15display_drivers6ConfigE","espp::Ili9341::initialize"],[40,4,1,"_CPPv4N4espp7Ili934110initializeERKN15display_drivers6ConfigE","espp::Ili9341::initialize::config"],[40,3,1,"_CPPv4N4espp7Ili93416rotateERK15DisplayRotation","espp::Ili9341::rotate"],[40,4,1,"_CPPv4N4espp7Ili93416rotateERK15DisplayRotation","espp::Ili9341::rotate::rotation"],[40,3,1,"_CPPv4N4espp7Ili934112send_commandE7Command","espp::Ili9341::send_command"],[40,3,1,"_CPPv4N4espp7Ili934112send_commandE7uint8_t","espp::Ili9341::send_command"],[40,4,1,"_CPPv4N4espp7Ili934112send_commandE7Command","espp::Ili9341::send_command::command"],[40,4,1,"_CPPv4N4espp7Ili934112send_commandE7uint8_t","espp::Ili9341::send_command::command"],[40,3,1,"_CPPv4N4espp7Ili93419send_dataEPK7uint8_t6size_t8uint32_t","espp::Ili9341::send_data"],[40,4,1,"_CPPv4N4espp7Ili93419send_dataEPK7uint8_t6size_t8uint32_t","espp::Ili9341::send_data::data"],[40,4,1,"_CPPv4N4espp7Ili93419send_dataEPK7uint8_t6size_t8uint32_t","espp::Ili9341::send_data::flags"],[40,4,1,"_CPPv4N4espp7Ili93419send_dataEPK7uint8_t6size_t8uint32_t","espp::Ili9341::send_data::length"],[40,3,1,"_CPPv4N4espp7Ili934116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Ili9341::set_drawing_area"],[40,3,1,"_CPPv4N4espp7Ili934116set_drawing_areaEPK9lv_area_t","espp::Ili9341::set_drawing_area"],[40,4,1,"_CPPv4N4espp7Ili934116set_drawing_areaEPK9lv_area_t","espp::Ili9341::set_drawing_area::area"],[40,4,1,"_CPPv4N4espp7Ili934116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Ili9341::set_drawing_area::xe"],[40,4,1,"_CPPv4N4espp7Ili934116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Ili9341::set_drawing_area::xs"],[40,4,1,"_CPPv4N4espp7Ili934116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Ili9341::set_drawing_area::ye"],[40,4,1,"_CPPv4N4espp7Ili934116set_drawing_areaE6size_t6size_t6size_t6size_t","espp::Ili9341::set_drawing_area::ys"],[40,3,1,"_CPPv4N4espp7Ili934110set_offsetEii","espp::Ili9341::set_offset"],[40,4,1,"_CPPv4N4espp7Ili934110set_offsetEii","espp::Ili9341::set_offset::x"],[40,4,1,"_CPPv4N4espp7Ili934110set_offsetEii","espp::Ili9341::set_offset::y"],[98,2,1,"_CPPv4N4espp9InterruptE","espp::Interrupt"],[98,6,1,"_CPPv4N4espp9Interrupt11ActiveLevelE","espp::Interrupt::ActiveLevel"],[98,7,1,"_CPPv4N4espp9Interrupt11ActiveLevel4HIGHE","espp::Interrupt::ActiveLevel::HIGH"],[98,7,1,"_CPPv4N4espp9Interrupt11ActiveLevel3LOWE","espp::Interrupt::ActiveLevel::LOW"],[98,2,1,"_CPPv4N4espp9Interrupt6ConfigE","espp::Interrupt::Config"],[98,1,1,"_CPPv4N4espp9Interrupt6Config16event_queue_sizeE","espp::Interrupt::Config::event_queue_size"],[98,1,1,"_CPPv4N4espp9Interrupt6Config10interruptsE","espp::Interrupt::Config::interrupts"],[98,1,1,"_CPPv4N4espp9Interrupt6Config11isr_core_idE","espp::Interrupt::Config::isr_core_id"],[98,1,1,"_CPPv4N4espp9Interrupt6Config9log_levelE","espp::Interrupt::Config::log_level"],[98,1,1,"_CPPv4N4espp9Interrupt6Config11task_configE","espp::Interrupt::Config::task_config"],[98,2,1,"_CPPv4N4espp9Interrupt5EventE","espp::Interrupt::Event"],[98,1,1,"_CPPv4N4espp9Interrupt5Event6activeE","espp::Interrupt::Event::active"],[98,1,1,"_CPPv4N4espp9Interrupt5Event8gpio_numE","espp::Interrupt::Event::gpio_num"],[98,2,1,"_CPPv4N4espp9Interrupt12FilterConfigE","espp::Interrupt::FilterConfig"],[98,1,1,"_CPPv4N4espp9Interrupt12FilterConfig19window_threshold_nsE","espp::Interrupt::FilterConfig::window_threshold_ns"],[98,1,1,"_CPPv4N4espp9Interrupt12FilterConfig15window_width_nsE","espp::Interrupt::FilterConfig::window_width_ns"],[98,3,1,"_CPPv4N4espp9Interrupt9InterruptERK6Config","espp::Interrupt::Interrupt"],[98,4,1,"_CPPv4N4espp9Interrupt9InterruptERK6Config","espp::Interrupt::Interrupt::config"],[98,2,1,"_CPPv4N4espp9Interrupt9PinConfigE","espp::Interrupt::PinConfig"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig12active_levelE","espp::Interrupt::PinConfig::active_level"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig13auto_reenableE","espp::Interrupt::PinConfig::auto_reenable"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig8callbackE","espp::Interrupt::PinConfig::callback"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig13filter_configE","espp::Interrupt::PinConfig::filter_config"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig11filter_typeE","espp::Interrupt::PinConfig::filter_type"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig8gpio_numE","espp::Interrupt::PinConfig::gpio_num"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig14interrupt_typeE","espp::Interrupt::PinConfig::interrupt_type"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig16pulldown_enabledE","espp::Interrupt::PinConfig::pulldown_enabled"],[98,1,1,"_CPPv4N4espp9Interrupt9PinConfig14pullup_enabledE","espp::Interrupt::PinConfig::pullup_enabled"],[98,6,1,"_CPPv4N4espp9Interrupt4TypeE","espp::Interrupt::Type"],[98,7,1,"_CPPv4N4espp9Interrupt4Type8ANY_EDGEE","espp::Interrupt::Type::ANY_EDGE"],[98,7,1,"_CPPv4N4espp9Interrupt4Type12FALLING_EDGEE","espp::Interrupt::Type::FALLING_EDGE"],[98,7,1,"_CPPv4N4espp9Interrupt4Type10HIGH_LEVELE","espp::Interrupt::Type::HIGH_LEVEL"],[98,7,1,"_CPPv4N4espp9Interrupt4Type9LOW_LEVELE","espp::Interrupt::Type::LOW_LEVEL"],[98,7,1,"_CPPv4N4espp9Interrupt4Type11RISING_EDGEE","espp::Interrupt::Type::RISING_EDGE"],[98,3,1,"_CPPv4N4espp9Interrupt13add_interruptERK9PinConfig","espp::Interrupt::add_interrupt"],[98,4,1,"_CPPv4N4espp9Interrupt13add_interruptERK9PinConfig","espp::Interrupt::add_interrupt::interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt11disable_allEv","espp::Interrupt::disable_all"],[98,3,1,"_CPPv4N4espp9Interrupt17disable_interruptERK9PinConfig","espp::Interrupt::disable_interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt17disable_interruptEi","espp::Interrupt::disable_interrupt"],[98,4,1,"_CPPv4N4espp9Interrupt17disable_interruptEi","espp::Interrupt::disable_interrupt::gpio_num"],[98,4,1,"_CPPv4N4espp9Interrupt17disable_interruptERK9PinConfig","espp::Interrupt::disable_interrupt::interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt16enable_interruptERK9PinConfig","espp::Interrupt::enable_interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt16enable_interruptEi","espp::Interrupt::enable_interrupt"],[98,4,1,"_CPPv4N4espp9Interrupt16enable_interruptEi","espp::Interrupt::enable_interrupt::gpio_num"],[98,4,1,"_CPPv4N4espp9Interrupt16enable_interruptERK9PinConfig","espp::Interrupt::enable_interrupt::interrupt"],[98,8,1,"_CPPv4N4espp9Interrupt17event_callback_fnE","espp::Interrupt::event_callback_fn"],[98,3,1,"_CPPv4N4espp9Interrupt17get_active_statesEv","espp::Interrupt::get_active_states"],[98,3,1,"_CPPv4NK4espp9Interrupt13get_log_levelEv","espp::Interrupt::get_log_level"],[98,3,1,"_CPPv4NK4espp9Interrupt17get_log_verbosityEv","espp::Interrupt::get_log_verbosity"],[98,3,1,"_CPPv4NK4espp9Interrupt18get_min_queue_sizeEv","espp::Interrupt::get_min_queue_size"],[98,3,1,"_CPPv4NK4espp9Interrupt8get_nameEv","espp::Interrupt::get_name"],[98,3,1,"_CPPv4NK4espp9Interrupt9is_activeERK9PinConfig","espp::Interrupt::is_active"],[98,4,1,"_CPPv4NK4espp9Interrupt9is_activeERK9PinConfig","espp::Interrupt::is_active::interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt10remove_allEv","espp::Interrupt::remove_all"],[98,3,1,"_CPPv4N4espp9Interrupt16remove_interruptERK9PinConfig","espp::Interrupt::remove_interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt16remove_interruptEi","espp::Interrupt::remove_interrupt"],[98,4,1,"_CPPv4N4espp9Interrupt16remove_interruptEi","espp::Interrupt::remove_interrupt::gpio_num"],[98,4,1,"_CPPv4N4espp9Interrupt16remove_interruptERK9PinConfig","espp::Interrupt::remove_interrupt::interrupt"],[98,3,1,"_CPPv4N4espp9Interrupt13set_log_levelEN4espp6Logger9VerbosityE","espp::Interrupt::set_log_level"],[98,4,1,"_CPPv4N4espp9Interrupt13set_log_levelEN4espp6Logger9VerbosityE","espp::Interrupt::set_log_level::level"],[98,3,1,"_CPPv4N4espp9Interrupt18set_log_rate_limitENSt6chrono8durationIfEE","espp::Interrupt::set_log_rate_limit"],[98,4,1,"_CPPv4N4espp9Interrupt18set_log_rate_limitENSt6chrono8durationIfEE","espp::Interrupt::set_log_rate_limit::rate_limit"],[98,3,1,"_CPPv4N4espp9Interrupt11set_log_tagERKNSt11string_viewE","espp::Interrupt::set_log_tag"],[98,4,1,"_CPPv4N4espp9Interrupt11set_log_tagERKNSt11string_viewE","espp::Interrupt::set_log_tag::tag"],[98,3,1,"_CPPv4N4espp9Interrupt17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Interrupt::set_log_verbosity"],[98,4,1,"_CPPv4N4espp9Interrupt17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Interrupt::set_log_verbosity::level"],[98,3,1,"_CPPv4N4espp9InterruptD0Ev","espp::Interrupt::~Interrupt"],[107,2,1,"_CPPv4N4espp8JoystickE","espp::Joystick"],[107,2,1,"_CPPv4N4espp8Joystick6ConfigE","espp::Joystick::Config"],[107,1,1,"_CPPv4N4espp8Joystick6Config22center_deadzone_radiusE","espp::Joystick::Config::center_deadzone_radius"],[107,1,1,"_CPPv4N4espp8Joystick6Config10get_valuesE","espp::Joystick::Config::get_values"],[107,1,1,"_CPPv4N4espp8Joystick6Config9log_levelE","espp::Joystick::Config::log_level"],[107,1,1,"_CPPv4N4espp8Joystick6Config14range_deadzoneE","espp::Joystick::Config::range_deadzone"],[107,1,1,"_CPPv4N4espp8Joystick6Config4typeE","espp::Joystick::Config::type"],[107,1,1,"_CPPv4N4espp8Joystick6Config13x_calibrationE","espp::Joystick::Config::x_calibration"],[107,1,1,"_CPPv4N4espp8Joystick6Config13y_calibrationE","espp::Joystick::Config::y_calibration"],[107,3,1,"_CPPv4N4espp8Joystick8JoystickERKN4espp8Joystick6ConfigE","espp::Joystick::Joystick"],[107,4,1,"_CPPv4N4espp8Joystick8JoystickERKN4espp8Joystick6ConfigE","espp::Joystick::Joystick::config"],[107,6,1,"_CPPv4N4espp8Joystick4TypeE","espp::Joystick::Type"],[107,7,1,"_CPPv4N4espp8Joystick4Type8CIRCULARE","espp::Joystick::Type::CIRCULAR"],[107,7,1,"_CPPv4N4espp8Joystick4Type11RECTANGULARE","espp::Joystick::Type::RECTANGULAR"],[107,3,1,"_CPPv4NK4espp8Joystick22center_deadzone_radiusEv","espp::Joystick::center_deadzone_radius"],[107,3,1,"_CPPv4NK4espp8Joystick13get_log_levelEv","espp::Joystick::get_log_level"],[107,3,1,"_CPPv4NK4espp8Joystick17get_log_verbosityEv","espp::Joystick::get_log_verbosity"],[107,3,1,"_CPPv4NK4espp8Joystick8get_nameEv","espp::Joystick::get_name"],[107,8,1,"_CPPv4N4espp8Joystick13get_values_fnE","espp::Joystick::get_values_fn"],[107,3,1,"_CPPv4NK4espp8Joystick8positionEv","espp::Joystick::position"],[107,3,1,"_CPPv4NK4espp8Joystick14range_deadzoneEv","espp::Joystick::range_deadzone"],[107,3,1,"_CPPv4NK4espp8Joystick3rawEv","espp::Joystick::raw"],[107,3,1,"_CPPv4N4espp8Joystick15set_calibrationERKN4espp16FloatRangeMapper6ConfigERKN4espp16FloatRangeMapper6ConfigEff","espp::Joystick::set_calibration"],[107,4,1,"_CPPv4N4espp8Joystick15set_calibrationERKN4espp16FloatRangeMapper6ConfigERKN4espp16FloatRangeMapper6ConfigEff","espp::Joystick::set_calibration::center_deadzone_radius"],[107,4,1,"_CPPv4N4espp8Joystick15set_calibrationERKN4espp16FloatRangeMapper6ConfigERKN4espp16FloatRangeMapper6ConfigEff","espp::Joystick::set_calibration::range_deadzone"],[107,4,1,"_CPPv4N4espp8Joystick15set_calibrationERKN4espp16FloatRangeMapper6ConfigERKN4espp16FloatRangeMapper6ConfigEff","espp::Joystick::set_calibration::x_calibration"],[107,4,1,"_CPPv4N4espp8Joystick15set_calibrationERKN4espp16FloatRangeMapper6ConfigERKN4espp16FloatRangeMapper6ConfigEff","espp::Joystick::set_calibration::y_calibration"],[107,3,1,"_CPPv4N4espp8Joystick26set_center_deadzone_radiusEf","espp::Joystick::set_center_deadzone_radius"],[107,4,1,"_CPPv4N4espp8Joystick26set_center_deadzone_radiusEf","espp::Joystick::set_center_deadzone_radius::radius"],[107,3,1,"_CPPv4N4espp8Joystick13set_log_levelEN4espp6Logger9VerbosityE","espp::Joystick::set_log_level"],[107,4,1,"_CPPv4N4espp8Joystick13set_log_levelEN4espp6Logger9VerbosityE","espp::Joystick::set_log_level::level"],[107,3,1,"_CPPv4N4espp8Joystick18set_log_rate_limitENSt6chrono8durationIfEE","espp::Joystick::set_log_rate_limit"],[107,4,1,"_CPPv4N4espp8Joystick18set_log_rate_limitENSt6chrono8durationIfEE","espp::Joystick::set_log_rate_limit::rate_limit"],[107,3,1,"_CPPv4N4espp8Joystick11set_log_tagERKNSt11string_viewE","espp::Joystick::set_log_tag"],[107,4,1,"_CPPv4N4espp8Joystick11set_log_tagERKNSt11string_viewE","espp::Joystick::set_log_tag::tag"],[107,3,1,"_CPPv4N4espp8Joystick17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Joystick::set_log_verbosity"],[107,4,1,"_CPPv4N4espp8Joystick17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Joystick::set_log_verbosity::level"],[107,3,1,"_CPPv4N4espp8Joystick18set_range_deadzoneEf","espp::Joystick::set_range_deadzone"],[107,4,1,"_CPPv4N4espp8Joystick18set_range_deadzoneEf","espp::Joystick::set_range_deadzone::range_deadzone"],[107,3,1,"_CPPv4N4espp8Joystick8set_typeEN4espp8Joystick4TypeEff","espp::Joystick::set_type"],[107,4,1,"_CPPv4N4espp8Joystick8set_typeEN4espp8Joystick4TypeEff","espp::Joystick::set_type::radius"],[107,4,1,"_CPPv4N4espp8Joystick8set_typeEN4espp8Joystick4TypeEff","espp::Joystick::set_type::range_deadzone"],[107,4,1,"_CPPv4N4espp8Joystick8set_typeEN4espp8Joystick4TypeEff","espp::Joystick::set_type::type"],[107,3,1,"_CPPv4NK4espp8Joystick4typeEv","espp::Joystick::type"],[107,3,1,"_CPPv4N4espp8Joystick6updateEff","espp::Joystick::update"],[107,3,1,"_CPPv4N4espp8Joystick6updateEv","espp::Joystick::update"],[107,4,1,"_CPPv4N4espp8Joystick6updateEff","espp::Joystick::update::raw_x"],[107,4,1,"_CPPv4N4espp8Joystick6updateEff","espp::Joystick::update::raw_y"],[107,3,1,"_CPPv4NK4espp8Joystick1xEv","espp::Joystick::x"],[107,3,1,"_CPPv4NK4espp8Joystick1yEv","espp::Joystick::y"],[148,2,1,"_CPPv4N4espp9JpegFrameE","espp::JpegFrame"],[148,3,1,"_CPPv4N4espp9JpegFrame9JpegFrameEPKc6size_t","espp::JpegFrame::JpegFrame"],[148,3,1,"_CPPv4N4espp9JpegFrame9JpegFrameERK13RtpJpegPacket","espp::JpegFrame::JpegFrame"],[148,4,1,"_CPPv4N4espp9JpegFrame9JpegFrameEPKc6size_t","espp::JpegFrame::JpegFrame::data"],[148,4,1,"_CPPv4N4espp9JpegFrame9JpegFrameERK13RtpJpegPacket","espp::JpegFrame::JpegFrame::packet"],[148,4,1,"_CPPv4N4espp9JpegFrame9JpegFrameEPKc6size_t","espp::JpegFrame::JpegFrame::size"],[148,3,1,"_CPPv4N4espp9JpegFrame8add_scanERK13RtpJpegPacket","espp::JpegFrame::add_scan"],[148,4,1,"_CPPv4N4espp9JpegFrame8add_scanERK13RtpJpegPacket","espp::JpegFrame::add_scan::packet"],[148,3,1,"_CPPv4N4espp9JpegFrame6appendERK13RtpJpegPacket","espp::JpegFrame::append"],[148,4,1,"_CPPv4N4espp9JpegFrame6appendERK13RtpJpegPacket","espp::JpegFrame::append::packet"],[148,3,1,"_CPPv4NK4espp9JpegFrame8get_dataEv","espp::JpegFrame::get_data"],[148,3,1,"_CPPv4NK4espp9JpegFrame10get_headerEv","espp::JpegFrame::get_header"],[148,3,1,"_CPPv4NK4espp9JpegFrame10get_heightEv","espp::JpegFrame::get_height"],[148,3,1,"_CPPv4NK4espp9JpegFrame13get_scan_dataEv","espp::JpegFrame::get_scan_data"],[148,3,1,"_CPPv4NK4espp9JpegFrame9get_widthEv","espp::JpegFrame::get_width"],[148,3,1,"_CPPv4NK4espp9JpegFrame11is_completeEv","espp::JpegFrame::is_complete"],[148,2,1,"_CPPv4N4espp10JpegHeaderE","espp::JpegHeader"],[148,3,1,"_CPPv4N4espp10JpegHeader10JpegHeaderENSt11string_viewE","espp::JpegHeader::JpegHeader"],[148,3,1,"_CPPv4N4espp10JpegHeader10JpegHeaderEiiNSt11string_viewENSt11string_viewE","espp::JpegHeader::JpegHeader"],[148,4,1,"_CPPv4N4espp10JpegHeader10JpegHeaderENSt11string_viewE","espp::JpegHeader::JpegHeader::data"],[148,4,1,"_CPPv4N4espp10JpegHeader10JpegHeaderEiiNSt11string_viewENSt11string_viewE","espp::JpegHeader::JpegHeader::height"],[148,4,1,"_CPPv4N4espp10JpegHeader10JpegHeaderEiiNSt11string_viewENSt11string_viewE","espp::JpegHeader::JpegHeader::q0_table"],[148,4,1,"_CPPv4N4espp10JpegHeader10JpegHeaderEiiNSt11string_viewENSt11string_viewE","espp::JpegHeader::JpegHeader::q1_table"],[148,4,1,"_CPPv4N4espp10JpegHeader10JpegHeaderEiiNSt11string_viewENSt11string_viewE","espp::JpegHeader::JpegHeader::width"],[148,3,1,"_CPPv4NK4espp10JpegHeader8get_dataEv","espp::JpegHeader::get_data"],[148,3,1,"_CPPv4NK4espp10JpegHeader10get_heightEv","espp::JpegHeader::get_height"],[148,3,1,"_CPPv4NK4espp10JpegHeader22get_quantization_tableEi","espp::JpegHeader::get_quantization_table"],[148,4,1,"_CPPv4NK4espp10JpegHeader22get_quantization_tableEi","espp::JpegHeader::get_quantization_table::index"],[148,3,1,"_CPPv4NK4espp10JpegHeader9get_widthEv","espp::JpegHeader::get_width"],[91,2,1,"_CPPv4N4espp11KeypadInputE","espp::KeypadInput"],[91,2,1,"_CPPv4N4espp11KeypadInput6ConfigE","espp::KeypadInput::Config"],[91,1,1,"_CPPv4N4espp11KeypadInput6Config9log_levelE","espp::KeypadInput::Config::log_level"],[91,1,1,"_CPPv4N4espp11KeypadInput6Config4readE","espp::KeypadInput::Config::read"],[91,3,1,"_CPPv4N4espp11KeypadInput11KeypadInputERK6Config","espp::KeypadInput::KeypadInput"],[91,4,1,"_CPPv4N4espp11KeypadInput11KeypadInputERK6Config","espp::KeypadInput::KeypadInput::config"],[91,3,1,"_CPPv4N4espp11KeypadInput16get_input_deviceEv","espp::KeypadInput::get_input_device"],[91,3,1,"_CPPv4NK4espp11KeypadInput13get_log_levelEv","espp::KeypadInput::get_log_level"],[91,3,1,"_CPPv4NK4espp11KeypadInput17get_log_verbosityEv","espp::KeypadInput::get_log_verbosity"],[91,3,1,"_CPPv4NK4espp11KeypadInput8get_nameEv","espp::KeypadInput::get_name"],[91,3,1,"_CPPv4N4espp11KeypadInput13set_log_levelEN4espp6Logger9VerbosityE","espp::KeypadInput::set_log_level"],[91,4,1,"_CPPv4N4espp11KeypadInput13set_log_levelEN4espp6Logger9VerbosityE","espp::KeypadInput::set_log_level::level"],[91,3,1,"_CPPv4N4espp11KeypadInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::KeypadInput::set_log_rate_limit"],[91,4,1,"_CPPv4N4espp11KeypadInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::KeypadInput::set_log_rate_limit::rate_limit"],[91,3,1,"_CPPv4N4espp11KeypadInput11set_log_tagERKNSt11string_viewE","espp::KeypadInput::set_log_tag"],[91,4,1,"_CPPv4N4espp11KeypadInput11set_log_tagERKNSt11string_viewE","espp::KeypadInput::set_log_tag::tag"],[91,3,1,"_CPPv4N4espp11KeypadInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::KeypadInput::set_log_verbosity"],[91,4,1,"_CPPv4N4espp11KeypadInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::KeypadInput::set_log_verbosity::level"],[91,3,1,"_CPPv4N4espp11KeypadInputD0Ev","espp::KeypadInput::~KeypadInput"],[103,2,1,"_CPPv4N4espp7Kts1622E","espp::Kts1622"],[103,2,1,"_CPPv4N4espp7Kts16226ConfigE","espp::Kts1622::Config"],[103,1,1,"_CPPv4N4espp7Kts16226Config9auto_initE","espp::Kts1622::Config::auto_init"],[103,1,1,"_CPPv4N4espp7Kts16226Config14device_addressE","espp::Kts1622::Config::device_address"],[103,1,1,"_CPPv4N4espp7Kts16226Config9log_levelE","espp::Kts1622::Config::log_level"],[103,1,1,"_CPPv4N4espp7Kts16226Config17output_drive_modeE","espp::Kts1622::Config::output_drive_mode"],[103,1,1,"_CPPv4N4espp7Kts16226Config21port_0_direction_maskE","espp::Kts1622::Config::port_0_direction_mask"],[103,1,1,"_CPPv4N4espp7Kts16226Config21port_0_interrupt_maskE","espp::Kts1622::Config::port_0_interrupt_mask"],[103,1,1,"_CPPv4N4espp7Kts16226Config21port_1_direction_maskE","espp::Kts1622::Config::port_1_direction_mask"],[103,1,1,"_CPPv4N4espp7Kts16226Config21port_1_interrupt_maskE","espp::Kts1622::Config::port_1_interrupt_mask"],[103,1,1,"_CPPv4N4espp7Kts16226Config5writeE","espp::Kts1622::Config::write"],[103,1,1,"_CPPv4N4espp7Kts16226Config15write_then_readE","espp::Kts1622::Config::write_then_read"],[103,1,1,"_CPPv4N4espp7Kts162215DEFAULT_ADDRESSE","espp::Kts1622::DEFAULT_ADDRESS"],[103,3,1,"_CPPv4N4espp7Kts16227Kts1622ERK6Config","espp::Kts1622::Kts1622"],[103,4,1,"_CPPv4N4espp7Kts16227Kts1622ERK6Config","espp::Kts1622::Kts1622::config"],[103,6,1,"_CPPv4N4espp7Kts162215OutputDriveModeE","espp::Kts1622::OutputDriveMode"],[103,7,1,"_CPPv4N4espp7Kts162215OutputDriveMode10OPEN_DRAINE","espp::Kts1622::OutputDriveMode::OPEN_DRAIN"],[103,7,1,"_CPPv4N4espp7Kts162215OutputDriveMode9PUSH_PULLE","espp::Kts1622::OutputDriveMode::PUSH_PULL"],[103,6,1,"_CPPv4N4espp7Kts162219OutputDriveStrengthE","espp::Kts1622::OutputDriveStrength"],[103,7,1,"_CPPv4N4espp7Kts162219OutputDriveStrength6F_0_25E","espp::Kts1622::OutputDriveStrength::F_0_25"],[103,7,1,"_CPPv4N4espp7Kts162219OutputDriveStrength5F_0_5E","espp::Kts1622::OutputDriveStrength::F_0_5"],[103,7,1,"_CPPv4N4espp7Kts162219OutputDriveStrength6F_0_75E","espp::Kts1622::OutputDriveStrength::F_0_75"],[103,7,1,"_CPPv4N4espp7Kts162219OutputDriveStrength3F_1E","espp::Kts1622::OutputDriveStrength::F_1"],[103,6,1,"_CPPv4N4espp7Kts16224PortE","espp::Kts1622::Port"],[103,7,1,"_CPPv4N4espp7Kts16224Port5PORT0E","espp::Kts1622::Port::PORT0"],[103,7,1,"_CPPv4N4espp7Kts16224Port5PORT1E","espp::Kts1622::Port::PORT1"],[103,6,1,"_CPPv4N4espp7Kts162212PullResistorE","espp::Kts1622::PullResistor"],[103,7,1,"_CPPv4N4espp7Kts162212PullResistor7NO_PULLE","espp::Kts1622::PullResistor::NO_PULL"],[103,7,1,"_CPPv4N4espp7Kts162212PullResistor9PULL_DOWNE","espp::Kts1622::PullResistor::PULL_DOWN"],[103,7,1,"_CPPv4N4espp7Kts162212PullResistor7PULL_UPE","espp::Kts1622::PullResistor::PULL_UP"],[103,3,1,"_CPPv4N4espp7Kts162215clear_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt"],[103,3,1,"_CPPv4N4espp7Kts162215clear_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt"],[103,3,1,"_CPPv4N4espp7Kts162215clear_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_interrupt"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::mask"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::mask"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::p0"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::p1"],[103,4,1,"_CPPv4N4espp7Kts162215clear_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_interrupt::port"],[103,3,1,"_CPPv4N4espp7Kts162216clear_interruptsERNSt10error_codeE","espp::Kts1622::clear_interrupts"],[103,4,1,"_CPPv4N4espp7Kts162216clear_interruptsERNSt10error_codeE","espp::Kts1622::clear_interrupts::ec"],[103,3,1,"_CPPv4N4espp7Kts162210clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins"],[103,3,1,"_CPPv4N4espp7Kts162210clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins"],[103,3,1,"_CPPv4N4espp7Kts162210clear_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_pins"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::mask"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::clear_pins::mask"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::p0"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::p1"],[103,4,1,"_CPPv4N4espp7Kts162210clear_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::clear_pins::port"],[103,3,1,"_CPPv4N4espp7Kts162219configure_interruptE4Port7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt"],[103,3,1,"_CPPv4N4espp7Kts162219configure_interruptE7uint8_t7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE4Port7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE7uint8_t7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE4Port7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::mask"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE7uint8_t7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::p0"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE7uint8_t7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::p1"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE4Port7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::port"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE4Port7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::type"],[103,4,1,"_CPPv4N4espp7Kts162219configure_interruptE7uint8_t7uint8_t13InterruptTypeRNSt10error_codeE","espp::Kts1622::configure_interrupt::type"],[103,3,1,"_CPPv4N4espp7Kts162216enable_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt"],[103,3,1,"_CPPv4N4espp7Kts162216enable_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt"],[103,3,1,"_CPPv4N4espp7Kts162216enable_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::enable_interrupt"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::ec"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::mask"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE8uint16_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::mask"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::p0"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::p1"],[103,4,1,"_CPPv4N4espp7Kts162216enable_interruptE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::enable_interrupt::port"],[103,3,1,"_CPPv4NK4espp7Kts162213get_log_levelEv","espp::Kts1622::get_log_level"],[103,3,1,"_CPPv4NK4espp7Kts162217get_log_verbosityEv","espp::Kts1622::get_log_verbosity"],[103,3,1,"_CPPv4NK4espp7Kts16228get_nameEv","espp::Kts1622::get_name"],[103,3,1,"_CPPv4N4espp7Kts162210get_outputE4PortRNSt10error_codeE","espp::Kts1622::get_output"],[103,3,1,"_CPPv4N4espp7Kts162210get_outputERNSt10error_codeE","espp::Kts1622::get_output"],[103,4,1,"_CPPv4N4espp7Kts162210get_outputE4PortRNSt10error_codeE","espp::Kts1622::get_output::ec"],[103,4,1,"_CPPv4N4espp7Kts162210get_outputERNSt10error_codeE","espp::Kts1622::get_output::ec"],[103,4,1,"_CPPv4N4espp7Kts162210get_outputE4PortRNSt10error_codeE","espp::Kts1622::get_output::port"],[103,3,1,"_CPPv4N4espp7Kts16228get_pinsE4PortRNSt10error_codeE","espp::Kts1622::get_pins"],[103,3,1,"_CPPv4N4espp7Kts16228get_pinsERNSt10error_codeE","espp::Kts1622::get_pins"],[103,4,1,"_CPPv4N4espp7Kts16228get_pinsE4PortRNSt10error_codeE","espp::Kts1622::get_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts16228get_pinsERNSt10error_codeE","espp::Kts1622::get_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts16228get_pinsE4PortRNSt10error_codeE","espp::Kts1622::get_pins::port"],[103,3,1,"_CPPv4N4espp7Kts162210initializeERNSt10error_codeE","espp::Kts1622::initialize"],[103,4,1,"_CPPv4N4espp7Kts162210initializeERNSt10error_codeE","espp::Kts1622::initialize::ec"],[103,3,1,"_CPPv4N4espp7Kts16226outputE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::output"],[103,3,1,"_CPPv4N4espp7Kts16226outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::output"],[103,3,1,"_CPPv4N4espp7Kts16226outputE8uint16_tRNSt10error_codeE","espp::Kts1622::output"],[103,4,1,"_CPPv4N4espp7Kts16226outputE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::output::ec"],[103,4,1,"_CPPv4N4espp7Kts16226outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::output::ec"],[103,4,1,"_CPPv4N4espp7Kts16226outputE8uint16_tRNSt10error_codeE","espp::Kts1622::output::ec"],[103,4,1,"_CPPv4N4espp7Kts16226outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::output::p0"],[103,4,1,"_CPPv4N4espp7Kts16226outputE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::output::p1"],[103,4,1,"_CPPv4N4espp7Kts16226outputE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::output::port"],[103,4,1,"_CPPv4N4espp7Kts16226outputE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::output::value"],[103,4,1,"_CPPv4N4espp7Kts16226outputE8uint16_tRNSt10error_codeE","espp::Kts1622::output::value"],[103,3,1,"_CPPv4N4espp7Kts16225probeERNSt10error_codeE","espp::Kts1622::probe"],[103,4,1,"_CPPv4N4espp7Kts16225probeERNSt10error_codeE","espp::Kts1622::probe::ec"],[103,8,1,"_CPPv4N4espp7Kts16228probe_fnE","espp::Kts1622::probe_fn"],[103,3,1,"_CPPv4N4espp7Kts162211set_addressE7uint8_t","espp::Kts1622::set_address"],[103,4,1,"_CPPv4N4espp7Kts162211set_addressE7uint8_t","espp::Kts1622::set_address::address"],[103,3,1,"_CPPv4N4espp7Kts162210set_configERK6Config","espp::Kts1622::set_config"],[103,3,1,"_CPPv4N4espp7Kts162210set_configERR6Config","espp::Kts1622::set_config"],[103,4,1,"_CPPv4N4espp7Kts162210set_configERK6Config","espp::Kts1622::set_config::config"],[103,4,1,"_CPPv4N4espp7Kts162210set_configERR6Config","espp::Kts1622::set_config::config"],[103,3,1,"_CPPv4N4espp7Kts162213set_directionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction"],[103,3,1,"_CPPv4N4espp7Kts162213set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction"],[103,3,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_direction"],[103,3,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tbRNSt10error_codeE","espp::Kts1622::set_direction"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tbRNSt10error_codeE","espp::Kts1622::set_direction::direction"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::ec"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::ec"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_direction::ec"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tbRNSt10error_codeE","espp::Kts1622::set_direction::ec"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::mask"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_direction::mask"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE8uint16_tbRNSt10error_codeE","espp::Kts1622::set_direction::mask"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::p0"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::p1"],[103,4,1,"_CPPv4N4espp7Kts162213set_directionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_direction::port"],[103,3,1,"_CPPv4N4espp7Kts162215set_input_latchE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch"],[103,3,1,"_CPPv4N4espp7Kts162215set_input_latchE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch"],[103,3,1,"_CPPv4N4espp7Kts162215set_input_latchE8uint16_tRNSt10error_codeE","espp::Kts1622::set_input_latch"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::ec"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::ec"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE8uint16_tRNSt10error_codeE","espp::Kts1622::set_input_latch::ec"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::latch"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE8uint16_tRNSt10error_codeE","espp::Kts1622::set_input_latch::mask"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::p0"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::p1"],[103,4,1,"_CPPv4N4espp7Kts162215set_input_latchE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_input_latch::port"],[103,3,1,"_CPPv4N4espp7Kts162213set_log_levelEN4espp6Logger9VerbosityE","espp::Kts1622::set_log_level"],[103,4,1,"_CPPv4N4espp7Kts162213set_log_levelEN4espp6Logger9VerbosityE","espp::Kts1622::set_log_level::level"],[103,3,1,"_CPPv4N4espp7Kts162218set_log_rate_limitENSt6chrono8durationIfEE","espp::Kts1622::set_log_rate_limit"],[103,4,1,"_CPPv4N4espp7Kts162218set_log_rate_limitENSt6chrono8durationIfEE","espp::Kts1622::set_log_rate_limit::rate_limit"],[103,3,1,"_CPPv4N4espp7Kts162211set_log_tagERKNSt11string_viewE","espp::Kts1622::set_log_tag"],[103,4,1,"_CPPv4N4espp7Kts162211set_log_tagERKNSt11string_viewE","espp::Kts1622::set_log_tag::tag"],[103,3,1,"_CPPv4N4espp7Kts162217set_log_verbosityEN4espp6Logger9VerbosityE","espp::Kts1622::set_log_verbosity"],[103,4,1,"_CPPv4N4espp7Kts162217set_log_verbosityEN4espp6Logger9VerbosityE","espp::Kts1622::set_log_verbosity::level"],[103,3,1,"_CPPv4N4espp7Kts16228set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins"],[103,3,1,"_CPPv4N4espp7Kts16228set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins"],[103,3,1,"_CPPv4N4espp7Kts16228set_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::set_pins"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::set_pins::ec"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::mask"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE8uint16_tRNSt10error_codeE","espp::Kts1622::set_pins::mask"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::p0"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::p1"],[103,4,1,"_CPPv4N4espp7Kts16228set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_pins::port"],[103,3,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion"],[103,3,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion"],[103,3,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::ec"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::ec"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::ec"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::mask"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE8uint16_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::mask"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::p0"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE7uint8_t7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::p1"],[103,4,1,"_CPPv4N4espp7Kts162222set_polarity_inversionE4Port7uint8_tRNSt10error_codeE","espp::Kts1622::set_polarity_inversion::port"],[103,3,1,"_CPPv4N4espp7Kts162226set_port_output_drive_modeE4Port15OutputDriveModeRNSt10error_codeE","espp::Kts1622::set_port_output_drive_mode"],[103,4,1,"_CPPv4N4espp7Kts162226set_port_output_drive_modeE4Port15OutputDriveModeRNSt10error_codeE","espp::Kts1622::set_port_output_drive_mode::ec"],[103,4,1,"_CPPv4N4espp7Kts162226set_port_output_drive_modeE4Port15OutputDriveModeRNSt10error_codeE","espp::Kts1622::set_port_output_drive_mode::mode"],[103,4,1,"_CPPv4N4espp7Kts162226set_port_output_drive_modeE4Port15OutputDriveModeRNSt10error_codeE","espp::Kts1622::set_port_output_drive_mode::port"],[103,3,1,"_CPPv4N4espp7Kts16229set_probeERK8probe_fn","espp::Kts1622::set_probe"],[103,4,1,"_CPPv4N4espp7Kts16229set_probeERK8probe_fn","espp::Kts1622::set_probe::probe"],[103,3,1,"_CPPv4N4espp7Kts162225set_pull_resistor_for_pinE4Port7uint8_t12PullResistorRNSt10error_codeE","espp::Kts1622::set_pull_resistor_for_pin"],[103,4,1,"_CPPv4N4espp7Kts162225set_pull_resistor_for_pinE4Port7uint8_t12PullResistorRNSt10error_codeE","espp::Kts1622::set_pull_resistor_for_pin::ec"],[103,4,1,"_CPPv4N4espp7Kts162225set_pull_resistor_for_pinE4Port7uint8_t12PullResistorRNSt10error_codeE","espp::Kts1622::set_pull_resistor_for_pin::pin_mask"],[103,4,1,"_CPPv4N4espp7Kts162225set_pull_resistor_for_pinE4Port7uint8_t12PullResistorRNSt10error_codeE","espp::Kts1622::set_pull_resistor_for_pin::port"],[103,4,1,"_CPPv4N4espp7Kts162225set_pull_resistor_for_pinE4Port7uint8_t12PullResistorRNSt10error_codeE","espp::Kts1622::set_pull_resistor_for_pin::pull"],[103,3,1,"_CPPv4N4espp7Kts16228set_readERK7read_fn","espp::Kts1622::set_read"],[103,4,1,"_CPPv4N4espp7Kts16228set_readERK7read_fn","espp::Kts1622::set_read::read"],[103,3,1,"_CPPv4N4espp7Kts162217set_read_registerERK16read_register_fn","espp::Kts1622::set_read_register"],[103,4,1,"_CPPv4N4espp7Kts162217set_read_registerERK16read_register_fn","espp::Kts1622::set_read_register::read_register"],[103,3,1,"_CPPv4N4espp7Kts162234set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Kts1622::set_separate_write_then_read_delay"],[103,4,1,"_CPPv4N4espp7Kts162234set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Kts1622::set_separate_write_then_read_delay::delay"],[103,3,1,"_CPPv4N4espp7Kts16229set_writeERK8write_fn","espp::Kts1622::set_write"],[103,4,1,"_CPPv4N4espp7Kts16229set_writeERK8write_fn","espp::Kts1622::set_write::write"],[103,3,1,"_CPPv4N4espp7Kts162219set_write_then_readERK18write_then_read_fn","espp::Kts1622::set_write_then_read"],[103,4,1,"_CPPv4N4espp7Kts162219set_write_then_readERK18write_then_read_fn","espp::Kts1622::set_write_then_read::write_then_read"],[109,2,1,"_CPPv4N4espp3LedE","espp::Led"],[109,2,1,"_CPPv4N4espp3Led13ChannelConfigE","espp::Led::ChannelConfig"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig7channelE","espp::Led::ChannelConfig::channel"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig4dutyE","espp::Led::ChannelConfig::duty"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig4gpioE","espp::Led::ChannelConfig::gpio"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig13output_invertE","espp::Led::ChannelConfig::output_invert"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig10sleep_modeE","espp::Led::ChannelConfig::sleep_mode"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig10speed_modeE","espp::Led::ChannelConfig::speed_mode"],[109,1,1,"_CPPv4N4espp3Led13ChannelConfig5timerE","espp::Led::ChannelConfig::timer"],[109,2,1,"_CPPv4N4espp3Led6ConfigE","espp::Led::Config"],[109,1,1,"_CPPv4N4espp3Led6Config8channelsE","espp::Led::Config::channels"],[109,1,1,"_CPPv4N4espp3Led6Config12clock_configE","espp::Led::Config::clock_config"],[109,1,1,"_CPPv4N4espp3Led6Config15duty_resolutionE","espp::Led::Config::duty_resolution"],[109,1,1,"_CPPv4N4espp3Led6Config12frequency_hzE","espp::Led::Config::frequency_hz"],[109,1,1,"_CPPv4N4espp3Led6Config11isr_core_idE","espp::Led::Config::isr_core_id"],[109,1,1,"_CPPv4N4espp3Led6Config9log_levelE","espp::Led::Config::log_level"],[109,1,1,"_CPPv4N4espp3Led6Config10speed_modeE","espp::Led::Config::speed_mode"],[109,1,1,"_CPPv4N4espp3Led6Config5timerE","espp::Led::Config::timer"],[109,3,1,"_CPPv4N4espp3Led3LedERK6Config","espp::Led::Led"],[109,4,1,"_CPPv4N4espp3Led3LedERK6Config","espp::Led::Led::config"],[109,3,1,"_CPPv4N4espp3Led10can_changeE14ledc_channel_t","espp::Led::can_change"],[109,4,1,"_CPPv4N4espp3Led10can_changeE14ledc_channel_t","espp::Led::can_change::channel"],[109,3,1,"_CPPv4NK4espp3Led8get_dutyE14ledc_channel_t","espp::Led::get_duty"],[109,4,1,"_CPPv4NK4espp3Led8get_dutyE14ledc_channel_t","espp::Led::get_duty::channel"],[109,3,1,"_CPPv4NK4espp3Led13get_log_levelEv","espp::Led::get_log_level"],[109,3,1,"_CPPv4NK4espp3Led17get_log_verbosityEv","espp::Led::get_log_verbosity"],[109,3,1,"_CPPv4NK4espp3Led8get_nameEv","espp::Led::get_name"],[109,3,1,"_CPPv4N4espp3Led8set_dutyE14ledc_channel_tf","espp::Led::set_duty"],[109,4,1,"_CPPv4N4espp3Led8set_dutyE14ledc_channel_tf","espp::Led::set_duty::channel"],[109,4,1,"_CPPv4N4espp3Led8set_dutyE14ledc_channel_tf","espp::Led::set_duty::duty_percent"],[109,3,1,"_CPPv4N4espp3Led18set_fade_with_timeE14ledc_channel_tf8uint32_t","espp::Led::set_fade_with_time"],[109,4,1,"_CPPv4N4espp3Led18set_fade_with_timeE14ledc_channel_tf8uint32_t","espp::Led::set_fade_with_time::channel"],[109,4,1,"_CPPv4N4espp3Led18set_fade_with_timeE14ledc_channel_tf8uint32_t","espp::Led::set_fade_with_time::duty_percent"],[109,4,1,"_CPPv4N4espp3Led18set_fade_with_timeE14ledc_channel_tf8uint32_t","espp::Led::set_fade_with_time::fade_time_ms"],[109,3,1,"_CPPv4N4espp3Led13set_log_levelEN4espp6Logger9VerbosityE","espp::Led::set_log_level"],[109,4,1,"_CPPv4N4espp3Led13set_log_levelEN4espp6Logger9VerbosityE","espp::Led::set_log_level::level"],[109,3,1,"_CPPv4N4espp3Led18set_log_rate_limitENSt6chrono8durationIfEE","espp::Led::set_log_rate_limit"],[109,4,1,"_CPPv4N4espp3Led18set_log_rate_limitENSt6chrono8durationIfEE","espp::Led::set_log_rate_limit::rate_limit"],[109,3,1,"_CPPv4N4espp3Led11set_log_tagERKNSt11string_viewE","espp::Led::set_log_tag"],[109,4,1,"_CPPv4N4espp3Led11set_log_tagERKNSt11string_viewE","espp::Led::set_log_tag::tag"],[109,3,1,"_CPPv4N4espp3Led17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Led::set_log_verbosity"],[109,4,1,"_CPPv4N4espp3Led17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Led::set_log_verbosity::level"],[109,3,1,"_CPPv4N4espp3Led13uninstall_isrEv","espp::Led::uninstall_isr"],[109,3,1,"_CPPv4N4espp3LedD0Ev","espp::Led::~Led"],[111,2,1,"_CPPv4N4espp8LedStripE","espp::LedStrip"],[111,1,1,"_CPPv4N4espp8LedStrip18APA102_START_FRAMEE","espp::LedStrip::APA102_START_FRAME"],[111,6,1,"_CPPv4N4espp8LedStrip9ByteOrderE","espp::LedStrip::ByteOrder"],[111,7,1,"_CPPv4N4espp8LedStrip9ByteOrder3BGRE","espp::LedStrip::ByteOrder::BGR"],[111,7,1,"_CPPv4N4espp8LedStrip9ByteOrder3GRBE","espp::LedStrip::ByteOrder::GRB"],[111,7,1,"_CPPv4N4espp8LedStrip9ByteOrder3RGBE","espp::LedStrip::ByteOrder::RGB"],[111,2,1,"_CPPv4N4espp8LedStrip6ConfigE","espp::LedStrip::Config"],[111,1,1,"_CPPv4N4espp8LedStrip6Config10byte_orderE","espp::LedStrip::Config::byte_order"],[111,1,1,"_CPPv4N4espp8LedStrip6Config9end_frameE","espp::LedStrip::Config::end_frame"],[111,1,1,"_CPPv4N4espp8LedStrip6Config9log_levelE","espp::LedStrip::Config::log_level"],[111,1,1,"_CPPv4N4espp8LedStrip6Config8num_ledsE","espp::LedStrip::Config::num_leds"],[111,1,1,"_CPPv4N4espp8LedStrip6Config15send_brightnessE","espp::LedStrip::Config::send_brightness"],[111,1,1,"_CPPv4N4espp8LedStrip6Config11start_frameE","espp::LedStrip::Config::start_frame"],[111,1,1,"_CPPv4N4espp8LedStrip6Config5writeE","espp::LedStrip::Config::write"],[111,3,1,"_CPPv4N4espp8LedStrip8LedStripERK6Config","espp::LedStrip::LedStrip"],[111,4,1,"_CPPv4N4espp8LedStrip8LedStripERK6Config","espp::LedStrip::LedStrip::config"],[111,3,1,"_CPPv4NK4espp8LedStrip10byte_orderEv","espp::LedStrip::byte_order"],[111,3,1,"_CPPv4NK4espp8LedStrip13get_log_levelEv","espp::LedStrip::get_log_level"],[111,3,1,"_CPPv4NK4espp8LedStrip17get_log_verbosityEv","espp::LedStrip::get_log_verbosity"],[111,3,1,"_CPPv4NK4espp8LedStrip8get_nameEv","espp::LedStrip::get_name"],[111,3,1,"_CPPv4NK4espp8LedStrip8num_ledsEv","espp::LedStrip::num_leds"],[111,3,1,"_CPPv4N4espp8LedStrip7set_allE3Hsvf","espp::LedStrip::set_all"],[111,3,1,"_CPPv4N4espp8LedStrip7set_allE3Rgbf","espp::LedStrip::set_all"],[111,3,1,"_CPPv4N4espp8LedStrip7set_allE7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_all"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_all::b"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE3Hsvf","espp::LedStrip::set_all::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE3Rgbf","espp::LedStrip::set_all::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_all::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_all::g"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE3Hsvf","espp::LedStrip::set_all::hsv"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_all::r"],[111,4,1,"_CPPv4N4espp8LedStrip7set_allE3Rgbf","espp::LedStrip::set_all::rgb"],[111,3,1,"_CPPv4N4espp8LedStrip13set_log_levelEN4espp6Logger9VerbosityE","espp::LedStrip::set_log_level"],[111,4,1,"_CPPv4N4espp8LedStrip13set_log_levelEN4espp6Logger9VerbosityE","espp::LedStrip::set_log_level::level"],[111,3,1,"_CPPv4N4espp8LedStrip18set_log_rate_limitENSt6chrono8durationIfEE","espp::LedStrip::set_log_rate_limit"],[111,4,1,"_CPPv4N4espp8LedStrip18set_log_rate_limitENSt6chrono8durationIfEE","espp::LedStrip::set_log_rate_limit::rate_limit"],[111,3,1,"_CPPv4N4espp8LedStrip11set_log_tagERKNSt11string_viewE","espp::LedStrip::set_log_tag"],[111,4,1,"_CPPv4N4espp8LedStrip11set_log_tagERKNSt11string_viewE","espp::LedStrip::set_log_tag::tag"],[111,3,1,"_CPPv4N4espp8LedStrip17set_log_verbosityEN4espp6Logger9VerbosityE","espp::LedStrip::set_log_verbosity"],[111,4,1,"_CPPv4N4espp8LedStrip17set_log_verbosityEN4espp6Logger9VerbosityE","espp::LedStrip::set_log_verbosity::level"],[111,3,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Hsvf","espp::LedStrip::set_pixel"],[111,3,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Rgbf","espp::LedStrip::set_pixel"],[111,3,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel::b"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Hsvf","espp::LedStrip::set_pixel::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Rgbf","espp::LedStrip::set_pixel::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel::brightness"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel::g"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Hsvf","espp::LedStrip::set_pixel::hsv"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Hsvf","espp::LedStrip::set_pixel::index"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Rgbf","espp::LedStrip::set_pixel::index"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel::index"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi7uint8_t7uint8_t7uint8_t7uint8_t","espp::LedStrip::set_pixel::r"],[111,4,1,"_CPPv4N4espp8LedStrip9set_pixelEi3Rgbf","espp::LedStrip::set_pixel::rgb"],[111,3,1,"_CPPv4N4espp8LedStrip10shift_leftEi","espp::LedStrip::shift_left"],[111,4,1,"_CPPv4N4espp8LedStrip10shift_leftEi","espp::LedStrip::shift_left::shift_by"],[111,3,1,"_CPPv4N4espp8LedStrip11shift_rightEi","espp::LedStrip::shift_right"],[111,4,1,"_CPPv4N4espp8LedStrip11shift_rightEi","espp::LedStrip::shift_right::shift_by"],[111,3,1,"_CPPv4N4espp8LedStrip4showEv","espp::LedStrip::show"],[111,8,1,"_CPPv4N4espp8LedStrip8write_fnE","espp::LedStrip::write_fn"],[113,2,1,"_CPPv4N4espp6LoggerE","espp::Logger"],[113,2,1,"_CPPv4N4espp6Logger6ConfigE","espp::Logger::Config"],[113,1,1,"_CPPv4N4espp6Logger6Config12include_timeE","espp::Logger::Config::include_time"],[113,1,1,"_CPPv4N4espp6Logger6Config5levelE","espp::Logger::Config::level"],[113,1,1,"_CPPv4N4espp6Logger6Config10rate_limitE","espp::Logger::Config::rate_limit"],[113,1,1,"_CPPv4N4espp6Logger6Config3tagE","espp::Logger::Config::tag"],[113,3,1,"_CPPv4N4espp6Logger6LoggerERK6Config","espp::Logger::Logger"],[113,4,1,"_CPPv4N4espp6Logger6LoggerERK6Config","espp::Logger::Logger::config"],[113,6,1,"_CPPv4N4espp6Logger9VerbosityE","espp::Logger::Verbosity"],[113,7,1,"_CPPv4N4espp6Logger9Verbosity5DEBUGE","espp::Logger::Verbosity::DEBUG"],[113,7,1,"_CPPv4N4espp6Logger9Verbosity5ERRORE","espp::Logger::Verbosity::ERROR"],[113,7,1,"_CPPv4N4espp6Logger9Verbosity4INFOE","espp::Logger::Verbosity::INFO"],[113,7,1,"_CPPv4N4espp6Logger9Verbosity4NONEE","espp::Logger::Verbosity::NONE"],[113,7,1,"_CPPv4N4espp6Logger9Verbosity4WARNE","espp::Logger::Verbosity::WARN"],[113,3,1,"_CPPv4N4espp6Logger10clear_lineEv","espp::Logger::clear_line"],[113,3,1,"_CPPv4N4espp6Logger12clear_screenEv","espp::Logger::clear_screen"],[113,3,1,"_CPPv4IDpEN4espp6Logger5debugEvNSt11string_viewEDpRR4Args","espp::Logger::debug"],[113,5,1,"_CPPv4IDpEN4espp6Logger5debugEvNSt11string_viewEDpRR4Args","espp::Logger::debug::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger5debugEvNSt11string_viewEDpRR4Args","espp::Logger::debug::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger5debugEvNSt11string_viewEDpRR4Args","espp::Logger::debug::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger18debug_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::debug_rate_limited"],[113,5,1,"_CPPv4IDpEN4espp6Logger18debug_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::debug_rate_limited::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger18debug_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::debug_rate_limited::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger18debug_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::debug_rate_limited::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger5errorEvNSt11string_viewEDpRR4Args","espp::Logger::error"],[113,5,1,"_CPPv4IDpEN4espp6Logger5errorEvNSt11string_viewEDpRR4Args","espp::Logger::error::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger5errorEvNSt11string_viewEDpRR4Args","espp::Logger::error::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger5errorEvNSt11string_viewEDpRR4Args","espp::Logger::error::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger18error_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::error_rate_limited"],[113,5,1,"_CPPv4IDpEN4espp6Logger18error_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::error_rate_limited::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger18error_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::error_rate_limited::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger18error_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::error_rate_limited::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger6formatENSt6stringENSt11string_viewEDpRR4Args","espp::Logger::format"],[113,5,1,"_CPPv4IDpEN4espp6Logger6formatENSt6stringENSt11string_viewEDpRR4Args","espp::Logger::format::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger6formatENSt6stringENSt11string_viewEDpRR4Args","espp::Logger::format::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger6formatENSt6stringENSt11string_viewEDpRR4Args","espp::Logger::format::rt_fmt_str"],[113,3,1,"_CPPv4NK4espp6Logger14get_rate_limitEv","espp::Logger::get_rate_limit"],[113,3,1,"_CPPv4NK4espp6Logger7get_tagEv","espp::Logger::get_tag"],[113,3,1,"_CPPv4N4espp6Logger8get_timeEv","espp::Logger::get_time"],[113,3,1,"_CPPv4NK4espp6Logger13get_verbosityEv","espp::Logger::get_verbosity"],[113,3,1,"_CPPv4IDpEN4espp6Logger4infoEvNSt11string_viewEDpRR4Args","espp::Logger::info"],[113,5,1,"_CPPv4IDpEN4espp6Logger4infoEvNSt11string_viewEDpRR4Args","espp::Logger::info::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger4infoEvNSt11string_viewEDpRR4Args","espp::Logger::info::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger4infoEvNSt11string_viewEDpRR4Args","espp::Logger::info::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger17info_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::info_rate_limited"],[113,5,1,"_CPPv4IDpEN4espp6Logger17info_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::info_rate_limited::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger17info_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::info_rate_limited::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger17info_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::info_rate_limited::rt_fmt_str"],[113,3,1,"_CPPv4N4espp6Logger9move_downEi","espp::Logger::move_down"],[113,3,1,"_CPPv4N4espp6Logger9move_downEv","espp::Logger::move_down"],[113,4,1,"_CPPv4N4espp6Logger9move_downEi","espp::Logger::move_down::lines"],[113,3,1,"_CPPv4N4espp6Logger7move_toEii","espp::Logger::move_to"],[113,4,1,"_CPPv4N4espp6Logger7move_toEii","espp::Logger::move_to::x"],[113,4,1,"_CPPv4N4espp6Logger7move_toEii","espp::Logger::move_to::y"],[113,3,1,"_CPPv4N4espp6Logger13move_to_startEv","espp::Logger::move_to_start"],[113,3,1,"_CPPv4N4espp6Logger7move_upEi","espp::Logger::move_up"],[113,3,1,"_CPPv4N4espp6Logger7move_upEv","espp::Logger::move_up"],[113,4,1,"_CPPv4N4espp6Logger7move_upEi","espp::Logger::move_up::lines"],[113,3,1,"_CPPv4N4espp6Logger16set_include_timeEb","espp::Logger::set_include_time"],[113,4,1,"_CPPv4N4espp6Logger16set_include_timeEb","espp::Logger::set_include_time::include_time"],[113,3,1,"_CPPv4N4espp6Logger14set_rate_limitEKNSt6chrono8durationIfEE","espp::Logger::set_rate_limit"],[113,4,1,"_CPPv4N4espp6Logger14set_rate_limitEKNSt6chrono8durationIfEE","espp::Logger::set_rate_limit::rate_limit"],[113,3,1,"_CPPv4N4espp6Logger7set_tagEKNSt11string_viewE","espp::Logger::set_tag"],[113,4,1,"_CPPv4N4espp6Logger7set_tagEKNSt11string_viewE","espp::Logger::set_tag::tag"],[113,3,1,"_CPPv4N4espp6Logger13set_verbosityEKN4espp6Logger9VerbosityE","espp::Logger::set_verbosity"],[113,4,1,"_CPPv4N4espp6Logger13set_verbosityEKN4espp6Logger9VerbosityE","espp::Logger::set_verbosity::level"],[113,3,1,"_CPPv4IDpEN4espp6Logger4warnEvNSt11string_viewEDpRR4Args","espp::Logger::warn"],[113,5,1,"_CPPv4IDpEN4espp6Logger4warnEvNSt11string_viewEDpRR4Args","espp::Logger::warn::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger4warnEvNSt11string_viewEDpRR4Args","espp::Logger::warn::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger4warnEvNSt11string_viewEDpRR4Args","espp::Logger::warn::rt_fmt_str"],[113,3,1,"_CPPv4IDpEN4espp6Logger17warn_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::warn_rate_limited"],[113,5,1,"_CPPv4IDpEN4espp6Logger17warn_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::warn_rate_limited::Args"],[113,4,1,"_CPPv4IDpEN4espp6Logger17warn_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::warn_rate_limited::args"],[113,4,1,"_CPPv4IDpEN4espp6Logger17warn_rate_limitedEvNSt11string_viewEDpRR4Args","espp::Logger::warn_rate_limited::rt_fmt_str"],[63,2,1,"_CPPv4N4espp13LowpassFilterE","espp::LowpassFilter"],[63,2,1,"_CPPv4N4espp13LowpassFilter6ConfigE","espp::LowpassFilter::Config"],[63,1,1,"_CPPv4N4espp13LowpassFilter6Config27normalized_cutoff_frequencyE","espp::LowpassFilter::Config::normalized_cutoff_frequency"],[63,1,1,"_CPPv4N4espp13LowpassFilter6Config8q_factorE","espp::LowpassFilter::Config::q_factor"],[63,3,1,"_CPPv4N4espp13LowpassFilter13LowpassFilterERK6Config","espp::LowpassFilter::LowpassFilter"],[63,3,1,"_CPPv4N4espp13LowpassFilter13LowpassFilterEv","espp::LowpassFilter::LowpassFilter"],[63,4,1,"_CPPv4N4espp13LowpassFilter13LowpassFilterERK6Config","espp::LowpassFilter::LowpassFilter::config"],[63,3,1,"_CPPv4N4espp13LowpassFilter9configureERK6Config","espp::LowpassFilter::configure"],[63,4,1,"_CPPv4N4espp13LowpassFilter9configureERK6Config","espp::LowpassFilter::configure::config"],[63,3,1,"_CPPv4N4espp13LowpassFilterclEf","espp::LowpassFilter::operator()"],[63,4,1,"_CPPv4N4espp13LowpassFilterclEf","espp::LowpassFilter::operator()::input"],[63,3,1,"_CPPv4N4espp13LowpassFilter5resetEv","espp::LowpassFilter::reset"],[63,3,1,"_CPPv4N4espp13LowpassFilter6updateEKf","espp::LowpassFilter::update"],[63,3,1,"_CPPv4N4espp13LowpassFilter6updateEPKfPf6size_t","espp::LowpassFilter::update"],[63,4,1,"_CPPv4N4espp13LowpassFilter6updateEKf","espp::LowpassFilter::update::input"],[63,4,1,"_CPPv4N4espp13LowpassFilter6updateEPKfPf6size_t","espp::LowpassFilter::update::input"],[63,4,1,"_CPPv4N4espp13LowpassFilter6updateEPKfPf6size_t","espp::LowpassFilter::update::length"],[63,4,1,"_CPPv4N4espp13LowpassFilter6updateEPKfPf6size_t","espp::LowpassFilter::update::output"],[122,2,1,"_CPPv4N4espp20MatouchRotaryDisplayE","espp::MatouchRotaryDisplay"],[122,8,1,"_CPPv4N4espp20MatouchRotaryDisplay13DisplayDriverE","espp::MatouchRotaryDisplay::DisplayDriver"],[122,8,1,"_CPPv4N4espp20MatouchRotaryDisplay5PixelE","espp::MatouchRotaryDisplay::Pixel"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay10brightnessEf","espp::MatouchRotaryDisplay::brightness"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay10brightnessEv","espp::MatouchRotaryDisplay::brightness"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay10brightnessEf","espp::MatouchRotaryDisplay::brightness::brightness"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay12button_stateEv","espp::MatouchRotaryDisplay::button_state"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay7displayEv","espp::MatouchRotaryDisplay::display"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay7encoderEv","espp::MatouchRotaryDisplay::encoder"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay13encoder_valueEv","espp::MatouchRotaryDisplay::encoder_value"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay13frame_buffer0Ev","espp::MatouchRotaryDisplay::frame_buffer0"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay13frame_buffer1Ev","espp::MatouchRotaryDisplay::frame_buffer1"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay3getEv","espp::MatouchRotaryDisplay::get"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay15get_lcd_dc_gpioEv","espp::MatouchRotaryDisplay::get_lcd_dc_gpio"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay13get_log_levelEv","espp::MatouchRotaryDisplay::get_log_level"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay17get_log_verbosityEv","espp::MatouchRotaryDisplay::get_log_verbosity"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay8get_nameEv","espp::MatouchRotaryDisplay::get_name"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay17initialize_buttonERK17button_callback_t","espp::MatouchRotaryDisplay::initialize_button"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay17initialize_buttonERK17button_callback_t","espp::MatouchRotaryDisplay::initialize_button::callback"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay18initialize_encoderEv","espp::MatouchRotaryDisplay::initialize_encoder"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay14initialize_lcdEv","espp::MatouchRotaryDisplay::initialize_lcd"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay16initialize_touchERK16touch_callback_t","espp::MatouchRotaryDisplay::initialize_touch"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay16initialize_touchERK16touch_callback_t","espp::MatouchRotaryDisplay::initialize_touch::callback"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay12internal_i2cEv","espp::MatouchRotaryDisplay::internal_i2c"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay10interruptsEv","espp::MatouchRotaryDisplay::interrupts"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay10lcd_heightEv","espp::MatouchRotaryDisplay::lcd_height"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay9lcd_widthEv","espp::MatouchRotaryDisplay::lcd_width"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay13set_log_levelEN4espp6Logger9VerbosityE","espp::MatouchRotaryDisplay::set_log_level"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay13set_log_levelEN4espp6Logger9VerbosityE","espp::MatouchRotaryDisplay::set_log_level::level"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay18set_log_rate_limitENSt6chrono8durationIfEE","espp::MatouchRotaryDisplay::set_log_rate_limit"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay18set_log_rate_limitENSt6chrono8durationIfEE","espp::MatouchRotaryDisplay::set_log_rate_limit::rate_limit"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay11set_log_tagERKNSt11string_viewE","espp::MatouchRotaryDisplay::set_log_tag"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay11set_log_tagERKNSt11string_viewE","espp::MatouchRotaryDisplay::set_log_tag::tag"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay17set_log_verbosityEN4espp6Logger9VerbosityE","espp::MatouchRotaryDisplay::set_log_verbosity"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay17set_log_verbosityEN4espp6Logger9VerbosityE","espp::MatouchRotaryDisplay::set_log_verbosity::level"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay16touchpad_convertERK12TouchpadData","espp::MatouchRotaryDisplay::touchpad_convert"],[122,4,1,"_CPPv4NK4espp20MatouchRotaryDisplay16touchpad_convertERK12TouchpadData","espp::MatouchRotaryDisplay::touchpad_convert::data"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay13touchpad_dataEv","espp::MatouchRotaryDisplay::touchpad_data"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay14touchpad_inputEv","espp::MatouchRotaryDisplay::touchpad_input"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::touchpad_read"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::touchpad_read::btn_state"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::touchpad_read::num_touch_points"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::touchpad_read::x"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::touchpad_read::y"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay5vram0Ev","espp::MatouchRotaryDisplay::vram0"],[122,3,1,"_CPPv4NK4espp20MatouchRotaryDisplay5vram1Ev","espp::MatouchRotaryDisplay::vram1"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd::data"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd::length"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd::user_data"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame::data"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame::height"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame::width"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame::x"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::MatouchRotaryDisplay::write_lcd_frame::y"],[122,3,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::data"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::user_data"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::xe"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::xs"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::ye"],[122,4,1,"_CPPv4N4espp20MatouchRotaryDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::MatouchRotaryDisplay::write_lcd_lines::ys"],[14,2,1,"_CPPv4N4espp8Max1704xE","espp::Max1704x"],[14,2,1,"_CPPv4N4espp8Max1704x6ConfigE","espp::Max1704x::Config"],[14,1,1,"_CPPv4N4espp8Max1704x6Config9auto_initE","espp::Max1704x::Config::auto_init"],[14,1,1,"_CPPv4N4espp8Max1704x6Config14device_addressE","espp::Max1704x::Config::device_address"],[14,1,1,"_CPPv4N4espp8Max1704x6Config9log_levelE","espp::Max1704x::Config::log_level"],[14,1,1,"_CPPv4N4espp8Max1704x15DEFAULT_ADDRESSE","espp::Max1704x::DEFAULT_ADDRESS"],[14,3,1,"_CPPv4N4espp8Max1704x8Max1704xERK6Config","espp::Max1704x::Max1704x"],[14,4,1,"_CPPv4N4espp8Max1704x8Max1704xERK6Config","espp::Max1704x::Max1704x::config"],[14,3,1,"_CPPv4N4espp8Max1704x18clear_alert_statusE7uint8_tRNSt10error_codeE","espp::Max1704x::clear_alert_status"],[14,4,1,"_CPPv4N4espp8Max1704x18clear_alert_statusE7uint8_tRNSt10error_codeE","espp::Max1704x::clear_alert_status::ec"],[14,4,1,"_CPPv4N4espp8Max1704x18clear_alert_statusE7uint8_tRNSt10error_codeE","espp::Max1704x::clear_alert_status::flags_to_clear"],[14,3,1,"_CPPv4N4espp8Max1704x16get_alert_statusERNSt10error_codeE","espp::Max1704x::get_alert_status"],[14,4,1,"_CPPv4N4espp8Max1704x16get_alert_statusERNSt10error_codeE","espp::Max1704x::get_alert_status::ec"],[14,3,1,"_CPPv4N4espp8Max1704x23get_battery_charge_rateERNSt10error_codeE","espp::Max1704x::get_battery_charge_rate"],[14,4,1,"_CPPv4N4espp8Max1704x23get_battery_charge_rateERNSt10error_codeE","espp::Max1704x::get_battery_charge_rate::ec"],[14,3,1,"_CPPv4N4espp8Max1704x22get_battery_percentageERNSt10error_codeE","espp::Max1704x::get_battery_percentage"],[14,4,1,"_CPPv4N4espp8Max1704x22get_battery_percentageERNSt10error_codeE","espp::Max1704x::get_battery_percentage::ec"],[14,3,1,"_CPPv4N4espp8Max1704x19get_battery_voltageERNSt10error_codeE","espp::Max1704x::get_battery_voltage"],[14,4,1,"_CPPv4N4espp8Max1704x19get_battery_voltageERNSt10error_codeE","espp::Max1704x::get_battery_voltage::ec"],[14,3,1,"_CPPv4N4espp8Max1704x11get_chip_idERNSt10error_codeE","espp::Max1704x::get_chip_id"],[14,4,1,"_CPPv4N4espp8Max1704x11get_chip_idERNSt10error_codeE","espp::Max1704x::get_chip_id::ec"],[14,3,1,"_CPPv4NK4espp8Max1704x13get_log_levelEv","espp::Max1704x::get_log_level"],[14,3,1,"_CPPv4NK4espp8Max1704x17get_log_verbosityEv","espp::Max1704x::get_log_verbosity"],[14,3,1,"_CPPv4NK4espp8Max1704x8get_nameEv","espp::Max1704x::get_name"],[14,3,1,"_CPPv4N4espp8Max1704x11get_versionERNSt10error_codeE","espp::Max1704x::get_version"],[14,4,1,"_CPPv4N4espp8Max1704x11get_versionERNSt10error_codeE","espp::Max1704x::get_version::ec"],[14,3,1,"_CPPv4N4espp8Max1704x9initalizeERNSt10error_codeE","espp::Max1704x::initalize"],[14,4,1,"_CPPv4N4espp8Max1704x9initalizeERNSt10error_codeE","espp::Max1704x::initalize::ec"],[14,3,1,"_CPPv4N4espp8Max1704x5probeERNSt10error_codeE","espp::Max1704x::probe"],[14,4,1,"_CPPv4N4espp8Max1704x5probeERNSt10error_codeE","espp::Max1704x::probe::ec"],[14,8,1,"_CPPv4N4espp8Max1704x8probe_fnE","espp::Max1704x::probe_fn"],[14,3,1,"_CPPv4N4espp8Max1704x11set_addressE7uint8_t","espp::Max1704x::set_address"],[14,4,1,"_CPPv4N4espp8Max1704x11set_addressE7uint8_t","espp::Max1704x::set_address::address"],[14,3,1,"_CPPv4N4espp8Max1704x10set_configERK6Config","espp::Max1704x::set_config"],[14,3,1,"_CPPv4N4espp8Max1704x10set_configERR6Config","espp::Max1704x::set_config"],[14,4,1,"_CPPv4N4espp8Max1704x10set_configERK6Config","espp::Max1704x::set_config::config"],[14,4,1,"_CPPv4N4espp8Max1704x10set_configERR6Config","espp::Max1704x::set_config::config"],[14,3,1,"_CPPv4N4espp8Max1704x13set_log_levelEN4espp6Logger9VerbosityE","espp::Max1704x::set_log_level"],[14,4,1,"_CPPv4N4espp8Max1704x13set_log_levelEN4espp6Logger9VerbosityE","espp::Max1704x::set_log_level::level"],[14,3,1,"_CPPv4N4espp8Max1704x18set_log_rate_limitENSt6chrono8durationIfEE","espp::Max1704x::set_log_rate_limit"],[14,4,1,"_CPPv4N4espp8Max1704x18set_log_rate_limitENSt6chrono8durationIfEE","espp::Max1704x::set_log_rate_limit::rate_limit"],[14,3,1,"_CPPv4N4espp8Max1704x11set_log_tagERKNSt11string_viewE","espp::Max1704x::set_log_tag"],[14,4,1,"_CPPv4N4espp8Max1704x11set_log_tagERKNSt11string_viewE","espp::Max1704x::set_log_tag::tag"],[14,3,1,"_CPPv4N4espp8Max1704x17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Max1704x::set_log_verbosity"],[14,4,1,"_CPPv4N4espp8Max1704x17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Max1704x::set_log_verbosity::level"],[14,3,1,"_CPPv4N4espp8Max1704x9set_probeERK8probe_fn","espp::Max1704x::set_probe"],[14,4,1,"_CPPv4N4espp8Max1704x9set_probeERK8probe_fn","espp::Max1704x::set_probe::probe"],[14,3,1,"_CPPv4N4espp8Max1704x8set_readERK7read_fn","espp::Max1704x::set_read"],[14,4,1,"_CPPv4N4espp8Max1704x8set_readERK7read_fn","espp::Max1704x::set_read::read"],[14,3,1,"_CPPv4N4espp8Max1704x17set_read_registerERK16read_register_fn","espp::Max1704x::set_read_register"],[14,4,1,"_CPPv4N4espp8Max1704x17set_read_registerERK16read_register_fn","espp::Max1704x::set_read_register::read_register"],[14,3,1,"_CPPv4N4espp8Max1704x34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Max1704x::set_separate_write_then_read_delay"],[14,4,1,"_CPPv4N4espp8Max1704x34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Max1704x::set_separate_write_then_read_delay::delay"],[14,3,1,"_CPPv4N4espp8Max1704x9set_writeERK8write_fn","espp::Max1704x::set_write"],[14,4,1,"_CPPv4N4espp8Max1704x9set_writeERK8write_fn","espp::Max1704x::set_write::write"],[14,3,1,"_CPPv4N4espp8Max1704x19set_write_then_readERK18write_then_read_fn","espp::Max1704x::set_write_then_read"],[14,4,1,"_CPPv4N4espp8Max1704x19set_write_then_readERK18write_then_read_fn","espp::Max1704x::set_write_then_read::write_then_read"],[105,2,1,"_CPPv4N4espp8Mcp23x17E","espp::Mcp23x17"],[105,2,1,"_CPPv4N4espp8Mcp23x176ConfigE","espp::Mcp23x17::Config"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config9auto_initE","espp::Mcp23x17::Config::auto_init"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config14device_addressE","espp::Mcp23x17::Config::device_address"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config9log_levelE","espp::Mcp23x17::Config::log_level"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config21port_0_direction_maskE","espp::Mcp23x17::Config::port_0_direction_mask"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config21port_0_interrupt_maskE","espp::Mcp23x17::Config::port_0_interrupt_mask"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config21port_1_direction_maskE","espp::Mcp23x17::Config::port_1_direction_mask"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config21port_1_interrupt_maskE","espp::Mcp23x17::Config::port_1_interrupt_mask"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config13read_registerE","espp::Mcp23x17::Config::read_register"],[105,1,1,"_CPPv4N4espp8Mcp23x176Config5writeE","espp::Mcp23x17::Config::write"],[105,1,1,"_CPPv4N4espp8Mcp23x1715DEFAULT_ADDRESSE","espp::Mcp23x17::DEFAULT_ADDRESS"],[105,3,1,"_CPPv4N4espp8Mcp23x178Mcp23x17ERK6Config","espp::Mcp23x17::Mcp23x17"],[105,4,1,"_CPPv4N4espp8Mcp23x178Mcp23x17ERK6Config","espp::Mcp23x17::Mcp23x17::config"],[105,6,1,"_CPPv4N4espp8Mcp23x174PortE","espp::Mcp23x17::Port"],[105,7,1,"_CPPv4N4espp8Mcp23x174Port5PORT0E","espp::Mcp23x17::Port::PORT0"],[105,7,1,"_CPPv4N4espp8Mcp23x174Port5PORT1E","espp::Mcp23x17::Port::PORT1"],[105,3,1,"_CPPv4N4espp8Mcp23x1721get_interrupt_captureE4PortRNSt10error_codeE","espp::Mcp23x17::get_interrupt_capture"],[105,4,1,"_CPPv4N4espp8Mcp23x1721get_interrupt_captureE4PortRNSt10error_codeE","espp::Mcp23x17::get_interrupt_capture::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1721get_interrupt_captureE4PortRNSt10error_codeE","espp::Mcp23x17::get_interrupt_capture::port"],[105,3,1,"_CPPv4NK4espp8Mcp23x1713get_log_levelEv","espp::Mcp23x17::get_log_level"],[105,3,1,"_CPPv4NK4espp8Mcp23x1717get_log_verbosityEv","espp::Mcp23x17::get_log_verbosity"],[105,3,1,"_CPPv4NK4espp8Mcp23x178get_nameEv","espp::Mcp23x17::get_name"],[105,3,1,"_CPPv4N4espp8Mcp23x178get_pinsE4PortRNSt10error_codeE","espp::Mcp23x17::get_pins"],[105,3,1,"_CPPv4N4espp8Mcp23x178get_pinsERNSt10error_codeE","espp::Mcp23x17::get_pins"],[105,4,1,"_CPPv4N4espp8Mcp23x178get_pinsE4PortRNSt10error_codeE","espp::Mcp23x17::get_pins::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x178get_pinsERNSt10error_codeE","espp::Mcp23x17::get_pins::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x178get_pinsE4PortRNSt10error_codeE","espp::Mcp23x17::get_pins::port"],[105,3,1,"_CPPv4N4espp8Mcp23x1710initializeERNSt10error_codeE","espp::Mcp23x17::initialize"],[105,4,1,"_CPPv4N4espp8Mcp23x1710initializeERNSt10error_codeE","espp::Mcp23x17::initialize::ec"],[105,3,1,"_CPPv4N4espp8Mcp23x175probeERNSt10error_codeE","espp::Mcp23x17::probe"],[105,4,1,"_CPPv4N4espp8Mcp23x175probeERNSt10error_codeE","espp::Mcp23x17::probe::ec"],[105,8,1,"_CPPv4N4espp8Mcp23x178probe_fnE","espp::Mcp23x17::probe_fn"],[105,3,1,"_CPPv4N4espp8Mcp23x1711set_addressE7uint8_t","espp::Mcp23x17::set_address"],[105,4,1,"_CPPv4N4espp8Mcp23x1711set_addressE7uint8_t","espp::Mcp23x17::set_address::address"],[105,3,1,"_CPPv4N4espp8Mcp23x1710set_configERK6Config","espp::Mcp23x17::set_config"],[105,3,1,"_CPPv4N4espp8Mcp23x1710set_configERR6Config","espp::Mcp23x17::set_config"],[105,4,1,"_CPPv4N4espp8Mcp23x1710set_configERK6Config","espp::Mcp23x17::set_config::config"],[105,4,1,"_CPPv4N4espp8Mcp23x1710set_configERR6Config","espp::Mcp23x17::set_config::config"],[105,3,1,"_CPPv4N4espp8Mcp23x1713set_directionE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_direction"],[105,4,1,"_CPPv4N4espp8Mcp23x1713set_directionE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_direction::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1713set_directionE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_direction::mask"],[105,4,1,"_CPPv4N4espp8Mcp23x1713set_directionE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_direction::port"],[105,3,1,"_CPPv4N4espp8Mcp23x1718set_input_polarityE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_input_polarity"],[105,4,1,"_CPPv4N4espp8Mcp23x1718set_input_polarityE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_input_polarity::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1718set_input_polarityE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_input_polarity::mask"],[105,4,1,"_CPPv4N4espp8Mcp23x1718set_input_polarityE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_input_polarity::port"],[105,3,1,"_CPPv4N4espp8Mcp23x1720set_interrupt_mirrorEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_mirror"],[105,4,1,"_CPPv4N4espp8Mcp23x1720set_interrupt_mirrorEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_mirror::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1720set_interrupt_mirrorEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_mirror::mirror"],[105,3,1,"_CPPv4N4espp8Mcp23x1723set_interrupt_on_changeE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_change"],[105,4,1,"_CPPv4N4espp8Mcp23x1723set_interrupt_on_changeE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_change::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1723set_interrupt_on_changeE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_change::mask"],[105,4,1,"_CPPv4N4espp8Mcp23x1723set_interrupt_on_changeE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_change::port"],[105,3,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_on_valueE4Port7uint8_t7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_value"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_on_valueE4Port7uint8_t7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_value::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_on_valueE4Port7uint8_t7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_value::pin_mask"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_on_valueE4Port7uint8_t7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_value::port"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_on_valueE4Port7uint8_t7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_interrupt_on_value::val_mask"],[105,3,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_polarityEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_polarity"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_polarityEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_polarity::active_high"],[105,4,1,"_CPPv4N4espp8Mcp23x1722set_interrupt_polarityEbRNSt10error_codeE","espp::Mcp23x17::set_interrupt_polarity::ec"],[105,3,1,"_CPPv4N4espp8Mcp23x1713set_log_levelEN4espp6Logger9VerbosityE","espp::Mcp23x17::set_log_level"],[105,4,1,"_CPPv4N4espp8Mcp23x1713set_log_levelEN4espp6Logger9VerbosityE","espp::Mcp23x17::set_log_level::level"],[105,3,1,"_CPPv4N4espp8Mcp23x1718set_log_rate_limitENSt6chrono8durationIfEE","espp::Mcp23x17::set_log_rate_limit"],[105,4,1,"_CPPv4N4espp8Mcp23x1718set_log_rate_limitENSt6chrono8durationIfEE","espp::Mcp23x17::set_log_rate_limit::rate_limit"],[105,3,1,"_CPPv4N4espp8Mcp23x1711set_log_tagERKNSt11string_viewE","espp::Mcp23x17::set_log_tag"],[105,4,1,"_CPPv4N4espp8Mcp23x1711set_log_tagERKNSt11string_viewE","espp::Mcp23x17::set_log_tag::tag"],[105,3,1,"_CPPv4N4espp8Mcp23x1717set_log_verbosityEN4espp6Logger9VerbosityE","espp::Mcp23x17::set_log_verbosity"],[105,4,1,"_CPPv4N4espp8Mcp23x1717set_log_verbosityEN4espp6Logger9VerbosityE","espp::Mcp23x17::set_log_verbosity::level"],[105,3,1,"_CPPv4N4espp8Mcp23x178set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pins"],[105,4,1,"_CPPv4N4espp8Mcp23x178set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pins::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x178set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pins::output"],[105,4,1,"_CPPv4N4espp8Mcp23x178set_pinsE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pins::port"],[105,3,1,"_CPPv4N4espp8Mcp23x179set_probeERK8probe_fn","espp::Mcp23x17::set_probe"],[105,4,1,"_CPPv4N4espp8Mcp23x179set_probeERK8probe_fn","espp::Mcp23x17::set_probe::probe"],[105,3,1,"_CPPv4N4espp8Mcp23x1711set_pull_upE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pull_up"],[105,4,1,"_CPPv4N4espp8Mcp23x1711set_pull_upE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pull_up::ec"],[105,4,1,"_CPPv4N4espp8Mcp23x1711set_pull_upE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pull_up::mask"],[105,4,1,"_CPPv4N4espp8Mcp23x1711set_pull_upE4Port7uint8_tRNSt10error_codeE","espp::Mcp23x17::set_pull_up::port"],[105,3,1,"_CPPv4N4espp8Mcp23x178set_readERK7read_fn","espp::Mcp23x17::set_read"],[105,4,1,"_CPPv4N4espp8Mcp23x178set_readERK7read_fn","espp::Mcp23x17::set_read::read"],[105,3,1,"_CPPv4N4espp8Mcp23x1717set_read_registerERK16read_register_fn","espp::Mcp23x17::set_read_register"],[105,4,1,"_CPPv4N4espp8Mcp23x1717set_read_registerERK16read_register_fn","espp::Mcp23x17::set_read_register::read_register"],[105,3,1,"_CPPv4N4espp8Mcp23x1734set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Mcp23x17::set_separate_write_then_read_delay"],[105,4,1,"_CPPv4N4espp8Mcp23x1734set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Mcp23x17::set_separate_write_then_read_delay::delay"],[105,3,1,"_CPPv4N4espp8Mcp23x179set_writeERK8write_fn","espp::Mcp23x17::set_write"],[105,4,1,"_CPPv4N4espp8Mcp23x179set_writeERK8write_fn","espp::Mcp23x17::set_write::write"],[105,3,1,"_CPPv4N4espp8Mcp23x1719set_write_then_readERK18write_then_read_fn","espp::Mcp23x17::set_write_then_read"],[105,4,1,"_CPPv4N4espp8Mcp23x1719set_write_then_readERK18write_then_read_fn","espp::Mcp23x17::set_write_then_read::write_then_read"],[126,2,1,"_CPPv4N4espp11MotorGoMiniE","espp::MotorGoMini"],[126,3,1,"_CPPv4N4espp11MotorGoMini4adc1Ev","espp::MotorGoMini::adc1"],[126,3,1,"_CPPv4N4espp11MotorGoMini4adc2Ev","espp::MotorGoMini::adc2"],[126,3,1,"_CPPv4N4espp11MotorGoMini6buttonEv","espp::MotorGoMini::button"],[126,3,1,"_CPPv4N4espp11MotorGoMini8encoder1Ev","espp::MotorGoMini::encoder1"],[126,3,1,"_CPPv4N4espp11MotorGoMini8encoder2Ev","espp::MotorGoMini::encoder2"],[126,3,1,"_CPPv4N4espp11MotorGoMini8gaussianEv","espp::MotorGoMini::gaussian"],[126,3,1,"_CPPv4N4espp11MotorGoMini3getEv","espp::MotorGoMini::get"],[126,3,1,"_CPPv4N4espp11MotorGoMini16get_external_i2cEv","espp::MotorGoMini::get_external_i2c"],[126,3,1,"_CPPv4NK4espp11MotorGoMini13get_log_levelEv","espp::MotorGoMini::get_log_level"],[126,3,1,"_CPPv4NK4espp11MotorGoMini17get_log_verbosityEv","espp::MotorGoMini::get_log_verbosity"],[126,3,1,"_CPPv4NK4espp11MotorGoMini8get_nameEv","espp::MotorGoMini::get_name"],[126,3,1,"_CPPv4N4espp11MotorGoMini20init_motor_channel_1Ev","espp::MotorGoMini::init_motor_channel_1"],[126,3,1,"_CPPv4N4espp11MotorGoMini20init_motor_channel_2Ev","espp::MotorGoMini::init_motor_channel_2"],[126,3,1,"_CPPv4N4espp11MotorGoMini3ledEv","espp::MotorGoMini::led"],[126,3,1,"_CPPv4N4espp11MotorGoMini12led_channel0Ev","espp::MotorGoMini::led_channel0"],[126,3,1,"_CPPv4N4espp11MotorGoMini12led_channel1Ev","espp::MotorGoMini::led_channel1"],[126,3,1,"_CPPv4N4espp11MotorGoMini6motor1Ev","espp::MotorGoMini::motor1"],[126,3,1,"_CPPv4N4espp11MotorGoMini21motor1_current_u_ampsEv","espp::MotorGoMini::motor1_current_u_amps"],[126,3,1,"_CPPv4N4espp11MotorGoMini21motor1_current_w_ampsEv","espp::MotorGoMini::motor1_current_w_amps"],[126,3,1,"_CPPv4N4espp11MotorGoMini13motor1_driverEv","espp::MotorGoMini::motor1_driver"],[126,3,1,"_CPPv4N4espp11MotorGoMini6motor2Ev","espp::MotorGoMini::motor2"],[126,3,1,"_CPPv4N4espp11MotorGoMini21motor2_current_u_ampsEv","espp::MotorGoMini::motor2_current_u_amps"],[126,3,1,"_CPPv4N4espp11MotorGoMini21motor2_current_w_ampsEv","espp::MotorGoMini::motor2_current_w_amps"],[126,3,1,"_CPPv4N4espp11MotorGoMini13motor2_driverEv","espp::MotorGoMini::motor2_driver"],[126,3,1,"_CPPv4N4espp11MotorGoMini7red_ledEv","espp::MotorGoMini::red_led"],[126,3,1,"_CPPv4N4espp11MotorGoMini13set_log_levelEN4espp6Logger9VerbosityE","espp::MotorGoMini::set_log_level"],[126,4,1,"_CPPv4N4espp11MotorGoMini13set_log_levelEN4espp6Logger9VerbosityE","espp::MotorGoMini::set_log_level::level"],[126,3,1,"_CPPv4N4espp11MotorGoMini18set_log_rate_limitENSt6chrono8durationIfEE","espp::MotorGoMini::set_log_rate_limit"],[126,4,1,"_CPPv4N4espp11MotorGoMini18set_log_rate_limitENSt6chrono8durationIfEE","espp::MotorGoMini::set_log_rate_limit::rate_limit"],[126,3,1,"_CPPv4N4espp11MotorGoMini11set_log_tagERKNSt11string_viewE","espp::MotorGoMini::set_log_tag"],[126,4,1,"_CPPv4N4espp11MotorGoMini11set_log_tagERKNSt11string_viewE","espp::MotorGoMini::set_log_tag::tag"],[126,3,1,"_CPPv4N4espp11MotorGoMini17set_log_verbosityEN4espp6Logger9VerbosityE","espp::MotorGoMini::set_log_verbosity"],[126,4,1,"_CPPv4N4espp11MotorGoMini17set_log_verbosityEN4espp6Logger9VerbosityE","espp::MotorGoMini::set_log_verbosity::level"],[126,3,1,"_CPPv4N4espp11MotorGoMini16set_red_led_dutyEf","espp::MotorGoMini::set_red_led_duty"],[126,4,1,"_CPPv4N4espp11MotorGoMini16set_red_led_dutyEf","espp::MotorGoMini::set_red_led_duty::duty"],[126,3,1,"_CPPv4N4espp11MotorGoMini19set_yellow_led_dutyEf","espp::MotorGoMini::set_yellow_led_duty"],[126,4,1,"_CPPv4N4espp11MotorGoMini19set_yellow_led_dutyEf","espp::MotorGoMini::set_yellow_led_duty::duty"],[126,3,1,"_CPPv4N4espp11MotorGoMini15start_breathingEv","espp::MotorGoMini::start_breathing"],[126,3,1,"_CPPv4N4espp11MotorGoMini14stop_breathingEv","espp::MotorGoMini::stop_breathing"],[126,3,1,"_CPPv4N4espp11MotorGoMini10yellow_ledEv","espp::MotorGoMini::yellow_led"],[49,2,1,"_CPPv4I_15Mt6701InterfaceEN4espp6Mt6701E","espp::Mt6701"],[49,1,1,"_CPPv4N4espp6Mt670121COUNTS_PER_REVOLUTIONE","espp::Mt6701::COUNTS_PER_REVOLUTION"],[49,1,1,"_CPPv4N4espp6Mt670123COUNTS_PER_REVOLUTION_FE","espp::Mt6701::COUNTS_PER_REVOLUTION_F"],[49,1,1,"_CPPv4N4espp6Mt670117COUNTS_TO_DEGREESE","espp::Mt6701::COUNTS_TO_DEGREES"],[49,1,1,"_CPPv4N4espp6Mt670117COUNTS_TO_RADIANSE","espp::Mt6701::COUNTS_TO_RADIANS"],[49,2,1,"_CPPv4N4espp6Mt67016ConfigE","espp::Mt6701::Config"],[49,1,1,"_CPPv4N4espp6Mt67016Config9auto_initE","espp::Mt6701::Config::auto_init"],[49,1,1,"_CPPv4N4espp6Mt67016Config14device_addressE","espp::Mt6701::Config::device_address"],[49,1,1,"_CPPv4N4espp6Mt67016Config4readE","espp::Mt6701::Config::read"],[49,1,1,"_CPPv4N4espp6Mt67016Config8run_taskE","espp::Mt6701::Config::run_task"],[49,1,1,"_CPPv4N4espp6Mt67016Config13update_periodE","espp::Mt6701::Config::update_period"],[49,1,1,"_CPPv4N4espp6Mt67016Config15velocity_filterE","espp::Mt6701::Config::velocity_filter"],[49,1,1,"_CPPv4N4espp6Mt67016Config5writeE","espp::Mt6701::Config::write"],[49,1,1,"_CPPv4N4espp6Mt670115DEFAULT_ADDRESSE","espp::Mt6701::DEFAULT_ADDRESS"],[49,5,1,"_CPPv4I_15Mt6701InterfaceEN4espp6Mt6701E","espp::Mt6701::Interface"],[49,6,1,"_CPPv4N4espp6Mt670121MagneticFieldStrengthE","espp::Mt6701::MagneticFieldStrength"],[49,7,1,"_CPPv4N4espp6Mt670121MagneticFieldStrength6NORMALE","espp::Mt6701::MagneticFieldStrength::NORMAL"],[49,7,1,"_CPPv4N4espp6Mt670121MagneticFieldStrength10TOO_STRONGE","espp::Mt6701::MagneticFieldStrength::TOO_STRONG"],[49,7,1,"_CPPv4N4espp6Mt670121MagneticFieldStrength8TOO_WEAKE","espp::Mt6701::MagneticFieldStrength::TOO_WEAK"],[49,3,1,"_CPPv4N4espp6Mt67016Mt6701ERK6Config","espp::Mt6701::Mt6701"],[49,4,1,"_CPPv4N4espp6Mt67016Mt6701ERK6Config","espp::Mt6701::Mt6701::config"],[49,1,1,"_CPPv4N4espp6Mt670118SECONDS_PER_MINUTEE","espp::Mt6701::SECONDS_PER_MINUTE"],[49,6,1,"_CPPv4N4espp6Mt670114TrackingStatusE","espp::Mt6701::TrackingStatus"],[49,7,1,"_CPPv4N4espp6Mt670114TrackingStatus4LOSTE","espp::Mt6701::TrackingStatus::LOST"],[49,7,1,"_CPPv4N4espp6Mt670114TrackingStatus6NORMALE","espp::Mt6701::TrackingStatus::NORMAL"],[49,3,1,"_CPPv4NK4espp6Mt670115get_accumulatorEv","espp::Mt6701::get_accumulator"],[49,3,1,"_CPPv4NK4espp6Mt67019get_countEv","espp::Mt6701::get_count"],[49,3,1,"_CPPv4NK4espp6Mt670111get_degreesEv","espp::Mt6701::get_degrees"],[49,3,1,"_CPPv4NK4espp6Mt670113get_log_levelEv","espp::Mt6701::get_log_level"],[49,3,1,"_CPPv4NK4espp6Mt670117get_log_verbosityEv","espp::Mt6701::get_log_verbosity"],[49,3,1,"_CPPv4NK4espp6Mt670127get_magnetic_field_strengthEv","espp::Mt6701::get_magnetic_field_strength"],[49,3,1,"_CPPv4NK4espp6Mt670122get_mechanical_degreesEv","espp::Mt6701::get_mechanical_degrees"],[49,3,1,"_CPPv4NK4espp6Mt670122get_mechanical_radiansEv","espp::Mt6701::get_mechanical_radians"],[49,3,1,"_CPPv4NK4espp6Mt67018get_nameEv","espp::Mt6701::get_name"],[49,3,1,"_CPPv4NK4espp6Mt670115get_push_buttonEv","espp::Mt6701::get_push_button"],[49,3,1,"_CPPv4NK4espp6Mt670111get_radiansEv","espp::Mt6701::get_radians"],[49,3,1,"_CPPv4NK4espp6Mt67017get_rpmEv","espp::Mt6701::get_rpm"],[49,3,1,"_CPPv4NK4espp6Mt670119get_tracking_statusEv","espp::Mt6701::get_tracking_status"],[49,3,1,"_CPPv4N4espp6Mt670110initializeEbRNSt10error_codeE","espp::Mt6701::initialize"],[49,4,1,"_CPPv4N4espp6Mt670110initializeEbRNSt10error_codeE","espp::Mt6701::initialize::ec"],[49,4,1,"_CPPv4N4espp6Mt670110initializeEbRNSt10error_codeE","espp::Mt6701::initialize::run_task"],[49,3,1,"_CPPv4NK4espp6Mt670117needs_zero_searchEv","espp::Mt6701::needs_zero_search"],[49,3,1,"_CPPv4N4espp6Mt67015probeERNSt10error_codeE","espp::Mt6701::probe"],[49,4,1,"_CPPv4N4espp6Mt67015probeERNSt10error_codeE","espp::Mt6701::probe::ec"],[49,8,1,"_CPPv4N4espp6Mt67018probe_fnE","espp::Mt6701::probe_fn"],[49,3,1,"_CPPv4N4espp6Mt670111set_addressE7uint8_t","espp::Mt6701::set_address"],[49,4,1,"_CPPv4N4espp6Mt670111set_addressE7uint8_t","espp::Mt6701::set_address::address"],[49,3,1,"_CPPv4N4espp6Mt670110set_configERK6Config","espp::Mt6701::set_config"],[49,3,1,"_CPPv4N4espp6Mt670110set_configERR6Config","espp::Mt6701::set_config"],[49,4,1,"_CPPv4N4espp6Mt670110set_configERK6Config","espp::Mt6701::set_config::config"],[49,4,1,"_CPPv4N4espp6Mt670110set_configERR6Config","espp::Mt6701::set_config::config"],[49,3,1,"_CPPv4N4espp6Mt670113set_log_levelEN4espp6Logger9VerbosityE","espp::Mt6701::set_log_level"],[49,4,1,"_CPPv4N4espp6Mt670113set_log_levelEN4espp6Logger9VerbosityE","espp::Mt6701::set_log_level::level"],[49,3,1,"_CPPv4N4espp6Mt670118set_log_rate_limitENSt6chrono8durationIfEE","espp::Mt6701::set_log_rate_limit"],[49,4,1,"_CPPv4N4espp6Mt670118set_log_rate_limitENSt6chrono8durationIfEE","espp::Mt6701::set_log_rate_limit::rate_limit"],[49,3,1,"_CPPv4N4espp6Mt670111set_log_tagERKNSt11string_viewE","espp::Mt6701::set_log_tag"],[49,4,1,"_CPPv4N4espp6Mt670111set_log_tagERKNSt11string_viewE","espp::Mt6701::set_log_tag::tag"],[49,3,1,"_CPPv4N4espp6Mt670117set_log_verbosityEN4espp6Logger9VerbosityE","espp::Mt6701::set_log_verbosity"],[49,4,1,"_CPPv4N4espp6Mt670117set_log_verbosityEN4espp6Logger9VerbosityE","espp::Mt6701::set_log_verbosity::level"],[49,3,1,"_CPPv4N4espp6Mt67019set_probeERK8probe_fn","espp::Mt6701::set_probe"],[49,4,1,"_CPPv4N4espp6Mt67019set_probeERK8probe_fn","espp::Mt6701::set_probe::probe"],[49,3,1,"_CPPv4N4espp6Mt67018set_readERK7read_fn","espp::Mt6701::set_read"],[49,4,1,"_CPPv4N4espp6Mt67018set_readERK7read_fn","espp::Mt6701::set_read::read"],[49,3,1,"_CPPv4N4espp6Mt670117set_read_registerERK16read_register_fn","espp::Mt6701::set_read_register"],[49,4,1,"_CPPv4N4espp6Mt670117set_read_registerERK16read_register_fn","espp::Mt6701::set_read_register::read_register"],[49,3,1,"_CPPv4N4espp6Mt670134set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Mt6701::set_separate_write_then_read_delay"],[49,4,1,"_CPPv4N4espp6Mt670134set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Mt6701::set_separate_write_then_read_delay::delay"],[49,3,1,"_CPPv4N4espp6Mt67019set_writeERK8write_fn","espp::Mt6701::set_write"],[49,4,1,"_CPPv4N4espp6Mt67019set_writeERK8write_fn","espp::Mt6701::set_write::write"],[49,3,1,"_CPPv4N4espp6Mt670119set_write_then_readERK18write_then_read_fn","espp::Mt6701::set_write_then_read"],[49,4,1,"_CPPv4N4espp6Mt670119set_write_then_readERK18write_then_read_fn","espp::Mt6701::set_write_then_read::write_then_read"],[49,3,1,"_CPPv4N4espp6Mt67016updateERNSt10error_codeE","espp::Mt6701::update"],[49,4,1,"_CPPv4N4espp6Mt67016updateERNSt10error_codeE","espp::Mt6701::update::ec"],[49,8,1,"_CPPv4N4espp6Mt670118velocity_filter_fnE","espp::Mt6701::velocity_filter_fn"],[134,2,1,"_CPPv4N4espp4NdefE","espp::Ndef"],[134,6,1,"_CPPv4N4espp4Ndef7BleRoleE","espp::Ndef::BleRole"],[134,7,1,"_CPPv4N4espp4Ndef7BleRole12CENTRAL_ONLYE","espp::Ndef::BleRole::CENTRAL_ONLY"],[134,7,1,"_CPPv4N4espp4Ndef7BleRole18CENTRAL_PERIPHERALE","espp::Ndef::BleRole::CENTRAL_PERIPHERAL"],[134,7,1,"_CPPv4N4espp4Ndef7BleRole18PERIPHERAL_CENTRALE","espp::Ndef::BleRole::PERIPHERAL_CENTRAL"],[134,7,1,"_CPPv4N4espp4Ndef7BleRole15PERIPHERAL_ONLYE","espp::Ndef::BleRole::PERIPHERAL_ONLY"],[134,6,1,"_CPPv4N4espp4Ndef12BtAppearanceE","espp::Ndef::BtAppearance"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance5CLOCKE","espp::Ndef::BtAppearance::CLOCK"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance8COMPUTERE","espp::Ndef::BtAppearance::COMPUTER"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance7DISPLAYE","espp::Ndef::BtAppearance::DISPLAY"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance7GAMEPADE","espp::Ndef::BtAppearance::GAMEPAD"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance6GAMINGE","espp::Ndef::BtAppearance::GAMING"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance11GENERIC_HIDE","espp::Ndef::BtAppearance::GENERIC_HID"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance8JOYSTICKE","espp::Ndef::BtAppearance::JOYSTICK"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance8KEYBOARDE","espp::Ndef::BtAppearance::KEYBOARD"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance5MOUSEE","espp::Ndef::BtAppearance::MOUSE"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance5PHONEE","espp::Ndef::BtAppearance::PHONE"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance14REMOTE_CONTROLE","espp::Ndef::BtAppearance::REMOTE_CONTROL"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance8TOUCHPADE","espp::Ndef::BtAppearance::TOUCHPAD"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance7UNKNOWNE","espp::Ndef::BtAppearance::UNKNOWN"],[134,7,1,"_CPPv4N4espp4Ndef12BtAppearance5WATCHE","espp::Ndef::BtAppearance::WATCH"],[134,6,1,"_CPPv4N4espp4Ndef5BtEirE","espp::Ndef::BtEir"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir10APPEARANCEE","espp::Ndef::BtEir::APPEARANCE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir15CLASS_OF_DEVICEE","espp::Ndef::BtEir::CLASS_OF_DEVICE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir5FLAGSE","espp::Ndef::BtEir::FLAGS"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir7LE_ROLEE","espp::Ndef::BtEir::LE_ROLE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir18LE_SC_CONFIRMATIONE","espp::Ndef::BtEir::LE_SC_CONFIRMATION"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir12LE_SC_RANDOME","espp::Ndef::BtEir::LE_SC_RANDOM"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir15LONG_LOCAL_NAMEE","espp::Ndef::BtEir::LONG_LOCAL_NAME"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir3MACE","espp::Ndef::BtEir::MAC"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir22SECURITY_MANAGER_FLAGSE","espp::Ndef::BtEir::SECURITY_MANAGER_FLAGS"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir19SECURITY_MANAGER_TKE","espp::Ndef::BtEir::SECURITY_MANAGER_TK"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir16SHORT_LOCAL_NAMEE","espp::Ndef::BtEir::SHORT_LOCAL_NAME"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir12SP_HASH_C192E","espp::Ndef::BtEir::SP_HASH_C192"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir12SP_HASH_C256E","espp::Ndef::BtEir::SP_HASH_C256"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir12SP_HASH_R256E","espp::Ndef::BtEir::SP_HASH_R256"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir14SP_RANDOM_R192E","espp::Ndef::BtEir::SP_RANDOM_R192"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir14TX_POWER_LEVELE","espp::Ndef::BtEir::TX_POWER_LEVEL"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir22UUIDS_128_BIT_COMPLETEE","espp::Ndef::BtEir::UUIDS_128_BIT_COMPLETE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir21UUIDS_128_BIT_PARTIALE","espp::Ndef::BtEir::UUIDS_128_BIT_PARTIAL"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir21UUIDS_16_BIT_COMPLETEE","espp::Ndef::BtEir::UUIDS_16_BIT_COMPLETE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir20UUIDS_16_BIT_PARTIALE","espp::Ndef::BtEir::UUIDS_16_BIT_PARTIAL"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir21UUIDS_32_BIT_COMPLETEE","espp::Ndef::BtEir::UUIDS_32_BIT_COMPLETE"],[134,7,1,"_CPPv4N4espp4Ndef5BtEir20UUIDS_32_BIT_PARTIALE","espp::Ndef::BtEir::UUIDS_32_BIT_PARTIAL"],[134,6,1,"_CPPv4N4espp4Ndef6BtTypeE","espp::Ndef::BtType"],[134,7,1,"_CPPv4N4espp4Ndef6BtType3BLEE","espp::Ndef::BtType::BLE"],[134,7,1,"_CPPv4N4espp4Ndef6BtType5BREDRE","espp::Ndef::BtType::BREDR"],[134,6,1,"_CPPv4N4espp4Ndef17CarrierPowerStateE","espp::Ndef::CarrierPowerState"],[134,7,1,"_CPPv4N4espp4Ndef17CarrierPowerState10ACTIVATINGE","espp::Ndef::CarrierPowerState::ACTIVATING"],[134,7,1,"_CPPv4N4espp4Ndef17CarrierPowerState6ACTIVEE","espp::Ndef::CarrierPowerState::ACTIVE"],[134,7,1,"_CPPv4N4espp4Ndef17CarrierPowerState8INACTIVEE","espp::Ndef::CarrierPowerState::INACTIVE"],[134,7,1,"_CPPv4N4espp4Ndef17CarrierPowerState7UNKNOWNE","espp::Ndef::CarrierPowerState::UNKNOWN"],[134,1,1,"_CPPv4N4espp4Ndef16HANDOVER_VERSIONE","espp::Ndef::HANDOVER_VERSION"],[134,3,1,"_CPPv4N4espp4Ndef4NdefEN4espp4Ndef3TNFENSt11string_viewENSt11string_viewE","espp::Ndef::Ndef"],[134,4,1,"_CPPv4N4espp4Ndef4NdefEN4espp4Ndef3TNFENSt11string_viewENSt11string_viewE","espp::Ndef::Ndef::payload"],[134,4,1,"_CPPv4N4espp4Ndef4NdefEN4espp4Ndef3TNFENSt11string_viewENSt11string_viewE","espp::Ndef::Ndef::tnf"],[134,4,1,"_CPPv4N4espp4Ndef4NdefEN4espp4Ndef3TNFENSt11string_viewENSt11string_viewE","espp::Ndef::Ndef::type"],[134,6,1,"_CPPv4N4espp4Ndef3TNFE","espp::Ndef::TNF"],[134,7,1,"_CPPv4N4espp4Ndef3TNF12ABSOLUTE_URIE","espp::Ndef::TNF::ABSOLUTE_URI"],[134,7,1,"_CPPv4N4espp4Ndef3TNF5EMPTYE","espp::Ndef::TNF::EMPTY"],[134,7,1,"_CPPv4N4espp4Ndef3TNF13EXTERNAL_TYPEE","espp::Ndef::TNF::EXTERNAL_TYPE"],[134,7,1,"_CPPv4N4espp4Ndef3TNF10MIME_MEDIAE","espp::Ndef::TNF::MIME_MEDIA"],[134,7,1,"_CPPv4N4espp4Ndef3TNF8RESERVEDE","espp::Ndef::TNF::RESERVED"],[134,7,1,"_CPPv4N4espp4Ndef3TNF9UNCHANGEDE","espp::Ndef::TNF::UNCHANGED"],[134,7,1,"_CPPv4N4espp4Ndef3TNF7UNKNOWNE","espp::Ndef::TNF::UNKNOWN"],[134,7,1,"_CPPv4N4espp4Ndef3TNF10WELL_KNOWNE","espp::Ndef::TNF::WELL_KNOWN"],[134,6,1,"_CPPv4N4espp4Ndef3UicE","espp::Ndef::Uic"],[134,7,1,"_CPPv4N4espp4Ndef3Uic6BTGOEPE","espp::Ndef::Uic::BTGOEP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic7BTL2CAPE","espp::Ndef::Uic::BTL2CAP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic5BTSPPE","espp::Ndef::Uic::BTSPP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3DAVE","espp::Ndef::Uic::DAV"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4FILEE","espp::Ndef::Uic::FILE"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3FTPE","espp::Ndef::Uic::FTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4FTPSE","espp::Ndef::Uic::FTPS"],[134,7,1,"_CPPv4N4espp4Ndef3Uic8FTP_ANONE","espp::Ndef::Uic::FTP_ANON"],[134,7,1,"_CPPv4N4espp4Ndef3Uic7FTP_FTPE","espp::Ndef::Uic::FTP_FTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4HTTPE","espp::Ndef::Uic::HTTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic5HTTPSE","espp::Ndef::Uic::HTTPS"],[134,7,1,"_CPPv4N4espp4Ndef3Uic9HTTPS_WWWE","espp::Ndef::Uic::HTTPS_WWW"],[134,7,1,"_CPPv4N4espp4Ndef3Uic8HTTP_WWWE","espp::Ndef::Uic::HTTP_WWW"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4IMAPE","espp::Ndef::Uic::IMAP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic8IRDAOBEXE","espp::Ndef::Uic::IRDAOBEX"],[134,7,1,"_CPPv4N4espp4Ndef3Uic6MAILTOE","espp::Ndef::Uic::MAILTO"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4NEWSE","espp::Ndef::Uic::NEWS"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3NFSE","espp::Ndef::Uic::NFS"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4NONEE","espp::Ndef::Uic::NONE"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3POPE","espp::Ndef::Uic::POP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4RSTPE","espp::Ndef::Uic::RSTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4SFTPE","espp::Ndef::Uic::SFTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3SIPE","espp::Ndef::Uic::SIP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4SIPSE","espp::Ndef::Uic::SIPS"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3SMBE","espp::Ndef::Uic::SMB"],[134,7,1,"_CPPv4N4espp4Ndef3Uic7TCPOBEXE","espp::Ndef::Uic::TCPOBEX"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3TELE","espp::Ndef::Uic::TEL"],[134,7,1,"_CPPv4N4espp4Ndef3Uic6TELNETE","espp::Ndef::Uic::TELNET"],[134,7,1,"_CPPv4N4espp4Ndef3Uic4TFTPE","espp::Ndef::Uic::TFTP"],[134,7,1,"_CPPv4N4espp4Ndef3Uic3URNE","espp::Ndef::Uic::URN"],[134,7,1,"_CPPv4N4espp4Ndef3Uic7URN_EPCE","espp::Ndef::Uic::URN_EPC"],[134,7,1,"_CPPv4N4espp4Ndef3Uic10URN_EPC_IDE","espp::Ndef::Uic::URN_EPC_ID"],[134,7,1,"_CPPv4N4espp4Ndef3Uic11URN_EPC_PATE","espp::Ndef::Uic::URN_EPC_PAT"],[134,7,1,"_CPPv4N4espp4Ndef3Uic11URN_EPC_RAWE","espp::Ndef::Uic::URN_EPC_RAW"],[134,7,1,"_CPPv4N4espp4Ndef3Uic11URN_EPC_TAGE","espp::Ndef::Uic::URN_EPC_TAG"],[134,7,1,"_CPPv4N4espp4Ndef3Uic7URN_NFCE","espp::Ndef::Uic::URN_NFC"],[134,6,1,"_CPPv4N4espp4Ndef22WifiAuthenticationTypeE","espp::Ndef::WifiAuthenticationType"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType4OPENE","espp::Ndef::WifiAuthenticationType::OPEN"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType6SHAREDE","espp::Ndef::WifiAuthenticationType::SHARED"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType15WPA2_ENTERPRISEE","espp::Ndef::WifiAuthenticationType::WPA2_ENTERPRISE"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType13WPA2_PERSONALE","espp::Ndef::WifiAuthenticationType::WPA2_PERSONAL"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType14WPA_ENTERPRISEE","espp::Ndef::WifiAuthenticationType::WPA_ENTERPRISE"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType12WPA_PERSONALE","espp::Ndef::WifiAuthenticationType::WPA_PERSONAL"],[134,7,1,"_CPPv4N4espp4Ndef22WifiAuthenticationType17WPA_WPA2_PERSONALE","espp::Ndef::WifiAuthenticationType::WPA_WPA2_PERSONAL"],[134,2,1,"_CPPv4N4espp4Ndef10WifiConfigE","espp::Ndef::WifiConfig"],[134,1,1,"_CPPv4N4espp4Ndef10WifiConfig14authenticationE","espp::Ndef::WifiConfig::authentication"],[134,1,1,"_CPPv4N4espp4Ndef10WifiConfig10encryptionE","espp::Ndef::WifiConfig::encryption"],[134,1,1,"_CPPv4N4espp4Ndef10WifiConfig3keyE","espp::Ndef::WifiConfig::key"],[134,1,1,"_CPPv4N4espp4Ndef10WifiConfig11mac_addressE","espp::Ndef::WifiConfig::mac_address"],[134,1,1,"_CPPv4N4espp4Ndef10WifiConfig4ssidE","espp::Ndef::WifiConfig::ssid"],[134,6,1,"_CPPv4N4espp4Ndef18WifiEncryptionTypeE","espp::Ndef::WifiEncryptionType"],[134,7,1,"_CPPv4N4espp4Ndef18WifiEncryptionType3AESE","espp::Ndef::WifiEncryptionType::AES"],[134,7,1,"_CPPv4N4espp4Ndef18WifiEncryptionType4NONEE","espp::Ndef::WifiEncryptionType::NONE"],[134,7,1,"_CPPv4N4espp4Ndef18WifiEncryptionType4TKIPE","espp::Ndef::WifiEncryptionType::TKIP"],[134,7,1,"_CPPv4N4espp4Ndef18WifiEncryptionType3WEPE","espp::Ndef::WifiEncryptionType::WEP"],[134,3,1,"_CPPv4NK4espp4Ndef6get_idEv","espp::Ndef::get_id"],[134,3,1,"_CPPv4NK4espp4Ndef8get_sizeEv","espp::Ndef::get_size"],[134,3,1,"_CPPv4N4espp4Ndef24make_alternative_carrierERK17CarrierPowerStatei","espp::Ndef::make_alternative_carrier"],[134,4,1,"_CPPv4N4espp4Ndef24make_alternative_carrierERK17CarrierPowerStatei","espp::Ndef::make_alternative_carrier::carrier_data_ref"],[134,4,1,"_CPPv4N4espp4Ndef24make_alternative_carrierERK17CarrierPowerStatei","espp::Ndef::make_alternative_carrier::power_state"],[134,3,1,"_CPPv4N4espp4Ndef21make_android_launcherENSt11string_viewE","espp::Ndef::make_android_launcher"],[134,4,1,"_CPPv4N4espp4Ndef21make_android_launcherENSt11string_viewE","espp::Ndef::make_android_launcher::uri"],[134,3,1,"_CPPv4N4espp4Ndef21make_handover_requestEi","espp::Ndef::make_handover_request"],[134,4,1,"_CPPv4N4espp4Ndef21make_handover_requestEi","espp::Ndef::make_handover_request::carrier_data_ref"],[134,3,1,"_CPPv4N4espp4Ndef20make_handover_selectEi","espp::Ndef::make_handover_select"],[134,4,1,"_CPPv4N4espp4Ndef20make_handover_selectEi","espp::Ndef::make_handover_select::carrier_data_ref"],[134,3,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::appearance"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::confirm_value"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::mac_addr"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::name"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::random_value"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::role"],[134,4,1,"_CPPv4N4espp4Ndef19make_le_oob_pairingE8uint64_tN4espp4Ndef7BleRoleENSt11string_viewEN4espp4Ndef12BtAppearanceENSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_le_oob_pairing::tk"],[134,3,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing"],[134,4,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing::confirm_value"],[134,4,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing::device_class"],[134,4,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing::mac_addr"],[134,4,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing::name"],[134,4,1,"_CPPv4N4espp4Ndef16make_oob_pairingE8uint64_t8uint32_tNSt11string_viewENSt11string_viewENSt11string_viewE","espp::Ndef::make_oob_pairing::random_value"],[134,3,1,"_CPPv4N4espp4Ndef9make_textENSt11string_viewE","espp::Ndef::make_text"],[134,4,1,"_CPPv4N4espp4Ndef9make_textENSt11string_viewE","espp::Ndef::make_text::text"],[134,3,1,"_CPPv4N4espp4Ndef8make_uriENSt11string_viewEN4espp4Ndef3UicE","espp::Ndef::make_uri"],[134,4,1,"_CPPv4N4espp4Ndef8make_uriENSt11string_viewEN4espp4Ndef3UicE","espp::Ndef::make_uri::uic"],[134,4,1,"_CPPv4N4espp4Ndef8make_uriENSt11string_viewEN4espp4Ndef3UicE","espp::Ndef::make_uri::uri"],[134,3,1,"_CPPv4N4espp4Ndef16make_wifi_configERKN4espp4Ndef10WifiConfigE","espp::Ndef::make_wifi_config"],[134,4,1,"_CPPv4N4espp4Ndef16make_wifi_configERKN4espp4Ndef10WifiConfigE","espp::Ndef::make_wifi_config::config"],[134,3,1,"_CPPv4N4espp4Ndef7payloadEv","espp::Ndef::payload"],[134,3,1,"_CPPv4N4espp4Ndef9serializeEbb","espp::Ndef::serialize"],[134,4,1,"_CPPv4N4espp4Ndef9serializeEbb","espp::Ndef::serialize::message_begin"],[134,4,1,"_CPPv4N4espp4Ndef9serializeEbb","espp::Ndef::serialize::message_end"],[134,3,1,"_CPPv4N4espp4Ndef6set_idEi","espp::Ndef::set_id"],[134,4,1,"_CPPv4N4espp4Ndef6set_idEi","espp::Ndef::set_id::id"],[137,2,1,"_CPPv4N4espp3NvsE","espp::Nvs"],[137,3,1,"_CPPv4N4espp3Nvs3NvsEv","espp::Nvs::Nvs"],[137,3,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewENSt11string_viewERNSt10error_codeE","espp::Nvs::erase"],[137,3,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewERNSt10error_codeE","espp::Nvs::erase"],[137,3,1,"_CPPv4N4espp3Nvs5eraseERNSt10error_codeE","espp::Nvs::erase"],[137,4,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewENSt11string_viewERNSt10error_codeE","espp::Nvs::erase::ec"],[137,4,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewERNSt10error_codeE","espp::Nvs::erase::ec"],[137,4,1,"_CPPv4N4espp3Nvs5eraseERNSt10error_codeE","espp::Nvs::erase::ec"],[137,4,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewENSt11string_viewERNSt10error_codeE","espp::Nvs::erase::key"],[137,4,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewENSt11string_viewERNSt10error_codeE","espp::Nvs::erase::ns_name"],[137,4,1,"_CPPv4N4espp3Nvs5eraseENSt11string_viewERNSt10error_codeE","espp::Nvs::erase::ns_name"],[137,3,1,"_CPPv4NK4espp3Nvs13get_log_levelEv","espp::Nvs::get_log_level"],[137,3,1,"_CPPv4NK4espp3Nvs17get_log_verbosityEv","espp::Nvs::get_log_verbosity"],[137,3,1,"_CPPv4NK4espp3Nvs8get_nameEv","espp::Nvs::get_name"],[137,3,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var"],[137,3,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var"],[137,5,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::T"],[137,5,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::T"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::default_value"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::default_value"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvNSt11string_viewENSt11string_viewER1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::value"],[137,4,1,"_CPPv4I0EN4espp3Nvs14get_or_set_varEvPKcPKcR1T1TRNSt10error_codeE","espp::Nvs::get_or_set_var::value"],[137,3,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var"],[137,3,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var"],[137,5,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var::T"],[137,5,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var::T"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvNSt11string_viewENSt11string_viewER1TRNSt10error_codeE","espp::Nvs::get_var::value"],[137,4,1,"_CPPv4I0EN4espp3Nvs7get_varEvPKcPKcR1TRNSt10error_codeE","espp::Nvs::get_var::value"],[137,3,1,"_CPPv4N4espp3Nvs4initERNSt10error_codeE","espp::Nvs::init"],[137,4,1,"_CPPv4N4espp3Nvs4initERNSt10error_codeE","espp::Nvs::init::ec"],[137,3,1,"_CPPv4N4espp3Nvs13set_log_levelEN4espp6Logger9VerbosityE","espp::Nvs::set_log_level"],[137,4,1,"_CPPv4N4espp3Nvs13set_log_levelEN4espp6Logger9VerbosityE","espp::Nvs::set_log_level::level"],[137,3,1,"_CPPv4N4espp3Nvs18set_log_rate_limitENSt6chrono8durationIfEE","espp::Nvs::set_log_rate_limit"],[137,4,1,"_CPPv4N4espp3Nvs18set_log_rate_limitENSt6chrono8durationIfEE","espp::Nvs::set_log_rate_limit::rate_limit"],[137,3,1,"_CPPv4N4espp3Nvs11set_log_tagERKNSt11string_viewE","espp::Nvs::set_log_tag"],[137,4,1,"_CPPv4N4espp3Nvs11set_log_tagERKNSt11string_viewE","espp::Nvs::set_log_tag::tag"],[137,3,1,"_CPPv4N4espp3Nvs17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Nvs::set_log_verbosity"],[137,4,1,"_CPPv4N4espp3Nvs17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Nvs::set_log_verbosity::level"],[137,3,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var"],[137,3,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var"],[137,5,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var::T"],[137,5,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var::T"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var::ec"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var::key"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var::ns_name"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvNSt11string_viewENSt11string_viewE1TRNSt10error_codeE","espp::Nvs::set_var::value"],[137,4,1,"_CPPv4I0EN4espp3Nvs7set_varEvPKcPKc1TRNSt10error_codeE","espp::Nvs::set_var::value"],[137,2,1,"_CPPv4N4espp9NvsHandleE","espp::NvsHandle"],[137,3,1,"_CPPv4N4espp9NvsHandle9NvsHandleEPKcRNSt10error_codeE","espp::NvsHandle::NvsHandle"],[137,4,1,"_CPPv4N4espp9NvsHandle9NvsHandleEPKcRNSt10error_codeE","espp::NvsHandle::NvsHandle::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle9NvsHandleEPKcRNSt10error_codeE","espp::NvsHandle::NvsHandle::ns_name"],[137,3,1,"_CPPv4N4espp9NvsHandle6commitERNSt10error_codeE","espp::NvsHandle::commit"],[137,4,1,"_CPPv4N4espp9NvsHandle6commitERNSt10error_codeE","espp::NvsHandle::commit::ec"],[137,3,1,"_CPPv4N4espp9NvsHandle5eraseENSt11string_viewERNSt10error_codeE","espp::NvsHandle::erase"],[137,3,1,"_CPPv4N4espp9NvsHandle5eraseEPKcRNSt10error_codeE","espp::NvsHandle::erase"],[137,3,1,"_CPPv4N4espp9NvsHandle5eraseERNSt10error_codeE","espp::NvsHandle::erase"],[137,4,1,"_CPPv4N4espp9NvsHandle5eraseENSt11string_viewERNSt10error_codeE","espp::NvsHandle::erase::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle5eraseEPKcRNSt10error_codeE","espp::NvsHandle::erase::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle5eraseERNSt10error_codeE","espp::NvsHandle::erase::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle5eraseENSt11string_viewERNSt10error_codeE","espp::NvsHandle::erase::key"],[137,4,1,"_CPPv4N4espp9NvsHandle5eraseEPKcRNSt10error_codeE","espp::NvsHandle::erase::key"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbKbRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfKfRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRbKbRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRbRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRfKfRNSt10error_codeE","espp::NvsHandle::get"],[137,3,1,"_CPPv4N4espp9NvsHandle3getEPKcRfRNSt10error_codeE","espp::NvsHandle::get"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get::T"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TRNSt10error_codeE","espp::NvsHandle::get::T"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get::T"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TRNSt10error_codeE","espp::NvsHandle::get::T"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbKbRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfKfRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbKbRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfKfRNSt10error_codeE","espp::NvsHandle::get::default_value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbKbRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfKfRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbKbRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfKfRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfRNSt10error_codeE","espp::NvsHandle::get::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbKbRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfKfRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbKbRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfKfRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfRNSt10error_codeE","espp::NvsHandle::get::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TK1TRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvNSt11string_viewER1TRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TK1TRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3getEvPKcR1TRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERNSt6stringERNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbKbRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERbRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfKfRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getENSt11string_viewERfRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERKNSt6stringERNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRNSt6stringERNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbKbRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRbRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfKfRNSt10error_codeE","espp::NvsHandle::get::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3getEPKcRfRNSt10error_codeE","espp::NvsHandle::get::value"],[137,3,1,"_CPPv4NK4espp9NvsHandle13get_log_levelEv","espp::NvsHandle::get_log_level"],[137,3,1,"_CPPv4NK4espp9NvsHandle17get_log_verbosityEv","espp::NvsHandle::get_log_verbosity"],[137,3,1,"_CPPv4NK4espp9NvsHandle8get_nameEv","espp::NvsHandle::get_name"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3setEvNSt11string_viewE1TRNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4I0EN4espp9NvsHandle3setEvPKc1TRNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewERKNSt6stringERNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEbRNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEfRNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setEPKcRKNSt6stringERNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setEPKcbRNSt10error_codeE","espp::NvsHandle::set"],[137,3,1,"_CPPv4N4espp9NvsHandle3setEPKcfRNSt10error_codeE","espp::NvsHandle::set"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3setEvNSt11string_viewE1TRNSt10error_codeE","espp::NvsHandle::set::T"],[137,5,1,"_CPPv4I0EN4espp9NvsHandle3setEvPKc1TRNSt10error_codeE","espp::NvsHandle::set::T"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvNSt11string_viewE1TRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvPKc1TRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewERKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEbRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEfRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcRKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcbRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcfRNSt10error_codeE","espp::NvsHandle::set::ec"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvNSt11string_viewE1TRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvPKc1TRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewERKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEbRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEfRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcRKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcbRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcfRNSt10error_codeE","espp::NvsHandle::set::key"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvNSt11string_viewE1TRNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4I0EN4espp9NvsHandle3setEvPKc1TRNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewERKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEbRNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setENSt11string_viewEfRNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcRKNSt6stringERNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcbRNSt10error_codeE","espp::NvsHandle::set::value"],[137,4,1,"_CPPv4N4espp9NvsHandle3setEPKcfRNSt10error_codeE","espp::NvsHandle::set::value"],[137,3,1,"_CPPv4N4espp9NvsHandle13set_log_levelEN4espp6Logger9VerbosityE","espp::NvsHandle::set_log_level"],[137,4,1,"_CPPv4N4espp9NvsHandle13set_log_levelEN4espp6Logger9VerbosityE","espp::NvsHandle::set_log_level::level"],[137,3,1,"_CPPv4N4espp9NvsHandle18set_log_rate_limitENSt6chrono8durationIfEE","espp::NvsHandle::set_log_rate_limit"],[137,4,1,"_CPPv4N4espp9NvsHandle18set_log_rate_limitENSt6chrono8durationIfEE","espp::NvsHandle::set_log_rate_limit::rate_limit"],[137,3,1,"_CPPv4N4espp9NvsHandle11set_log_tagERKNSt11string_viewE","espp::NvsHandle::set_log_tag"],[137,4,1,"_CPPv4N4espp9NvsHandle11set_log_tagERKNSt11string_viewE","espp::NvsHandle::set_log_tag::tag"],[137,3,1,"_CPPv4N4espp9NvsHandle17set_log_verbosityEN4espp6Logger9VerbosityE","espp::NvsHandle::set_log_verbosity"],[137,4,1,"_CPPv4N4espp9NvsHandle17set_log_verbosityEN4espp6Logger9VerbosityE","espp::NvsHandle::set_log_verbosity::level"],[8,2,1,"_CPPv4N4espp10OneshotAdcE","espp::OneshotAdc"],[8,2,1,"_CPPv4N4espp10OneshotAdc6ConfigE","espp::OneshotAdc::Config"],[8,1,1,"_CPPv4N4espp10OneshotAdc6Config8channelsE","espp::OneshotAdc::Config::channels"],[8,1,1,"_CPPv4N4espp10OneshotAdc6Config9log_levelE","espp::OneshotAdc::Config::log_level"],[8,1,1,"_CPPv4N4espp10OneshotAdc6Config4unitE","espp::OneshotAdc::Config::unit"],[8,3,1,"_CPPv4N4espp10OneshotAdc10OneshotAdcERK6Config","espp::OneshotAdc::OneshotAdc"],[8,4,1,"_CPPv4N4espp10OneshotAdc10OneshotAdcERK6Config","espp::OneshotAdc::OneshotAdc::config"],[8,3,1,"_CPPv4NK4espp10OneshotAdc13get_log_levelEv","espp::OneshotAdc::get_log_level"],[8,3,1,"_CPPv4NK4espp10OneshotAdc17get_log_verbosityEv","espp::OneshotAdc::get_log_verbosity"],[8,3,1,"_CPPv4NK4espp10OneshotAdc8get_nameEv","espp::OneshotAdc::get_name"],[8,3,1,"_CPPv4N4espp10OneshotAdc11read_all_mvEv","espp::OneshotAdc::read_all_mv"],[8,3,1,"_CPPv4N4espp10OneshotAdc7read_mvERK9AdcConfig","espp::OneshotAdc::read_mv"],[8,4,1,"_CPPv4N4espp10OneshotAdc7read_mvERK9AdcConfig","espp::OneshotAdc::read_mv::config"],[8,3,1,"_CPPv4N4espp10OneshotAdc8read_rawERK9AdcConfig","espp::OneshotAdc::read_raw"],[8,4,1,"_CPPv4N4espp10OneshotAdc8read_rawERK9AdcConfig","espp::OneshotAdc::read_raw::config"],[8,3,1,"_CPPv4N4espp10OneshotAdc13set_log_levelEN4espp6Logger9VerbosityE","espp::OneshotAdc::set_log_level"],[8,4,1,"_CPPv4N4espp10OneshotAdc13set_log_levelEN4espp6Logger9VerbosityE","espp::OneshotAdc::set_log_level::level"],[8,3,1,"_CPPv4N4espp10OneshotAdc18set_log_rate_limitENSt6chrono8durationIfEE","espp::OneshotAdc::set_log_rate_limit"],[8,4,1,"_CPPv4N4espp10OneshotAdc18set_log_rate_limitENSt6chrono8durationIfEE","espp::OneshotAdc::set_log_rate_limit::rate_limit"],[8,3,1,"_CPPv4N4espp10OneshotAdc11set_log_tagERKNSt11string_viewE","espp::OneshotAdc::set_log_tag"],[8,4,1,"_CPPv4N4espp10OneshotAdc11set_log_tagERKNSt11string_viewE","espp::OneshotAdc::set_log_tag::tag"],[8,3,1,"_CPPv4N4espp10OneshotAdc17set_log_verbosityEN4espp6Logger9VerbosityE","espp::OneshotAdc::set_log_verbosity"],[8,4,1,"_CPPv4N4espp10OneshotAdc17set_log_verbosityEN4espp6Logger9VerbosityE","espp::OneshotAdc::set_log_verbosity::level"],[8,3,1,"_CPPv4N4espp10OneshotAdcD0Ev","espp::OneshotAdc::~OneshotAdc"],[139,2,1,"_CPPv4N4espp3PidE","espp::Pid"],[139,2,1,"_CPPv4N4espp3Pid6ConfigE","espp::Pid::Config"],[139,1,1,"_CPPv4N4espp3Pid6Config14integrator_maxE","espp::Pid::Config::integrator_max"],[139,1,1,"_CPPv4N4espp3Pid6Config14integrator_minE","espp::Pid::Config::integrator_min"],[139,1,1,"_CPPv4N4espp3Pid6Config2kdE","espp::Pid::Config::kd"],[139,1,1,"_CPPv4N4espp3Pid6Config2kiE","espp::Pid::Config::ki"],[139,1,1,"_CPPv4N4espp3Pid6Config2kpE","espp::Pid::Config::kp"],[139,1,1,"_CPPv4N4espp3Pid6Config9log_levelE","espp::Pid::Config::log_level"],[139,1,1,"_CPPv4N4espp3Pid6Config10output_maxE","espp::Pid::Config::output_max"],[139,1,1,"_CPPv4N4espp3Pid6Config10output_minE","espp::Pid::Config::output_min"],[139,3,1,"_CPPv4N4espp3Pid3PidERK6Config","espp::Pid::Pid"],[139,4,1,"_CPPv4N4espp3Pid3PidERK6Config","espp::Pid::Pid::config"],[139,3,1,"_CPPv4N4espp3Pid12change_gainsERK6Configb","espp::Pid::change_gains"],[139,4,1,"_CPPv4N4espp3Pid12change_gainsERK6Configb","espp::Pid::change_gains::config"],[139,4,1,"_CPPv4N4espp3Pid12change_gainsERK6Configb","espp::Pid::change_gains::reset_state"],[139,3,1,"_CPPv4N4espp3Pid5clearEv","espp::Pid::clear"],[139,3,1,"_CPPv4NK4espp3Pid10get_configEv","espp::Pid::get_config"],[139,3,1,"_CPPv4NK4espp3Pid9get_errorEv","espp::Pid::get_error"],[139,3,1,"_CPPv4NK4espp3Pid14get_integratorEv","espp::Pid::get_integrator"],[139,3,1,"_CPPv4NK4espp3Pid13get_log_levelEv","espp::Pid::get_log_level"],[139,3,1,"_CPPv4NK4espp3Pid17get_log_verbosityEv","espp::Pid::get_log_verbosity"],[139,3,1,"_CPPv4NK4espp3Pid8get_nameEv","espp::Pid::get_name"],[139,3,1,"_CPPv4N4espp3PidclEf","espp::Pid::operator()"],[139,4,1,"_CPPv4N4espp3PidclEf","espp::Pid::operator()::error"],[139,3,1,"_CPPv4N4espp3Pid10set_configERK6Configb","espp::Pid::set_config"],[139,4,1,"_CPPv4N4espp3Pid10set_configERK6Configb","espp::Pid::set_config::config"],[139,4,1,"_CPPv4N4espp3Pid10set_configERK6Configb","espp::Pid::set_config::reset_state"],[139,3,1,"_CPPv4N4espp3Pid13set_log_levelEN4espp6Logger9VerbosityE","espp::Pid::set_log_level"],[139,4,1,"_CPPv4N4espp3Pid13set_log_levelEN4espp6Logger9VerbosityE","espp::Pid::set_log_level::level"],[139,3,1,"_CPPv4N4espp3Pid18set_log_rate_limitENSt6chrono8durationIfEE","espp::Pid::set_log_rate_limit"],[139,4,1,"_CPPv4N4espp3Pid18set_log_rate_limitENSt6chrono8durationIfEE","espp::Pid::set_log_rate_limit::rate_limit"],[139,3,1,"_CPPv4N4espp3Pid11set_log_tagERKNSt11string_viewE","espp::Pid::set_log_tag"],[139,4,1,"_CPPv4N4espp3Pid11set_log_tagERKNSt11string_viewE","espp::Pid::set_log_tag::tag"],[139,3,1,"_CPPv4N4espp3Pid17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Pid::set_log_verbosity"],[139,4,1,"_CPPv4N4espp3Pid17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Pid::set_log_verbosity::level"],[139,3,1,"_CPPv4N4espp3Pid6updateEf","espp::Pid::update"],[139,4,1,"_CPPv4N4espp3Pid6updateEf","espp::Pid::update::error"],[92,2,1,"_CPPv4N4espp12PointerInputE","espp::PointerInput"],[92,2,1,"_CPPv4N4espp12PointerInput6ConfigE","espp::PointerInput::Config"],[92,1,1,"_CPPv4N4espp12PointerInput6Config13cursor_radiusE","espp::PointerInput::Config::cursor_radius"],[92,1,1,"_CPPv4N4espp12PointerInput6Config9log_levelE","espp::PointerInput::Config::log_level"],[92,1,1,"_CPPv4N4espp12PointerInput6Config4readE","espp::PointerInput::Config::read"],[92,3,1,"_CPPv4N4espp12PointerInput12PointerInputERK6Config","espp::PointerInput::PointerInput"],[92,4,1,"_CPPv4N4espp12PointerInput12PointerInputERK6Config","espp::PointerInput::PointerInput::config"],[92,3,1,"_CPPv4N4espp12PointerInput17get_cursor_objectEv","espp::PointerInput::get_cursor_object"],[92,3,1,"_CPPv4NK4espp12PointerInput13get_log_levelEv","espp::PointerInput::get_log_level"],[92,3,1,"_CPPv4NK4espp12PointerInput17get_log_verbosityEv","espp::PointerInput::get_log_verbosity"],[92,3,1,"_CPPv4NK4espp12PointerInput8get_nameEv","espp::PointerInput::get_name"],[92,3,1,"_CPPv4N4espp12PointerInput24get_pointer_input_deviceEv","espp::PointerInput::get_pointer_input_device"],[92,8,1,"_CPPv4N4espp12PointerInput7read_fnE","espp::PointerInput::read_fn"],[92,3,1,"_CPPv4N4espp12PointerInput10set_cursorEP8lv_obj_t","espp::PointerInput::set_cursor"],[92,3,1,"_CPPv4N4espp12PointerInput10set_cursorEPK14lv_image_dsc_t","espp::PointerInput::set_cursor"],[92,4,1,"_CPPv4N4espp12PointerInput10set_cursorEP8lv_obj_t","espp::PointerInput::set_cursor::cursor_obj"],[92,4,1,"_CPPv4N4espp12PointerInput10set_cursorEPK14lv_image_dsc_t","espp::PointerInput::set_cursor::icon"],[92,3,1,"_CPPv4N4espp12PointerInput13set_log_levelEN4espp6Logger9VerbosityE","espp::PointerInput::set_log_level"],[92,4,1,"_CPPv4N4espp12PointerInput13set_log_levelEN4espp6Logger9VerbosityE","espp::PointerInput::set_log_level::level"],[92,3,1,"_CPPv4N4espp12PointerInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::PointerInput::set_log_rate_limit"],[92,4,1,"_CPPv4N4espp12PointerInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::PointerInput::set_log_rate_limit::rate_limit"],[92,3,1,"_CPPv4N4espp12PointerInput11set_log_tagERKNSt11string_viewE","espp::PointerInput::set_log_tag"],[92,4,1,"_CPPv4N4espp12PointerInput11set_log_tagERKNSt11string_viewE","espp::PointerInput::set_log_tag::tag"],[92,3,1,"_CPPv4N4espp12PointerInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::PointerInput::set_log_verbosity"],[92,4,1,"_CPPv4N4espp12PointerInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::PointerInput::set_log_verbosity::level"],[92,3,1,"_CPPv4N4espp12PointerInputD0Ev","espp::PointerInput::~PointerInput"],[141,2,1,"_CPPv4N4espp8QwiicNesE","espp::QwiicNes"],[141,6,1,"_CPPv4N4espp8QwiicNes6ButtonE","espp::QwiicNes::Button"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button1AE","espp::QwiicNes::Button::A"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button1BE","espp::QwiicNes::Button::B"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button4DOWNE","espp::QwiicNes::Button::DOWN"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button4LEFTE","espp::QwiicNes::Button::LEFT"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button5RIGHTE","espp::QwiicNes::Button::RIGHT"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button6SELECTE","espp::QwiicNes::Button::SELECT"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button5STARTE","espp::QwiicNes::Button::START"],[141,7,1,"_CPPv4N4espp8QwiicNes6Button2UPE","espp::QwiicNes::Button::UP"],[141,2,1,"_CPPv4N4espp8QwiicNes11ButtonStateE","espp::QwiicNes::ButtonState"],[141,2,1,"_CPPv4N4espp8QwiicNes6ConfigE","espp::QwiicNes::Config"],[141,1,1,"_CPPv4N4espp8QwiicNes6Config9log_levelE","espp::QwiicNes::Config::log_level"],[141,1,1,"_CPPv4N4espp8QwiicNes6Config13read_registerE","espp::QwiicNes::Config::read_register"],[141,1,1,"_CPPv4N4espp8QwiicNes6Config5writeE","espp::QwiicNes::Config::write"],[141,1,1,"_CPPv4N4espp8QwiicNes15DEFAULT_ADDRESSE","espp::QwiicNes::DEFAULT_ADDRESS"],[141,3,1,"_CPPv4N4espp8QwiicNes8QwiicNesERK6Config","espp::QwiicNes::QwiicNes"],[141,4,1,"_CPPv4N4espp8QwiicNes8QwiicNesERK6Config","espp::QwiicNes::QwiicNes::config"],[141,3,1,"_CPPv4NK4espp8QwiicNes16get_button_stateEv","espp::QwiicNes::get_button_state"],[141,3,1,"_CPPv4NK4espp8QwiicNes13get_log_levelEv","espp::QwiicNes::get_log_level"],[141,3,1,"_CPPv4NK4espp8QwiicNes17get_log_verbosityEv","espp::QwiicNes::get_log_verbosity"],[141,3,1,"_CPPv4NK4espp8QwiicNes8get_nameEv","espp::QwiicNes::get_name"],[141,3,1,"_CPPv4N4espp8QwiicNes10is_pressedE7uint8_t6Button","espp::QwiicNes::is_pressed"],[141,3,1,"_CPPv4NK4espp8QwiicNes10is_pressedE6Button","espp::QwiicNes::is_pressed"],[141,4,1,"_CPPv4N4espp8QwiicNes10is_pressedE7uint8_t6Button","espp::QwiicNes::is_pressed::button"],[141,4,1,"_CPPv4NK4espp8QwiicNes10is_pressedE6Button","espp::QwiicNes::is_pressed::button"],[141,4,1,"_CPPv4N4espp8QwiicNes10is_pressedE7uint8_t6Button","espp::QwiicNes::is_pressed::state"],[141,3,1,"_CPPv4N4espp8QwiicNes5probeERNSt10error_codeE","espp::QwiicNes::probe"],[141,4,1,"_CPPv4N4espp8QwiicNes5probeERNSt10error_codeE","espp::QwiicNes::probe::ec"],[141,8,1,"_CPPv4N4espp8QwiicNes8probe_fnE","espp::QwiicNes::probe_fn"],[141,3,1,"_CPPv4N4espp8QwiicNes12read_addressERNSt10error_codeE","espp::QwiicNes::read_address"],[141,4,1,"_CPPv4N4espp8QwiicNes12read_addressERNSt10error_codeE","espp::QwiicNes::read_address::ec"],[141,3,1,"_CPPv4N4espp8QwiicNes18read_current_stateERNSt10error_codeE","espp::QwiicNes::read_current_state"],[141,4,1,"_CPPv4N4espp8QwiicNes18read_current_stateERNSt10error_codeE","espp::QwiicNes::read_current_state::ec"],[141,3,1,"_CPPv4N4espp8QwiicNes11set_addressE7uint8_t","espp::QwiicNes::set_address"],[141,4,1,"_CPPv4N4espp8QwiicNes11set_addressE7uint8_t","espp::QwiicNes::set_address::address"],[141,3,1,"_CPPv4N4espp8QwiicNes10set_configERK6Config","espp::QwiicNes::set_config"],[141,3,1,"_CPPv4N4espp8QwiicNes10set_configERR6Config","espp::QwiicNes::set_config"],[141,4,1,"_CPPv4N4espp8QwiicNes10set_configERK6Config","espp::QwiicNes::set_config::config"],[141,4,1,"_CPPv4N4espp8QwiicNes10set_configERR6Config","espp::QwiicNes::set_config::config"],[141,3,1,"_CPPv4N4espp8QwiicNes13set_log_levelEN4espp6Logger9VerbosityE","espp::QwiicNes::set_log_level"],[141,4,1,"_CPPv4N4espp8QwiicNes13set_log_levelEN4espp6Logger9VerbosityE","espp::QwiicNes::set_log_level::level"],[141,3,1,"_CPPv4N4espp8QwiicNes18set_log_rate_limitENSt6chrono8durationIfEE","espp::QwiicNes::set_log_rate_limit"],[141,4,1,"_CPPv4N4espp8QwiicNes18set_log_rate_limitENSt6chrono8durationIfEE","espp::QwiicNes::set_log_rate_limit::rate_limit"],[141,3,1,"_CPPv4N4espp8QwiicNes11set_log_tagERKNSt11string_viewE","espp::QwiicNes::set_log_tag"],[141,4,1,"_CPPv4N4espp8QwiicNes11set_log_tagERKNSt11string_viewE","espp::QwiicNes::set_log_tag::tag"],[141,3,1,"_CPPv4N4espp8QwiicNes17set_log_verbosityEN4espp6Logger9VerbosityE","espp::QwiicNes::set_log_verbosity"],[141,4,1,"_CPPv4N4espp8QwiicNes17set_log_verbosityEN4espp6Logger9VerbosityE","espp::QwiicNes::set_log_verbosity::level"],[141,3,1,"_CPPv4N4espp8QwiicNes9set_probeERK8probe_fn","espp::QwiicNes::set_probe"],[141,4,1,"_CPPv4N4espp8QwiicNes9set_probeERK8probe_fn","espp::QwiicNes::set_probe::probe"],[141,3,1,"_CPPv4N4espp8QwiicNes8set_readERK7read_fn","espp::QwiicNes::set_read"],[141,4,1,"_CPPv4N4espp8QwiicNes8set_readERK7read_fn","espp::QwiicNes::set_read::read"],[141,3,1,"_CPPv4N4espp8QwiicNes17set_read_registerERK16read_register_fn","espp::QwiicNes::set_read_register"],[141,4,1,"_CPPv4N4espp8QwiicNes17set_read_registerERK16read_register_fn","espp::QwiicNes::set_read_register::read_register"],[141,3,1,"_CPPv4N4espp8QwiicNes34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::QwiicNes::set_separate_write_then_read_delay"],[141,4,1,"_CPPv4N4espp8QwiicNes34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::QwiicNes::set_separate_write_then_read_delay::delay"],[141,3,1,"_CPPv4N4espp8QwiicNes9set_writeERK8write_fn","espp::QwiicNes::set_write"],[141,4,1,"_CPPv4N4espp8QwiicNes9set_writeERK8write_fn","espp::QwiicNes::set_write::write"],[141,3,1,"_CPPv4N4espp8QwiicNes19set_write_then_readERK18write_then_read_fn","espp::QwiicNes::set_write_then_read"],[141,4,1,"_CPPv4N4espp8QwiicNes19set_write_then_readERK18write_then_read_fn","espp::QwiicNes::set_write_then_read::write_then_read"],[141,3,1,"_CPPv4N4espp8QwiicNes6updateERNSt10error_codeE","espp::QwiicNes::update"],[141,4,1,"_CPPv4N4espp8QwiicNes6updateERNSt10error_codeE","espp::QwiicNes::update::ec"],[141,3,1,"_CPPv4N4espp8QwiicNes14update_addressE7uint8_tRNSt10error_codeE","espp::QwiicNes::update_address"],[141,4,1,"_CPPv4N4espp8QwiicNes14update_addressE7uint8_tRNSt10error_codeE","espp::QwiicNes::update_address::ec"],[141,4,1,"_CPPv4N4espp8QwiicNes14update_addressE7uint8_tRNSt10error_codeE","espp::QwiicNes::update_address::new_address"],[120,2,1,"_CPPv4I0EN4espp11RangeMapperE","espp::RangeMapper"],[120,2,1,"_CPPv4N4espp11RangeMapper6ConfigE","espp::RangeMapper::Config"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config6centerE","espp::RangeMapper::Config::center"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config15center_deadbandE","espp::RangeMapper::Config::center_deadband"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config13invert_outputE","espp::RangeMapper::Config::invert_output"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config7maximumE","espp::RangeMapper::Config::maximum"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config7minimumE","espp::RangeMapper::Config::minimum"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config13output_centerE","espp::RangeMapper::Config::output_center"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config12output_rangeE","espp::RangeMapper::Config::output_range"],[120,1,1,"_CPPv4N4espp11RangeMapper6Config14range_deadbandE","espp::RangeMapper::Config::range_deadband"],[120,3,1,"_CPPv4N4espp11RangeMapper11RangeMapperERK6Config","espp::RangeMapper::RangeMapper"],[120,3,1,"_CPPv4N4espp11RangeMapper11RangeMapperEv","espp::RangeMapper::RangeMapper"],[120,4,1,"_CPPv4N4espp11RangeMapper11RangeMapperERK6Config","espp::RangeMapper::RangeMapper::config"],[120,5,1,"_CPPv4I0EN4espp11RangeMapperE","espp::RangeMapper::T"],[120,3,1,"_CPPv4N4espp11RangeMapper9configureERK6Config","espp::RangeMapper::configure"],[120,4,1,"_CPPv4N4espp11RangeMapper9configureERK6Config","espp::RangeMapper::configure::config"],[120,3,1,"_CPPv4NK4espp11RangeMapper10get_centerEv","espp::RangeMapper::get_center"],[120,3,1,"_CPPv4NK4espp11RangeMapper19get_center_deadbandEv","espp::RangeMapper::get_center_deadband"],[120,3,1,"_CPPv4NK4espp11RangeMapper11get_maximumEv","espp::RangeMapper::get_maximum"],[120,3,1,"_CPPv4NK4espp11RangeMapper11get_minimumEv","espp::RangeMapper::get_minimum"],[120,3,1,"_CPPv4NK4espp11RangeMapper17get_output_centerEv","espp::RangeMapper::get_output_center"],[120,3,1,"_CPPv4NK4espp11RangeMapper14get_output_maxEv","espp::RangeMapper::get_output_max"],[120,3,1,"_CPPv4NK4espp11RangeMapper14get_output_minEv","espp::RangeMapper::get_output_min"],[120,3,1,"_CPPv4NK4espp11RangeMapper16get_output_rangeEv","espp::RangeMapper::get_output_range"],[120,3,1,"_CPPv4NK4espp11RangeMapper9get_rangeEv","espp::RangeMapper::get_range"],[120,3,1,"_CPPv4NK4espp11RangeMapper18get_range_deadbandEv","espp::RangeMapper::get_range_deadband"],[120,3,1,"_CPPv4NK4espp11RangeMapper3mapERK1T","espp::RangeMapper::map"],[120,4,1,"_CPPv4NK4espp11RangeMapper3mapERK1T","espp::RangeMapper::map::v"],[120,3,1,"_CPPv4N4espp11RangeMapper19set_center_deadbandE1T","espp::RangeMapper::set_center_deadband"],[120,4,1,"_CPPv4N4espp11RangeMapper19set_center_deadbandE1T","espp::RangeMapper::set_center_deadband::deadband"],[120,3,1,"_CPPv4N4espp11RangeMapper18set_range_deadbandE1T","espp::RangeMapper::set_range_deadband"],[120,4,1,"_CPPv4N4espp11RangeMapper18set_range_deadbandE1T","espp::RangeMapper::set_range_deadband::deadband"],[120,3,1,"_CPPv4NK4espp11RangeMapper5unmapERK1T","espp::RangeMapper::unmap"],[120,4,1,"_CPPv4NK4espp11RangeMapper5unmapERK1T","espp::RangeMapper::unmap::v"],[33,2,1,"_CPPv4N4espp3RgbE","espp::Rgb"],[33,3,1,"_CPPv4N4espp3Rgb3RgbERK3Hsv","espp::Rgb::Rgb"],[33,3,1,"_CPPv4N4espp3Rgb3RgbERK3Rgb","espp::Rgb::Rgb"],[33,3,1,"_CPPv4N4espp3Rgb3RgbERK8uint32_t","espp::Rgb::Rgb"],[33,3,1,"_CPPv4N4espp3Rgb3RgbERKfRKfRKf","espp::Rgb::Rgb"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERKfRKfRKf","espp::Rgb::Rgb::b"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERKfRKfRKf","espp::Rgb::Rgb::g"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERK8uint32_t","espp::Rgb::Rgb::hex"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERK3Hsv","espp::Rgb::Rgb::hsv"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERKfRKfRKf","espp::Rgb::Rgb::r"],[33,4,1,"_CPPv4N4espp3Rgb3RgbERK3Rgb","espp::Rgb::Rgb::rgb"],[33,1,1,"_CPPv4N4espp3Rgb1bE","espp::Rgb::b"],[33,1,1,"_CPPv4N4espp3Rgb1gE","espp::Rgb::g"],[33,3,1,"_CPPv4NK4espp3Rgb3hexEv","espp::Rgb::hex"],[33,3,1,"_CPPv4NK4espp3Rgb3hsvEv","espp::Rgb::hsv"],[33,3,1,"_CPPv4NK4espp3RgbplERK3Rgb","espp::Rgb::operator+"],[33,4,1,"_CPPv4NK4espp3RgbplERK3Rgb","espp::Rgb::operator+::rhs"],[33,3,1,"_CPPv4N4espp3RgbpLERK3Rgb","espp::Rgb::operator+="],[33,4,1,"_CPPv4N4espp3RgbpLERK3Rgb","espp::Rgb::operator+=::rhs"],[33,3,1,"_CPPv4N4espp3RgbaSERK3Hsv","espp::Rgb::operator="],[33,3,1,"_CPPv4N4espp3RgbaSERK3Rgb","espp::Rgb::operator="],[33,4,1,"_CPPv4N4espp3RgbaSERK3Hsv","espp::Rgb::operator=::hsv"],[33,4,1,"_CPPv4N4espp3RgbaSERK3Rgb","espp::Rgb::operator=::other"],[33,1,1,"_CPPv4N4espp3Rgb1rE","espp::Rgb::r"],[143,2,1,"_CPPv4N4espp3RmtE","espp::Rmt"],[143,2,1,"_CPPv4N4espp3Rmt6ConfigE","espp::Rmt::Config"],[143,1,1,"_CPPv4N4espp3Rmt6Config10block_sizeE","espp::Rmt::Config::block_size"],[143,1,1,"_CPPv4N4espp3Rmt6Config9clock_srcE","espp::Rmt::Config::clock_src"],[143,1,1,"_CPPv4N4espp3Rmt6Config11dma_enabledE","espp::Rmt::Config::dma_enabled"],[143,1,1,"_CPPv4N4espp3Rmt6Config8gpio_numE","espp::Rmt::Config::gpio_num"],[143,1,1,"_CPPv4N4espp3Rmt6Config9log_levelE","espp::Rmt::Config::log_level"],[143,1,1,"_CPPv4N4espp3Rmt6Config13resolution_hzE","espp::Rmt::Config::resolution_hz"],[143,1,1,"_CPPv4N4espp3Rmt6Config23transaction_queue_depthE","espp::Rmt::Config::transaction_queue_depth"],[143,3,1,"_CPPv4N4espp3Rmt3RmtERK6Config","espp::Rmt::Rmt"],[143,4,1,"_CPPv4N4espp3Rmt3RmtERK6Config","espp::Rmt::Rmt::config"],[143,3,1,"_CPPv4NK4espp3Rmt13get_log_levelEv","espp::Rmt::get_log_level"],[143,3,1,"_CPPv4NK4espp3Rmt17get_log_verbosityEv","espp::Rmt::get_log_verbosity"],[143,3,1,"_CPPv4NK4espp3Rmt8get_nameEv","espp::Rmt::get_name"],[143,3,1,"_CPPv4N4espp3Rmt13set_log_levelEN4espp6Logger9VerbosityE","espp::Rmt::set_log_level"],[143,4,1,"_CPPv4N4espp3Rmt13set_log_levelEN4espp6Logger9VerbosityE","espp::Rmt::set_log_level::level"],[143,3,1,"_CPPv4N4espp3Rmt18set_log_rate_limitENSt6chrono8durationIfEE","espp::Rmt::set_log_rate_limit"],[143,4,1,"_CPPv4N4espp3Rmt18set_log_rate_limitENSt6chrono8durationIfEE","espp::Rmt::set_log_rate_limit::rate_limit"],[143,3,1,"_CPPv4N4espp3Rmt11set_log_tagERKNSt11string_viewE","espp::Rmt::set_log_tag"],[143,4,1,"_CPPv4N4espp3Rmt11set_log_tagERKNSt11string_viewE","espp::Rmt::set_log_tag::tag"],[143,3,1,"_CPPv4N4espp3Rmt17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Rmt::set_log_verbosity"],[143,4,1,"_CPPv4N4espp3Rmt17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Rmt::set_log_verbosity::level"],[143,3,1,"_CPPv4N4espp3Rmt8transmitEPK7uint8_t6size_t","espp::Rmt::transmit"],[143,4,1,"_CPPv4N4espp3Rmt8transmitEPK7uint8_t6size_t","espp::Rmt::transmit::data"],[143,4,1,"_CPPv4N4espp3Rmt8transmitEPK7uint8_t6size_t","espp::Rmt::transmit::length"],[143,3,1,"_CPPv4N4espp3RmtD0Ev","espp::Rmt::~Rmt"],[143,2,1,"_CPPv4N4espp10RmtEncoderE","espp::RmtEncoder"],[143,2,1,"_CPPv4N4espp10RmtEncoder6ConfigE","espp::RmtEncoder::Config"],[143,1,1,"_CPPv4N4espp10RmtEncoder6Config20bytes_encoder_configE","espp::RmtEncoder::Config::bytes_encoder_config"],[143,1,1,"_CPPv4N4espp10RmtEncoder6Config3delE","espp::RmtEncoder::Config::del"],[143,1,1,"_CPPv4N4espp10RmtEncoder6Config6encodeE","espp::RmtEncoder::Config::encode"],[143,1,1,"_CPPv4N4espp10RmtEncoder6Config5resetE","espp::RmtEncoder::Config::reset"],[143,3,1,"_CPPv4N4espp10RmtEncoder10RmtEncoderERK6Config","espp::RmtEncoder::RmtEncoder"],[143,4,1,"_CPPv4N4espp10RmtEncoder10RmtEncoderERK6Config","espp::RmtEncoder::RmtEncoder::config"],[143,8,1,"_CPPv4N4espp10RmtEncoder9delete_fnE","espp::RmtEncoder::delete_fn"],[143,8,1,"_CPPv4N4espp10RmtEncoder9encode_fnE","espp::RmtEncoder::encode_fn"],[143,3,1,"_CPPv4NK4espp10RmtEncoder6handleEv","espp::RmtEncoder::handle"],[143,8,1,"_CPPv4N4espp10RmtEncoder8reset_fnE","espp::RmtEncoder::reset_fn"],[143,3,1,"_CPPv4N4espp10RmtEncoderD0Ev","espp::RmtEncoder::~RmtEncoder"],[148,2,1,"_CPPv4N4espp10RtcpPacketE","espp::RtcpPacket"],[148,3,1,"_CPPv4N4espp10RtcpPacket10RtcpPacketEv","espp::RtcpPacket::RtcpPacket"],[148,3,1,"_CPPv4NK4espp10RtcpPacket8get_dataEv","espp::RtcpPacket::get_data"],[148,3,1,"_CPPv4N4espp10RtcpPacketD0Ev","espp::RtcpPacket::~RtcpPacket"],[148,2,1,"_CPPv4N4espp13RtpJpegPacketE","espp::RtpJpegPacket"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::data"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::frag_type"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::frag_type"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::height"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::height"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::offset"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::q"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::q"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::q0"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::q1"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::scan_data"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::scan_data"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::type_specific"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::type_specific"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiKiNSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::width"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13RtpJpegPacketEKiKiKiKiKiNSt11string_viewENSt11string_viewENSt11string_viewE","espp::RtpJpegPacket::RtpJpegPacket::width"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket14get_csrc_countEv","espp::RtpJpegPacket::get_csrc_count"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket8get_dataEv","espp::RtpJpegPacket::get_data"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket13get_extensionEv","espp::RtpJpegPacket::get_extension"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket10get_heightEv","espp::RtpJpegPacket::get_height"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket13get_jpeg_dataEv","espp::RtpJpegPacket::get_jpeg_data"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket10get_markerEv","espp::RtpJpegPacket::get_marker"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket16get_mjpeg_headerEv","espp::RtpJpegPacket::get_mjpeg_header"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket16get_num_q_tablesEv","espp::RtpJpegPacket::get_num_q_tables"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket10get_offsetEv","espp::RtpJpegPacket::get_offset"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket10get_packetEv","espp::RtpJpegPacket::get_packet"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket11get_paddingEv","espp::RtpJpegPacket::get_padding"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket11get_payloadEv","espp::RtpJpegPacket::get_payload"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket16get_payload_typeEv","espp::RtpJpegPacket::get_payload_type"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket5get_qEv","espp::RtpJpegPacket::get_q"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket11get_q_tableEi","espp::RtpJpegPacket::get_q_table"],[148,4,1,"_CPPv4NK4espp13RtpJpegPacket11get_q_tableEi","espp::RtpJpegPacket::get_q_table::index"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket14get_rpt_headerEv","espp::RtpJpegPacket::get_rpt_header"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket19get_rtp_header_sizeEv","espp::RtpJpegPacket::get_rtp_header_size"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket19get_sequence_numberEv","espp::RtpJpegPacket::get_sequence_number"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket8get_ssrcEv","espp::RtpJpegPacket::get_ssrc"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket13get_timestampEv","espp::RtpJpegPacket::get_timestamp"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket17get_type_specificEv","espp::RtpJpegPacket::get_type_specific"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket11get_versionEv","espp::RtpJpegPacket::get_version"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket9get_widthEv","espp::RtpJpegPacket::get_width"],[148,3,1,"_CPPv4NK4espp13RtpJpegPacket12has_q_tablesEv","espp::RtpJpegPacket::has_q_tables"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket9serializeEv","espp::RtpJpegPacket::serialize"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket14set_csrc_countEi","espp::RtpJpegPacket::set_csrc_count"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket14set_csrc_countEi","espp::RtpJpegPacket::set_csrc_count::csrc_count"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket13set_extensionEb","espp::RtpJpegPacket::set_extension"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13set_extensionEb","espp::RtpJpegPacket::set_extension::extension"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket10set_markerEb","espp::RtpJpegPacket::set_marker"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket10set_markerEb","espp::RtpJpegPacket::set_marker::marker"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket11set_paddingEb","espp::RtpJpegPacket::set_padding"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket11set_paddingEb","espp::RtpJpegPacket::set_padding::padding"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket11set_payloadENSt11string_viewE","espp::RtpJpegPacket::set_payload"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket11set_payloadENSt11string_viewE","espp::RtpJpegPacket::set_payload::payload"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket16set_payload_typeEi","espp::RtpJpegPacket::set_payload_type"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket16set_payload_typeEi","espp::RtpJpegPacket::set_payload_type::payload_type"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket19set_sequence_numberEi","espp::RtpJpegPacket::set_sequence_number"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket19set_sequence_numberEi","espp::RtpJpegPacket::set_sequence_number::sequence_number"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket8set_ssrcEi","espp::RtpJpegPacket::set_ssrc"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket8set_ssrcEi","espp::RtpJpegPacket::set_ssrc::ssrc"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket13set_timestampEi","espp::RtpJpegPacket::set_timestamp"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket13set_timestampEi","espp::RtpJpegPacket::set_timestamp::timestamp"],[148,3,1,"_CPPv4N4espp13RtpJpegPacket11set_versionEi","espp::RtpJpegPacket::set_version"],[148,4,1,"_CPPv4N4espp13RtpJpegPacket11set_versionEi","espp::RtpJpegPacket::set_version::version"],[148,2,1,"_CPPv4N4espp9RtpPacketE","espp::RtpPacket"],[148,3,1,"_CPPv4N4espp9RtpPacket9RtpPacketE6size_t","espp::RtpPacket::RtpPacket"],[148,3,1,"_CPPv4N4espp9RtpPacket9RtpPacketENSt11string_viewE","espp::RtpPacket::RtpPacket"],[148,3,1,"_CPPv4N4espp9RtpPacket9RtpPacketEv","espp::RtpPacket::RtpPacket"],[148,4,1,"_CPPv4N4espp9RtpPacket9RtpPacketENSt11string_viewE","espp::RtpPacket::RtpPacket::data"],[148,4,1,"_CPPv4N4espp9RtpPacket9RtpPacketE6size_t","espp::RtpPacket::RtpPacket::payload_size"],[148,3,1,"_CPPv4NK4espp9RtpPacket14get_csrc_countEv","espp::RtpPacket::get_csrc_count"],[148,3,1,"_CPPv4NK4espp9RtpPacket8get_dataEv","espp::RtpPacket::get_data"],[148,3,1,"_CPPv4NK4espp9RtpPacket13get_extensionEv","espp::RtpPacket::get_extension"],[148,3,1,"_CPPv4NK4espp9RtpPacket10get_markerEv","espp::RtpPacket::get_marker"],[148,3,1,"_CPPv4N4espp9RtpPacket10get_packetEv","espp::RtpPacket::get_packet"],[148,3,1,"_CPPv4NK4espp9RtpPacket11get_paddingEv","espp::RtpPacket::get_padding"],[148,3,1,"_CPPv4NK4espp9RtpPacket11get_payloadEv","espp::RtpPacket::get_payload"],[148,3,1,"_CPPv4NK4espp9RtpPacket16get_payload_typeEv","espp::RtpPacket::get_payload_type"],[148,3,1,"_CPPv4NK4espp9RtpPacket14get_rpt_headerEv","espp::RtpPacket::get_rpt_header"],[148,3,1,"_CPPv4NK4espp9RtpPacket19get_rtp_header_sizeEv","espp::RtpPacket::get_rtp_header_size"],[148,3,1,"_CPPv4NK4espp9RtpPacket19get_sequence_numberEv","espp::RtpPacket::get_sequence_number"],[148,3,1,"_CPPv4NK4espp9RtpPacket8get_ssrcEv","espp::RtpPacket::get_ssrc"],[148,3,1,"_CPPv4NK4espp9RtpPacket13get_timestampEv","espp::RtpPacket::get_timestamp"],[148,3,1,"_CPPv4NK4espp9RtpPacket11get_versionEv","espp::RtpPacket::get_version"],[148,3,1,"_CPPv4N4espp9RtpPacket9serializeEv","espp::RtpPacket::serialize"],[148,3,1,"_CPPv4N4espp9RtpPacket14set_csrc_countEi","espp::RtpPacket::set_csrc_count"],[148,4,1,"_CPPv4N4espp9RtpPacket14set_csrc_countEi","espp::RtpPacket::set_csrc_count::csrc_count"],[148,3,1,"_CPPv4N4espp9RtpPacket13set_extensionEb","espp::RtpPacket::set_extension"],[148,4,1,"_CPPv4N4espp9RtpPacket13set_extensionEb","espp::RtpPacket::set_extension::extension"],[148,3,1,"_CPPv4N4espp9RtpPacket10set_markerEb","espp::RtpPacket::set_marker"],[148,4,1,"_CPPv4N4espp9RtpPacket10set_markerEb","espp::RtpPacket::set_marker::marker"],[148,3,1,"_CPPv4N4espp9RtpPacket11set_paddingEb","espp::RtpPacket::set_padding"],[148,4,1,"_CPPv4N4espp9RtpPacket11set_paddingEb","espp::RtpPacket::set_padding::padding"],[148,3,1,"_CPPv4N4espp9RtpPacket11set_payloadENSt11string_viewE","espp::RtpPacket::set_payload"],[148,4,1,"_CPPv4N4espp9RtpPacket11set_payloadENSt11string_viewE","espp::RtpPacket::set_payload::payload"],[148,3,1,"_CPPv4N4espp9RtpPacket16set_payload_typeEi","espp::RtpPacket::set_payload_type"],[148,4,1,"_CPPv4N4espp9RtpPacket16set_payload_typeEi","espp::RtpPacket::set_payload_type::payload_type"],[148,3,1,"_CPPv4N4espp9RtpPacket19set_sequence_numberEi","espp::RtpPacket::set_sequence_number"],[148,4,1,"_CPPv4N4espp9RtpPacket19set_sequence_numberEi","espp::RtpPacket::set_sequence_number::sequence_number"],[148,3,1,"_CPPv4N4espp9RtpPacket8set_ssrcEi","espp::RtpPacket::set_ssrc"],[148,4,1,"_CPPv4N4espp9RtpPacket8set_ssrcEi","espp::RtpPacket::set_ssrc::ssrc"],[148,3,1,"_CPPv4N4espp9RtpPacket13set_timestampEi","espp::RtpPacket::set_timestamp"],[148,4,1,"_CPPv4N4espp9RtpPacket13set_timestampEi","espp::RtpPacket::set_timestamp::timestamp"],[148,3,1,"_CPPv4N4espp9RtpPacket11set_versionEi","espp::RtpPacket::set_version"],[148,4,1,"_CPPv4N4espp9RtpPacket11set_versionEi","espp::RtpPacket::set_version::version"],[148,3,1,"_CPPv4N4espp9RtpPacketD0Ev","espp::RtpPacket::~RtpPacket"],[148,2,1,"_CPPv4N4espp10RtspClientE","espp::RtspClient"],[148,2,1,"_CPPv4N4espp10RtspClient6ConfigE","espp::RtspClient::Config"],[148,1,1,"_CPPv4N4espp10RtspClient6Config9log_levelE","espp::RtspClient::Config::log_level"],[148,1,1,"_CPPv4N4espp10RtspClient6Config13on_jpeg_frameE","espp::RtspClient::Config::on_jpeg_frame"],[148,1,1,"_CPPv4N4espp10RtspClient6Config4pathE","espp::RtspClient::Config::path"],[148,1,1,"_CPPv4N4espp10RtspClient6Config9rtsp_portE","espp::RtspClient::Config::rtsp_port"],[148,1,1,"_CPPv4N4espp10RtspClient6Config14server_addressE","espp::RtspClient::Config::server_address"],[148,3,1,"_CPPv4N4espp10RtspClient10RtspClientERK6Config","espp::RtspClient::RtspClient"],[148,4,1,"_CPPv4N4espp10RtspClient10RtspClientERK6Config","espp::RtspClient::RtspClient::config"],[148,3,1,"_CPPv4N4espp10RtspClient7connectERNSt10error_codeE","espp::RtspClient::connect"],[148,4,1,"_CPPv4N4espp10RtspClient7connectERNSt10error_codeE","espp::RtspClient::connect::ec"],[148,3,1,"_CPPv4N4espp10RtspClient8describeERNSt10error_codeE","espp::RtspClient::describe"],[148,4,1,"_CPPv4N4espp10RtspClient8describeERNSt10error_codeE","espp::RtspClient::describe::ec"],[148,3,1,"_CPPv4N4espp10RtspClient10disconnectERNSt10error_codeE","espp::RtspClient::disconnect"],[148,4,1,"_CPPv4N4espp10RtspClient10disconnectERNSt10error_codeE","espp::RtspClient::disconnect::ec"],[148,3,1,"_CPPv4NK4espp10RtspClient13get_log_levelEv","espp::RtspClient::get_log_level"],[148,3,1,"_CPPv4NK4espp10RtspClient17get_log_verbosityEv","espp::RtspClient::get_log_verbosity"],[148,3,1,"_CPPv4NK4espp10RtspClient8get_nameEv","espp::RtspClient::get_name"],[148,8,1,"_CPPv4N4espp10RtspClient21jpeg_frame_callback_tE","espp::RtspClient::jpeg_frame_callback_t"],[148,3,1,"_CPPv4N4espp10RtspClient5pauseERNSt10error_codeE","espp::RtspClient::pause"],[148,4,1,"_CPPv4N4espp10RtspClient5pauseERNSt10error_codeE","espp::RtspClient::pause::ec"],[148,3,1,"_CPPv4N4espp10RtspClient4playERNSt10error_codeE","espp::RtspClient::play"],[148,4,1,"_CPPv4N4espp10RtspClient4playERNSt10error_codeE","espp::RtspClient::play::ec"],[148,3,1,"_CPPv4N4espp10RtspClient12send_requestERKNSt6stringERKNSt6stringERKNSt13unordered_mapINSt6stringENSt6stringEEERNSt10error_codeE","espp::RtspClient::send_request"],[148,4,1,"_CPPv4N4espp10RtspClient12send_requestERKNSt6stringERKNSt6stringERKNSt13unordered_mapINSt6stringENSt6stringEEERNSt10error_codeE","espp::RtspClient::send_request::ec"],[148,4,1,"_CPPv4N4espp10RtspClient12send_requestERKNSt6stringERKNSt6stringERKNSt13unordered_mapINSt6stringENSt6stringEEERNSt10error_codeE","espp::RtspClient::send_request::extra_headers"],[148,4,1,"_CPPv4N4espp10RtspClient12send_requestERKNSt6stringERKNSt6stringERKNSt13unordered_mapINSt6stringENSt6stringEEERNSt10error_codeE","espp::RtspClient::send_request::method"],[148,4,1,"_CPPv4N4espp10RtspClient12send_requestERKNSt6stringERKNSt6stringERKNSt13unordered_mapINSt6stringENSt6stringEEERNSt10error_codeE","espp::RtspClient::send_request::path"],[148,3,1,"_CPPv4N4espp10RtspClient13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspClient::set_log_level"],[148,4,1,"_CPPv4N4espp10RtspClient13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspClient::set_log_level::level"],[148,3,1,"_CPPv4N4espp10RtspClient18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspClient::set_log_rate_limit"],[148,4,1,"_CPPv4N4espp10RtspClient18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspClient::set_log_rate_limit::rate_limit"],[148,3,1,"_CPPv4N4espp10RtspClient11set_log_tagERKNSt11string_viewE","espp::RtspClient::set_log_tag"],[148,4,1,"_CPPv4N4espp10RtspClient11set_log_tagERKNSt11string_viewE","espp::RtspClient::set_log_tag::tag"],[148,3,1,"_CPPv4N4espp10RtspClient17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspClient::set_log_verbosity"],[148,4,1,"_CPPv4N4espp10RtspClient17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspClient::set_log_verbosity::level"],[148,3,1,"_CPPv4N4espp10RtspClient5setupE6size_t6size_tRNSt10error_codeE","espp::RtspClient::setup"],[148,3,1,"_CPPv4N4espp10RtspClient5setupERNSt10error_codeE","espp::RtspClient::setup"],[148,4,1,"_CPPv4N4espp10RtspClient5setupE6size_t6size_tRNSt10error_codeE","espp::RtspClient::setup::ec"],[148,4,1,"_CPPv4N4espp10RtspClient5setupERNSt10error_codeE","espp::RtspClient::setup::ec"],[148,4,1,"_CPPv4N4espp10RtspClient5setupE6size_t6size_tRNSt10error_codeE","espp::RtspClient::setup::rtcp_port"],[148,4,1,"_CPPv4N4espp10RtspClient5setupE6size_t6size_tRNSt10error_codeE","espp::RtspClient::setup::rtp_port"],[148,3,1,"_CPPv4N4espp10RtspClient8teardownERNSt10error_codeE","espp::RtspClient::teardown"],[148,4,1,"_CPPv4N4espp10RtspClient8teardownERNSt10error_codeE","espp::RtspClient::teardown::ec"],[148,3,1,"_CPPv4N4espp10RtspClientD0Ev","espp::RtspClient::~RtspClient"],[148,2,1,"_CPPv4N4espp10RtspServerE","espp::RtspServer"],[148,2,1,"_CPPv4N4espp10RtspServer6ConfigE","espp::RtspServer::Config"],[148,1,1,"_CPPv4N4espp10RtspServer6Config9log_levelE","espp::RtspServer::Config::log_level"],[148,1,1,"_CPPv4N4espp10RtspServer6Config13max_data_sizeE","espp::RtspServer::Config::max_data_size"],[148,1,1,"_CPPv4N4espp10RtspServer6Config4pathE","espp::RtspServer::Config::path"],[148,1,1,"_CPPv4N4espp10RtspServer6Config4portE","espp::RtspServer::Config::port"],[148,1,1,"_CPPv4N4espp10RtspServer6Config14server_addressE","espp::RtspServer::Config::server_address"],[148,3,1,"_CPPv4N4espp10RtspServer10RtspServerERK6Config","espp::RtspServer::RtspServer"],[148,4,1,"_CPPv4N4espp10RtspServer10RtspServerERK6Config","espp::RtspServer::RtspServer::config"],[148,3,1,"_CPPv4NK4espp10RtspServer13get_log_levelEv","espp::RtspServer::get_log_level"],[148,3,1,"_CPPv4NK4espp10RtspServer17get_log_verbosityEv","espp::RtspServer::get_log_verbosity"],[148,3,1,"_CPPv4NK4espp10RtspServer8get_nameEv","espp::RtspServer::get_name"],[148,3,1,"_CPPv4N4espp10RtspServer10send_frameERKN4espp9JpegFrameE","espp::RtspServer::send_frame"],[148,4,1,"_CPPv4N4espp10RtspServer10send_frameERKN4espp9JpegFrameE","espp::RtspServer::send_frame::frame"],[148,3,1,"_CPPv4N4espp10RtspServer13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspServer::set_log_level"],[148,4,1,"_CPPv4N4espp10RtspServer13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspServer::set_log_level::level"],[148,3,1,"_CPPv4N4espp10RtspServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspServer::set_log_rate_limit"],[148,4,1,"_CPPv4N4espp10RtspServer18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspServer::set_log_rate_limit::rate_limit"],[148,3,1,"_CPPv4N4espp10RtspServer11set_log_tagERKNSt11string_viewE","espp::RtspServer::set_log_tag"],[148,4,1,"_CPPv4N4espp10RtspServer11set_log_tagERKNSt11string_viewE","espp::RtspServer::set_log_tag::tag"],[148,3,1,"_CPPv4N4espp10RtspServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspServer::set_log_verbosity"],[148,4,1,"_CPPv4N4espp10RtspServer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspServer::set_log_verbosity::level"],[148,3,1,"_CPPv4N4espp10RtspServer21set_session_log_levelEN4espp6Logger9VerbosityE","espp::RtspServer::set_session_log_level"],[148,4,1,"_CPPv4N4espp10RtspServer21set_session_log_levelEN4espp6Logger9VerbosityE","espp::RtspServer::set_session_log_level::log_level"],[148,3,1,"_CPPv4N4espp10RtspServer5startEv","espp::RtspServer::start"],[148,3,1,"_CPPv4N4espp10RtspServer4stopEv","espp::RtspServer::stop"],[148,3,1,"_CPPv4N4espp10RtspServerD0Ev","espp::RtspServer::~RtspServer"],[148,2,1,"_CPPv4N4espp11RtspSessionE","espp::RtspSession"],[148,2,1,"_CPPv4N4espp11RtspSession6ConfigE","espp::RtspSession::Config"],[148,1,1,"_CPPv4N4espp11RtspSession6Config9log_levelE","espp::RtspSession::Config::log_level"],[148,1,1,"_CPPv4N4espp11RtspSession6Config9rtsp_pathE","espp::RtspSession::Config::rtsp_path"],[148,1,1,"_CPPv4N4espp11RtspSession6Config14server_addressE","espp::RtspSession::Config::server_address"],[148,3,1,"_CPPv4N4espp11RtspSession11RtspSessionENSt10unique_ptrIN4espp9TcpSocketEEERK6Config","espp::RtspSession::RtspSession"],[148,4,1,"_CPPv4N4espp11RtspSession11RtspSessionENSt10unique_ptrIN4espp9TcpSocketEEERK6Config","espp::RtspSession::RtspSession::config"],[148,4,1,"_CPPv4N4espp11RtspSession11RtspSessionENSt10unique_ptrIN4espp9TcpSocketEEERK6Config","espp::RtspSession::RtspSession::control_socket"],[148,3,1,"_CPPv4NK4espp11RtspSession13get_log_levelEv","espp::RtspSession::get_log_level"],[148,3,1,"_CPPv4NK4espp11RtspSession17get_log_verbosityEv","espp::RtspSession::get_log_verbosity"],[148,3,1,"_CPPv4NK4espp11RtspSession8get_nameEv","espp::RtspSession::get_name"],[148,3,1,"_CPPv4NK4espp11RtspSession14get_session_idEv","espp::RtspSession::get_session_id"],[148,3,1,"_CPPv4NK4espp11RtspSession9is_activeEv","espp::RtspSession::is_active"],[148,3,1,"_CPPv4NK4espp11RtspSession9is_closedEv","espp::RtspSession::is_closed"],[148,3,1,"_CPPv4NK4espp11RtspSession12is_connectedEv","espp::RtspSession::is_connected"],[148,3,1,"_CPPv4N4espp11RtspSession5pauseEv","espp::RtspSession::pause"],[148,3,1,"_CPPv4N4espp11RtspSession4playEv","espp::RtspSession::play"],[148,3,1,"_CPPv4N4espp11RtspSession16send_rtcp_packetERKN4espp10RtcpPacketE","espp::RtspSession::send_rtcp_packet"],[148,4,1,"_CPPv4N4espp11RtspSession16send_rtcp_packetERKN4espp10RtcpPacketE","espp::RtspSession::send_rtcp_packet::packet"],[148,3,1,"_CPPv4N4espp11RtspSession15send_rtp_packetERKN4espp9RtpPacketE","espp::RtspSession::send_rtp_packet"],[148,4,1,"_CPPv4N4espp11RtspSession15send_rtp_packetERKN4espp9RtpPacketE","espp::RtspSession::send_rtp_packet::packet"],[148,3,1,"_CPPv4N4espp11RtspSession13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspSession::set_log_level"],[148,4,1,"_CPPv4N4espp11RtspSession13set_log_levelEN4espp6Logger9VerbosityE","espp::RtspSession::set_log_level::level"],[148,3,1,"_CPPv4N4espp11RtspSession18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspSession::set_log_rate_limit"],[148,4,1,"_CPPv4N4espp11RtspSession18set_log_rate_limitENSt6chrono8durationIfEE","espp::RtspSession::set_log_rate_limit::rate_limit"],[148,3,1,"_CPPv4N4espp11RtspSession11set_log_tagERKNSt11string_viewE","espp::RtspSession::set_log_tag"],[148,4,1,"_CPPv4N4espp11RtspSession11set_log_tagERKNSt11string_viewE","espp::RtspSession::set_log_tag::tag"],[148,3,1,"_CPPv4N4espp11RtspSession17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspSession::set_log_verbosity"],[148,4,1,"_CPPv4N4espp11RtspSession17set_log_verbosityEN4espp6Logger9VerbosityE","espp::RtspSession::set_log_verbosity::level"],[148,3,1,"_CPPv4N4espp11RtspSession8teardownEv","espp::RtspSession::teardown"],[148,3,1,"_CPPv4N4espp11RtspSessionD0Ev","espp::RtspSession::~RtspSession"],[64,2,1,"_CPPv4N4espp19SimpleLowpassFilterE","espp::SimpleLowpassFilter"],[64,2,1,"_CPPv4N4espp19SimpleLowpassFilter6ConfigE","espp::SimpleLowpassFilter::Config"],[64,1,1,"_CPPv4N4espp19SimpleLowpassFilter6Config13time_constantE","espp::SimpleLowpassFilter::Config::time_constant"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilter19SimpleLowpassFilterERK6Config","espp::SimpleLowpassFilter::SimpleLowpassFilter"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilter19SimpleLowpassFilterEv","espp::SimpleLowpassFilter::SimpleLowpassFilter"],[64,4,1,"_CPPv4N4espp19SimpleLowpassFilter19SimpleLowpassFilterERK6Config","espp::SimpleLowpassFilter::SimpleLowpassFilter::config"],[64,3,1,"_CPPv4NK4espp19SimpleLowpassFilter17get_time_constantEv","espp::SimpleLowpassFilter::get_time_constant"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilterclEf","espp::SimpleLowpassFilter::operator()"],[64,4,1,"_CPPv4N4espp19SimpleLowpassFilterclEf","espp::SimpleLowpassFilter::operator()::input"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilter5resetEv","espp::SimpleLowpassFilter::reset"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilter17set_time_constantEKf","espp::SimpleLowpassFilter::set_time_constant"],[64,4,1,"_CPPv4N4espp19SimpleLowpassFilter17set_time_constantEKf","espp::SimpleLowpassFilter::set_time_constant::time_constant"],[64,3,1,"_CPPv4N4espp19SimpleLowpassFilter6updateEKf","espp::SimpleLowpassFilter::update"],[64,4,1,"_CPPv4N4espp19SimpleLowpassFilter6updateEKf","espp::SimpleLowpassFilter::update::input"],[129,2,1,"_CPPv4N4espp6SocketE","espp::Socket"],[129,2,1,"_CPPv4N4espp6Socket4InfoE","espp::Socket::Info"],[129,1,1,"_CPPv4N4espp6Socket4Info7addressE","espp::Socket::Info::address"],[129,3,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK11sockaddr_in","espp::Socket::Info::from_sockaddr"],[129,3,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK12sockaddr_in6","espp::Socket::Info::from_sockaddr"],[129,3,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK16sockaddr_storage","espp::Socket::Info::from_sockaddr"],[129,4,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK11sockaddr_in","espp::Socket::Info::from_sockaddr::source_address"],[129,4,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK12sockaddr_in6","espp::Socket::Info::from_sockaddr::source_address"],[129,4,1,"_CPPv4N4espp6Socket4Info13from_sockaddrERK16sockaddr_storage","espp::Socket::Info::from_sockaddr::source_address"],[129,3,1,"_CPPv4N4espp6Socket4Info9init_ipv4ERKNSt6stringE6size_t","espp::Socket::Info::init_ipv4"],[129,4,1,"_CPPv4N4espp6Socket4Info9init_ipv4ERKNSt6stringE6size_t","espp::Socket::Info::init_ipv4::addr"],[129,4,1,"_CPPv4N4espp6Socket4Info9init_ipv4ERKNSt6stringE6size_t","espp::Socket::Info::init_ipv4::prt"],[129,3,1,"_CPPv4N4espp6Socket4Info8ipv4_ptrEv","espp::Socket::Info::ipv4_ptr"],[129,3,1,"_CPPv4N4espp6Socket4Info8ipv6_ptrEv","espp::Socket::Info::ipv6_ptr"],[129,1,1,"_CPPv4N4espp6Socket4Info4portE","espp::Socket::Info::port"],[129,3,1,"_CPPv4N4espp6Socket4Info6updateEv","espp::Socket::Info::update"],[129,3,1,"_CPPv4N4espp6Socket6SocketE11sock_type_tRKN4espp6Logger6ConfigE","espp::Socket::Socket"],[129,3,1,"_CPPv4N4espp6Socket6SocketE4TypeRKN4espp6Logger6ConfigE","espp::Socket::Socket"],[129,4,1,"_CPPv4N4espp6Socket6SocketE11sock_type_tRKN4espp6Logger6ConfigE","espp::Socket::Socket::logger_config"],[129,4,1,"_CPPv4N4espp6Socket6SocketE4TypeRKN4espp6Logger6ConfigE","espp::Socket::Socket::logger_config"],[129,4,1,"_CPPv4N4espp6Socket6SocketE11sock_type_tRKN4espp6Logger6ConfigE","espp::Socket::Socket::socket_fd"],[129,4,1,"_CPPv4N4espp6Socket6SocketE4TypeRKN4espp6Logger6ConfigE","espp::Socket::Socket::type"],[129,3,1,"_CPPv4N4espp6Socket19add_multicast_groupERKNSt6stringE","espp::Socket::add_multicast_group"],[129,4,1,"_CPPv4N4espp6Socket19add_multicast_groupERKNSt6stringE","espp::Socket::add_multicast_group::multicast_group"],[129,3,1,"_CPPv4N4espp6Socket12enable_reuseEv","espp::Socket::enable_reuse"],[129,3,1,"_CPPv4N4espp6Socket13get_ipv4_infoEv","espp::Socket::get_ipv4_info"],[129,3,1,"_CPPv4NK4espp6Socket13get_log_levelEv","espp::Socket::get_log_level"],[129,3,1,"_CPPv4NK4espp6Socket17get_log_verbosityEv","espp::Socket::get_log_verbosity"],[129,3,1,"_CPPv4NK4espp6Socket8get_nameEv","espp::Socket::get_name"],[129,3,1,"_CPPv4NK4espp6Socket8is_validEv","espp::Socket::is_valid"],[129,3,1,"_CPPv4N4espp6Socket11is_valid_fdE11sock_type_t","espp::Socket::is_valid_fd"],[129,4,1,"_CPPv4N4espp6Socket11is_valid_fdE11sock_type_t","espp::Socket::is_valid_fd::socket_fd"],[129,3,1,"_CPPv4N4espp6Socket14make_multicastE7uint8_t7uint8_t","espp::Socket::make_multicast"],[129,4,1,"_CPPv4N4espp6Socket14make_multicastE7uint8_t7uint8_t","espp::Socket::make_multicast::loopback_enabled"],[129,4,1,"_CPPv4N4espp6Socket14make_multicastE7uint8_t7uint8_t","espp::Socket::make_multicast::time_to_live"],[129,8,1,"_CPPv4N4espp6Socket19receive_callback_fnE","espp::Socket::receive_callback_fn"],[129,8,1,"_CPPv4N4espp6Socket20response_callback_fnE","espp::Socket::response_callback_fn"],[129,3,1,"_CPPv4N4espp6Socket6selectERKNSt6chrono12microsecondsE","espp::Socket::select"],[129,4,1,"_CPPv4N4espp6Socket6selectERKNSt6chrono12microsecondsE","espp::Socket::select::timeout"],[129,3,1,"_CPPv4N4espp6Socket13set_log_levelEN4espp6Logger9VerbosityE","espp::Socket::set_log_level"],[129,4,1,"_CPPv4N4espp6Socket13set_log_levelEN4espp6Logger9VerbosityE","espp::Socket::set_log_level::level"],[129,3,1,"_CPPv4N4espp6Socket18set_log_rate_limitENSt6chrono8durationIfEE","espp::Socket::set_log_rate_limit"],[129,4,1,"_CPPv4N4espp6Socket18set_log_rate_limitENSt6chrono8durationIfEE","espp::Socket::set_log_rate_limit::rate_limit"],[129,3,1,"_CPPv4N4espp6Socket11set_log_tagERKNSt11string_viewE","espp::Socket::set_log_tag"],[129,4,1,"_CPPv4N4espp6Socket11set_log_tagERKNSt11string_viewE","espp::Socket::set_log_tag::tag"],[129,3,1,"_CPPv4N4espp6Socket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Socket::set_log_verbosity"],[129,4,1,"_CPPv4N4espp6Socket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Socket::set_log_verbosity::level"],[129,3,1,"_CPPv4N4espp6Socket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::Socket::set_receive_timeout"],[129,4,1,"_CPPv4N4espp6Socket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::Socket::set_receive_timeout::timeout"],[129,3,1,"_CPPv4N4espp6SocketD0Ev","espp::Socket::~Socket"],[65,2,1,"_CPPv4I_6size_t0EN4espp9SosFilterE","espp::SosFilter"],[65,5,1,"_CPPv4I_6size_t0EN4espp9SosFilterE","espp::SosFilter::N"],[65,5,1,"_CPPv4I_6size_t0EN4espp9SosFilterE","espp::SosFilter::SectionImpl"],[65,3,1,"_CPPv4N4espp9SosFilter9SosFilterERKNSt5arrayI16TransferFunctionIXL3EEE1NEE","espp::SosFilter::SosFilter"],[65,4,1,"_CPPv4N4espp9SosFilter9SosFilterERKNSt5arrayI16TransferFunctionIXL3EEE1NEE","espp::SosFilter::SosFilter::config"],[65,3,1,"_CPPv4N4espp9SosFilterclEf","espp::SosFilter::operator()"],[65,4,1,"_CPPv4N4espp9SosFilterclEf","espp::SosFilter::operator()::input"],[65,3,1,"_CPPv4N4espp9SosFilter6updateEf","espp::SosFilter::update"],[65,4,1,"_CPPv4N4espp9SosFilter6updateEf","espp::SosFilter::update::input"],[150,2,1,"_CPPv4N4espp14SsRoundDisplayE","espp::SsRoundDisplay"],[150,8,1,"_CPPv4N4espp14SsRoundDisplay13DisplayDriverE","espp::SsRoundDisplay::DisplayDriver"],[150,2,1,"_CPPv4N4espp14SsRoundDisplay9PinConfigE","espp::SsRoundDisplay::PinConfig"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig13lcd_backlightE","espp::SsRoundDisplay::PinConfig::lcd_backlight"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig6lcd_csE","espp::SsRoundDisplay::PinConfig::lcd_cs"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig6lcd_dcE","espp::SsRoundDisplay::PinConfig::lcd_dc"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig4misoE","espp::SsRoundDisplay::PinConfig::miso"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig4mosiE","espp::SsRoundDisplay::PinConfig::mosi"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig3sckE","espp::SsRoundDisplay::PinConfig::sck"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig3sclE","espp::SsRoundDisplay::PinConfig::scl"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig3sdaE","espp::SsRoundDisplay::PinConfig::sda"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig15touch_interruptE","espp::SsRoundDisplay::PinConfig::touch_interrupt"],[150,1,1,"_CPPv4N4espp14SsRoundDisplay9PinConfig6usd_csE","espp::SsRoundDisplay::PinConfig::usd_cs"],[150,8,1,"_CPPv4N4espp14SsRoundDisplay5PixelE","espp::SsRoundDisplay::Pixel"],[150,8,1,"_CPPv4N4espp14SsRoundDisplay11TouchDriverE","espp::SsRoundDisplay::TouchDriver"],[150,8,1,"_CPPv4N4espp14SsRoundDisplay12TouchpadDataE","espp::SsRoundDisplay::TouchpadData"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay10brightnessEf","espp::SsRoundDisplay::brightness"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay10brightnessEv","espp::SsRoundDisplay::brightness"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay10brightnessEf","espp::SsRoundDisplay::brightness::brightness"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay7displayEv","espp::SsRoundDisplay::display"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay13frame_buffer0Ev","espp::SsRoundDisplay::frame_buffer0"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay13frame_buffer1Ev","espp::SsRoundDisplay::frame_buffer1"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay3getEv","espp::SsRoundDisplay::get"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay15get_lcd_dc_gpioEv","espp::SsRoundDisplay::get_lcd_dc_gpio"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay13get_log_levelEv","espp::SsRoundDisplay::get_log_level"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay17get_log_verbosityEv","espp::SsRoundDisplay::get_log_verbosity"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay8get_nameEv","espp::SsRoundDisplay::get_name"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay14initialize_lcdEv","espp::SsRoundDisplay::initialize_lcd"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay16initialize_touchERK16touch_callback_t","espp::SsRoundDisplay::initialize_touch"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay16initialize_touchERK16touch_callback_t","espp::SsRoundDisplay::initialize_touch::callback"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay12internal_i2cEv","espp::SsRoundDisplay::internal_i2c"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay10interruptsEv","espp::SsRoundDisplay::interrupts"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay10lcd_heightEv","espp::SsRoundDisplay::lcd_height"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay9lcd_widthEv","espp::SsRoundDisplay::lcd_width"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay13set_log_levelEN4espp6Logger9VerbosityE","espp::SsRoundDisplay::set_log_level"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay13set_log_levelEN4espp6Logger9VerbosityE","espp::SsRoundDisplay::set_log_level::level"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay18set_log_rate_limitENSt6chrono8durationIfEE","espp::SsRoundDisplay::set_log_rate_limit"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay18set_log_rate_limitENSt6chrono8durationIfEE","espp::SsRoundDisplay::set_log_rate_limit::rate_limit"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay11set_log_tagERKNSt11string_viewE","espp::SsRoundDisplay::set_log_tag"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay11set_log_tagERKNSt11string_viewE","espp::SsRoundDisplay::set_log_tag::tag"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay17set_log_verbosityEN4espp6Logger9VerbosityE","espp::SsRoundDisplay::set_log_verbosity"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay17set_log_verbosityEN4espp6Logger9VerbosityE","espp::SsRoundDisplay::set_log_verbosity::level"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay14set_pin_configERK9PinConfig","espp::SsRoundDisplay::set_pin_config"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay14set_pin_configERK9PinConfig","espp::SsRoundDisplay::set_pin_config::pin_config"],[150,8,1,"_CPPv4N4espp14SsRoundDisplay16touch_callback_tE","espp::SsRoundDisplay::touch_callback_t"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay16touchpad_convertERK12TouchpadData","espp::SsRoundDisplay::touchpad_convert"],[150,4,1,"_CPPv4NK4espp14SsRoundDisplay16touchpad_convertERK12TouchpadData","espp::SsRoundDisplay::touchpad_convert::data"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay13touchpad_dataEv","espp::SsRoundDisplay::touchpad_data"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay14touchpad_inputEv","espp::SsRoundDisplay::touchpad_input"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::SsRoundDisplay::touchpad_read"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::SsRoundDisplay::touchpad_read::btn_state"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::SsRoundDisplay::touchpad_read::num_touch_points"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::SsRoundDisplay::touchpad_read::x"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::SsRoundDisplay::touchpad_read::y"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay5vram0Ev","espp::SsRoundDisplay::vram0"],[150,3,1,"_CPPv4NK4espp14SsRoundDisplay5vram1Ev","espp::SsRoundDisplay::vram1"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::SsRoundDisplay::write_lcd"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::SsRoundDisplay::write_lcd::data"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::SsRoundDisplay::write_lcd::length"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay9write_lcdEPK7uint8_t6size_t8uint32_t","espp::SsRoundDisplay::write_lcd::user_data"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame::data"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame::height"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame::width"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame::x"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::SsRoundDisplay::write_lcd_frame::y"],[150,3,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::data"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::user_data"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::xe"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::xs"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::ye"],[150,4,1,"_CPPv4N4espp14SsRoundDisplay15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::SsRoundDisplay::write_lcd_lines::ys"],[135,2,1,"_CPPv4N4espp6St25dvE","espp::St25dv"],[135,2,1,"_CPPv4N4espp6St25dv6ConfigE","espp::St25dv::Config"],[135,1,1,"_CPPv4N4espp6St25dv6Config9auto_initE","espp::St25dv::Config::auto_init"],[135,1,1,"_CPPv4N4espp6St25dv6Config9log_levelE","espp::St25dv::Config::log_level"],[135,1,1,"_CPPv4N4espp6St25dv6Config4readE","espp::St25dv::Config::read"],[135,1,1,"_CPPv4N4espp6St25dv6Config5writeE","espp::St25dv::Config::write"],[135,1,1,"_CPPv4N4espp6St25dv12DATA_ADDRESSE","espp::St25dv::DATA_ADDRESS"],[135,2,1,"_CPPv4N4espp6St25dv7EH_CTRLE","espp::St25dv::EH_CTRL"],[135,2,1,"_CPPv4N4espp6St25dv3GPOE","espp::St25dv::GPO"],[135,2,1,"_CPPv4N4espp6St25dv6IT_STSE","espp::St25dv::IT_STS"],[135,2,1,"_CPPv4N4espp6St25dv7MB_CTRLE","espp::St25dv::MB_CTRL"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError13FIELD_FALLINGE","espp::St25dv::PhonyNameDueToError::FIELD_FALLING"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError12FIELD_RISINGE","espp::St25dv::PhonyNameDueToError::FIELD_RISING"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError11RF_ACTIVITYE","espp::St25dv::PhonyNameDueToError::RF_ACTIVITY"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError10RF_GET_MSGE","espp::St25dv::PhonyNameDueToError::RF_GET_MSG"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError12RF_INTTERUPTE","espp::St25dv::PhonyNameDueToError::RF_INTTERUPT"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError10RF_PUT_MSGE","espp::St25dv::PhonyNameDueToError::RF_PUT_MSG"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError7RF_USERE","espp::St25dv::PhonyNameDueToError::RF_USER"],[135,1,1,"_CPPv4N4espp6St25dv19PhonyNameDueToError8RF_WRITEE","espp::St25dv::PhonyNameDueToError::RF_WRITE"],[135,1,1,"_CPPv4N4espp6St25dv12SYST_ADDRESSE","espp::St25dv::SYST_ADDRESS"],[135,3,1,"_CPPv4N4espp6St25dv6St25dvERK6Config","espp::St25dv::St25dv"],[135,4,1,"_CPPv4N4espp6St25dv6St25dvERK6Config","espp::St25dv::St25dv::config"],[135,3,1,"_CPPv4N4espp6St25dv14get_ftm_lengthERNSt10error_codeE","espp::St25dv::get_ftm_length"],[135,4,1,"_CPPv4N4espp6St25dv14get_ftm_lengthERNSt10error_codeE","espp::St25dv::get_ftm_length::ec"],[135,3,1,"_CPPv4N4espp6St25dv20get_interrupt_statusERNSt10error_codeE","espp::St25dv::get_interrupt_status"],[135,4,1,"_CPPv4N4espp6St25dv20get_interrupt_statusERNSt10error_codeE","espp::St25dv::get_interrupt_status::ec"],[135,3,1,"_CPPv4NK4espp6St25dv13get_log_levelEv","espp::St25dv::get_log_level"],[135,3,1,"_CPPv4NK4espp6St25dv17get_log_verbosityEv","espp::St25dv::get_log_verbosity"],[135,3,1,"_CPPv4NK4espp6St25dv8get_nameEv","espp::St25dv::get_name"],[135,3,1,"_CPPv4N4espp6St25dv10initializeERNSt10error_codeE","espp::St25dv::initialize"],[135,4,1,"_CPPv4N4espp6St25dv10initializeERNSt10error_codeE","espp::St25dv::initialize::ec"],[135,3,1,"_CPPv4N4espp6St25dv5probeERNSt10error_codeE","espp::St25dv::probe"],[135,4,1,"_CPPv4N4espp6St25dv5probeERNSt10error_codeE","espp::St25dv::probe::ec"],[135,8,1,"_CPPv4N4espp6St25dv8probe_fnE","espp::St25dv::probe_fn"],[135,3,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_t8uint16_tRNSt10error_codeE","espp::St25dv::read"],[135,3,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::read"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_t8uint16_tRNSt10error_codeE","espp::St25dv::read::data"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::read::data"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_t8uint16_tRNSt10error_codeE","espp::St25dv::read::ec"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::read::ec"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_t8uint16_tRNSt10error_codeE","espp::St25dv::read::length"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::read::length"],[135,4,1,"_CPPv4N4espp6St25dv4readEP7uint8_t7uint8_t8uint16_tRNSt10error_codeE","espp::St25dv::read::offset"],[135,3,1,"_CPPv4N4espp6St25dv7receiveEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::receive"],[135,4,1,"_CPPv4N4espp6St25dv7receiveEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::receive::data"],[135,4,1,"_CPPv4N4espp6St25dv7receiveEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::receive::ec"],[135,4,1,"_CPPv4N4espp6St25dv7receiveEP7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::receive::length"],[135,3,1,"_CPPv4N4espp6St25dv11set_addressE7uint8_t","espp::St25dv::set_address"],[135,4,1,"_CPPv4N4espp6St25dv11set_addressE7uint8_t","espp::St25dv::set_address::address"],[135,3,1,"_CPPv4N4espp6St25dv10set_configERK6Config","espp::St25dv::set_config"],[135,3,1,"_CPPv4N4espp6St25dv10set_configERR6Config","espp::St25dv::set_config"],[135,4,1,"_CPPv4N4espp6St25dv10set_configERK6Config","espp::St25dv::set_config::config"],[135,4,1,"_CPPv4N4espp6St25dv10set_configERR6Config","espp::St25dv::set_config::config"],[135,3,1,"_CPPv4N4espp6St25dv13set_log_levelEN4espp6Logger9VerbosityE","espp::St25dv::set_log_level"],[135,4,1,"_CPPv4N4espp6St25dv13set_log_levelEN4espp6Logger9VerbosityE","espp::St25dv::set_log_level::level"],[135,3,1,"_CPPv4N4espp6St25dv18set_log_rate_limitENSt6chrono8durationIfEE","espp::St25dv::set_log_rate_limit"],[135,4,1,"_CPPv4N4espp6St25dv18set_log_rate_limitENSt6chrono8durationIfEE","espp::St25dv::set_log_rate_limit::rate_limit"],[135,3,1,"_CPPv4N4espp6St25dv11set_log_tagERKNSt11string_viewE","espp::St25dv::set_log_tag"],[135,4,1,"_CPPv4N4espp6St25dv11set_log_tagERKNSt11string_viewE","espp::St25dv::set_log_tag::tag"],[135,3,1,"_CPPv4N4espp6St25dv17set_log_verbosityEN4espp6Logger9VerbosityE","espp::St25dv::set_log_verbosity"],[135,4,1,"_CPPv4N4espp6St25dv17set_log_verbosityEN4espp6Logger9VerbosityE","espp::St25dv::set_log_verbosity::level"],[135,3,1,"_CPPv4N4espp6St25dv9set_probeERK8probe_fn","espp::St25dv::set_probe"],[135,4,1,"_CPPv4N4espp6St25dv9set_probeERK8probe_fn","espp::St25dv::set_probe::probe"],[135,3,1,"_CPPv4N4espp6St25dv8set_readERK7read_fn","espp::St25dv::set_read"],[135,4,1,"_CPPv4N4espp6St25dv8set_readERK7read_fn","espp::St25dv::set_read::read"],[135,3,1,"_CPPv4N4espp6St25dv17set_read_registerERK16read_register_fn","espp::St25dv::set_read_register"],[135,4,1,"_CPPv4N4espp6St25dv17set_read_registerERK16read_register_fn","espp::St25dv::set_read_register::read_register"],[135,3,1,"_CPPv4N4espp6St25dv10set_recordER4NdefRNSt10error_codeE","espp::St25dv::set_record"],[135,3,1,"_CPPv4N4espp6St25dv10set_recordERKNSt6vectorI7uint8_tEERNSt10error_codeE","espp::St25dv::set_record"],[135,4,1,"_CPPv4N4espp6St25dv10set_recordER4NdefRNSt10error_codeE","espp::St25dv::set_record::ec"],[135,4,1,"_CPPv4N4espp6St25dv10set_recordERKNSt6vectorI7uint8_tEERNSt10error_codeE","espp::St25dv::set_record::ec"],[135,4,1,"_CPPv4N4espp6St25dv10set_recordER4NdefRNSt10error_codeE","espp::St25dv::set_record::record"],[135,4,1,"_CPPv4N4espp6St25dv10set_recordERKNSt6vectorI7uint8_tEERNSt10error_codeE","espp::St25dv::set_record::record_data"],[135,3,1,"_CPPv4N4espp6St25dv11set_recordsERNSt6vectorI4NdefEERNSt10error_codeE","espp::St25dv::set_records"],[135,4,1,"_CPPv4N4espp6St25dv11set_recordsERNSt6vectorI4NdefEERNSt10error_codeE","espp::St25dv::set_records::ec"],[135,4,1,"_CPPv4N4espp6St25dv11set_recordsERNSt6vectorI4NdefEERNSt10error_codeE","espp::St25dv::set_records::records"],[135,3,1,"_CPPv4N4espp6St25dv34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::St25dv::set_separate_write_then_read_delay"],[135,4,1,"_CPPv4N4espp6St25dv34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::St25dv::set_separate_write_then_read_delay::delay"],[135,3,1,"_CPPv4N4espp6St25dv9set_writeERK8write_fn","espp::St25dv::set_write"],[135,4,1,"_CPPv4N4espp6St25dv9set_writeERK8write_fn","espp::St25dv::set_write::write"],[135,3,1,"_CPPv4N4espp6St25dv19set_write_then_readERK18write_then_read_fn","espp::St25dv::set_write_then_read"],[135,4,1,"_CPPv4N4espp6St25dv19set_write_then_readERK18write_then_read_fn","espp::St25dv::set_write_then_read::write_then_read"],[135,3,1,"_CPPv4N4espp6St25dv24start_fast_transfer_modeERNSt10error_codeE","espp::St25dv::start_fast_transfer_mode"],[135,4,1,"_CPPv4N4espp6St25dv24start_fast_transfer_modeERNSt10error_codeE","espp::St25dv::start_fast_transfer_mode::ec"],[135,3,1,"_CPPv4N4espp6St25dv23stop_fast_transfer_modeERNSt10error_codeE","espp::St25dv::stop_fast_transfer_mode"],[135,4,1,"_CPPv4N4espp6St25dv23stop_fast_transfer_modeERNSt10error_codeE","espp::St25dv::stop_fast_transfer_mode::ec"],[135,3,1,"_CPPv4N4espp6St25dv8transferEPK7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::transfer"],[135,4,1,"_CPPv4N4espp6St25dv8transferEPK7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::transfer::data"],[135,4,1,"_CPPv4N4espp6St25dv8transferEPK7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::transfer::ec"],[135,4,1,"_CPPv4N4espp6St25dv8transferEPK7uint8_t7uint8_tRNSt10error_codeE","espp::St25dv::transfer::length"],[135,3,1,"_CPPv4N4espp6St25dv5writeENSt11string_viewERNSt10error_codeE","espp::St25dv::write"],[135,4,1,"_CPPv4N4espp6St25dv5writeENSt11string_viewERNSt10error_codeE","espp::St25dv::write::ec"],[135,4,1,"_CPPv4N4espp6St25dv5writeENSt11string_viewERNSt10error_codeE","espp::St25dv::write::payload"],[40,2,1,"_CPPv4N4espp6St7789E","espp::St7789"],[40,3,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear"],[40,4,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear::color"],[40,4,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear::height"],[40,4,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear::width"],[40,4,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear::x"],[40,4,1,"_CPPv4N4espp6St77895clearE6size_t6size_t6size_t6size_t8uint16_t","espp::St7789::clear::y"],[40,3,1,"_CPPv4N4espp6St77894fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::St7789::fill"],[40,4,1,"_CPPv4N4espp6St77894fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::St7789::fill::area"],[40,4,1,"_CPPv4N4espp6St77894fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::St7789::fill::color_map"],[40,4,1,"_CPPv4N4espp6St77894fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::St7789::fill::disp"],[40,4,1,"_CPPv4N4espp6St77894fillEP12lv_display_tPK9lv_area_tP7uint8_t8uint32_t","espp::St7789::fill::flags"],[40,3,1,"_CPPv4N4espp6St77895flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::St7789::flush"],[40,4,1,"_CPPv4N4espp6St77895flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::St7789::flush::area"],[40,4,1,"_CPPv4N4espp6St77895flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::St7789::flush::color_map"],[40,4,1,"_CPPv4N4espp6St77895flushEP12lv_display_tPK9lv_area_tP7uint8_t","espp::St7789::flush::disp"],[40,3,1,"_CPPv4N4espp6St778910get_offsetERiRi","espp::St7789::get_offset"],[40,4,1,"_CPPv4N4espp6St778910get_offsetERiRi","espp::St7789::get_offset::x"],[40,4,1,"_CPPv4N4espp6St778910get_offsetERiRi","espp::St7789::get_offset::y"],[40,3,1,"_CPPv4N4espp6St778918get_offset_rotatedERiRi","espp::St7789::get_offset_rotated"],[40,4,1,"_CPPv4N4espp6St778918get_offset_rotatedERiRi","espp::St7789::get_offset_rotated::x"],[40,4,1,"_CPPv4N4espp6St778918get_offset_rotatedERiRi","espp::St7789::get_offset_rotated::y"],[40,3,1,"_CPPv4N4espp6St778910initializeERKN15display_drivers6ConfigE","espp::St7789::initialize"],[40,4,1,"_CPPv4N4espp6St778910initializeERKN15display_drivers6ConfigE","espp::St7789::initialize::config"],[40,3,1,"_CPPv4N4espp6St77896rotateERK15DisplayRotation","espp::St7789::rotate"],[40,4,1,"_CPPv4N4espp6St77896rotateERK15DisplayRotation","espp::St7789::rotate::rotation"],[40,3,1,"_CPPv4N4espp6St778912send_commandE7Command","espp::St7789::send_command"],[40,3,1,"_CPPv4N4espp6St778912send_commandE7uint8_t","espp::St7789::send_command"],[40,4,1,"_CPPv4N4espp6St778912send_commandE7Command","espp::St7789::send_command::command"],[40,4,1,"_CPPv4N4espp6St778912send_commandE7uint8_t","espp::St7789::send_command::command"],[40,3,1,"_CPPv4N4espp6St77899send_dataEPK7uint8_t6size_t8uint32_t","espp::St7789::send_data"],[40,4,1,"_CPPv4N4espp6St77899send_dataEPK7uint8_t6size_t8uint32_t","espp::St7789::send_data::data"],[40,4,1,"_CPPv4N4espp6St77899send_dataEPK7uint8_t6size_t8uint32_t","espp::St7789::send_data::flags"],[40,4,1,"_CPPv4N4espp6St77899send_dataEPK7uint8_t6size_t8uint32_t","espp::St7789::send_data::length"],[40,3,1,"_CPPv4N4espp6St778916set_drawing_areaE6size_t6size_t6size_t6size_t","espp::St7789::set_drawing_area"],[40,3,1,"_CPPv4N4espp6St778916set_drawing_areaEPK9lv_area_t","espp::St7789::set_drawing_area"],[40,4,1,"_CPPv4N4espp6St778916set_drawing_areaEPK9lv_area_t","espp::St7789::set_drawing_area::area"],[40,4,1,"_CPPv4N4espp6St778916set_drawing_areaE6size_t6size_t6size_t6size_t","espp::St7789::set_drawing_area::xe"],[40,4,1,"_CPPv4N4espp6St778916set_drawing_areaE6size_t6size_t6size_t6size_t","espp::St7789::set_drawing_area::xs"],[40,4,1,"_CPPv4N4espp6St778916set_drawing_areaE6size_t6size_t6size_t6size_t","espp::St7789::set_drawing_area::ye"],[40,4,1,"_CPPv4N4espp6St778916set_drawing_areaE6size_t6size_t6size_t6size_t","espp::St7789::set_drawing_area::ys"],[40,3,1,"_CPPv4N4espp6St778910set_offsetEii","espp::St7789::set_offset"],[40,4,1,"_CPPv4N4espp6St778910set_offsetEii","espp::St7789::set_offset::x"],[40,4,1,"_CPPv4N4espp6St778910set_offsetEii","espp::St7789::set_offset::y"],[156,2,1,"_CPPv4N4espp5TDeckE","espp::TDeck"],[156,8,1,"_CPPv4N4espp5TDeck5PixelE","espp::TDeck::Pixel"],[156,3,1,"_CPPv4N4espp5TDeck10brightnessEf","espp::TDeck::brightness"],[156,3,1,"_CPPv4NK4espp5TDeck10brightnessEv","espp::TDeck::brightness"],[156,4,1,"_CPPv4N4espp5TDeck10brightnessEf","espp::TDeck::brightness::brightness"],[156,3,1,"_CPPv4NK4espp5TDeck7displayEv","espp::TDeck::display"],[156,3,1,"_CPPv4NK4espp5TDeck13frame_buffer0Ev","espp::TDeck::frame_buffer0"],[156,3,1,"_CPPv4NK4espp5TDeck13frame_buffer1Ev","espp::TDeck::frame_buffer1"],[156,3,1,"_CPPv4N4espp5TDeck3getEv","espp::TDeck::get"],[156,3,1,"_CPPv4N4espp5TDeck15get_lcd_dc_gpioEv","espp::TDeck::get_lcd_dc_gpio"],[156,3,1,"_CPPv4NK4espp5TDeck13get_log_levelEv","espp::TDeck::get_log_level"],[156,3,1,"_CPPv4NK4espp5TDeck17get_log_verbosityEv","espp::TDeck::get_log_verbosity"],[156,3,1,"_CPPv4NK4espp5TDeck8get_nameEv","espp::TDeck::get_name"],[156,3,1,"_CPPv4N4espp5TDeck19initialize_keyboardEbRK19keypress_callback_tNSt6chrono12millisecondsE","espp::TDeck::initialize_keyboard"],[156,4,1,"_CPPv4N4espp5TDeck19initialize_keyboardEbRK19keypress_callback_tNSt6chrono12millisecondsE","espp::TDeck::initialize_keyboard::key_cb"],[156,4,1,"_CPPv4N4espp5TDeck19initialize_keyboardEbRK19keypress_callback_tNSt6chrono12millisecondsE","espp::TDeck::initialize_keyboard::poll_interval"],[156,4,1,"_CPPv4N4espp5TDeck19initialize_keyboardEbRK19keypress_callback_tNSt6chrono12millisecondsE","espp::TDeck::initialize_keyboard::start_task"],[156,3,1,"_CPPv4N4espp5TDeck14initialize_lcdEv","espp::TDeck::initialize_lcd"],[156,3,1,"_CPPv4N4espp5TDeck16initialize_touchERK16touch_callback_t","espp::TDeck::initialize_touch"],[156,4,1,"_CPPv4N4espp5TDeck16initialize_touchERK16touch_callback_t","espp::TDeck::initialize_touch::touch_cb"],[156,3,1,"_CPPv4N4espp5TDeck20initialize_trackballERK20trackball_callback_ti","espp::TDeck::initialize_trackball"],[156,4,1,"_CPPv4N4espp5TDeck20initialize_trackballERK20trackball_callback_ti","espp::TDeck::initialize_trackball::sensitivity"],[156,4,1,"_CPPv4N4espp5TDeck20initialize_trackballERK20trackball_callback_ti","espp::TDeck::initialize_trackball::trackball_cb"],[156,3,1,"_CPPv4N4espp5TDeck12internal_i2cEv","espp::TDeck::internal_i2c"],[156,3,1,"_CPPv4N4espp5TDeck10interruptsEv","espp::TDeck::interrupts"],[156,3,1,"_CPPv4NK4espp5TDeck8keyboardEv","espp::TDeck::keyboard"],[156,3,1,"_CPPv4N4espp5TDeck18keyboard_interruptEv","espp::TDeck::keyboard_interrupt"],[156,3,1,"_CPPv4N4espp5TDeck10lcd_heightEv","espp::TDeck::lcd_height"],[156,3,1,"_CPPv4N4espp5TDeck9lcd_widthEv","espp::TDeck::lcd_width"],[156,3,1,"_CPPv4N4espp5TDeck16peripheral_powerEb","espp::TDeck::peripheral_power"],[156,3,1,"_CPPv4NK4espp5TDeck16peripheral_powerEv","espp::TDeck::peripheral_power"],[156,4,1,"_CPPv4N4espp5TDeck16peripheral_powerEb","espp::TDeck::peripheral_power::on"],[156,3,1,"_CPPv4N4espp5TDeck20peripheral_power_pinEv","espp::TDeck::peripheral_power_pin"],[156,3,1,"_CPPv4NK4espp5TDeck13pointer_inputEv","espp::TDeck::pointer_input"],[156,3,1,"_CPPv4N4espp5TDeck13set_log_levelEN4espp6Logger9VerbosityE","espp::TDeck::set_log_level"],[156,4,1,"_CPPv4N4espp5TDeck13set_log_levelEN4espp6Logger9VerbosityE","espp::TDeck::set_log_level::level"],[156,3,1,"_CPPv4N4espp5TDeck18set_log_rate_limitENSt6chrono8durationIfEE","espp::TDeck::set_log_rate_limit"],[156,4,1,"_CPPv4N4espp5TDeck18set_log_rate_limitENSt6chrono8durationIfEE","espp::TDeck::set_log_rate_limit::rate_limit"],[156,3,1,"_CPPv4N4espp5TDeck11set_log_tagERKNSt11string_viewE","espp::TDeck::set_log_tag"],[156,4,1,"_CPPv4N4espp5TDeck11set_log_tagERKNSt11string_viewE","espp::TDeck::set_log_tag::tag"],[156,3,1,"_CPPv4N4espp5TDeck17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TDeck::set_log_verbosity"],[156,4,1,"_CPPv4N4espp5TDeck17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TDeck::set_log_verbosity::level"],[156,3,1,"_CPPv4N4espp5TDeck25set_trackball_sensitivityEi","espp::TDeck::set_trackball_sensitivity"],[156,4,1,"_CPPv4N4espp5TDeck25set_trackball_sensitivityEi","espp::TDeck::set_trackball_sensitivity::sensitivity"],[156,3,1,"_CPPv4NK4espp5TDeck16touchpad_convertERKN4espp12TouchpadDataE","espp::TDeck::touchpad_convert"],[156,4,1,"_CPPv4NK4espp5TDeck16touchpad_convertERKN4espp12TouchpadDataE","espp::TDeck::touchpad_convert::data"],[156,3,1,"_CPPv4NK4espp5TDeck13touchpad_dataEv","espp::TDeck::touchpad_data"],[156,3,1,"_CPPv4NK4espp5TDeck14touchpad_inputEv","espp::TDeck::touchpad_input"],[156,3,1,"_CPPv4N4espp5TDeck13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::TDeck::touchpad_read"],[156,4,1,"_CPPv4N4espp5TDeck13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::TDeck::touchpad_read::btn_state"],[156,4,1,"_CPPv4N4espp5TDeck13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::TDeck::touchpad_read::num_touch_points"],[156,4,1,"_CPPv4N4espp5TDeck13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::TDeck::touchpad_read::x"],[156,4,1,"_CPPv4N4espp5TDeck13touchpad_readEP7uint8_tP8uint16_tP8uint16_tP7uint8_t","espp::TDeck::touchpad_read::y"],[156,3,1,"_CPPv4NK4espp5TDeck9trackballEv","espp::TDeck::trackball"],[156,3,1,"_CPPv4N4espp5TDeck18trackball_btn_gpioEv","espp::TDeck::trackball_btn_gpio"],[156,3,1,"_CPPv4NK4espp5TDeck14trackball_dataEv","espp::TDeck::trackball_data"],[156,3,1,"_CPPv4N4espp5TDeck19trackball_down_gpioEv","espp::TDeck::trackball_down_gpio"],[156,3,1,"_CPPv4N4espp5TDeck19trackball_left_gpioEv","espp::TDeck::trackball_left_gpio"],[156,3,1,"_CPPv4N4espp5TDeck14trackball_readERiRiRbRb","espp::TDeck::trackball_read"],[156,4,1,"_CPPv4N4espp5TDeck14trackball_readERiRiRbRb","espp::TDeck::trackball_read::left_pressed"],[156,4,1,"_CPPv4N4espp5TDeck14trackball_readERiRiRbRb","espp::TDeck::trackball_read::right_pressed"],[156,4,1,"_CPPv4N4espp5TDeck14trackball_readERiRiRbRb","espp::TDeck::trackball_read::x"],[156,4,1,"_CPPv4N4espp5TDeck14trackball_readERiRiRbRb","espp::TDeck::trackball_read::y"],[156,3,1,"_CPPv4N4espp5TDeck20trackball_right_gpioEv","espp::TDeck::trackball_right_gpio"],[156,3,1,"_CPPv4N4espp5TDeck17trackball_up_gpioEv","espp::TDeck::trackball_up_gpio"],[156,3,1,"_CPPv4NK4espp5TDeck5vram0Ev","espp::TDeck::vram0"],[156,3,1,"_CPPv4NK4espp5TDeck5vram1Ev","espp::TDeck::vram1"],[156,3,1,"_CPPv4N4espp5TDeck9write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDeck::write_lcd"],[156,4,1,"_CPPv4N4espp5TDeck9write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDeck::write_lcd::data"],[156,4,1,"_CPPv4N4espp5TDeck9write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDeck::write_lcd::length"],[156,4,1,"_CPPv4N4espp5TDeck9write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDeck::write_lcd::user_data"],[156,3,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame::data"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame::height"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame::width"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame::x"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDeck::write_lcd_frame::y"],[156,3,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::data"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::user_data"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::xe"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::xs"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::ye"],[156,4,1,"_CPPv4N4espp5TDeck15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDeck::write_lcd_lines::ys"],[158,2,1,"_CPPv4N4espp9TDongleS3E","espp::TDongleS3"],[158,8,1,"_CPPv4N4espp9TDongleS35PixelE","espp::TDongleS3::Pixel"],[158,3,1,"_CPPv4N4espp9TDongleS310brightnessEf","espp::TDongleS3::brightness"],[158,3,1,"_CPPv4NK4espp9TDongleS310brightnessEv","espp::TDongleS3::brightness"],[158,4,1,"_CPPv4N4espp9TDongleS310brightnessEf","espp::TDongleS3::brightness::brightness"],[158,3,1,"_CPPv4NK4espp9TDongleS37displayEv","espp::TDongleS3::display"],[158,3,1,"_CPPv4NK4espp9TDongleS313frame_buffer0Ev","espp::TDongleS3::frame_buffer0"],[158,3,1,"_CPPv4NK4espp9TDongleS313frame_buffer1Ev","espp::TDongleS3::frame_buffer1"],[158,3,1,"_CPPv4N4espp9TDongleS33getEv","espp::TDongleS3::get"],[158,3,1,"_CPPv4N4espp9TDongleS315get_lcd_dc_gpioEv","espp::TDongleS3::get_lcd_dc_gpio"],[158,3,1,"_CPPv4NK4espp9TDongleS313get_log_levelEv","espp::TDongleS3::get_log_level"],[158,3,1,"_CPPv4NK4espp9TDongleS317get_log_verbosityEv","espp::TDongleS3::get_log_verbosity"],[158,3,1,"_CPPv4NK4espp9TDongleS38get_nameEv","espp::TDongleS3::get_name"],[158,3,1,"_CPPv4N4espp9TDongleS314initialize_lcdEv","espp::TDongleS3::initialize_lcd"],[158,3,1,"_CPPv4N4espp9TDongleS314initialize_ledEv","espp::TDongleS3::initialize_led"],[158,3,1,"_CPPv4N4espp9TDongleS310lcd_heightEv","espp::TDongleS3::lcd_height"],[158,3,1,"_CPPv4N4espp9TDongleS39lcd_widthEv","espp::TDongleS3::lcd_width"],[158,3,1,"_CPPv4N4espp9TDongleS33ledERK3Hsvf","espp::TDongleS3::led"],[158,3,1,"_CPPv4N4espp9TDongleS33ledERK3Rgbf","espp::TDongleS3::led"],[158,3,1,"_CPPv4NK4espp9TDongleS33ledEv","espp::TDongleS3::led"],[158,4,1,"_CPPv4N4espp9TDongleS33ledERK3Hsvf","espp::TDongleS3::led::brightness"],[158,4,1,"_CPPv4N4espp9TDongleS33ledERK3Rgbf","espp::TDongleS3::led::brightness"],[158,4,1,"_CPPv4N4espp9TDongleS33ledERK3Hsvf","espp::TDongleS3::led::hsv"],[158,4,1,"_CPPv4N4espp9TDongleS33ledERK3Rgbf","espp::TDongleS3::led::rgb"],[158,3,1,"_CPPv4N4espp9TDongleS38num_ledsEv","espp::TDongleS3::num_leds"],[158,3,1,"_CPPv4N4espp9TDongleS313set_log_levelEN4espp6Logger9VerbosityE","espp::TDongleS3::set_log_level"],[158,4,1,"_CPPv4N4espp9TDongleS313set_log_levelEN4espp6Logger9VerbosityE","espp::TDongleS3::set_log_level::level"],[158,3,1,"_CPPv4N4espp9TDongleS318set_log_rate_limitENSt6chrono8durationIfEE","espp::TDongleS3::set_log_rate_limit"],[158,4,1,"_CPPv4N4espp9TDongleS318set_log_rate_limitENSt6chrono8durationIfEE","espp::TDongleS3::set_log_rate_limit::rate_limit"],[158,3,1,"_CPPv4N4espp9TDongleS311set_log_tagERKNSt11string_viewE","espp::TDongleS3::set_log_tag"],[158,4,1,"_CPPv4N4espp9TDongleS311set_log_tagERKNSt11string_viewE","espp::TDongleS3::set_log_tag::tag"],[158,3,1,"_CPPv4N4espp9TDongleS317set_log_verbosityEN4espp6Logger9VerbosityE","espp::TDongleS3::set_log_verbosity"],[158,4,1,"_CPPv4N4espp9TDongleS317set_log_verbosityEN4espp6Logger9VerbosityE","espp::TDongleS3::set_log_verbosity::level"],[158,3,1,"_CPPv4NK4espp9TDongleS35vram0Ev","espp::TDongleS3::vram0"],[158,3,1,"_CPPv4NK4espp9TDongleS35vram1Ev","espp::TDongleS3::vram1"],[158,3,1,"_CPPv4N4espp9TDongleS39write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDongleS3::write_lcd"],[158,4,1,"_CPPv4N4espp9TDongleS39write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDongleS3::write_lcd::data"],[158,4,1,"_CPPv4N4espp9TDongleS39write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDongleS3::write_lcd::length"],[158,4,1,"_CPPv4N4espp9TDongleS39write_lcdEPK7uint8_t6size_t8uint32_t","espp::TDongleS3::write_lcd::user_data"],[158,3,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame::data"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame::height"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame::width"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame::x"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::TDongleS3::write_lcd_frame::y"],[158,3,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::data"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::user_data"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::xe"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::xs"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::ye"],[158,4,1,"_CPPv4N4espp9TDongleS315write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::TDongleS3::write_lcd_lines::ys"],[93,2,1,"_CPPv4N4espp9TKeyboardE","espp::TKeyboard"],[93,2,1,"_CPPv4N4espp9TKeyboard6ConfigE","espp::TKeyboard::Config"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config7addressE","espp::TKeyboard::Config::address"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config10auto_startE","espp::TKeyboard::Config::auto_start"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config6key_cbE","espp::TKeyboard::Config::key_cb"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config9log_levelE","espp::TKeyboard::Config::log_level"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config16polling_intervalE","espp::TKeyboard::Config::polling_interval"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config4readE","espp::TKeyboard::Config::read"],[93,1,1,"_CPPv4N4espp9TKeyboard6Config5writeE","espp::TKeyboard::Config::write"],[93,1,1,"_CPPv4N4espp9TKeyboard15DEFAULT_ADDRESSE","espp::TKeyboard::DEFAULT_ADDRESS"],[93,3,1,"_CPPv4N4espp9TKeyboard9TKeyboardERK6Config","espp::TKeyboard::TKeyboard"],[93,4,1,"_CPPv4N4espp9TKeyboard9TKeyboardERK6Config","espp::TKeyboard::TKeyboard::config"],[93,3,1,"_CPPv4NK4espp9TKeyboard7get_keyEv","espp::TKeyboard::get_key"],[93,3,1,"_CPPv4NK4espp9TKeyboard13get_log_levelEv","espp::TKeyboard::get_log_level"],[93,3,1,"_CPPv4NK4espp9TKeyboard17get_log_verbosityEv","espp::TKeyboard::get_log_verbosity"],[93,3,1,"_CPPv4NK4espp9TKeyboard8get_nameEv","espp::TKeyboard::get_name"],[93,8,1,"_CPPv4N4espp9TKeyboard9key_cb_fnE","espp::TKeyboard::key_cb_fn"],[93,3,1,"_CPPv4N4espp9TKeyboard5probeERNSt10error_codeE","espp::TKeyboard::probe"],[93,4,1,"_CPPv4N4espp9TKeyboard5probeERNSt10error_codeE","espp::TKeyboard::probe::ec"],[93,8,1,"_CPPv4N4espp9TKeyboard8probe_fnE","espp::TKeyboard::probe_fn"],[93,3,1,"_CPPv4N4espp9TKeyboard8read_keyERNSt10error_codeE","espp::TKeyboard::read_key"],[93,4,1,"_CPPv4N4espp9TKeyboard8read_keyERNSt10error_codeE","espp::TKeyboard::read_key::ec"],[93,3,1,"_CPPv4N4espp9TKeyboard11set_addressE7uint8_t","espp::TKeyboard::set_address"],[93,4,1,"_CPPv4N4espp9TKeyboard11set_addressE7uint8_t","espp::TKeyboard::set_address::address"],[93,3,1,"_CPPv4N4espp9TKeyboard10set_configERK6Config","espp::TKeyboard::set_config"],[93,3,1,"_CPPv4N4espp9TKeyboard10set_configERR6Config","espp::TKeyboard::set_config"],[93,4,1,"_CPPv4N4espp9TKeyboard10set_configERK6Config","espp::TKeyboard::set_config::config"],[93,4,1,"_CPPv4N4espp9TKeyboard10set_configERR6Config","espp::TKeyboard::set_config::config"],[93,3,1,"_CPPv4N4espp9TKeyboard13set_log_levelEN4espp6Logger9VerbosityE","espp::TKeyboard::set_log_level"],[93,4,1,"_CPPv4N4espp9TKeyboard13set_log_levelEN4espp6Logger9VerbosityE","espp::TKeyboard::set_log_level::level"],[93,3,1,"_CPPv4N4espp9TKeyboard18set_log_rate_limitENSt6chrono8durationIfEE","espp::TKeyboard::set_log_rate_limit"],[93,4,1,"_CPPv4N4espp9TKeyboard18set_log_rate_limitENSt6chrono8durationIfEE","espp::TKeyboard::set_log_rate_limit::rate_limit"],[93,3,1,"_CPPv4N4espp9TKeyboard11set_log_tagERKNSt11string_viewE","espp::TKeyboard::set_log_tag"],[93,4,1,"_CPPv4N4espp9TKeyboard11set_log_tagERKNSt11string_viewE","espp::TKeyboard::set_log_tag::tag"],[93,3,1,"_CPPv4N4espp9TKeyboard17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TKeyboard::set_log_verbosity"],[93,4,1,"_CPPv4N4espp9TKeyboard17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TKeyboard::set_log_verbosity::level"],[93,3,1,"_CPPv4N4espp9TKeyboard9set_probeERK8probe_fn","espp::TKeyboard::set_probe"],[93,4,1,"_CPPv4N4espp9TKeyboard9set_probeERK8probe_fn","espp::TKeyboard::set_probe::probe"],[93,3,1,"_CPPv4N4espp9TKeyboard8set_readERK7read_fn","espp::TKeyboard::set_read"],[93,4,1,"_CPPv4N4espp9TKeyboard8set_readERK7read_fn","espp::TKeyboard::set_read::read"],[93,3,1,"_CPPv4N4espp9TKeyboard17set_read_registerERK16read_register_fn","espp::TKeyboard::set_read_register"],[93,4,1,"_CPPv4N4espp9TKeyboard17set_read_registerERK16read_register_fn","espp::TKeyboard::set_read_register::read_register"],[93,3,1,"_CPPv4N4espp9TKeyboard34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::TKeyboard::set_separate_write_then_read_delay"],[93,4,1,"_CPPv4N4espp9TKeyboard34set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::TKeyboard::set_separate_write_then_read_delay::delay"],[93,3,1,"_CPPv4N4espp9TKeyboard9set_writeERK8write_fn","espp::TKeyboard::set_write"],[93,4,1,"_CPPv4N4espp9TKeyboard9set_writeERK8write_fn","espp::TKeyboard::set_write::write"],[93,3,1,"_CPPv4N4espp9TKeyboard19set_write_then_readERK18write_then_read_fn","espp::TKeyboard::set_write_then_read"],[93,4,1,"_CPPv4N4espp9TKeyboard19set_write_then_readERK18write_then_read_fn","espp::TKeyboard::set_write_then_read::write_then_read"],[93,3,1,"_CPPv4N4espp9TKeyboard5startEv","espp::TKeyboard::start"],[93,3,1,"_CPPv4N4espp9TKeyboard4stopEv","espp::TKeyboard::stop"],[162,2,1,"_CPPv4N4espp4TaskE","espp::Task"],[162,2,1,"_CPPv4N4espp4Task10BaseConfigE","espp::Task::BaseConfig"],[162,1,1,"_CPPv4N4espp4Task10BaseConfig7core_idE","espp::Task::BaseConfig::core_id"],[162,1,1,"_CPPv4N4espp4Task10BaseConfig4nameE","espp::Task::BaseConfig::name"],[162,1,1,"_CPPv4N4espp4Task10BaseConfig8priorityE","espp::Task::BaseConfig::priority"],[162,1,1,"_CPPv4N4espp4Task10BaseConfig16stack_size_bytesE","espp::Task::BaseConfig::stack_size_bytes"],[162,2,1,"_CPPv4N4espp4Task6ConfigE","espp::Task::Config"],[162,1,1,"_CPPv4N4espp4Task6Config8callbackE","espp::Task::Config::callback"],[162,1,1,"_CPPv4N4espp4Task6Config9log_levelE","espp::Task::Config::log_level"],[162,1,1,"_CPPv4N4espp4Task6Config11task_configE","espp::Task::Config::task_config"],[162,3,1,"_CPPv4N4espp4Task4TaskERKN4espp4Task6ConfigE","espp::Task::Task"],[162,4,1,"_CPPv4N4espp4Task4TaskERKN4espp4Task6ConfigE","espp::Task::Task::config"],[162,8,1,"_CPPv4N4espp4Task16callback_m_cv_fnE","espp::Task::callback_m_cv_fn"],[162,8,1,"_CPPv4N4espp4Task25callback_m_cv_notified_fnE","espp::Task::callback_m_cv_notified_fn"],[162,8,1,"_CPPv4N4espp4Task21callback_no_params_fnE","espp::Task::callback_no_params_fn"],[162,8,1,"_CPPv4N4espp4Task16callback_variantE","espp::Task::callback_variant"],[162,3,1,"_CPPv4N4espp4Task23configure_task_watchdogE8uint32_tb","espp::Task::configure_task_watchdog"],[162,3,1,"_CPPv4N4espp4Task23configure_task_watchdogERKNSt6chrono12millisecondsEb","espp::Task::configure_task_watchdog"],[162,4,1,"_CPPv4N4espp4Task23configure_task_watchdogE8uint32_tb","espp::Task::configure_task_watchdog::panic_on_timeout"],[162,4,1,"_CPPv4N4espp4Task23configure_task_watchdogERKNSt6chrono12millisecondsEb","espp::Task::configure_task_watchdog::panic_on_timeout"],[162,4,1,"_CPPv4N4espp4Task23configure_task_watchdogERKNSt6chrono12millisecondsEb","espp::Task::configure_task_watchdog::timeout"],[162,4,1,"_CPPv4N4espp4Task23configure_task_watchdogE8uint32_tb","espp::Task::configure_task_watchdog::timeout_ms"],[162,3,1,"_CPPv4N4espp4Task14get_current_idEv","espp::Task::get_current_id"],[162,3,1,"_CPPv4NK4espp4Task6get_idEv","espp::Task::get_id"],[162,3,1,"_CPPv4N4espp4Task8get_infoERK4Task","espp::Task::get_info"],[162,3,1,"_CPPv4N4espp4Task8get_infoEv","espp::Task::get_info"],[162,4,1,"_CPPv4N4espp4Task8get_infoERK4Task","espp::Task::get_info::task"],[162,3,1,"_CPPv4NK4espp4Task13get_log_levelEv","espp::Task::get_log_level"],[162,3,1,"_CPPv4NK4espp4Task17get_log_verbosityEv","espp::Task::get_log_verbosity"],[162,3,1,"_CPPv4NK4espp4Task8get_nameEv","espp::Task::get_name"],[162,3,1,"_CPPv4N4espp4Task17get_watchdog_infoERNSt10error_codeE","espp::Task::get_watchdog_info"],[162,4,1,"_CPPv4N4espp4Task17get_watchdog_infoERNSt10error_codeE","espp::Task::get_watchdog_info::ec"],[162,3,1,"_CPPv4NK4espp4Task10is_runningEv","espp::Task::is_running"],[162,3,1,"_CPPv4NK4espp4Task10is_startedEv","espp::Task::is_started"],[162,3,1,"_CPPv4N4espp4Task11make_uniqueERKN4espp4Task6ConfigE","espp::Task::make_unique"],[162,4,1,"_CPPv4N4espp4Task11make_uniqueERKN4espp4Task6ConfigE","espp::Task::make_unique::config"],[162,3,1,"_CPPv4N4espp4Task13set_log_levelEN4espp6Logger9VerbosityE","espp::Task::set_log_level"],[162,4,1,"_CPPv4N4espp4Task13set_log_levelEN4espp6Logger9VerbosityE","espp::Task::set_log_level::level"],[162,3,1,"_CPPv4N4espp4Task18set_log_rate_limitENSt6chrono8durationIfEE","espp::Task::set_log_rate_limit"],[162,4,1,"_CPPv4N4espp4Task18set_log_rate_limitENSt6chrono8durationIfEE","espp::Task::set_log_rate_limit::rate_limit"],[162,3,1,"_CPPv4N4espp4Task11set_log_tagERKNSt11string_viewE","espp::Task::set_log_tag"],[162,4,1,"_CPPv4N4espp4Task11set_log_tagERKNSt11string_viewE","espp::Task::set_log_tag::tag"],[162,3,1,"_CPPv4N4espp4Task17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Task::set_log_verbosity"],[162,4,1,"_CPPv4N4espp4Task17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Task::set_log_verbosity::level"],[162,3,1,"_CPPv4N4espp4Task5startEv","espp::Task::start"],[162,3,1,"_CPPv4N4espp4Task14start_watchdogEv","espp::Task::start_watchdog"],[162,3,1,"_CPPv4N4espp4Task4stopEv","espp::Task::stop"],[162,3,1,"_CPPv4N4espp4Task13stop_watchdogEv","espp::Task::stop_watchdog"],[162,3,1,"_CPPv4N4espp4TaskD0Ev","espp::Task::~Task"],[124,2,1,"_CPPv4N4espp11TaskMonitorE","espp::TaskMonitor"],[124,2,1,"_CPPv4N4espp11TaskMonitor6ConfigE","espp::TaskMonitor::Config"],[124,1,1,"_CPPv4N4espp11TaskMonitor6Config6periodE","espp::TaskMonitor::Config::period"],[124,1,1,"_CPPv4N4espp11TaskMonitor6Config21task_stack_size_bytesE","espp::TaskMonitor::Config::task_stack_size_bytes"],[124,2,1,"_CPPv4N4espp11TaskMonitor8TaskInfoE","espp::TaskMonitor::TaskInfo"],[124,1,1,"_CPPv4N4espp11TaskMonitor8TaskInfo7core_idE","espp::TaskMonitor::TaskInfo::core_id"],[124,1,1,"_CPPv4N4espp11TaskMonitor8TaskInfo11cpu_percentE","espp::TaskMonitor::TaskInfo::cpu_percent"],[124,1,1,"_CPPv4N4espp11TaskMonitor8TaskInfo15high_water_markE","espp::TaskMonitor::TaskInfo::high_water_mark"],[124,1,1,"_CPPv4N4espp11TaskMonitor8TaskInfo4nameE","espp::TaskMonitor::TaskInfo::name"],[124,1,1,"_CPPv4N4espp11TaskMonitor8TaskInfo8priorityE","espp::TaskMonitor::TaskInfo::priority"],[124,3,1,"_CPPv4N4espp11TaskMonitor22get_latest_info_stringEv","espp::TaskMonitor::get_latest_info_string"],[124,3,1,"_CPPv4N4espp11TaskMonitor21get_latest_info_tableEv","espp::TaskMonitor::get_latest_info_table"],[124,3,1,"_CPPv4N4espp11TaskMonitor22get_latest_info_vectorEv","espp::TaskMonitor::get_latest_info_vector"],[124,3,1,"_CPPv4NK4espp11TaskMonitor13get_log_levelEv","espp::TaskMonitor::get_log_level"],[124,3,1,"_CPPv4NK4espp11TaskMonitor17get_log_verbosityEv","espp::TaskMonitor::get_log_verbosity"],[124,3,1,"_CPPv4NK4espp11TaskMonitor8get_nameEv","espp::TaskMonitor::get_name"],[124,3,1,"_CPPv4N4espp11TaskMonitor13set_log_levelEN4espp6Logger9VerbosityE","espp::TaskMonitor::set_log_level"],[124,4,1,"_CPPv4N4espp11TaskMonitor13set_log_levelEN4espp6Logger9VerbosityE","espp::TaskMonitor::set_log_level::level"],[124,3,1,"_CPPv4N4espp11TaskMonitor18set_log_rate_limitENSt6chrono8durationIfEE","espp::TaskMonitor::set_log_rate_limit"],[124,4,1,"_CPPv4N4espp11TaskMonitor18set_log_rate_limitENSt6chrono8durationIfEE","espp::TaskMonitor::set_log_rate_limit::rate_limit"],[124,3,1,"_CPPv4N4espp11TaskMonitor11set_log_tagERKNSt11string_viewE","espp::TaskMonitor::set_log_tag"],[124,4,1,"_CPPv4N4espp11TaskMonitor11set_log_tagERKNSt11string_viewE","espp::TaskMonitor::set_log_tag::tag"],[124,3,1,"_CPPv4N4espp11TaskMonitor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TaskMonitor::set_log_verbosity"],[124,4,1,"_CPPv4N4espp11TaskMonitor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TaskMonitor::set_log_verbosity::level"],[131,2,1,"_CPPv4N4espp9TcpSocketE","espp::TcpSocket"],[131,2,1,"_CPPv4N4espp9TcpSocket6ConfigE","espp::TcpSocket::Config"],[131,1,1,"_CPPv4N4espp9TcpSocket6Config9log_levelE","espp::TcpSocket::Config::log_level"],[131,2,1,"_CPPv4N4espp9TcpSocket13ConnectConfigE","espp::TcpSocket::ConnectConfig"],[131,1,1,"_CPPv4N4espp9TcpSocket13ConnectConfig10ip_addressE","espp::TcpSocket::ConnectConfig::ip_address"],[131,1,1,"_CPPv4N4espp9TcpSocket13ConnectConfig4portE","espp::TcpSocket::ConnectConfig::port"],[131,3,1,"_CPPv4N4espp9TcpSocket9TcpSocketERKN4espp9TcpSocket6ConfigE","espp::TcpSocket::TcpSocket"],[131,4,1,"_CPPv4N4espp9TcpSocket9TcpSocketERKN4espp9TcpSocket6ConfigE","espp::TcpSocket::TcpSocket::config"],[131,2,1,"_CPPv4N4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::TransmitConfig"],[131,1,1,"_CPPv4N4espp9TcpSocket14TransmitConfig20on_response_callbackE","espp::TcpSocket::TransmitConfig::on_response_callback"],[131,1,1,"_CPPv4N4espp9TcpSocket14TransmitConfig13response_sizeE","espp::TcpSocket::TransmitConfig::response_size"],[131,1,1,"_CPPv4N4espp9TcpSocket14TransmitConfig16response_timeoutE","espp::TcpSocket::TransmitConfig::response_timeout"],[131,1,1,"_CPPv4N4espp9TcpSocket14TransmitConfig17wait_for_responseE","espp::TcpSocket::TransmitConfig::wait_for_response"],[131,3,1,"_CPPv4N4espp9TcpSocket6acceptEv","espp::TcpSocket::accept"],[131,3,1,"_CPPv4N4espp9TcpSocket19add_multicast_groupERKNSt6stringE","espp::TcpSocket::add_multicast_group"],[131,4,1,"_CPPv4N4espp9TcpSocket19add_multicast_groupERKNSt6stringE","espp::TcpSocket::add_multicast_group::multicast_group"],[131,3,1,"_CPPv4N4espp9TcpSocket4bindEi","espp::TcpSocket::bind"],[131,4,1,"_CPPv4N4espp9TcpSocket4bindEi","espp::TcpSocket::bind::port"],[131,3,1,"_CPPv4N4espp9TcpSocket5closeEv","espp::TcpSocket::close"],[131,3,1,"_CPPv4N4espp9TcpSocket7connectERKN4espp9TcpSocket13ConnectConfigE","espp::TcpSocket::connect"],[131,4,1,"_CPPv4N4espp9TcpSocket7connectERKN4espp9TcpSocket13ConnectConfigE","espp::TcpSocket::connect::connect_config"],[131,3,1,"_CPPv4N4espp9TcpSocket12enable_reuseEv","espp::TcpSocket::enable_reuse"],[131,3,1,"_CPPv4N4espp9TcpSocket13get_ipv4_infoEv","espp::TcpSocket::get_ipv4_info"],[131,3,1,"_CPPv4NK4espp9TcpSocket13get_log_levelEv","espp::TcpSocket::get_log_level"],[131,3,1,"_CPPv4NK4espp9TcpSocket17get_log_verbosityEv","espp::TcpSocket::get_log_verbosity"],[131,3,1,"_CPPv4NK4espp9TcpSocket8get_nameEv","espp::TcpSocket::get_name"],[131,3,1,"_CPPv4NK4espp9TcpSocket15get_remote_infoEv","espp::TcpSocket::get_remote_info"],[131,3,1,"_CPPv4NK4espp9TcpSocket12is_connectedEv","espp::TcpSocket::is_connected"],[131,3,1,"_CPPv4NK4espp9TcpSocket8is_validEv","espp::TcpSocket::is_valid"],[131,3,1,"_CPPv4N4espp9TcpSocket11is_valid_fdE11sock_type_t","espp::TcpSocket::is_valid_fd"],[131,4,1,"_CPPv4N4espp9TcpSocket11is_valid_fdE11sock_type_t","espp::TcpSocket::is_valid_fd::socket_fd"],[131,3,1,"_CPPv4N4espp9TcpSocket6listenEi","espp::TcpSocket::listen"],[131,4,1,"_CPPv4N4espp9TcpSocket6listenEi","espp::TcpSocket::listen::max_pending_connections"],[131,3,1,"_CPPv4N4espp9TcpSocket14make_multicastE7uint8_t7uint8_t","espp::TcpSocket::make_multicast"],[131,4,1,"_CPPv4N4espp9TcpSocket14make_multicastE7uint8_t7uint8_t","espp::TcpSocket::make_multicast::loopback_enabled"],[131,4,1,"_CPPv4N4espp9TcpSocket14make_multicastE7uint8_t7uint8_t","espp::TcpSocket::make_multicast::time_to_live"],[131,3,1,"_CPPv4N4espp9TcpSocket7receiveEP7uint8_t6size_t","espp::TcpSocket::receive"],[131,3,1,"_CPPv4N4espp9TcpSocket7receiveERNSt6vectorI7uint8_tEE6size_t","espp::TcpSocket::receive"],[131,4,1,"_CPPv4N4espp9TcpSocket7receiveEP7uint8_t6size_t","espp::TcpSocket::receive::data"],[131,4,1,"_CPPv4N4espp9TcpSocket7receiveERNSt6vectorI7uint8_tEE6size_t","espp::TcpSocket::receive::data"],[131,4,1,"_CPPv4N4espp9TcpSocket7receiveEP7uint8_t6size_t","espp::TcpSocket::receive::max_num_bytes"],[131,4,1,"_CPPv4N4espp9TcpSocket7receiveERNSt6vectorI7uint8_tEE6size_t","espp::TcpSocket::receive::max_num_bytes"],[131,8,1,"_CPPv4N4espp9TcpSocket19receive_callback_fnE","espp::TcpSocket::receive_callback_fn"],[131,3,1,"_CPPv4N4espp9TcpSocket6reinitEv","espp::TcpSocket::reinit"],[131,8,1,"_CPPv4N4espp9TcpSocket20response_callback_fnE","espp::TcpSocket::response_callback_fn"],[131,3,1,"_CPPv4N4espp9TcpSocket6selectERKNSt6chrono12microsecondsE","espp::TcpSocket::select"],[131,4,1,"_CPPv4N4espp9TcpSocket6selectERKNSt6chrono12microsecondsE","espp::TcpSocket::select::timeout"],[131,3,1,"_CPPv4N4espp9TcpSocket13set_log_levelEN4espp6Logger9VerbosityE","espp::TcpSocket::set_log_level"],[131,4,1,"_CPPv4N4espp9TcpSocket13set_log_levelEN4espp6Logger9VerbosityE","espp::TcpSocket::set_log_level::level"],[131,3,1,"_CPPv4N4espp9TcpSocket18set_log_rate_limitENSt6chrono8durationIfEE","espp::TcpSocket::set_log_rate_limit"],[131,4,1,"_CPPv4N4espp9TcpSocket18set_log_rate_limitENSt6chrono8durationIfEE","espp::TcpSocket::set_log_rate_limit::rate_limit"],[131,3,1,"_CPPv4N4espp9TcpSocket11set_log_tagERKNSt11string_viewE","espp::TcpSocket::set_log_tag"],[131,4,1,"_CPPv4N4espp9TcpSocket11set_log_tagERKNSt11string_viewE","espp::TcpSocket::set_log_tag::tag"],[131,3,1,"_CPPv4N4espp9TcpSocket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TcpSocket::set_log_verbosity"],[131,4,1,"_CPPv4N4espp9TcpSocket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TcpSocket::set_log_verbosity::level"],[131,3,1,"_CPPv4N4espp9TcpSocket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::TcpSocket::set_receive_timeout"],[131,4,1,"_CPPv4N4espp9TcpSocket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::TcpSocket::set_receive_timeout::timeout"],[131,3,1,"_CPPv4N4espp9TcpSocket8transmitENSt11string_viewERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit"],[131,3,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorI7uint8_tEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit"],[131,3,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorIcEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitENSt11string_viewERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::data"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorI7uint8_tEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::data"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorIcEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::data"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitENSt11string_viewERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::transmit_config"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorI7uint8_tEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::transmit_config"],[131,4,1,"_CPPv4N4espp9TcpSocket8transmitERKNSt6vectorIcEERKN4espp9TcpSocket14TransmitConfigE","espp::TcpSocket::transmit::transmit_config"],[131,3,1,"_CPPv4N4espp9TcpSocketD0Ev","espp::TcpSocket::~TcpSocket"],[164,2,1,"_CPPv4N4espp10ThermistorE","espp::Thermistor"],[164,2,1,"_CPPv4N4espp10Thermistor6ConfigE","espp::Thermistor::Config"],[164,1,1,"_CPPv4N4espp10Thermistor6Config4betaE","espp::Thermistor::Config::beta"],[164,1,1,"_CPPv4N4espp10Thermistor6Config14divider_configE","espp::Thermistor::Config::divider_config"],[164,1,1,"_CPPv4N4espp10Thermistor6Config21fixed_resistance_ohmsE","espp::Thermistor::Config::fixed_resistance_ohms"],[164,1,1,"_CPPv4N4espp10Thermistor6Config9log_levelE","espp::Thermistor::Config::log_level"],[164,1,1,"_CPPv4N4espp10Thermistor6Config23nominal_resistance_ohmsE","espp::Thermistor::Config::nominal_resistance_ohms"],[164,1,1,"_CPPv4N4espp10Thermistor6Config7read_mvE","espp::Thermistor::Config::read_mv"],[164,1,1,"_CPPv4N4espp10Thermistor6Config9supply_mvE","espp::Thermistor::Config::supply_mv"],[164,6,1,"_CPPv4N4espp10Thermistor21ResistorDividerConfigE","espp::Thermistor::ResistorDividerConfig"],[164,7,1,"_CPPv4N4espp10Thermistor21ResistorDividerConfig5LOWERE","espp::Thermistor::ResistorDividerConfig::LOWER"],[164,7,1,"_CPPv4N4espp10Thermistor21ResistorDividerConfig5UPPERE","espp::Thermistor::ResistorDividerConfig::UPPER"],[164,3,1,"_CPPv4N4espp10Thermistor10ThermistorERK6Config","espp::Thermistor::Thermistor"],[164,4,1,"_CPPv4N4espp10Thermistor10ThermistorERK6Config","espp::Thermistor::Thermistor::config"],[164,3,1,"_CPPv4N4espp10Thermistor11get_celsiusEv","espp::Thermistor::get_celsius"],[164,3,1,"_CPPv4N4espp10Thermistor14get_fahrenheitEv","espp::Thermistor::get_fahrenheit"],[164,3,1,"_CPPv4N4espp10Thermistor10get_kelvinEv","espp::Thermistor::get_kelvin"],[164,3,1,"_CPPv4NK4espp10Thermistor13get_log_levelEv","espp::Thermistor::get_log_level"],[164,3,1,"_CPPv4NK4espp10Thermistor17get_log_verbosityEv","espp::Thermistor::get_log_verbosity"],[164,3,1,"_CPPv4NK4espp10Thermistor8get_nameEv","espp::Thermistor::get_name"],[164,3,1,"_CPPv4N4espp10Thermistor14get_resistanceEv","espp::Thermistor::get_resistance"],[164,8,1,"_CPPv4N4espp10Thermistor10read_mv_fnE","espp::Thermistor::read_mv_fn"],[164,3,1,"_CPPv4N4espp10Thermistor13set_log_levelEN4espp6Logger9VerbosityE","espp::Thermistor::set_log_level"],[164,4,1,"_CPPv4N4espp10Thermistor13set_log_levelEN4espp6Logger9VerbosityE","espp::Thermistor::set_log_level::level"],[164,3,1,"_CPPv4N4espp10Thermistor18set_log_rate_limitENSt6chrono8durationIfEE","espp::Thermistor::set_log_rate_limit"],[164,4,1,"_CPPv4N4espp10Thermistor18set_log_rate_limitENSt6chrono8durationIfEE","espp::Thermistor::set_log_rate_limit::rate_limit"],[164,3,1,"_CPPv4N4espp10Thermistor11set_log_tagERKNSt11string_viewE","espp::Thermistor::set_log_tag"],[164,4,1,"_CPPv4N4espp10Thermistor11set_log_tagERKNSt11string_viewE","espp::Thermistor::set_log_tag::tag"],[164,3,1,"_CPPv4N4espp10Thermistor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Thermistor::set_log_verbosity"],[164,4,1,"_CPPv4N4espp10Thermistor17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Thermistor::set_log_verbosity::level"],[166,2,1,"_CPPv4N4espp5TimerE","espp::Timer"],[166,2,1,"_CPPv4N4espp5Timer14AdvancedConfigE","espp::Timer::AdvancedConfig"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig10auto_startE","espp::Timer::AdvancedConfig::auto_start"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig8callbackE","espp::Timer::AdvancedConfig::callback"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig5delayE","espp::Timer::AdvancedConfig::delay"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig9log_levelE","espp::Timer::AdvancedConfig::log_level"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig6periodE","espp::Timer::AdvancedConfig::period"],[166,1,1,"_CPPv4N4espp5Timer14AdvancedConfig11task_configE","espp::Timer::AdvancedConfig::task_config"],[166,2,1,"_CPPv4N4espp5Timer6ConfigE","espp::Timer::Config"],[166,1,1,"_CPPv4N4espp5Timer6Config10auto_startE","espp::Timer::Config::auto_start"],[166,1,1,"_CPPv4N4espp5Timer6Config8callbackE","espp::Timer::Config::callback"],[166,1,1,"_CPPv4N4espp5Timer6Config7core_idE","espp::Timer::Config::core_id"],[166,1,1,"_CPPv4N4espp5Timer6Config5delayE","espp::Timer::Config::delay"],[166,1,1,"_CPPv4N4espp5Timer6Config9log_levelE","espp::Timer::Config::log_level"],[166,1,1,"_CPPv4N4espp5Timer6Config4nameE","espp::Timer::Config::name"],[166,1,1,"_CPPv4N4espp5Timer6Config6periodE","espp::Timer::Config::period"],[166,1,1,"_CPPv4N4espp5Timer6Config8priorityE","espp::Timer::Config::priority"],[166,1,1,"_CPPv4N4espp5Timer6Config16stack_size_bytesE","espp::Timer::Config::stack_size_bytes"],[166,3,1,"_CPPv4N4espp5Timer5TimerERK14AdvancedConfig","espp::Timer::Timer"],[166,3,1,"_CPPv4N4espp5Timer5TimerERK6Config","espp::Timer::Timer"],[166,4,1,"_CPPv4N4espp5Timer5TimerERK14AdvancedConfig","espp::Timer::Timer::config"],[166,4,1,"_CPPv4N4espp5Timer5TimerERK6Config","espp::Timer::Timer::config"],[166,8,1,"_CPPv4N4espp5Timer11callback_fnE","espp::Timer::callback_fn"],[166,3,1,"_CPPv4N4espp5Timer6cancelEv","espp::Timer::cancel"],[166,3,1,"_CPPv4NK4espp5Timer13get_log_levelEv","espp::Timer::get_log_level"],[166,3,1,"_CPPv4NK4espp5Timer17get_log_verbosityEv","espp::Timer::get_log_verbosity"],[166,3,1,"_CPPv4NK4espp5Timer8get_nameEv","espp::Timer::get_name"],[166,3,1,"_CPPv4NK4espp5Timer10is_runningEv","espp::Timer::is_running"],[166,3,1,"_CPPv4N4espp5Timer13set_log_levelEN4espp6Logger9VerbosityE","espp::Timer::set_log_level"],[166,4,1,"_CPPv4N4espp5Timer13set_log_levelEN4espp6Logger9VerbosityE","espp::Timer::set_log_level::level"],[166,3,1,"_CPPv4N4espp5Timer18set_log_rate_limitENSt6chrono8durationIfEE","espp::Timer::set_log_rate_limit"],[166,4,1,"_CPPv4N4espp5Timer18set_log_rate_limitENSt6chrono8durationIfEE","espp::Timer::set_log_rate_limit::rate_limit"],[166,3,1,"_CPPv4N4espp5Timer11set_log_tagERKNSt11string_viewE","espp::Timer::set_log_tag"],[166,4,1,"_CPPv4N4espp5Timer11set_log_tagERKNSt11string_viewE","espp::Timer::set_log_tag::tag"],[166,3,1,"_CPPv4N4espp5Timer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Timer::set_log_verbosity"],[166,4,1,"_CPPv4N4espp5Timer17set_log_verbosityEN4espp6Logger9VerbosityE","espp::Timer::set_log_verbosity::level"],[166,3,1,"_CPPv4N4espp5Timer10set_periodERKNSt6chrono8durationIfEE","espp::Timer::set_period"],[166,4,1,"_CPPv4N4espp5Timer10set_periodERKNSt6chrono8durationIfEE","espp::Timer::set_period::period"],[166,3,1,"_CPPv4N4espp5Timer5startERKNSt6chrono8durationIfEE","espp::Timer::start"],[166,3,1,"_CPPv4N4espp5Timer5startEv","espp::Timer::start"],[166,4,1,"_CPPv4N4espp5Timer5startERKNSt6chrono8durationIfEE","espp::Timer::start::delay"],[166,3,1,"_CPPv4N4espp5Timer14start_watchdogEv","espp::Timer::start_watchdog"],[166,3,1,"_CPPv4N4espp5Timer4stopEv","espp::Timer::stop"],[166,3,1,"_CPPv4N4espp5Timer13stop_watchdogEv","espp::Timer::stop_watchdog"],[166,3,1,"_CPPv4N4espp5TimerD0Ev","espp::Timer::~Timer"],[9,2,1,"_CPPv4N4espp7Tla2528E","espp::Tla2528"],[9,6,1,"_CPPv4N4espp7Tla252810AlertLogicE","espp::Tla2528::AlertLogic"],[9,7,1,"_CPPv4N4espp7Tla252810AlertLogic11ACTIVE_HIGHE","espp::Tla2528::AlertLogic::ACTIVE_HIGH"],[9,7,1,"_CPPv4N4espp7Tla252810AlertLogic10ACTIVE_LOWE","espp::Tla2528::AlertLogic::ACTIVE_LOW"],[9,7,1,"_CPPv4N4espp7Tla252810AlertLogic11PULSED_HIGHE","espp::Tla2528::AlertLogic::PULSED_HIGH"],[9,7,1,"_CPPv4N4espp7Tla252810AlertLogic10PULSED_LOWE","espp::Tla2528::AlertLogic::PULSED_LOW"],[9,6,1,"_CPPv4N4espp7Tla25286AppendE","espp::Tla2528::Append"],[9,7,1,"_CPPv4N4espp7Tla25286Append10CHANNEL_IDE","espp::Tla2528::Append::CHANNEL_ID"],[9,7,1,"_CPPv4N4espp7Tla25286Append4NONEE","espp::Tla2528::Append::NONE"],[9,6,1,"_CPPv4N4espp7Tla25287ChannelE","espp::Tla2528::Channel"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH0E","espp::Tla2528::Channel::CH0"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH1E","espp::Tla2528::Channel::CH1"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH2E","espp::Tla2528::Channel::CH2"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH3E","espp::Tla2528::Channel::CH3"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH4E","espp::Tla2528::Channel::CH4"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH5E","espp::Tla2528::Channel::CH5"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH6E","espp::Tla2528::Channel::CH6"],[9,7,1,"_CPPv4N4espp7Tla25287Channel3CH7E","espp::Tla2528::Channel::CH7"],[9,2,1,"_CPPv4N4espp7Tla25286ConfigE","espp::Tla2528::Config"],[9,1,1,"_CPPv4N4espp7Tla25286Config13analog_inputsE","espp::Tla2528::Config::analog_inputs"],[9,1,1,"_CPPv4N4espp7Tla25286Config6appendE","espp::Tla2528::Config::append"],[9,1,1,"_CPPv4N4espp7Tla25286Config9auto_initE","espp::Tla2528::Config::auto_init"],[9,1,1,"_CPPv4N4espp7Tla25286Config10avdd_voltsE","espp::Tla2528::Config::avdd_volts"],[9,1,1,"_CPPv4N4espp7Tla25286Config14device_addressE","espp::Tla2528::Config::device_address"],[9,1,1,"_CPPv4N4espp7Tla25286Config14digital_inputsE","espp::Tla2528::Config::digital_inputs"],[9,1,1,"_CPPv4N4espp7Tla25286Config20digital_output_modesE","espp::Tla2528::Config::digital_output_modes"],[9,1,1,"_CPPv4N4espp7Tla25286Config21digital_output_valuesE","espp::Tla2528::Config::digital_output_values"],[9,1,1,"_CPPv4N4espp7Tla25286Config15digital_outputsE","espp::Tla2528::Config::digital_outputs"],[9,1,1,"_CPPv4N4espp7Tla25286Config9log_levelE","espp::Tla2528::Config::log_level"],[9,1,1,"_CPPv4N4espp7Tla25286Config4modeE","espp::Tla2528::Config::mode"],[9,1,1,"_CPPv4N4espp7Tla25286Config18oversampling_ratioE","espp::Tla2528::Config::oversampling_ratio"],[9,1,1,"_CPPv4N4espp7Tla25286Config4readE","espp::Tla2528::Config::read"],[9,1,1,"_CPPv4N4espp7Tla25286Config5writeE","espp::Tla2528::Config::write"],[9,1,1,"_CPPv4N4espp7Tla252815DEFAULT_ADDRESSE","espp::Tla2528::DEFAULT_ADDRESS"],[9,6,1,"_CPPv4N4espp7Tla252810DataFormatE","espp::Tla2528::DataFormat"],[9,7,1,"_CPPv4N4espp7Tla252810DataFormat8AVERAGEDE","espp::Tla2528::DataFormat::AVERAGED"],[9,7,1,"_CPPv4N4espp7Tla252810DataFormat3RAWE","espp::Tla2528::DataFormat::RAW"],[9,6,1,"_CPPv4N4espp7Tla25284ModeE","espp::Tla2528::Mode"],[9,7,1,"_CPPv4N4espp7Tla25284Mode8AUTO_SEQE","espp::Tla2528::Mode::AUTO_SEQ"],[9,7,1,"_CPPv4N4espp7Tla25284Mode6MANUALE","espp::Tla2528::Mode::MANUAL"],[9,6,1,"_CPPv4N4espp7Tla252810OutputModeE","espp::Tla2528::OutputMode"],[9,7,1,"_CPPv4N4espp7Tla252810OutputMode10OPEN_DRAINE","espp::Tla2528::OutputMode::OPEN_DRAIN"],[9,7,1,"_CPPv4N4espp7Tla252810OutputMode9PUSH_PULLE","espp::Tla2528::OutputMode::PUSH_PULL"],[9,6,1,"_CPPv4N4espp7Tla252817OversamplingRatioE","espp::Tla2528::OversamplingRatio"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio4NONEE","espp::Tla2528::OversamplingRatio::NONE"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio7OSR_128E","espp::Tla2528::OversamplingRatio::OSR_128"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio6OSR_16E","espp::Tla2528::OversamplingRatio::OSR_16"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio5OSR_2E","espp::Tla2528::OversamplingRatio::OSR_2"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio6OSR_32E","espp::Tla2528::OversamplingRatio::OSR_32"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio5OSR_4E","espp::Tla2528::OversamplingRatio::OSR_4"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio6OSR_64E","espp::Tla2528::OversamplingRatio::OSR_64"],[9,7,1,"_CPPv4N4espp7Tla252817OversamplingRatio5OSR_8E","espp::Tla2528::OversamplingRatio::OSR_8"],[9,3,1,"_CPPv4N4espp7Tla25287Tla2528ERK6Config","espp::Tla2528::Tla2528"],[9,4,1,"_CPPv4N4espp7Tla25287Tla2528ERK6Config","espp::Tla2528::Tla2528::config"],[9,3,1,"_CPPv4N4espp7Tla252810get_all_mvERNSt10error_codeE","espp::Tla2528::get_all_mv"],[9,4,1,"_CPPv4N4espp7Tla252810get_all_mvERNSt10error_codeE","espp::Tla2528::get_all_mv::ec"],[9,3,1,"_CPPv4N4espp7Tla252814get_all_mv_mapERNSt10error_codeE","espp::Tla2528::get_all_mv_map"],[9,4,1,"_CPPv4N4espp7Tla252814get_all_mv_mapERNSt10error_codeE","espp::Tla2528::get_all_mv_map::ec"],[9,3,1,"_CPPv4N4espp7Tla252823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Tla2528::get_digital_input_value"],[9,4,1,"_CPPv4N4espp7Tla252823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Tla2528::get_digital_input_value::channel"],[9,4,1,"_CPPv4N4espp7Tla252823get_digital_input_valueE7ChannelRNSt10error_codeE","espp::Tla2528::get_digital_input_value::ec"],[9,3,1,"_CPPv4N4espp7Tla252824get_digital_input_valuesERNSt10error_codeE","espp::Tla2528::get_digital_input_values"],[9,4,1,"_CPPv4N4espp7Tla252824get_digital_input_valuesERNSt10error_codeE","espp::Tla2528::get_digital_input_values::ec"],[9,3,1,"_CPPv4NK4espp7Tla252813get_log_levelEv","espp::Tla2528::get_log_level"],[9,3,1,"_CPPv4NK4espp7Tla252817get_log_verbosityEv","espp::Tla2528::get_log_verbosity"],[9,3,1,"_CPPv4N4espp7Tla25286get_mvE7ChannelRNSt10error_codeE","espp::Tla2528::get_mv"],[9,4,1,"_CPPv4N4espp7Tla25286get_mvE7ChannelRNSt10error_codeE","espp::Tla2528::get_mv::channel"],[9,4,1,"_CPPv4N4espp7Tla25286get_mvE7ChannelRNSt10error_codeE","espp::Tla2528::get_mv::ec"],[9,3,1,"_CPPv4NK4espp7Tla25288get_nameEv","espp::Tla2528::get_name"],[9,3,1,"_CPPv4N4espp7Tla252810initializeERNSt10error_codeE","espp::Tla2528::initialize"],[9,4,1,"_CPPv4N4espp7Tla252810initializeERNSt10error_codeE","espp::Tla2528::initialize::ec"],[9,3,1,"_CPPv4N4espp7Tla25285probeERNSt10error_codeE","espp::Tla2528::probe"],[9,4,1,"_CPPv4N4espp7Tla25285probeERNSt10error_codeE","espp::Tla2528::probe::ec"],[9,8,1,"_CPPv4N4espp7Tla25288probe_fnE","espp::Tla2528::probe_fn"],[9,3,1,"_CPPv4N4espp7Tla25285resetERNSt10error_codeE","espp::Tla2528::reset"],[9,4,1,"_CPPv4N4espp7Tla25285resetERNSt10error_codeE","espp::Tla2528::reset::ec"],[9,3,1,"_CPPv4N4espp7Tla252811set_addressE7uint8_t","espp::Tla2528::set_address"],[9,4,1,"_CPPv4N4espp7Tla252811set_addressE7uint8_t","espp::Tla2528::set_address::address"],[9,3,1,"_CPPv4N4espp7Tla252810set_configERK6Config","espp::Tla2528::set_config"],[9,3,1,"_CPPv4N4espp7Tla252810set_configERR6Config","espp::Tla2528::set_config"],[9,4,1,"_CPPv4N4espp7Tla252810set_configERK6Config","espp::Tla2528::set_config::config"],[9,4,1,"_CPPv4N4espp7Tla252810set_configERR6Config","espp::Tla2528::set_config::config"],[9,3,1,"_CPPv4N4espp7Tla252823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Tla2528::set_digital_output_mode"],[9,4,1,"_CPPv4N4espp7Tla252823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Tla2528::set_digital_output_mode::channel"],[9,4,1,"_CPPv4N4espp7Tla252823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Tla2528::set_digital_output_mode::ec"],[9,4,1,"_CPPv4N4espp7Tla252823set_digital_output_modeE7Channel10OutputModeRNSt10error_codeE","espp::Tla2528::set_digital_output_mode::output_mode"],[9,3,1,"_CPPv4N4espp7Tla252824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Tla2528::set_digital_output_value"],[9,4,1,"_CPPv4N4espp7Tla252824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Tla2528::set_digital_output_value::channel"],[9,4,1,"_CPPv4N4espp7Tla252824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Tla2528::set_digital_output_value::ec"],[9,4,1,"_CPPv4N4espp7Tla252824set_digital_output_valueE7ChannelbRNSt10error_codeE","espp::Tla2528::set_digital_output_value::value"],[9,3,1,"_CPPv4N4espp7Tla252813set_log_levelEN4espp6Logger9VerbosityE","espp::Tla2528::set_log_level"],[9,4,1,"_CPPv4N4espp7Tla252813set_log_levelEN4espp6Logger9VerbosityE","espp::Tla2528::set_log_level::level"],[9,3,1,"_CPPv4N4espp7Tla252818set_log_rate_limitENSt6chrono8durationIfEE","espp::Tla2528::set_log_rate_limit"],[9,4,1,"_CPPv4N4espp7Tla252818set_log_rate_limitENSt6chrono8durationIfEE","espp::Tla2528::set_log_rate_limit::rate_limit"],[9,3,1,"_CPPv4N4espp7Tla252811set_log_tagERKNSt11string_viewE","espp::Tla2528::set_log_tag"],[9,4,1,"_CPPv4N4espp7Tla252811set_log_tagERKNSt11string_viewE","espp::Tla2528::set_log_tag::tag"],[9,3,1,"_CPPv4N4espp7Tla252817set_log_verbosityEN4espp6Logger9VerbosityE","espp::Tla2528::set_log_verbosity"],[9,4,1,"_CPPv4N4espp7Tla252817set_log_verbosityEN4espp6Logger9VerbosityE","espp::Tla2528::set_log_verbosity::level"],[9,3,1,"_CPPv4N4espp7Tla25289set_probeERK8probe_fn","espp::Tla2528::set_probe"],[9,4,1,"_CPPv4N4espp7Tla25289set_probeERK8probe_fn","espp::Tla2528::set_probe::probe"],[9,3,1,"_CPPv4N4espp7Tla25288set_readERK7read_fn","espp::Tla2528::set_read"],[9,4,1,"_CPPv4N4espp7Tla25288set_readERK7read_fn","espp::Tla2528::set_read::read"],[9,3,1,"_CPPv4N4espp7Tla252817set_read_registerERK16read_register_fn","espp::Tla2528::set_read_register"],[9,4,1,"_CPPv4N4espp7Tla252817set_read_registerERK16read_register_fn","espp::Tla2528::set_read_register::read_register"],[9,3,1,"_CPPv4N4espp7Tla252834set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Tla2528::set_separate_write_then_read_delay"],[9,4,1,"_CPPv4N4espp7Tla252834set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Tla2528::set_separate_write_then_read_delay::delay"],[9,3,1,"_CPPv4N4espp7Tla25289set_writeERK8write_fn","espp::Tla2528::set_write"],[9,4,1,"_CPPv4N4espp7Tla25289set_writeERK8write_fn","espp::Tla2528::set_write::write"],[9,3,1,"_CPPv4N4espp7Tla252819set_write_then_readERK18write_then_read_fn","espp::Tla2528::set_write_then_read"],[9,4,1,"_CPPv4N4espp7Tla252819set_write_then_readERK18write_then_read_fn","espp::Tla2528::set_write_then_read::write_then_read"],[95,2,1,"_CPPv4N4espp13TouchpadInputE","espp::TouchpadInput"],[95,2,1,"_CPPv4N4espp13TouchpadInput6ConfigE","espp::TouchpadInput::Config"],[95,1,1,"_CPPv4N4espp13TouchpadInput6Config8invert_xE","espp::TouchpadInput::Config::invert_x"],[95,1,1,"_CPPv4N4espp13TouchpadInput6Config8invert_yE","espp::TouchpadInput::Config::invert_y"],[95,1,1,"_CPPv4N4espp13TouchpadInput6Config9log_levelE","espp::TouchpadInput::Config::log_level"],[95,1,1,"_CPPv4N4espp13TouchpadInput6Config7swap_xyE","espp::TouchpadInput::Config::swap_xy"],[95,1,1,"_CPPv4N4espp13TouchpadInput6Config13touchpad_readE","espp::TouchpadInput::Config::touchpad_read"],[95,3,1,"_CPPv4N4espp13TouchpadInput13TouchpadInputERK6Config","espp::TouchpadInput::TouchpadInput"],[95,4,1,"_CPPv4N4espp13TouchpadInput13TouchpadInputERK6Config","espp::TouchpadInput::TouchpadInput::config"],[95,3,1,"_CPPv4N4espp13TouchpadInput28get_home_button_input_deviceEv","espp::TouchpadInput::get_home_button_input_device"],[95,3,1,"_CPPv4NK4espp13TouchpadInput13get_log_levelEv","espp::TouchpadInput::get_log_level"],[95,3,1,"_CPPv4NK4espp13TouchpadInput17get_log_verbosityEv","espp::TouchpadInput::get_log_verbosity"],[95,3,1,"_CPPv4NK4espp13TouchpadInput8get_nameEv","espp::TouchpadInput::get_name"],[95,3,1,"_CPPv4N4espp13TouchpadInput25get_touchpad_input_deviceEv","espp::TouchpadInput::get_touchpad_input_device"],[95,3,1,"_CPPv4N4espp13TouchpadInput13set_log_levelEN4espp6Logger9VerbosityE","espp::TouchpadInput::set_log_level"],[95,4,1,"_CPPv4N4espp13TouchpadInput13set_log_levelEN4espp6Logger9VerbosityE","espp::TouchpadInput::set_log_level::level"],[95,3,1,"_CPPv4N4espp13TouchpadInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::TouchpadInput::set_log_rate_limit"],[95,4,1,"_CPPv4N4espp13TouchpadInput18set_log_rate_limitENSt6chrono8durationIfEE","espp::TouchpadInput::set_log_rate_limit::rate_limit"],[95,3,1,"_CPPv4N4espp13TouchpadInput11set_log_tagERKNSt11string_viewE","espp::TouchpadInput::set_log_tag"],[95,4,1,"_CPPv4N4espp13TouchpadInput11set_log_tagERKNSt11string_viewE","espp::TouchpadInput::set_log_tag::tag"],[95,3,1,"_CPPv4N4espp13TouchpadInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TouchpadInput::set_log_verbosity"],[95,4,1,"_CPPv4N4espp13TouchpadInput17set_log_verbosityEN4espp6Logger9VerbosityE","espp::TouchpadInput::set_log_verbosity::level"],[95,8,1,"_CPPv4N4espp13TouchpadInput16touchpad_read_fnE","espp::TouchpadInput::touchpad_read_fn"],[95,3,1,"_CPPv4N4espp13TouchpadInputD0Ev","espp::TouchpadInput::~TouchpadInput"],[96,2,1,"_CPPv4N4espp7Tt21100E","espp::Tt21100"],[96,2,1,"_CPPv4N4espp7Tt211006ConfigE","espp::Tt21100::Config"],[96,1,1,"_CPPv4N4espp7Tt211006Config9log_levelE","espp::Tt21100::Config::log_level"],[96,1,1,"_CPPv4N4espp7Tt211006Config4readE","espp::Tt21100::Config::read"],[96,1,1,"_CPPv4N4espp7Tt211006Config5writeE","espp::Tt21100::Config::write"],[96,1,1,"_CPPv4N4espp7Tt2110015DEFAULT_ADDRESSE","espp::Tt21100::DEFAULT_ADDRESS"],[96,3,1,"_CPPv4N4espp7Tt211007Tt21100ERK6Config","espp::Tt21100::Tt21100"],[96,4,1,"_CPPv4N4espp7Tt211007Tt21100ERK6Config","espp::Tt21100::Tt21100::config"],[96,3,1,"_CPPv4NK4espp7Tt2110021get_home_button_stateEv","espp::Tt21100::get_home_button_state"],[96,3,1,"_CPPv4NK4espp7Tt2110013get_log_levelEv","espp::Tt21100::get_log_level"],[96,3,1,"_CPPv4NK4espp7Tt2110017get_log_verbosityEv","espp::Tt21100::get_log_verbosity"],[96,3,1,"_CPPv4NK4espp7Tt211008get_nameEv","espp::Tt21100::get_name"],[96,3,1,"_CPPv4NK4espp7Tt2110020get_num_touch_pointsEv","espp::Tt21100::get_num_touch_points"],[96,3,1,"_CPPv4NK4espp7Tt2110015get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Tt21100::get_touch_point"],[96,4,1,"_CPPv4NK4espp7Tt2110015get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Tt21100::get_touch_point::num_touch_points"],[96,4,1,"_CPPv4NK4espp7Tt2110015get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Tt21100::get_touch_point::x"],[96,4,1,"_CPPv4NK4espp7Tt2110015get_touch_pointEP7uint8_tP8uint16_tP8uint16_t","espp::Tt21100::get_touch_point::y"],[96,3,1,"_CPPv4N4espp7Tt211005probeERNSt10error_codeE","espp::Tt21100::probe"],[96,4,1,"_CPPv4N4espp7Tt211005probeERNSt10error_codeE","espp::Tt21100::probe::ec"],[96,8,1,"_CPPv4N4espp7Tt211008probe_fnE","espp::Tt21100::probe_fn"],[96,3,1,"_CPPv4N4espp7Tt2110011set_addressE7uint8_t","espp::Tt21100::set_address"],[96,4,1,"_CPPv4N4espp7Tt2110011set_addressE7uint8_t","espp::Tt21100::set_address::address"],[96,3,1,"_CPPv4N4espp7Tt2110010set_configERK6Config","espp::Tt21100::set_config"],[96,3,1,"_CPPv4N4espp7Tt2110010set_configERR6Config","espp::Tt21100::set_config"],[96,4,1,"_CPPv4N4espp7Tt2110010set_configERK6Config","espp::Tt21100::set_config::config"],[96,4,1,"_CPPv4N4espp7Tt2110010set_configERR6Config","espp::Tt21100::set_config::config"],[96,3,1,"_CPPv4N4espp7Tt2110013set_log_levelEN4espp6Logger9VerbosityE","espp::Tt21100::set_log_level"],[96,4,1,"_CPPv4N4espp7Tt2110013set_log_levelEN4espp6Logger9VerbosityE","espp::Tt21100::set_log_level::level"],[96,3,1,"_CPPv4N4espp7Tt2110018set_log_rate_limitENSt6chrono8durationIfEE","espp::Tt21100::set_log_rate_limit"],[96,4,1,"_CPPv4N4espp7Tt2110018set_log_rate_limitENSt6chrono8durationIfEE","espp::Tt21100::set_log_rate_limit::rate_limit"],[96,3,1,"_CPPv4N4espp7Tt2110011set_log_tagERKNSt11string_viewE","espp::Tt21100::set_log_tag"],[96,4,1,"_CPPv4N4espp7Tt2110011set_log_tagERKNSt11string_viewE","espp::Tt21100::set_log_tag::tag"],[96,3,1,"_CPPv4N4espp7Tt2110017set_log_verbosityEN4espp6Logger9VerbosityE","espp::Tt21100::set_log_verbosity"],[96,4,1,"_CPPv4N4espp7Tt2110017set_log_verbosityEN4espp6Logger9VerbosityE","espp::Tt21100::set_log_verbosity::level"],[96,3,1,"_CPPv4N4espp7Tt211009set_probeERK8probe_fn","espp::Tt21100::set_probe"],[96,4,1,"_CPPv4N4espp7Tt211009set_probeERK8probe_fn","espp::Tt21100::set_probe::probe"],[96,3,1,"_CPPv4N4espp7Tt211008set_readERK7read_fn","espp::Tt21100::set_read"],[96,4,1,"_CPPv4N4espp7Tt211008set_readERK7read_fn","espp::Tt21100::set_read::read"],[96,3,1,"_CPPv4N4espp7Tt2110017set_read_registerERK16read_register_fn","espp::Tt21100::set_read_register"],[96,4,1,"_CPPv4N4espp7Tt2110017set_read_registerERK16read_register_fn","espp::Tt21100::set_read_register::read_register"],[96,3,1,"_CPPv4N4espp7Tt2110034set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Tt21100::set_separate_write_then_read_delay"],[96,4,1,"_CPPv4N4espp7Tt2110034set_separate_write_then_read_delayERKNSt6chrono12millisecondsE","espp::Tt21100::set_separate_write_then_read_delay::delay"],[96,3,1,"_CPPv4N4espp7Tt211009set_writeERK8write_fn","espp::Tt21100::set_write"],[96,4,1,"_CPPv4N4espp7Tt211009set_writeERK8write_fn","espp::Tt21100::set_write::write"],[96,3,1,"_CPPv4N4espp7Tt2110019set_write_then_readERK18write_then_read_fn","espp::Tt21100::set_write_then_read"],[96,4,1,"_CPPv4N4espp7Tt2110019set_write_then_readERK18write_then_read_fn","espp::Tt21100::set_write_then_read::write_then_read"],[96,3,1,"_CPPv4N4espp7Tt211006updateERNSt10error_codeE","espp::Tt21100::update"],[96,4,1,"_CPPv4N4espp7Tt211006updateERNSt10error_codeE","espp::Tt21100::update::ec"],[132,2,1,"_CPPv4N4espp9UdpSocketE","espp::UdpSocket"],[132,2,1,"_CPPv4N4espp9UdpSocket6ConfigE","espp::UdpSocket::Config"],[132,1,1,"_CPPv4N4espp9UdpSocket6Config9log_levelE","espp::UdpSocket::Config::log_level"],[132,2,1,"_CPPv4N4espp9UdpSocket13ReceiveConfigE","espp::UdpSocket::ReceiveConfig"],[132,1,1,"_CPPv4N4espp9UdpSocket13ReceiveConfig11buffer_sizeE","espp::UdpSocket::ReceiveConfig::buffer_size"],[132,1,1,"_CPPv4N4espp9UdpSocket13ReceiveConfig21is_multicast_endpointE","espp::UdpSocket::ReceiveConfig::is_multicast_endpoint"],[132,1,1,"_CPPv4N4espp9UdpSocket13ReceiveConfig15multicast_groupE","espp::UdpSocket::ReceiveConfig::multicast_group"],[132,1,1,"_CPPv4N4espp9UdpSocket13ReceiveConfig19on_receive_callbackE","espp::UdpSocket::ReceiveConfig::on_receive_callback"],[132,1,1,"_CPPv4N4espp9UdpSocket13ReceiveConfig4portE","espp::UdpSocket::ReceiveConfig::port"],[132,2,1,"_CPPv4N4espp9UdpSocket10SendConfigE","espp::UdpSocket::SendConfig"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig10ip_addressE","espp::UdpSocket::SendConfig::ip_address"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig21is_multicast_endpointE","espp::UdpSocket::SendConfig::is_multicast_endpoint"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig20on_response_callbackE","espp::UdpSocket::SendConfig::on_response_callback"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig4portE","espp::UdpSocket::SendConfig::port"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig13response_sizeE","espp::UdpSocket::SendConfig::response_size"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig16response_timeoutE","espp::UdpSocket::SendConfig::response_timeout"],[132,1,1,"_CPPv4N4espp9UdpSocket10SendConfig17wait_for_responseE","espp::UdpSocket::SendConfig::wait_for_response"],[132,3,1,"_CPPv4N4espp9UdpSocket9UdpSocketERK6Config","espp::UdpSocket::UdpSocket"],[132,4,1,"_CPPv4N4espp9UdpSocket9UdpSocketERK6Config","espp::UdpSocket::UdpSocket::config"],[132,3,1,"_CPPv4N4espp9UdpSocket19add_multicast_groupERKNSt6stringE","espp::UdpSocket::add_multicast_group"],[132,4,1,"_CPPv4N4espp9UdpSocket19add_multicast_groupERKNSt6stringE","espp::UdpSocket::add_multicast_group::multicast_group"],[132,3,1,"_CPPv4N4espp9UdpSocket12enable_reuseEv","espp::UdpSocket::enable_reuse"],[132,3,1,"_CPPv4N4espp9UdpSocket13get_ipv4_infoEv","espp::UdpSocket::get_ipv4_info"],[132,3,1,"_CPPv4NK4espp9UdpSocket13get_log_levelEv","espp::UdpSocket::get_log_level"],[132,3,1,"_CPPv4NK4espp9UdpSocket17get_log_verbosityEv","espp::UdpSocket::get_log_verbosity"],[132,3,1,"_CPPv4NK4espp9UdpSocket8get_nameEv","espp::UdpSocket::get_name"],[132,3,1,"_CPPv4NK4espp9UdpSocket8is_validEv","espp::UdpSocket::is_valid"],[132,3,1,"_CPPv4N4espp9UdpSocket11is_valid_fdE11sock_type_t","espp::UdpSocket::is_valid_fd"],[132,4,1,"_CPPv4N4espp9UdpSocket11is_valid_fdE11sock_type_t","espp::UdpSocket::is_valid_fd::socket_fd"],[132,3,1,"_CPPv4N4espp9UdpSocket14make_multicastE7uint8_t7uint8_t","espp::UdpSocket::make_multicast"],[132,4,1,"_CPPv4N4espp9UdpSocket14make_multicastE7uint8_t7uint8_t","espp::UdpSocket::make_multicast::loopback_enabled"],[132,4,1,"_CPPv4N4espp9UdpSocket14make_multicastE7uint8_t7uint8_t","espp::UdpSocket::make_multicast::time_to_live"],[132,3,1,"_CPPv4N4espp9UdpSocket7receiveE6size_tRNSt6vectorI7uint8_tEERN6Socket4InfoE","espp::UdpSocket::receive"],[132,4,1,"_CPPv4N4espp9UdpSocket7receiveE6size_tRNSt6vectorI7uint8_tEERN6Socket4InfoE","espp::UdpSocket::receive::data"],[132,4,1,"_CPPv4N4espp9UdpSocket7receiveE6size_tRNSt6vectorI7uint8_tEERN6Socket4InfoE","espp::UdpSocket::receive::max_num_bytes"],[132,4,1,"_CPPv4N4espp9UdpSocket7receiveE6size_tRNSt6vectorI7uint8_tEERN6Socket4InfoE","espp::UdpSocket::receive::remote_info"],[132,8,1,"_CPPv4N4espp9UdpSocket19receive_callback_fnE","espp::UdpSocket::receive_callback_fn"],[132,8,1,"_CPPv4N4espp9UdpSocket20response_callback_fnE","espp::UdpSocket::response_callback_fn"],[132,3,1,"_CPPv4N4espp9UdpSocket6selectERKNSt6chrono12microsecondsE","espp::UdpSocket::select"],[132,4,1,"_CPPv4N4espp9UdpSocket6selectERKNSt6chrono12microsecondsE","espp::UdpSocket::select::timeout"],[132,3,1,"_CPPv4N4espp9UdpSocket4sendENSt11string_viewERK10SendConfig","espp::UdpSocket::send"],[132,3,1,"_CPPv4N4espp9UdpSocket4sendERKNSt6vectorI7uint8_tEERK10SendConfig","espp::UdpSocket::send"],[132,4,1,"_CPPv4N4espp9UdpSocket4sendENSt11string_viewERK10SendConfig","espp::UdpSocket::send::data"],[132,4,1,"_CPPv4N4espp9UdpSocket4sendERKNSt6vectorI7uint8_tEERK10SendConfig","espp::UdpSocket::send::data"],[132,4,1,"_CPPv4N4espp9UdpSocket4sendENSt11string_viewERK10SendConfig","espp::UdpSocket::send::send_config"],[132,4,1,"_CPPv4N4espp9UdpSocket4sendERKNSt6vectorI7uint8_tEERK10SendConfig","espp::UdpSocket::send::send_config"],[132,3,1,"_CPPv4N4espp9UdpSocket13set_log_levelEN4espp6Logger9VerbosityE","espp::UdpSocket::set_log_level"],[132,4,1,"_CPPv4N4espp9UdpSocket13set_log_levelEN4espp6Logger9VerbosityE","espp::UdpSocket::set_log_level::level"],[132,3,1,"_CPPv4N4espp9UdpSocket18set_log_rate_limitENSt6chrono8durationIfEE","espp::UdpSocket::set_log_rate_limit"],[132,4,1,"_CPPv4N4espp9UdpSocket18set_log_rate_limitENSt6chrono8durationIfEE","espp::UdpSocket::set_log_rate_limit::rate_limit"],[132,3,1,"_CPPv4N4espp9UdpSocket11set_log_tagERKNSt11string_viewE","espp::UdpSocket::set_log_tag"],[132,4,1,"_CPPv4N4espp9UdpSocket11set_log_tagERKNSt11string_viewE","espp::UdpSocket::set_log_tag::tag"],[132,3,1,"_CPPv4N4espp9UdpSocket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::UdpSocket::set_log_verbosity"],[132,4,1,"_CPPv4N4espp9UdpSocket17set_log_verbosityEN4espp6Logger9VerbosityE","espp::UdpSocket::set_log_verbosity::level"],[132,3,1,"_CPPv4N4espp9UdpSocket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::UdpSocket::set_receive_timeout"],[132,4,1,"_CPPv4N4espp9UdpSocket19set_receive_timeoutERKNSt6chrono8durationIfEE","espp::UdpSocket::set_receive_timeout::timeout"],[132,3,1,"_CPPv4N4espp9UdpSocket15start_receivingERN4Task10BaseConfigERK13ReceiveConfig","espp::UdpSocket::start_receiving"],[132,4,1,"_CPPv4N4espp9UdpSocket15start_receivingERN4Task10BaseConfigERK13ReceiveConfig","espp::UdpSocket::start_receiving::receive_config"],[132,4,1,"_CPPv4N4espp9UdpSocket15start_receivingERN4Task10BaseConfigERK13ReceiveConfig","espp::UdpSocket::start_receiving::task_config"],[132,3,1,"_CPPv4N4espp9UdpSocketD0Ev","espp::UdpSocket::~UdpSocket"],[121,2,1,"_CPPv4I0EN4espp8Vector2dE","espp::Vector2d"],[121,5,1,"_CPPv4I0EN4espp8Vector2dE","espp::Vector2d::T"],[121,3,1,"_CPPv4N4espp8Vector2d8Vector2dE1T1T","espp::Vector2d::Vector2d"],[121,3,1,"_CPPv4N4espp8Vector2d8Vector2dERK8Vector2d","espp::Vector2d::Vector2d"],[121,4,1,"_CPPv4N4espp8Vector2d8Vector2dERK8Vector2d","espp::Vector2d::Vector2d::other"],[121,4,1,"_CPPv4N4espp8Vector2d8Vector2dE1T1T","espp::Vector2d::Vector2d::x"],[121,4,1,"_CPPv4N4espp8Vector2d8Vector2dE1T1T","espp::Vector2d::Vector2d::y"],[121,3,1,"_CPPv4NK4espp8Vector2d3dotERK8Vector2d","espp::Vector2d::dot"],[121,4,1,"_CPPv4NK4espp8Vector2d3dotERK8Vector2d","espp::Vector2d::dot::other"],[121,3,1,"_CPPv4NK4espp8Vector2d9magnitudeEv","espp::Vector2d::magnitude"],[121,3,1,"_CPPv4NK4espp8Vector2d17magnitude_squaredEv","espp::Vector2d::magnitude_squared"],[121,3,1,"_CPPv4NK4espp8Vector2d10normalizedEv","espp::Vector2d::normalized"],[121,3,1,"_CPPv4NK4espp8Vector2dmlERK1T","espp::Vector2d::operator*"],[121,4,1,"_CPPv4NK4espp8Vector2dmlERK1T","espp::Vector2d::operator*::v"],[121,3,1,"_CPPv4N4espp8Vector2dmLERK1T","espp::Vector2d::operator*="],[121,4,1,"_CPPv4N4espp8Vector2dmLERK1T","espp::Vector2d::operator*=::v"],[121,3,1,"_CPPv4NK4espp8Vector2dplERK8Vector2d","espp::Vector2d::operator+"],[121,4,1,"_CPPv4NK4espp8Vector2dplERK8Vector2d","espp::Vector2d::operator+::rhs"],[121,3,1,"_CPPv4N4espp8Vector2dpLERK8Vector2d","espp::Vector2d::operator+="],[121,4,1,"_CPPv4N4espp8Vector2dpLERK8Vector2d","espp::Vector2d::operator+=::rhs"],[121,3,1,"_CPPv4NK4espp8Vector2dmiERK8Vector2d","espp::Vector2d::operator-"],[121,3,1,"_CPPv4NK4espp8Vector2dmiEv","espp::Vector2d::operator-"],[121,4,1,"_CPPv4NK4espp8Vector2dmiERK8Vector2d","espp::Vector2d::operator-::rhs"],[121,3,1,"_CPPv4N4espp8Vector2dmIERK8Vector2d","espp::Vector2d::operator-="],[121,4,1,"_CPPv4N4espp8Vector2dmIERK8Vector2d","espp::Vector2d::operator-=::rhs"],[121,3,1,"_CPPv4NK4espp8Vector2ddvERK1T","espp::Vector2d::operator/"],[121,3,1,"_CPPv4NK4espp8Vector2ddvERK8Vector2d","espp::Vector2d::operator/"],[121,4,1,"_CPPv4NK4espp8Vector2ddvERK1T","espp::Vector2d::operator/::v"],[121,4,1,"_CPPv4NK4espp8Vector2ddvERK8Vector2d","espp::Vector2d::operator/::v"],[121,3,1,"_CPPv4N4espp8Vector2ddVERK1T","espp::Vector2d::operator/="],[121,3,1,"_CPPv4N4espp8Vector2ddVERK8Vector2d","espp::Vector2d::operator/="],[121,4,1,"_CPPv4N4espp8Vector2ddVERK1T","espp::Vector2d::operator/=::v"],[121,4,1,"_CPPv4N4espp8Vector2ddVERK8Vector2d","espp::Vector2d::operator/=::v"],[121,3,1,"_CPPv4NK4espp8Vector2dssERK8Vector2d","espp::Vector2d::operator<=>"],[121,4,1,"_CPPv4NK4espp8Vector2dssERK8Vector2d","espp::Vector2d::operator<=>::other"],[121,3,1,"_CPPv4N4espp8Vector2daSERK8Vector2d","espp::Vector2d::operator="],[121,4,1,"_CPPv4N4espp8Vector2daSERK8Vector2d","espp::Vector2d::operator=::other"],[121,3,1,"_CPPv4NK4espp8Vector2deqERK8Vector2d","espp::Vector2d::operator=="],[121,4,1,"_CPPv4NK4espp8Vector2deqERK8Vector2d","espp::Vector2d::operator==::other"],[121,3,1,"_CPPv4N4espp8Vector2dixEi","espp::Vector2d::operator[]"],[121,4,1,"_CPPv4N4espp8Vector2dixEi","espp::Vector2d::operator[]::index"],[121,3,1,"_CPPv4I0_PNSt9enable_ifINSt17is_floating_pointI1UE5valueEE4typeEENK4espp8Vector2d7rotatedE8Vector2d1T","espp::Vector2d::rotated"],[121,5,1,"_CPPv4I0_PNSt9enable_ifINSt17is_floating_pointI1UE5valueEE4typeEENK4espp8Vector2d7rotatedE8Vector2d1T","espp::Vector2d::rotated::U"],[121,4,1,"_CPPv4I0_PNSt9enable_ifINSt17is_floating_pointI1UE5valueEE4typeEENK4espp8Vector2d7rotatedE8Vector2d1T","espp::Vector2d::rotated::radians"],[121,3,1,"_CPPv4N4espp8Vector2d1xE1T","espp::Vector2d::x"],[121,3,1,"_CPPv4NK4espp8Vector2d1xEv","espp::Vector2d::x"],[121,4,1,"_CPPv4N4espp8Vector2d1xE1T","espp::Vector2d::x::v"],[121,3,1,"_CPPv4N4espp8Vector2d1yE1T","espp::Vector2d::y"],[121,3,1,"_CPPv4NK4espp8Vector2d1yEv","espp::Vector2d::y"],[121,4,1,"_CPPv4N4espp8Vector2d1yE1T","espp::Vector2d::y::v"],[169,2,1,"_CPPv4N4espp6WifiApE","espp::WifiAp"],[169,2,1,"_CPPv4N4espp6WifiAp6ConfigE","espp::WifiAp::Config"],[169,1,1,"_CPPv4N4espp6WifiAp6Config7channelE","espp::WifiAp::Config::channel"],[169,1,1,"_CPPv4N4espp6WifiAp6Config9log_levelE","espp::WifiAp::Config::log_level"],[169,1,1,"_CPPv4N4espp6WifiAp6Config22max_number_of_stationsE","espp::WifiAp::Config::max_number_of_stations"],[169,1,1,"_CPPv4N4espp6WifiAp6Config8passwordE","espp::WifiAp::Config::password"],[169,1,1,"_CPPv4N4espp6WifiAp6Config4ssidE","espp::WifiAp::Config::ssid"],[169,3,1,"_CPPv4N4espp6WifiAp6WifiApERK6Config","espp::WifiAp::WifiAp"],[169,4,1,"_CPPv4N4espp6WifiAp6WifiApERK6Config","espp::WifiAp::WifiAp::config"],[169,3,1,"_CPPv4NK4espp6WifiAp13get_log_levelEv","espp::WifiAp::get_log_level"],[169,3,1,"_CPPv4NK4espp6WifiAp17get_log_verbosityEv","espp::WifiAp::get_log_verbosity"],[169,3,1,"_CPPv4NK4espp6WifiAp8get_nameEv","espp::WifiAp::get_name"],[169,3,1,"_CPPv4N4espp6WifiAp13set_log_levelEN4espp6Logger9VerbosityE","espp::WifiAp::set_log_level"],[169,4,1,"_CPPv4N4espp6WifiAp13set_log_levelEN4espp6Logger9VerbosityE","espp::WifiAp::set_log_level::level"],[169,3,1,"_CPPv4N4espp6WifiAp18set_log_rate_limitENSt6chrono8durationIfEE","espp::WifiAp::set_log_rate_limit"],[169,4,1,"_CPPv4N4espp6WifiAp18set_log_rate_limitENSt6chrono8durationIfEE","espp::WifiAp::set_log_rate_limit::rate_limit"],[169,3,1,"_CPPv4N4espp6WifiAp11set_log_tagERKNSt11string_viewE","espp::WifiAp::set_log_tag"],[169,4,1,"_CPPv4N4espp6WifiAp11set_log_tagERKNSt11string_viewE","espp::WifiAp::set_log_tag::tag"],[169,3,1,"_CPPv4N4espp6WifiAp17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WifiAp::set_log_verbosity"],[169,4,1,"_CPPv4N4espp6WifiAp17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WifiAp::set_log_verbosity::level"],[171,2,1,"_CPPv4N4espp7WifiStaE","espp::WifiSta"],[171,2,1,"_CPPv4N4espp7WifiSta6ConfigE","espp::WifiSta::Config"],[171,1,1,"_CPPv4N4espp7WifiSta6Config6ap_macE","espp::WifiSta::Config::ap_mac"],[171,1,1,"_CPPv4N4espp7WifiSta6Config7channelE","espp::WifiSta::Config::channel"],[171,1,1,"_CPPv4N4espp7WifiSta6Config9log_levelE","espp::WifiSta::Config::log_level"],[171,1,1,"_CPPv4N4espp7WifiSta6Config19num_connect_retriesE","espp::WifiSta::Config::num_connect_retries"],[171,1,1,"_CPPv4N4espp7WifiSta6Config12on_connectedE","espp::WifiSta::Config::on_connected"],[171,1,1,"_CPPv4N4espp7WifiSta6Config15on_disconnectedE","espp::WifiSta::Config::on_disconnected"],[171,1,1,"_CPPv4N4espp7WifiSta6Config9on_got_ipE","espp::WifiSta::Config::on_got_ip"],[171,1,1,"_CPPv4N4espp7WifiSta6Config8passwordE","espp::WifiSta::Config::password"],[171,1,1,"_CPPv4N4espp7WifiSta6Config10set_ap_macE","espp::WifiSta::Config::set_ap_mac"],[171,1,1,"_CPPv4N4espp7WifiSta6Config4ssidE","espp::WifiSta::Config::ssid"],[171,3,1,"_CPPv4N4espp7WifiSta7WifiStaERK6Config","espp::WifiSta::WifiSta"],[171,4,1,"_CPPv4N4espp7WifiSta7WifiStaERK6Config","espp::WifiSta::WifiSta::config"],[171,8,1,"_CPPv4N4espp7WifiSta16connect_callbackE","espp::WifiSta::connect_callback"],[171,8,1,"_CPPv4N4espp7WifiSta19disconnect_callbackE","espp::WifiSta::disconnect_callback"],[171,3,1,"_CPPv4NK4espp7WifiSta13get_log_levelEv","espp::WifiSta::get_log_level"],[171,3,1,"_CPPv4NK4espp7WifiSta17get_log_verbosityEv","espp::WifiSta::get_log_verbosity"],[171,3,1,"_CPPv4NK4espp7WifiSta8get_nameEv","espp::WifiSta::get_name"],[171,8,1,"_CPPv4N4espp7WifiSta11ip_callbackE","espp::WifiSta::ip_callback"],[171,3,1,"_CPPv4NK4espp7WifiSta12is_connectedEv","espp::WifiSta::is_connected"],[171,3,1,"_CPPv4N4espp7WifiSta13set_log_levelEN4espp6Logger9VerbosityE","espp::WifiSta::set_log_level"],[171,4,1,"_CPPv4N4espp7WifiSta13set_log_levelEN4espp6Logger9VerbosityE","espp::WifiSta::set_log_level::level"],[171,3,1,"_CPPv4N4espp7WifiSta18set_log_rate_limitENSt6chrono8durationIfEE","espp::WifiSta::set_log_rate_limit"],[171,4,1,"_CPPv4N4espp7WifiSta18set_log_rate_limitENSt6chrono8durationIfEE","espp::WifiSta::set_log_rate_limit::rate_limit"],[171,3,1,"_CPPv4N4espp7WifiSta11set_log_tagERKNSt11string_viewE","espp::WifiSta::set_log_tag"],[171,4,1,"_CPPv4N4espp7WifiSta11set_log_tagERKNSt11string_viewE","espp::WifiSta::set_log_tag::tag"],[171,3,1,"_CPPv4N4espp7WifiSta17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WifiSta::set_log_verbosity"],[171,4,1,"_CPPv4N4espp7WifiSta17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WifiSta::set_log_verbosity::level"],[171,3,1,"_CPPv4N4espp7WifiStaD0Ev","espp::WifiSta::~WifiSta"],[172,2,1,"_CPPv4N4espp9WroverKitE","espp::WroverKit"],[172,8,1,"_CPPv4N4espp9WroverKit5PixelE","espp::WroverKit::Pixel"],[172,2,1,"_CPPv4N4espp9WroverKit12TouchpadDataE","espp::WroverKit::TouchpadData"],[172,1,1,"_CPPv4N4espp9WroverKit12TouchpadData9btn_stateE","espp::WroverKit::TouchpadData::btn_state"],[172,1,1,"_CPPv4N4espp9WroverKit12TouchpadData16num_touch_pointsE","espp::WroverKit::TouchpadData::num_touch_points"],[172,3,1,"_CPPv4NK4espp9WroverKit12TouchpadDataeqERK12TouchpadData","espp::WroverKit::TouchpadData::operator=="],[172,4,1,"_CPPv4NK4espp9WroverKit12TouchpadDataeqERK12TouchpadData","espp::WroverKit::TouchpadData::operator==::rhs"],[172,1,1,"_CPPv4N4espp9WroverKit12TouchpadData1xE","espp::WroverKit::TouchpadData::x"],[172,1,1,"_CPPv4N4espp9WroverKit12TouchpadData1yE","espp::WroverKit::TouchpadData::y"],[172,3,1,"_CPPv4N4espp9WroverKit10brightnessEf","espp::WroverKit::brightness"],[172,3,1,"_CPPv4NK4espp9WroverKit10brightnessEv","espp::WroverKit::brightness"],[172,4,1,"_CPPv4N4espp9WroverKit10brightnessEf","espp::WroverKit::brightness::brightness"],[172,3,1,"_CPPv4NK4espp9WroverKit7displayEv","espp::WroverKit::display"],[172,3,1,"_CPPv4NK4espp9WroverKit13frame_buffer0Ev","espp::WroverKit::frame_buffer0"],[172,3,1,"_CPPv4NK4espp9WroverKit13frame_buffer1Ev","espp::WroverKit::frame_buffer1"],[172,3,1,"_CPPv4N4espp9WroverKit3getEv","espp::WroverKit::get"],[172,3,1,"_CPPv4N4espp9WroverKit15get_lcd_dc_gpioEv","espp::WroverKit::get_lcd_dc_gpio"],[172,3,1,"_CPPv4NK4espp9WroverKit13get_log_levelEv","espp::WroverKit::get_log_level"],[172,3,1,"_CPPv4NK4espp9WroverKit17get_log_verbosityEv","espp::WroverKit::get_log_verbosity"],[172,3,1,"_CPPv4NK4espp9WroverKit8get_nameEv","espp::WroverKit::get_name"],[172,3,1,"_CPPv4N4espp9WroverKit14initialize_lcdEv","espp::WroverKit::initialize_lcd"],[172,3,1,"_CPPv4N4espp9WroverKit10lcd_heightEv","espp::WroverKit::lcd_height"],[172,3,1,"_CPPv4N4espp9WroverKit9lcd_widthEv","espp::WroverKit::lcd_width"],[172,3,1,"_CPPv4N4espp9WroverKit13set_log_levelEN4espp6Logger9VerbosityE","espp::WroverKit::set_log_level"],[172,4,1,"_CPPv4N4espp9WroverKit13set_log_levelEN4espp6Logger9VerbosityE","espp::WroverKit::set_log_level::level"],[172,3,1,"_CPPv4N4espp9WroverKit18set_log_rate_limitENSt6chrono8durationIfEE","espp::WroverKit::set_log_rate_limit"],[172,4,1,"_CPPv4N4espp9WroverKit18set_log_rate_limitENSt6chrono8durationIfEE","espp::WroverKit::set_log_rate_limit::rate_limit"],[172,3,1,"_CPPv4N4espp9WroverKit11set_log_tagERKNSt11string_viewE","espp::WroverKit::set_log_tag"],[172,4,1,"_CPPv4N4espp9WroverKit11set_log_tagERKNSt11string_viewE","espp::WroverKit::set_log_tag::tag"],[172,3,1,"_CPPv4N4espp9WroverKit17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WroverKit::set_log_verbosity"],[172,4,1,"_CPPv4N4espp9WroverKit17set_log_verbosityEN4espp6Logger9VerbosityE","espp::WroverKit::set_log_verbosity::level"],[172,3,1,"_CPPv4NK4espp9WroverKit5vram0Ev","espp::WroverKit::vram0"],[172,3,1,"_CPPv4NK4espp9WroverKit5vram1Ev","espp::WroverKit::vram1"],[172,3,1,"_CPPv4N4espp9WroverKit9write_lcdEPK7uint8_t6size_t8uint32_t","espp::WroverKit::write_lcd"],[172,4,1,"_CPPv4N4espp9WroverKit9write_lcdEPK7uint8_t6size_t8uint32_t","espp::WroverKit::write_lcd::data"],[172,4,1,"_CPPv4N4espp9WroverKit9write_lcdEPK7uint8_t6size_t8uint32_t","espp::WroverKit::write_lcd::length"],[172,4,1,"_CPPv4N4espp9WroverKit9write_lcdEPK7uint8_t6size_t8uint32_t","espp::WroverKit::write_lcd::user_data"],[172,3,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame::data"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame::height"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame::width"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame::x"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_frameEK8uint16_tK8uint16_tK8uint16_tK8uint16_tP7uint8_t","espp::WroverKit::write_lcd_frame::y"],[172,3,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::data"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::user_data"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::xe"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::xs"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::ye"],[172,4,1,"_CPPv4N4espp9WroverKit15write_lcd_linesEiiiiPK7uint8_t8uint32_t","espp::WroverKit::write_lcd_lines::ys"],[75,2,1,"_CPPv4I_7uint8_tEN4espp22XboxBatteryInputReportE","espp::XboxBatteryInputReport"],[75,6,1,"_CPPv4N4espp22XboxBatteryInputReport5ErrorE","espp::XboxBatteryInputReport::Error"],[75,7,1,"_CPPv4N4espp22XboxBatteryInputReport5Error16BATTERY_CRITICALE","espp::XboxBatteryInputReport::Error::BATTERY_CRITICAL"],[75,7,1,"_CPPv4N4espp22XboxBatteryInputReport5Error11BATTERY_LOWE","espp::XboxBatteryInputReport::Error::BATTERY_LOW"],[75,7,1,"_CPPv4N4espp22XboxBatteryInputReport5Error4NONEE","espp::XboxBatteryInputReport::Error::NONE"],[75,5,1,"_CPPv4I_7uint8_tEN4espp22XboxBatteryInputReportE","espp::XboxBatteryInputReport::REPORT_ID"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport14get_descriptorEv","espp::XboxBatteryInputReport::get_descriptor"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport10get_reportEv","espp::XboxBatteryInputReport::get_report"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport5resetEv","espp::XboxBatteryInputReport::reset"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport17set_battery_levelEi","espp::XboxBatteryInputReport::set_battery_level"],[75,4,1,"_CPPv4N4espp22XboxBatteryInputReport17set_battery_levelEi","espp::XboxBatteryInputReport::set_battery_level::level"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport19set_cable_connectedEb","espp::XboxBatteryInputReport::set_cable_connected"],[75,4,1,"_CPPv4N4espp22XboxBatteryInputReport19set_cable_connectedEb","espp::XboxBatteryInputReport::set_cable_connected::connected"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport12set_chargingEb","espp::XboxBatteryInputReport::set_charging"],[75,4,1,"_CPPv4N4espp22XboxBatteryInputReport12set_chargingEb","espp::XboxBatteryInputReport::set_charging::charging"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport9set_errorE5Error","espp::XboxBatteryInputReport::set_error"],[75,4,1,"_CPPv4N4espp22XboxBatteryInputReport9set_errorE5Error","espp::XboxBatteryInputReport::set_error::error"],[75,3,1,"_CPPv4N4espp22XboxBatteryInputReport16set_rechargeableEb","espp::XboxBatteryInputReport::set_rechargeable"],[75,4,1,"_CPPv4N4espp22XboxBatteryInputReport16set_rechargeableEb","espp::XboxBatteryInputReport::set_rechargeable::rechargeable"],[37,2,1,"_CPPv4N4espp21__csv_documentation__E","espp::__csv_documentation__"],[152,2,1,"_CPPv4N4espp31__serialization_documentation__E","espp::__serialization_documentation__"],[154,2,1,"_CPPv4N4espp31__state_machine_documentation__E","espp::__state_machine_documentation__"],[160,2,1,"_CPPv4N4espp26__tabulate_documentation__E","espp::__tabulate_documentation__"],[154,2,1,"_CPPv4N4espp13state_machine16DeepHistoryStateE","espp::state_machine::DeepHistoryState"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState16DeepHistoryStateEP9StateBase","espp::state_machine::DeepHistoryState::DeepHistoryState"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState16DeepHistoryStateEv","espp::state_machine::DeepHistoryState::DeepHistoryState"],[154,4,1,"_CPPv4N4espp13state_machine16DeepHistoryState16DeepHistoryStateEP9StateBase","espp::state_machine::DeepHistoryState::DeepHistoryState::_parent"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState5entryEv","espp::state_machine::DeepHistoryState::entry"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState4exitEv","espp::state_machine::DeepHistoryState::exit"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState12exitChildrenEv","espp::state_machine::DeepHistoryState::exitChildren"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14getActiveChildEv","espp::state_machine::DeepHistoryState::getActiveChild"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState13getActiveLeafEv","espp::state_machine::DeepHistoryState::getActiveLeaf"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState10getInitialEv","espp::state_machine::DeepHistoryState::getInitial"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14getParentStateEv","espp::state_machine::DeepHistoryState::getParentState"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14getTimerPeriodEv","espp::state_machine::DeepHistoryState::getTimerPeriod"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState11handleEventEP9EventBase","espp::state_machine::DeepHistoryState::handleEvent"],[154,4,1,"_CPPv4N4espp13state_machine16DeepHistoryState11handleEventEP9EventBase","espp::state_machine::DeepHistoryState::handleEvent::event"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState10initializeEv","espp::state_machine::DeepHistoryState::initialize"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState10makeActiveEv","espp::state_machine::DeepHistoryState::makeActive"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14setActiveChildEP9StateBase","espp::state_machine::DeepHistoryState::setActiveChild"],[154,4,1,"_CPPv4N4espp13state_machine16DeepHistoryState14setActiveChildEP9StateBase","espp::state_machine::DeepHistoryState::setActiveChild::childState"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14setDeepHistoryEv","espp::state_machine::DeepHistoryState::setDeepHistory"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState14setParentStateEP9StateBase","espp::state_machine::DeepHistoryState::setParentState"],[154,4,1,"_CPPv4N4espp13state_machine16DeepHistoryState14setParentStateEP9StateBase","espp::state_machine::DeepHistoryState::setParentState::parent"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState17setShallowHistoryEv","espp::state_machine::DeepHistoryState::setShallowHistory"],[154,3,1,"_CPPv4N4espp13state_machine16DeepHistoryState4tickEv","espp::state_machine::DeepHistoryState::tick"],[154,2,1,"_CPPv4N4espp13state_machine9EventBaseE","espp::state_machine::EventBase"],[154,3,1,"_CPPv4NK4espp13state_machine9EventBase9to_stringEv","espp::state_machine::EventBase::to_string"],[154,3,1,"_CPPv4N4espp13state_machine9EventBaseD0Ev","espp::state_machine::EventBase::~EventBase"],[154,2,1,"_CPPv4N4espp13state_machine19ShallowHistoryStateE","espp::state_machine::ShallowHistoryState"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState19ShallowHistoryStateEP9StateBase","espp::state_machine::ShallowHistoryState::ShallowHistoryState"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState19ShallowHistoryStateEv","espp::state_machine::ShallowHistoryState::ShallowHistoryState"],[154,4,1,"_CPPv4N4espp13state_machine19ShallowHistoryState19ShallowHistoryStateEP9StateBase","espp::state_machine::ShallowHistoryState::ShallowHistoryState::_parent"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState5entryEv","espp::state_machine::ShallowHistoryState::entry"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState4exitEv","espp::state_machine::ShallowHistoryState::exit"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState12exitChildrenEv","espp::state_machine::ShallowHistoryState::exitChildren"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14getActiveChildEv","espp::state_machine::ShallowHistoryState::getActiveChild"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState13getActiveLeafEv","espp::state_machine::ShallowHistoryState::getActiveLeaf"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState10getInitialEv","espp::state_machine::ShallowHistoryState::getInitial"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14getParentStateEv","espp::state_machine::ShallowHistoryState::getParentState"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14getTimerPeriodEv","espp::state_machine::ShallowHistoryState::getTimerPeriod"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState11handleEventEP9EventBase","espp::state_machine::ShallowHistoryState::handleEvent"],[154,4,1,"_CPPv4N4espp13state_machine19ShallowHistoryState11handleEventEP9EventBase","espp::state_machine::ShallowHistoryState::handleEvent::event"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState10initializeEv","espp::state_machine::ShallowHistoryState::initialize"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState10makeActiveEv","espp::state_machine::ShallowHistoryState::makeActive"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14setActiveChildEP9StateBase","espp::state_machine::ShallowHistoryState::setActiveChild"],[154,4,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14setActiveChildEP9StateBase","espp::state_machine::ShallowHistoryState::setActiveChild::childState"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14setDeepHistoryEv","espp::state_machine::ShallowHistoryState::setDeepHistory"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14setParentStateEP9StateBase","espp::state_machine::ShallowHistoryState::setParentState"],[154,4,1,"_CPPv4N4espp13state_machine19ShallowHistoryState14setParentStateEP9StateBase","espp::state_machine::ShallowHistoryState::setParentState::parent"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState17setShallowHistoryEv","espp::state_machine::ShallowHistoryState::setShallowHistory"],[154,3,1,"_CPPv4N4espp13state_machine19ShallowHistoryState4tickEv","espp::state_machine::ShallowHistoryState::tick"],[154,2,1,"_CPPv4N4espp13state_machine9StateBaseE","espp::state_machine::StateBase"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase9StateBaseEP9StateBase","espp::state_machine::StateBase::StateBase"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase9StateBaseEv","espp::state_machine::StateBase::StateBase"],[154,4,1,"_CPPv4N4espp13state_machine9StateBase9StateBaseEP9StateBase","espp::state_machine::StateBase::StateBase::parent"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase5entryEv","espp::state_machine::StateBase::entry"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase4exitEv","espp::state_machine::StateBase::exit"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase12exitChildrenEv","espp::state_machine::StateBase::exitChildren"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14getActiveChildEv","espp::state_machine::StateBase::getActiveChild"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase13getActiveLeafEv","espp::state_machine::StateBase::getActiveLeaf"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase10getInitialEv","espp::state_machine::StateBase::getInitial"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14getParentStateEv","espp::state_machine::StateBase::getParentState"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14getTimerPeriodEv","espp::state_machine::StateBase::getTimerPeriod"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase11handleEventEP9EventBase","espp::state_machine::StateBase::handleEvent"],[154,4,1,"_CPPv4N4espp13state_machine9StateBase11handleEventEP9EventBase","espp::state_machine::StateBase::handleEvent::event"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase10initializeEv","espp::state_machine::StateBase::initialize"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase10makeActiveEv","espp::state_machine::StateBase::makeActive"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14setActiveChildEP9StateBase","espp::state_machine::StateBase::setActiveChild"],[154,4,1,"_CPPv4N4espp13state_machine9StateBase14setActiveChildEP9StateBase","espp::state_machine::StateBase::setActiveChild::childState"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14setDeepHistoryEv","espp::state_machine::StateBase::setDeepHistory"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase14setParentStateEP9StateBase","espp::state_machine::StateBase::setParentState"],[154,4,1,"_CPPv4N4espp13state_machine9StateBase14setParentStateEP9StateBase","espp::state_machine::StateBase::setParentState::parent"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase17setShallowHistoryEv","espp::state_machine::StateBase::setShallowHistory"],[154,3,1,"_CPPv4N4espp13state_machine9StateBase4tickEv","espp::state_machine::StateBase::tick"],[154,3,1,"_CPPv4N4espp13state_machine9StateBaseD0Ev","espp::state_machine::StateBase::~StateBase"],[129,8,1,"_CPPv411sock_type_t","sock_type_t"]]},objnames:{"0":["c","macro","C macro"],"1":["cpp","member","C++ member"],"2":["cpp","class","C++ class"],"3":["cpp","function","C++ function"],"4":["cpp","functionParam","C++ function parameter"],"5":["cpp","templateParam","C++ template parameter"],"6":["cpp","enum","C++ enum"],"7":["cpp","enumerator","C++ enumerator"],"8":["cpp","type","C++ type"]},objtypes:{"0":"c:macro","1":"cpp:member","2":"cpp:class","3":"cpp:function","4":"cpp:functionParam","5":"cpp:templateParam","6":"cpp:enum","7":"cpp:enumerator","8":"cpp:type"},terms:{"0":[2,4,5,9,12,14,16,17,18,20,21,24,26,29,33,35,37,39,40,43,44,49,51,53,55,57,59,60,63,64,70,71,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,138,139,141,143,148,150,154,156,158,159,160,162,164,165,166,171,172],"00":[44,57,103],"000":[14,149,160,164],"000f":17,"0017cf75fd8c":112,"001f":49,"00b":134,"01":[21,24,26,39,57,70,103,135],"010f":17,"011a":110,"01f":[44,49],"02":[103,135],"024v":2,"02f":51,"02x":[26,75,78,88],"03":[103,113,135],"038d79b1":71,"04":[70,135],"048v":2,"05":135,"054":160,"056edb418135":27,"05f":[111,115,117],"06":135,"061":138,"067488":164,"0693":160,"06f":162,"0755":57,"07b5bab3e51f":157,"096v":2,"0b00000011":100,"0b0000110":49,"0b00111111":100,"0b0100000":105,"0b0110110":44,"0b1000110":49,"0b11":100,"0b11111":111,"0b11111111":103,"0ce1":52,"0f":[16,17,26,35,44,49,53,55,64,70,75,107,109,111,113,115,117,120,121,122,124,126,139,143,150,156,158,172],"0m":166,"0s":109,"0x00":[26,100,105,135],"0x0000":40,"0x01":[21,23,26],"0x0100":[21,24,26],"0x02":[23,24,26],"0x02fd":26,"0x045e":26,"0x06":9,"0x060504030201":135,"0x10":[4,9],"0x13":134,"0x14":88,"0x15":83,"0x16":9,"0x180a":24,"0x20":103,"0x24":96,"0x2a26":24,"0x2e":81,"0x36":14,"0x38":86,"0x48":2,"0x51":145,"0x54":141,"0x55":93,"0x58":100,"0x5d":88,"0x80":49,"0xa6":135,"0xa8":141,"0xae":135,"0xbabe":24,"0xcafe":[21,24],"0xf412fa42fe9":134,"0xface":21,"0xff":[103,111],"0xffffffffffff":134,"0xrrggbb":33,"1":[2,4,5,6,9,14,16,17,21,24,26,29,33,35,36,37,39,40,43,44,49,51,52,53,54,55,57,59,60,72,73,75,78,93,98,100,103,105,107,109,113,115,117,120,121,122,123,124,126,129,131,132,134,135,138,139,141,148,150,152,156,158,159,160,162,164,169,172],"10":[4,5,17,21,29,39,43,49,53,55,78,93,96,98,107,109,113,120,122,124,137,138,150,152,156,158,160,162,164,166,172,173],"100":[16,20,21,24,26,40,53,55,75,81,83,88,105,107,109,122,126,139,150,156,158,162,164,166,172],"1000":[6,17,40,43,49,78,81,83,88,103,109,126,135,139,148,164,166],"10000":[98,164],"1000000":143,"10000000":143,"1000m":162,"100m":[40,51,109,113,139,154,158,166,171,172],"1023":[26,75],"1024":[2,4,6,9,14,35,44,49,53,72,100,103,105,111,120,124,126,131,132,135,143,150,162,164],"10f":117,"10k":[5,164,165],"10m":[4,9,49,55,109,124,126,131,162,164],"10mhz":143,"10u":98,"11":[145,160],"114":14,"115":115,"11k":9,"12":[4,9,29,98,120,134,159,160],"123":72,"123456":21,"1234567890":[21,24,26],"127":[107,120,131,132,134],"128":[2,4,9,78,131,132,134,148],"12800":40,"128x":[4,9],"13":[5,100,169],"135":40,"14":[100,159],"144v":2,"14763":164,"15":[4,9,26,49,75,100,137,145,152,160,164],"150":158,"1500":148,"1500000":[52,146],"151":115,"152":164,"15f":117,"15f57640":159,"16":[2,4,9,40,53,63,100,103,105,122,134,135,137,150,156,158,159,160,172],"1600":2,"16384":[40,44,49],"1661966692":14,"1678892742599":72,"16kb":135,"16m":[53,122,150,156,158,172],"16x":[4,9],"17":[159,160],"1700":[35,107],"176":115,"18":[134,143,159,160],"180":[53,122,150,156],"18688":134,"187":160,"19":53,"192":134,"1b":134,"1b4daf6a363a":71,"1d8e":27,"1e6f":126,"1e7cd53b":127,"1f":[9,26,43,55,107,109,139],"1m":124,"1mhz":103,"1s":[21,24,26,29,53,70,72,111,113,124,126,131,132,139,145,148,150,154,156,162,166],"1x":103,"2":[2,4,5,6,9,17,26,35,36,37,39,44,49,52,54,55,57,59,60,63,75,98,100,103,107,108,109,113,115,116,117,120,121,124,126,131,132,134,138,139,143,148,158,159,160,166,172],"20":[6,17,21,39,40,57,160,164],"200":[70,126,148,160],"200m":[2,162],"2013":160,"20143":44,"2016":160,"2019":160,"2023":145,"2046":134,"20df":44,"20f":117,"20m":35,"21":[5,17,35,146,159,160],"213467":[5,18,27,32,54,71,101,110,112,123,127,144,149,157,159],"217":115,"22":[5,146],"220":115,"224":[129,131,132],"225365600":101,"23":[145,160],"23017":105,"231188170":32,"232148096":110,"236601258":149,"239":[129,131,132],"23s17":105,"240":40,"2400":2,"240x240":150,"2435":148,"2494":164,"25":[55,100,160,164],"250":2,"250136576":134,"250m":[43,93],"255":[33,100,107,111,120,129,131,132,134,135,143],"256":[6,134,143,148,162],"2566":160,"256v":2,"25c":164,"25f":117,"25m":158,"25x":103,"264":148,"265":148,"2657":164,"270":[53,122,150,156],"273":164,"28":[122,123],"298":164,"299":160,"2a79":151,"2af81edb":71,"2c87":127,"2dec9a49daa7":71,"2ee3b50a8f62":123,"2f":[14,35,55,164],"2k":162,"2mm":14,"2pi":[44,49],"2s":[98,162,166],"2x":[4,9],"3":[2,4,5,9,16,17,24,37,51,53,54,65,70,89,100,105,109,115,116,121,126,131,132,134,138,143,152,159,160,162,164,166],"30":[21,145,158,160,164],"300f":17,"300m":[113,135,162,166],"30f":117,"30m":135,"31":[35,111,164],"313":160,"32":[2,4,9,35,49,134],"320":[17,40],"321cb604":144,"32x":[4,9],"33":[35,149],"3300":[2,107,164],"3380":164,"34":[4,9,17],"3422":164,"3435":164,"3453":164,"3484":143,"3484_datasheet":143,"350m":166,"3549be36b8cc":71,"35981":164,"35ca":5,"35f":117,"36":[17,35],"360":[33,44,49,111,143,158],"36005":44,"36d3d04d":27,"37":35,"370":160,"376":160,"37ma":100,"38":[35,159],"39":[35,159],"3940":164,"3950":164,"3986":134,"3\u00b5a":14,"3f":[2,4,9,29,43,44,49,72,98,100,103,105,113,126,135,139,164,166],"3k":162,"3s":6,"3v":5,"4":[2,4,5,9,17,26,35,36,37,41,44,49,53,72,75,98,111,115,117,122,126,131,132,134,135,138,143,145,156,158,159,160,169,172],"40":[21,40,45,75,159,160,164],"400":[78,81,83,88],"400khz":146,"400m":166,"4096":[39,43,53,122,150,156,158,162,166,172],"40d6":144,"40f":117,"41":45,"42":[35,134,152],"4284":71,"43173a3eb323":44,"4452":[5,149],"4456":27,"4477":157,"4498646f86e6":32,"44d2":18,"4529":127,"458":160,"45f":117,"461":160,"466d":52,"475":2,"47f45641":32,"48":[55,134,135],"48000":53,"4886":100,"488b":71,"48b":135,"48e6":127,"490":2,"49b1":110,"49d0":123,"4\u03c0":160,"4a40":159,"4a47":112,"4af9":71,"4b":134,"4b1d":27,"4b65":157,"4c15":5,"4c7c":151,"4cac7882":151,"4cc6":32,"4ce115c7e9cc":27,"4cfc":71,"4d56":54,"4d88dd97":123,"4d8a":32,"4ddc":101,"4kb":135,"4x":[4,9],"5":[2,4,5,6,9,14,17,29,37,44,45,49,50,55,60,63,70,72,73,75,86,98,100,103,105,111,117,120,124,126,131,132,134,135,138,143,152,158,159,160,164],"50":[40,53,75,100,109,115,122,126,135,143,150,156,160,164,172],"5000":[98,109,131,132,148],"5001":148,"500m":[6,8,35,55,86,107,113,124,162,166],"506e643a5e02":32,"50c":164,"50m":[14,44,81,83,88,96,100,103,105,111,122,126,141,143],"50u":143,"512":120,"512v":2,"53":40,"53229":164,"54c362a7":32,"55":160,"571":160,"5ad600e9":101,"5d7e7086":157,"5e18":149,"5f":[44,49,51,109,111,115,117,131,132,143],"5m":139,"5mbaud":52,"5s":[55,98,124],"5u":98,"5v":[5,18,71],"5x":103,"5x5":112,"6":[2,4,5,9,16,33,35,37,53,72,73,115,131,132,134,135,138,143,150,160,171],"60":[40,44,49,53,71,126,160],"607":14,"61067330":57,"614":160,"61622309":135,"6192":[98,166],"62":115,"625":21,"625mhz":49,"626":160,"64":[2,4,9,143],"649ee61c":44,"64kb":135,"64n":49,"64x":[4,9],"65":103,"65534":[26,75],"6742":160,"67b8":71,"68":160,"68d6":101,"6c56c2cf":5,"6e45":71,"7":[4,5,9,17,72,105,134,138,141,152,160,164],"70":[75,160],"709e2aa4":127,"720":[44,49],"72593":72,"730":160,"75":[53,100,122,150,156,158,164,172],"75x":103,"7736fdb35bcb":71,"792":160,"7cd9":71,"7mm":14,"8":[2,4,5,9,14,33,49,72,92,100,103,105,108,117,124,134,135,138,145,156,160],"80":[40,164],"80552":164,"80x160":159,"817":160,"8192":[29,43,55],"8235":27,"84bb":127,"85":164,"8502":164,"854":160,"8554":[148,149],"860":2,"8789":5,"882d":127,"8948":157,"89c7":71,"8c2d":157,"8c63":27,"8e995c43f5b9":144,"8ecb":144,"8f9a":44,"8x":[4,9],"9":[5,39,43,100,107,108,138,143,160],"90":[53,122,150,156,160],"920":2,"932c":159,"9338":112,"9354":110,"93hart_equ":164,"9489":144,"96":159,"9661":27,"96d6":101,"9781449324094":134,"99":[21,24,26],"9901":18,"9907":164,"99f2":32,"9a48a29f":18,"9bc2":54,"9e":134,"9e10":44,"9e37f54af15":54,"9eda3ff3f33f":157,"9mm":14,"9th":[4,9],"\u00b2":160,"\u00b3\u2074":160,"\u00b9":160,"\u00b9\u00b2f":160,"\u00b9\u00b9m\u00b3":160,"\u03ba":164,"\u03c9":[160,164],"\u16a0":160,"\u16a1":160,"\u16a2":160,"\u16a3":160,"\u16a4":160,"\u16a5":160,"\u16a6":160,"\u16a7":160,"\u16a8":160,"\u16a9":160,"\u16aa":160,"\u16ab":160,"\u16ac":160,"\u16ad":160,"\u16ae":160,"\u16af":160,"\u16b0":160,"\u16b1":160,"\u16b2":160,"\u16b3":160,"\u16b4":160,"\u16b5":160,"\u16b6":160,"\u16b7":160,"\u16b8":160,"\u16b9":160,"\u16ba":160,"\u16bb":160,"\u16bc":160,"\u16bd":160,"\u16be":160,"\u16bf":160,"\u16c0":160,"\u16c1":160,"\u16c2":160,"\u16c3":160,"\u16c4":160,"\u16c5":160,"\u16c6":160,"\u16c7":160,"\u16c8":160,"\u16c9":160,"\u16ca":160,"\u16cb":160,"\u16cc":160,"\u16cd":160,"\u16ce":160,"\u16cf":160,"\u16d0":160,"\u16d1":160,"\u16d2":160,"\u16d3":160,"\u2076":160,"\u2077":160,"abstract":[51,52,53,54,80,122,123,128,129,150,151,156,157,158,159,162,172,173],"boolean":57,"break":[21,154],"byte":[6,24,26,39,40,49,53,55,57,72,75,79,105,111,124,129,131,132,134,135,141,143,145,148],"case":[44,49,98,120,132,143],"char":[57,93,131,137,148,162],"class":[22,25,27,30,31,32,34,36,41,45,50,62,76,99,108,110,112,130,136,140,144,149],"const":[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,33,35,37,39,40,43,44,49,51,53,55,57,59,60,63,64,65,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],"default":[2,4,9,14,33,35,39,40,53,55,63,64,70,72,81,83,86,88,93,96,98,100,103,105,107,109,111,115,117,120,121,124,131,135,137,141,143,145,148,149,150,152,154,156,162,166,169,171,172],"do":[4,8,21,24,25,26,29,35,37,49,53,55,57,72,87,93,98,122,124,148,150,152,154,156,158,160,162,166,172],"enum":[2,4,9,21,29,35,49,53,72,75,86,98,100,103,105,107,111,113,126,134,141,164],"export":160,"final":[5,14,24,29,35,44,49,81,83,86,88,96,98,100,103,105,124,134,135,141,145,148,154,162],"float":[2,4,5,6,8,9,11,12,14,16,17,20,21,23,24,26,29,33,35,39,43,44,49,51,53,55,57,59,60,63,64,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],"function":[2,4,6,8,9,11,12,13,14,16,17,20,21,23,24,26,29,31,33,35,39,40,41,43,44,49,51,53,55,57,59,60,62,63,64,65,67,70,72,74,75,78,80,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,119,120,121,122,124,126,128,129,131,132,134,137,139,143,148,150,154,156,158,162,164,166,167,169,171,172],"goto":143,"int":[2,4,8,16,21,26,29,35,40,43,44,49,51,53,55,57,67,75,78,92,98,100,103,109,111,113,117,121,122,124,129,131,132,134,135,137,139,141,143,148,150,152,154,156,158,160,162,164,166,172],"long":[98,113,129,131,132,137,148,149,160,163,166],"new":[8,14,16,17,21,39,40,55,59,60,63,64,65,67,78,81,83,86,88,96,100,107,109,111,113,117,120,121,134,135,137,139,141,148,154,162,166],"null":[53,93,122,150,156,158,172],"public":[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,33,35,39,40,43,44,49,51,53,55,57,59,60,63,64,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],"return":[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,33,35,39,40,43,44,49,51,53,55,57,59,60,63,64,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],"short":[35,83,134],"static":[2,4,8,9,14,17,21,26,29,31,40,44,49,51,53,55,57,70,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,116,120,122,124,126,129,131,132,134,135,141,143,145,150,154,156,158,162,164,166,172],"super":37,"switch":[4,9,39,75,126,143],"throw":57,"true":[2,4,9,12,14,16,17,20,21,23,24,26,29,35,37,39,40,43,44,49,51,53,55,57,67,70,72,75,78,81,83,86,88,93,95,96,98,100,103,105,107,109,111,113,120,121,122,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,160,162,166,171,172],"try":135,"void":[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,40,43,44,49,51,53,55,57,59,63,64,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],"while":[14,21,24,26,29,31,40,51,53,55,78,93,98,109,113,115,122,124,126,148,150,154,156,158,162,171,172],A:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,66,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,156,158,159,160,162,164,165,166,169,171,172],And:111,As:[55,78],At:[18,29,71,148],For:[21,24,39,45,50,65,71,72,83,98,122,126,141,148,149,155,156,160,162],IN:72,IT:[57,135],If:[2,4,8,9,12,14,16,17,18,21,24,25,26,29,33,44,45,49,54,55,57,70,72,78,81,83,84,86,88,93,95,96,98,100,103,105,107,109,110,120,123,124,127,129,131,132,134,135,137,141,145,148,154,156,157,159,162,166,169,171],In:[29,35,55,98,100,103,120],Is:[129,131,132,162,166],It:[0,3,4,5,6,8,9,10,11,12,14,17,20,21,26,27,29,31,35,36,37,44,45,46,49,50,51,52,53,54,55,57,67,70,72,75,76,78,79,82,84,89,93,94,96,97,98,100,101,103,104,109,111,122,123,126,127,137,139,143,148,150,151,154,156,157,158,159,160,162,164,172,173],NOT:[4,24,35,126],No:[4,9,21,70,75,103,113,134,162,166],Not:57,ONE:2,On:[4,5,14,24,63,70,93],One:26,The:[2,4,5,6,8,9,11,12,14,15,16,17,19,20,21,23,24,26,29,31,32,33,34,35,37,39,41,43,44,49,51,53,55,57,58,59,60,63,64,65,66,67,69,70,72,73,75,78,81,83,84,85,86,88,91,92,93,95,96,97,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,127,128,129,131,132,134,135,137,138,139,140,141,143,145,148,150,152,154,156,158,160,162,164,165,166,169,171,172],There:[29,44,48,49,62,74,102,124,154,162],These:[0,4,9,13,19,28,77,143,148],To:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,55,56,58,61,68,71,73,76,79,82,83,84,87,89,94,97,99,101,104,106,108,110,112,113,114,119,123,125,127,130,136,138,140,141,142,144,146,148,149,151,153,155,157,159,161,163,165,167,170,173],Will:[16,44,49,100,103,120,124,129,135,148,154],_1:[4,9,14,17,35,44,49,72,81,83,86,88,93,96,100,103,105,124,135,141,145],_2:[4,9,14,17,35,44,49,72,81,83,86,88,93,96,100,103,105,124,135,141,145],_3:[4,9,14,17,35,44,49,72,81,83,86,88,93,96,100,103,105,124,135,141,145],_4:[44,72,86,100,103,105,141,145],_5:[44,100,103,145],_:37,__csv_documentation__:37,__gnu_linux__:[37,152],__serialization_documentation__:152,__state_machine_documentation__:154,__tabulate_documentation__:160,__unix__:160,__unnamed11__:141,__unnamed13__:141,__unnamed15__:135,__unnamed17__:135,__unnamed7__:134,__unnamed9__:134,_activest:154,_build:[135,141,145],_event_data:154,_lv_refr_get_disp_refresh:[53,122,156,158,172],_parent:154,_parentst:154,_rate_limit:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],_really_:111,_target1:126,_target2:126,a0061f7b:110,a0:[5,105],a139:151,a256b401:71,a2:105,a503:112,a68:18,a9fc:54,a_0:59,a_1:59,a_2:59,a_gpio:43,a_pin:105,aa26:32,aa8a3c81034a:110,ab1ace5c:71,ab:[26,75,120,124,164],abi:[46,48,80,122],abi_encod:43,abiencod:[11,46],abil:[113,124],abl:[67,87,98,107,131,154,166],about:[21,23,31,37,75,124,126,132,134,135,143,154,160,162,164],abov:[4,9,26,31,41,44,49,55,100,111,138,143,154],absolut:[44,49,57,134],absolute_uri:134,abxi:35,abz:[46,49],ac:134,acceler:[26,63,75,126],accept:[67,131,148],access:[12,14,24,26,43,51,53,57,80,122,126,129,135,150,154,156,158,168,170,171,172],accord:[29,57,98,100,103,105,107,109,113,148],accordingli:35,account:24,accumul:[43,44,49,141],accur:[14,139],ack:[4,9],acknowledg:[78,131],across:[6,24,70],act:[126,134,170],action:[98,154,162],activ:[4,5,9,14,16,29,30,35,98,105,122,134,135,148,154,158,172],active_high:[4,9,98,105],active_level:[29,98,158,172],active_low:[4,9,35,98],active_st:98,activeleaf:154,activelevel:[29,98,158,172],actual:[2,4,5,9,21,35,40,55,70,72,107,134,148,154,164],actual_celsiu:164,actual_kelvin:164,actuat:[72,73,74],ad0:100,ad1:100,ad:[2,4,17,21,35,55,121,134,148,172],adafruit:[5,10,14,15,35,36,72,73,100,106,112,134,136,143],adapt:97,adc1:[126,164,165],adc2:126,adc:[5,35,43,51,52,80,108,126,139],adc_atten_db_11:164,adc_atten_db_12:[6,8,35,107],adc_channel_1:35,adc_channel_2:35,adc_channel_6:[6,8],adc_channel_7:[6,8,164],adc_channel_i:107,adc_channel_t:[6,8,107],adc_channel_x:107,adc_conv_single_unit_1:[6,164],adc_decap:9,adc_digi_convert_mode_t:6,adc_typ:1,adc_unit:107,adc_unit_1:[6,8,107,126,164],adc_unit_2:[35,107,126],adc_unit_t:[8,107],adcconfig:[6,8,35,107,135,141,145,164],add:[5,16,20,21,23,29,33,40,53,75,78,98,120,121,122,129,131,132,148,150,156,158,172],add_interrupt:[29,98],add_multicast_group:[129,131,132],add_publish:55,add_row:160,add_scan:148,add_subscrib:[29,55],addit:[6,29,33,39,80,98,121,162],addition:[4,9,31,71,99,148],addr:[2,49,103,129,135],address:[2,4,9,12,14,21,40,44,49,67,72,78,79,81,83,86,88,93,96,100,103,105,129,131,132,134,135,141,145,148,166,171],addservic:21,addtxpow:[21,24,26],adjust:[70,131,166],ads1015:[2,3,36],ads1015config:[2,35],ads1015rat:2,ads1115:2,ads1115config:2,ads1115rat:2,ads1x15:[7,12,35,36,80],ads7128:[4,5,9],ads7138:[7,12,80],ads_read_task_fn:[2,4,35],ads_task:[2,4,35],adv_data:[21,24,26],advanc:166,adventur:37,advertis:[21,24,26],advertise_duration_m:26,advertise_on_disconnect:21,advertiseddata:[21,24,26],advertisement_complete_callback:21,advertisement_complete_callback_t:21,advertisement_stopped_callback:21,advertisement_stopped_callback_t:21,advertising_data:21,advertisingparamet:21,advis:120,ae7a:71,ae:134,affect:[44,49,103,148],affin:162,after:[2,4,9,12,14,20,21,23,24,26,39,40,44,49,53,57,72,81,83,86,88,93,96,98,100,103,105,111,120,122,129,131,132,135,137,138,141,143,145,148,150,156,162,166,171],again:[55,98,135,137,138,154],against:[24,121,137],agent:148,alarm:166,alert:[4,5,9,14],alert_1000m:72,alert_750m:72,alert_log:4,alert_pin:4,alert_task:4,alertlog:[4,9],alertstatu:14,algorithm:[14,16,17,19,33,140,160],alia:[53,122,150,156,158,172],alias:[44,49],align:[63,111,160],aliv:67,all:[4,8,9,11,12,16,17,21,23,29,36,55,57,72,78,98,100,103,111,113,120,121,124,132,137,141,143,148,149,154],all_mv:[4,9],all_mv_map:9,alloc:[6,39,53,122,124,150,156,158,162,172],allocatingconfig:[39,40],allocation_flag:39,allow:[2,4,6,8,9,14,16,24,26,31,35,39,43,44,49,56,70,72,81,83,86,88,93,96,100,103,105,107,109,111,113,117,120,126,128,129,131,132,137,139,141,143,145,148,154,162,164],along:[116,122,126,135],alongsid:58,alow:117,alpaca:[55,80,153],alpha:[109,117],alreadi:[21,24,26,55,57,59,98,125,131,132,148,162,166],also:[4,5,9,21,24,29,31,35,37,39,40,44,49,53,55,57,70,72,75,78,98,100,103,113,120,122,124,126,143,148,150,154,156,158,160,162,172],alt:[93,156],alter_unit:[6,164],altern:[4,6,57,88,134],alwai:[6,8,16,17,44,49,57,72,120,124,148,154],am:44,ambigu:121,amount:[6,57,120,121],amp:[17,126],amplitud:117,an:[1,2,3,4,5,8,9,10,12,14,16,21,24,26,27,29,30,31,33,35,36,41,43,44,45,46,49,50,51,53,55,57,59,60,63,64,65,66,69,70,72,75,76,78,79,81,83,86,87,88,93,95,96,98,99,100,101,103,104,105,106,107,108,111,112,115,117,120,122,124,126,129,131,132,134,135,136,137,141,143,144,145,148,149,150,154,155,156,158,160,162,165,166,171,172],analog:[0,3,4,5,6,8,9,10,36,49,72,107,108],analog_input:[4,9],analogev:4,analogjoystickconfig:35,analyz:124,anaolg:35,android:[24,134,135],angl:[17,26,44,49,75,126,127,158,172],angle_filt:17,angle_openloop:[17,126],angle_pid_config:17,ani:[0,4,8,9,15,16,17,18,21,22,23,25,26,27,29,31,37,44,49,55,67,71,76,82,89,94,97,98,100,101,103,104,111,129,131,132,135,137,143,146,148,154,160,162,165,166],anonym:[55,56,134],anoth:[29,31,55,57,98,121,166],any_edg:[29,98,158,172],anyth:[37,113,124,152,154,160],anywher:31,ap:[80,168,171],ap_mac:171,apa102_start_fram:111,apa:134,apach:21,api:[18,58,80],app:[24,134,135],app_main:124,appear:[107,134],append:[4,9,148],appli:[6,16,100,103,107,120],applic:[26,53,75,80,122,148,150,156,158,160,172],appropri:[16,17,53,98,131,132,150],approxim:[4,9,107,116],ar:[2,4,5,7,9,12,14,16,17,19,21,26,29,31,34,35,40,42,43,44,48,49,53,55,57,62,70,72,74,75,81,83,84,86,88,93,96,98,100,102,103,105,107,109,111,113,120,121,124,128,131,134,135,137,139,141,143,145,148,150,152,154,158,162,166,168,170,172],arari:152,arbitrari:[26,31,153],arduino:36,area:40,arg:113,argument:[113,135,141,145],arithmet:59,around:[6,8,16,31,37,39,57,75,78,85,91,92,95,107,109,113,115,117,120,129,143,152,154,160,162],arrai:[40,59,63,65,112,115,117,129,131,132,135,152],articl:164,artifact:143,as5600:[12,46,48,80],as5600_ds000365_5:44,asid:109,ask:162,aspect:31,assert:83,asset:[5,14,18,27,32,52,54,71,72,112,123,127,144,151,157,159],assign:[33,98,121],associ:[1,6,8,21,24,32,35,39,40,43,49,55,58,85,91,92,95,98,100,103,105,107,109,115,121,124,129,131,132,137,162],associt:[129,131,132],assum:[99,111,131,132,164],assumpt:[44,49],asymmetr:139,asynchron:56,atach:99,ate:57,atom:[17,35,49,126],attach:[24,40,46,49,52,100,101,104,112,151,157],attenu:[1,6,8,35,107,164],attribut:[2,4,9,14,44,49,63,81,83,86,88,93,96,100,103,105,111,134,135,141,143,145,150],audio:[51,53,54,72],audio_buffer_s:53,audio_sample_r:53,audiovib:72,authent:[21,24,26,67,134],authentication_complete_callback:[21,24,26],authentication_complete_callback_t:21,authentication_failur:21,auto:[2,4,6,8,9,14,17,21,24,26,29,35,37,40,43,44,49,53,55,57,61,70,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,131,132,135,139,141,143,145,150,152,154,156,158,160,162,164,166,172],auto_init:[4,9,14,17,44,49,72,78,100,103,105,135],auto_reen:98,auto_seq:[4,9],auto_start:[93,166],autoc:72,automat:[4,9,14,17,21,31,33,44,49,52,53,54,78,93,98,100,103,122,135,137,148,150,156,160,162,166],autonom:[4,9],autostop:162,avail:[2,4,6,9,12,14,21,43,44,49,55,72,81,83,86,88,93,96,100,103,105,121,135,141,145,156,162,166],avdd:[4,9],avdd_volt:[4,9],averag:[4,9,10,33,64],avoid:[121,162],aw9523:[12,80,102],aw9523b:100,awaken:37,ax:[35,36,75,107],axi:[4,5,17,35,75,107],b0:134,b0c0eb28:52,b1:134,b23a:123,b25:164,b27c9220cc24:18,b2:134,b304:71,b3:134,b48d:149,b4:134,b673:32,b6a2:123,b6e5:52,b711:127,b7:105,b7e8:71,b8cb:5,b:[16,32,33,35,37,43,52,66,93,100,105,111,115,124,134,135,141,143,152,156,162,164],b_0:59,b_1:59,b_2:59,b_bright:100,b_down:100,b_gpio:43,b_led:100,b_pin:105,b_up:100,back:[32,39,57,120,131,132,135,143],back_insert:[21,26],background:[53,70,122,150,156,158,166,172],background_color:160,backlight:[39,40,53,93,122,150,156,158,159,172],backlight_on_valu:[39,40],backlight_pin:[39,40],backward:162,bad559eaa4f2:127,bad:[33,164],band:134,bandwidth:131,base:[17,24,33,44,49,59,60,62,63,64,65,70,75,80,98,109,111,113,124,126,129,135,139,143,148,154,160,162,164],base_compon:11,base_encod:143,base_peripher:12,basecompon:[6,8,11,12,16,17,20,21,23,24,26,35,39,43,51,53,55,57,67,70,78,85,91,92,95,98,107,109,111,122,124,126,129,137,139,143,148,150,156,158,162,164,166,169,171,172],baseconfig:[29,39,53,55,98,122,132,150,156,158,162,166,172],baseperipher:[2,4,9,11,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],basi:[4,9],basic:[11,41,56],batch:160,batteri:[14,15,21,24,26,28,51,55,75,80,150],battery_crit:75,battery_input_report:[26,75],battery_level:[21,24,26],battery_low:75,battery_report:26,battery_report_id:[26,75],battery_servic:[20,21,24,26],batteryreport:[26,75],batteryservic:[11,20,21,24,26],batteryst:55,baudrat:[52,146],bcd2byte:145,bcd:145,beca:5,becaus:[17,44,49,57,98,137,143,160,162,166],becom:9,been:[2,4,9,10,12,14,17,20,21,23,24,26,44,49,53,59,72,81,83,86,87,88,93,96,100,103,104,105,111,122,131,132,135,138,141,143,145,148,150,156,158,162,166,172],befor:[4,9,17,21,43,55,57,70,98,103,111,131,135,148,150,154,162,166,171,173],beg:57,begin:[21,26,32,55,57,75,113,131,132,134,162],behav:[53,122,150,156],behavior:[70,71,139],behind:122,being:[2,4,6,8,9,14,21,24,29,31,35,43,44,49,55,72,81,83,86,88,96,98,100,103,105,107,111,126,139,141,143,145,154,162,164],belong:132,below:[4,9,17,21,26,98,154,155,160],bench:155,benchtop:[18,71],best:70,beta:[109,117,164],better:[63,139],between:[2,4,5,9,12,14,33,34,39,44,49,55,56,69,72,75,81,83,86,88,93,96,100,103,105,115,116,120,126,127,135,141,145],beyond:[31,37,143,160],bezier:[80,118],bezier_i:115,bezier_x:115,bezierinfo:115,bff:112,bg:[53,122,150,156,158,172],bgr:111,bi:135,bia:70,biequad:59,binari:[57,153],bind:[4,9,14,17,35,44,49,67,72,81,83,86,88,93,96,100,103,105,113,124,131,132,135,141,145,148],biquad:[60,62,65,80],biquad_filt:59,biquadfilt:59,biquadfilterdf1:[59,60],biquadfilterdf2:[44,49,59,126],biquadrat:59,bit0:143,bit1:143,bit:[4,9,35,40,49,55,100,103,105,109,134,135,141,162],bitfield:[4,9],bitmask:4,black:[53,122,150,156,158,172],bldc:[18,74,80,126,127],bldc_driver:16,bldc_haptic:70,bldc_motor:[17,19],bldc_type:17,bldcdriver:[11,16,17,18,71,126],bldchaptic:[11,70,71],bldcmotor:[11,17,44,49,70,71,126],ble:[20,23,24,25,26,80,134,135,159],ble_appear:[21,135],ble_gatt_serv:[20,21,23,24,26],ble_gatt_server_callback:21,ble_gatt_server_menu:21,ble_h:21,ble_hs_adv_f_disc_gen:[21,24,26],ble_hs_adv_f_disc_ltd:[21,24,26],ble_hs_io_display_onli:21,ble_hs_io_display_yesno:21,ble_hs_io_keyboard_displai:21,ble_hs_io_keyboard_onli:21,ble_hs_io_no_input_output:[21,26],ble_hs_return_cod:21,ble_menu:21,ble_radio_nam:135,ble_rol:135,ble_sm_pair_key_dist_enc:[21,26],ble_sm_pair_key_dist_id:[21,26],bleappear:[21,24,26],blegattserv:[11,21,22,24,25,26,27],blegattserveradvertisingcallback:21,blegattservercallback:21,blegattservermenu:21,blend:33,blerol:[134,135],blob:[40,156],block:[4,6,8,9,21,31,41,53,55,70,78,98,109,111,122,131,132,143,148,150,156,158,163,166,172],block_siz:143,blue:[33,37,51,111,143,160],bluetooth:[20,23,26,134,136],bm8563:[12,80,135,141,147],board:[0,3,5,10,15,17,22,25,27,30,32,34,36,38,40,41,45,46,50,51,52,53,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,122,123,125,126,127,130,136,138,140,141,142,144,146,149,150,151,153,155,156,157,158,159,161,163,165,167,170,172,173],bob:[17,18,71],bodmer:40,bold:160,bond:[21,24,26],bool:[2,4,8,9,12,14,16,17,21,24,26,29,35,39,40,43,44,49,51,53,55,57,67,70,72,75,78,81,83,86,88,92,93,95,96,98,100,103,105,107,109,111,113,120,121,122,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,166,171,172],boosterpack:5,boot:[93,99,113,126,127,158,172],border_bottom:160,border_color:160,border_left:160,border_right:160,border_top:160,both:[4,6,9,16,18,35,37,46,54,57,59,70,73,96,100,103,105,109,120,130,134,143,149,160,162,166,170],both_unit:[6,164],bother:96,bottom:[150,165],bound:[70,131,143],bounded_no_det:70,box3:[53,54],box:[0,35,41,51,80,87,89,96,97,135,149,165],box_typ:53,boxart:37,boxtyp:53,bp:[4,5],br:134,brake:[26,75],breadboard:[18,71,165],breakdown:[17,40,70],breakout:[15,73,106,136,141],breath:[51,126],breathing_period:[51,109],breathing_start:109,bredr:134,bright:[39,51,53,100,111,122,150,156,158,172],bro:37,broadcast:[132,134],broken:148,brushless:[16,17,19],bs:55,bsp:[40,83],bt:134,btappear:[134,135],bteir:134,btgoep:134,btl2cap:134,btn:[53,122,150,156],btn_clear:150,btn_state:[53,122,150,156,172],btspp:134,btssp_1_1:134,bttype:134,bu:[4,9,21,40,49,51,53,78,79,86,103,122,126,141,150,156],budget:160,bufer:162,buffer:[4,6,9,29,39,53,55,122,131,143,148,150,152,156,158,162,172],buffer_s:132,build:[2,4,6,8,9,14,17,21,24,26,29,31,33,35,37,40,43,44,49,51,53,55,57,62,67,70,72,75,78,80,81,83,86,88,93,96,98,100,103,105,107,109,111,113,122,124,126,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,172],built:[0,37,115,131,152,154,160],bump:14,bundl:[35,53,54,76],buscfg:[40,49],buse:[2,4,9,12,14,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],busi:132,butterworth:[62,80],butterworth_filt:60,butterworthfilt:[44,45,49,50,60,61,65,126],button:[4,5,26,35,36,49,53,54,75,80,83,85,88,89,91,92,95,96,98,99,100,101,104,122,123,126,127,141,150,156,157,158,159,172],button_2:29,button_callback_t:122,button_component_nam:29,button_count:75,button_index:[26,75],button_st:[96,122,126,141],button_top:29,buttonst:[135,141,145],buzz1:72,buzz2:72,buzz3:72,buzz4:72,buzz5:72,buzz:71,byte2bcd:145,byte_ord:111,byteord:111,bytes_encod:143,bytes_encoder_config:143,bytes_written:[29,152],c334e1ba:149,c:[16,37,40,51,55,57,78,80,98,134,143,152,160,164],c_str:[57,137],cabl:[5,10,75,104],cach:[81,83,88,148],calcul:[4,9,17,70,164],calibr:[8,17,18,71,72,107,108],call:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,39,43,44,49,51,53,55,57,67,70,72,73,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],call_onc:55,callback:[2,4,6,8,9,14,17,21,24,26,35,39,41,43,44,49,53,55,72,81,83,86,88,93,96,98,100,103,105,107,109,111,122,124,126,128,129,131,132,135,139,141,143,145,148,150,154,156,158,162,164,166,167,172],callback_fn:166,callback_m_cv_fn:162,callback_m_cv_notified_fn:162,callback_no_params_fn:162,callback_t:29,callback_vari:162,cam:[80,110,149],camera:[51,148,149],can:[0,2,4,5,9,12,14,15,16,17,18,19,21,23,24,26,29,31,33,35,39,40,41,43,44,49,51,53,55,57,58,67,68,69,70,71,72,73,75,78,81,83,84,86,88,93,96,97,98,100,101,103,104,105,109,111,113,115,120,122,124,126,131,132,134,135,139,141,143,145,146,148,149,150,151,152,154,156,158,160,162,164,166,167,169,172],can_chang:109,can_exit:21,cannot:[36,49,52,57,131,135,148,152,166],capabl:[21,23,100,103,134,135],capacit:[86,96],captain:160,captur:[4,9,105],card:[122,150,158,159],carrier:134,carrier_data_ref:134,carrierpowerst:134,cast:121,catalog:164,caus:[148,154],cb:[40,55,148],cc:135,cdn:[14,100,143],cell:[14,37,160],celsiu:164,center:[35,53,70,75,107,120,122,150,156,158,160,172],center_deadband:[35,107,120],center_deadzone_radiu:107,central:[20,23,26,134],central_onli:134,central_peripher:134,certain:[70,154],cf:134,ch04:134,ch0:[4,9],ch0_mv:9,ch1:[4,5,9],ch1_mv:9,ch2:[4,9],ch2_mv:9,ch3:[4,5,9],ch4:[4,9],ch5:[4,5,9],ch6:[4,9],ch7:[4,9],ch:9,chang:[2,4,5,9,12,14,17,18,26,29,33,44,45,49,70,71,72,81,83,86,88,93,96,98,100,101,103,104,105,109,113,117,126,135,137,139,141,145,148,154],change_gain:139,channel:[1,2,3,4,5,6,8,9,10,16,33,35,43,107,108,109,126,143,148,164,165,169,171],channel_id:[4,9],channel_sel:[4,9],channelconfig:[109,126],charact:[31,32,137],characterist:[20,21,23,24,26,160],charg:[13,14,75],charge_r:14,charger:150,chart:[124,160],chdir:57,check:[4,16,17,29,36,53,57,67,70,98,109,113,129,131,141,148,162,166,171],child:154,childstat:154,chip:[2,4,6,9,14,15,18,43,45,48,50,71,81,83,88,97,98,100,101,102,104,105,111,135,145,150,164],choos:[16,45,50],chose:164,chrono:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],chrono_liter:[2,4,9,35,72],chsc6x:[12,80,90,150],chunk:134,cin:[31,154],circl:[53,54,107,122,123,150,151,156,157,158,159,172,173],circuit:164,clamp:[16,20,33,107,139,143],clang:164,class_of_devic:134,classic:134,clean:[57,131,162],cleanup:[57,129],clear:[4,14,32,40,43,53,54,55,98,100,103,113,122,123,135,137,138,139,148,150,156,157,158,159,162,172,173],clear_alert_statu:14,clear_circl:[53,122,150,156,158,172],clear_event_high_flag:4,clear_event_low_flag:4,clear_interrupt:103,clear_lin:[21,51,113],clear_pin:[100,103],clear_screen:113,cli:[21,78,80,154,155],click:[53,54,71],client:[21,23,67,69,80,128,129,130,149],client_socket:[131,132],client_task:[131,132],client_task_fn:[131,132],clifilesesson:31,clint:160,clisess:31,clk:159,clk_speed:[49,78,81,83,88,103,135],clock:[4,9,49,51,78,98,103,109,111,134,143,150,159],clock_config:109,clock_spe:40,clock_speed_hz:[40,49],clock_src:143,close:[17,18,19,44,49,57,70,127,131,137,140,148],clutter:[21,154],cmd:[49,159],co:[26,75,111,143,158,172],coars:70,coarse_values_strong_det:70,code:[2,4,7,9,12,14,17,18,19,26,36,40,42,43,44,49,55,57,71,72,73,78,81,83,86,88,93,96,100,103,105,107,110,113,124,128,134,135,137,139,141,143,145,148,149,152,154,160,162,166,168],codec:[51,53],codepath:98,coeffici:[59,63,66,117,164,165],collect:[4,26,75,148],color:[39,40,53,80,111,122,143,150,156,158,159,160,172],color_map:40,column:[160,164],column_separ:160,com:[4,5,9,14,16,17,18,24,27,32,37,40,44,45,50,52,54,57,59,65,70,71,72,75,83,100,101,110,112,113,122,123,126,127,132,134,135,143,144,148,149,151,154,156,157,159,160,164,169,171],combin:[18,71,129,131,132],combo:129,come:132,comma:37,command:[17,21,32,40,41,53,67,78,80,83,122,150,156,158,172],comment:36,commit:[137,138],common:[12,13,35,40,72,134],commun:[2,3,4,5,9,10,12,14,17,35,44,45,49,50,56,72,73,79,81,83,86,88,93,96,100,101,103,104,105,106,126,131,132,135,136,141,145],compar:[24,121,172],comparison:[107,121,172],compat:[148,162],compens:14,compil:113,complet:[4,9,21,31,37,57,72,75,78,109,134,137,148,149,160,162],complex:[18,71,162],complex_root:154,compoen:80,compon:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,23,24,26,27,28,29,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,55,57,58,59,60,61,63,64,65,66,67,68,70,71,72,73,74,75,76,77,78,79,80,81,83,85,86,88,91,92,93,95,96,98,100,101,102,103,104,105,106,107,109,111,113,114,115,116,117,119,120,121,122,123,124,125,126,127,129,130,131,132,134,135,137,138,139,141,142,143,144,145,148,149,150,151,152,153,154,156,157,158,159,160,161,162,163,164,165,166,169,170,171,172,173],compos:134,comput:[33,44,49,69,116,120,134,139,163,164,165],compute_voltag:164,condit:[14,43,78,98,109,162],condition_vari:[2,4,6,8,9,14,35,43,44,49,53,72,81,83,86,88,96,100,103,105,107,111,122,126,135,139,141,143,145,150,154,156,158,162,164,172],conf:[6,8],config:[2,4,6,8,9,12,14,16,17,21,26,29,35,39,43,44,49,55,57,60,63,64,65,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,124,129,131,132,134,135,139,141,143,145,148,158,162,164,166,169,171,172],config_bt_ble_en:135,config_bt_nimble_ext_adv:[21,24,26],config_compiler_cxx_except:21,config_esp32_wifi_nvs_en:[169,171],config_esp_maximum_retri:171,config_esp_task_wdt_en:[162,166],config_esp_timer_profil:166,config_esp_timer_task_stack_s:166,config_esp_wifi_password:[135,169,171],config_esp_wifi_ssid:[135,169,171],config_espp_logger_log_level:113,config_example_adc_channel_i:107,config_example_adc_channel_x:107,config_example_adc_unit:107,config_example_alert_gpio:4,config_example_hardware_qtpys3:150,config_example_hardware_xiaos3:150,config_example_i2c_clock_speed_hz:78,config_example_i2c_device_addr:78,config_example_i2c_device_reg_addr:78,config_example_i2c_device_reg_s:78,config_example_i2c_scl_gpio:[2,4,9,14,35,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],config_example_i2c_sda_gpio:[2,4,9,14,35,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],config_example_spi_clock_spe:49,config_example_spi_cs_gpio:49,config_example_spi_miso_gpio:49,config_example_spi_sclk_gpio:49,config_freertos_generate_run_time_stat:124,config_freertos_use_trace_facil:124,config_freertos_vtasklist_include_coreid:124,config_gpio_ctrl_func_in_iram:98,config_rtsp_server_port:148,config_soc_gpio_flex_glitch_filter_num:98,configur:[1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,21,22,25,26,27,29,30,32,34,35,36,38,39,40,43,44,45,46,49,50,52,53,54,55,56,57,58,60,61,63,64,65,67,70,71,72,73,75,76,78,79,81,83,85,86,87,88,91,92,93,94,95,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,113,114,115,117,119,120,122,123,124,127,129,130,131,132,134,135,136,138,139,140,141,142,143,144,145,146,148,150,151,152,153,154,155,156,157,158,161,162,163,164,165,166,167,171,172,173],configure_alert:4,configure_global_control:100,configure_interrupt:103,configure_l:100,configure_pow:16,configure_stdin_stdout:[31,154],configure_task_watchdog:[162,166],confirm:[21,24,26,134],confirm_passkey_callback:[21,24,26],confirm_passkey_callback_t:21,confirm_valu:134,conn_info:[21,24,26],connect:[5,9,15,17,18,21,22,24,25,26,27,29,30,35,45,50,67,68,71,72,75,76,79,84,94,99,101,104,105,106,108,109,126,127,131,134,136,142,146,148,149,150,156,165,169,170,171],connect_callback:[21,24,26,171],connect_callback_t:21,connect_config:131,connect_whitelist:21,connectconfig:131,connected_device_info:[21,26],connected_device_nam:[21,26],connected_device_rssi:26,connection_termin:21,connector:[126,158,159],conninfo:24,consecut:4,consid:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],consist:126,consol:[5,17,45,50,114,142,160,161],constant:[64,139,160],constantli:158,constexpr:[2,4,9,14,21,26,40,44,49,51,53,70,75,78,81,83,86,88,93,96,100,103,105,107,120,122,126,134,135,141,143,145,150,152,156,158,162,166,172],construct:[2,4,9,14,17,21,29,33,44,47,49,60,64,65,72,78,86,100,103,105,113,115,117,129,135,137,141,148,154,162,166],constructor:[2,4,9,12,14,17,20,21,23,24,26,29,31,33,44,49,55,63,70,72,78,81,83,86,88,93,96,98,100,103,105,109,111,113,121,129,135,141,143,145,148,154,164,166],consum:154,contain:[1,21,33,35,40,41,43,55,57,66,70,75,85,91,92,95,115,121,124,132,134,135,136,139,141,148,150,152,154,162,171],content:[57,138,160],context:[55,113,154,162,166],continu:[4,7,9,14,21,26,57,72,80,98,132,162,164],continuous_adc:6,continuousadc:[0,6,11,164],control:[4,9,11,15,16,17,18,19,21,24,26,40,44,49,55,67,70,72,73,80,82,84,87,89,90,93,100,103,105,109,110,111,112,115,126,127,134,137,139,140,141,142,144,148,150,156],control_point:115,control_socket:148,controller_driv:40,conveni:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,35,37,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],convers:[2,4,6,9,33,44,49,129],convert:[3,4,5,8,9,10,16,17,21,33,34,35,44,49,53,55,57,107,120,122,129,135,145,148,150,156,164],convert_mod:[6,164],convieni:[115,117],cool:113,coolei:160,coordin:[40,53,81,83,86,88,95,122,150,156,158,172],copi:[33,49,57,75,121,143,154,162],copy_encod:143,core:[29,78,98,109,124,134,166],core_id:[39,53,98,122,124,150,156,158,162,166,172],core_update_period:[17,126],core_update_period_u:[17,126],corner:[40,160],correct:[17,154],correspond:[4,9,40,72,100,103,141,164],cost:126,could:[2,4,9,12,14,18,21,24,26,33,37,44,49,57,71,72,78,81,83,86,88,93,96,98,100,103,105,135,139,141,145,152,154,160],couldn:[55,57],count:[2,4,9,14,17,29,43,44,45,49,50,72,98,100,103,105,109,111,113,122,124,126,138,139,143,148,162,164],counter:[43,44,49,137,138],countri:26,country_cod:26,counts_per_revolut:[43,44,49],counts_per_revolution_f:[44,49],counts_to_degre:[44,49],counts_to_radian:[44,49],coupl:[36,55],cours:98,cout:[124,160],cpp:[5,11,18,21,24,26,27,32,45,50,54,57,71,80,112,113,123,127,135,144,148,157,159],cpprefer:[57,113],cpu:[98,124],cpu_perc:124,cr:148,crd:43,creat:[2,4,9,12,14,17,18,20,21,22,23,24,25,26,27,29,31,33,35,36,37,40,43,44,49,57,67,70,71,72,75,77,81,83,86,88,93,96,98,100,103,105,107,111,113,120,124,126,131,132,134,135,137,139,141,143,145,148,154,160,161,162,164,166,169,170,171],create_directori:57,creation:[44,49],credenti:134,critic:75,cross:[4,113,162,166],cs:[11,12,17,159],cseq:148,csrc:148,csrc_count:148,cst816:[80,90,122],csv2:37,csv:[3,4,5,9,10,45,50,57,80,127],csv_data:37,ctrl:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],cube:116,cubic:115,curent:[129,154],current:[10,14,16,17,18,20,21,29,31,35,40,43,44,45,49,51,55,67,69,70,71,92,93,95,98,100,101,103,104,109,113,117,121,124,126,128,139,141,143,148,162,164,166,171],current_directori:67,current_duti:109,current_hfsm_period:154,current_limit:17,current_pid_config:17,current_sens:17,currentlyact:154,currentsensor:17,currentsensorconcept:17,cursor:[32,40,92],cursor_obj:92,cursor_radiu:92,curv:115,custom:[2,4,9,12,14,15,29,39,44,49,55,57,72,81,83,86,88,93,96,100,103,105,135,141,143,145,151,152],cutoff:[17,60,63],cv:[2,4,6,8,9,14,35,43,44,49,53,55,72,81,83,86,88,96,100,103,105,107,109,111,122,126,131,135,139,141,143,145,150,154,156,158,162,164,172],cv_retval:162,cv_statu:162,cyan:160,cycl:[14,16,26,72,109,126,143,158,172],d0:[51,159],d1455f7dbd67:5,d1:[51,159],d2:[35,51,159],d36e39322660:151,d3:[35,51,159],d3bc:159,d4:[35,51],d5379983:54,d5:[35,51],d6:[35,51],d7:51,d9309337301f:159,d:[11,17,26,35,55,75,113,122,129,131,132,145],d_current_filt:17,dai:[145,149],dam:164,damag:[18,71],daniele77:31,dashboard:25,data:[1,2,3,4,5,6,8,9,10,12,17,21,24,26,29,33,34,35,37,38,39,40,41,44,45,49,50,53,55,56,57,59,60,61,63,64,65,67,75,78,81,83,86,88,92,93,95,96,107,108,111,114,122,124,129,131,132,134,135,140,141,148,150,152,154,156,158,159,164,171,172],data_address:135,data_command_pin:40,data_len:78,data_s:143,data_sheet:164,data_str:55,dataformat:[4,9],datasheet:[44,72,83,100,135,143,164],datasheet_info:164,date:[6,57,135,141,145,160],date_tim:[57,145],datetim:[135,141,145],dav:134,db:164,dbm:134,dc476c3d:157,dc:[16,17,19,40,126,159],dc_level:41,dc_level_bit:40,dc_pin:40,dc_pin_num:40,dd9e:157,de:55,dead:16,dead_zone_n:16,deadband:[107,120],deadband_perc:107,deadzon:107,deadzone_radiu:107,deal:134,debbc0e7f3f6:52,debounc:[14,103],debug:[17,24,26,55,57,98,109,113,154,156,162,166],debug_rate_limit:113,deck:[80,89,93,94],decod:[17,44,49,81,83,86,88,93,135,141,148],dedic:35,deep:154,deep_history_st:154,deephistoryst:154,default_address:[2,4,9,14,44,49,72,81,83,86,93,96,100,103,105,141,145],default_address_1:88,default_address_2:88,default_audio_r:53,default_valu:137,defautl:117,defin:[20,23,27,55,111,115,120,143,148,152,154],definit:[47,51,55,101,104],deftail:141,degre:[43,44,49,53,122,150,156],deinit:[6,20,21,23,24,26,78,171],deiniti:[20,21,23,24,26,78],del:143,delai:[2,4,9,12,14,44,49,59,72,81,83,86,88,93,96,98,100,103,105,126,135,141,145],delet:[8,21,26,32,35,43,57,98,143,156],delete_fn:143,delimit:37,demo:[40,71],demonstr:[87,97,127,142],depend:[6,21,24,26,70,73,120,143,149,154],deploi:149,depth:[39,143],deriv:[139,140,154],describ:[26,40,120,131,134,138,148],descript:[21,78],descriptor:[26,27,75,92,129,131,132],deseri:[29,55,134,152,153],design:[5,12,18,30,35,36,41,44,49,52,53,54,70,71,74,82,84,85,87,89,91,92,93,94,95,97,98,99,101,104,106,108,110,111,112,122,123,136,144,148,149,150,151,154,156,157,158,159,162,164,172,173],desir:[1,16,70,98],destin:57,destroi:[2,4,6,8,9,14,16,17,35,43,44,49,67,72,81,83,86,88,96,100,103,105,107,111,126,139,141,143,145,148,154,162,164,166],destruct:162,destructor:[21,26,55,70,78,98,143,148,154,162,166],detail:[17,70,126,134],detect:[5,14,29,52,53,54,86,98,156],detent:70,detent_config:70,detentconfig:[70,71,135,141,145],determin:[23,29,44,49,53,98,122,150,156],determinist:6,dev:[0,15,18,40,41,45,50,71,82,97,99,101,104,159,165],dev_addr:78,dev_kit:40,devcfg:[40,49],develop:[17,22,24,25,27,40,51,53,76,122,134,150,154,156,158,172],devic:[2,4,9,13,20,21,24,25,26,28,40,44,49,70,71,72,78,79,80,85,91,92,95,96,100,103,105,134,135,141,169],device_address:[2,4,9,14,44,49,72,78,100,103,105],device_class:134,device_found:78,device_info_servic:[21,23,24,26],device_nam:[21,24,26],deviceinfo:23,deviceinfoservic:[11,21,23,24,26],devkit:[0,40],df2:126,di:24,diagno:72,diagnost:72,diametr:[45,50],did_pub:55,did_sub:[29,55],differ:[2,4,9,12,14,21,36,39,40,41,44,45,47,48,49,55,59,62,72,81,83,86,88,93,96,98,100,102,103,105,109,111,113,135,139,141,143,145,154,162,163,166,167],differnt:166,digial:[63,101],digit:[3,4,5,9,10,30,36,59,60,65,99,101,104,106],digital_biquad_filt:[59,65],digital_input:[4,9],digital_output:[4,9],digital_output_mod:[4,9],digital_output_valu:[4,9],digitalconfig:[35,36],digitalev:4,dim:100,dimension:121,dir_entri:57,dirac:160,direct:[8,17,21,35,59,75,100,103,105,135,137,156],directed_address:21,directli:[4,9,16,19,21,24,48,49,53,72,74,108,111,115,122,150,156],director:160,directori:[57,67,135,141,145],directory_iter:57,directory_list:57,disabl:[4,9,16,17,21,29,43,44,53,98,100,103,122,135,143,150,156],disable_al:[29,98],disable_interrupt:[29,98],discharg:14,disconnect:[21,24,26,148,171],disconnect_al:21,disconnect_callback:[21,24,26,171],disconnect_callback_t:21,disconnectreason:21,discontinu:120,discover:134,discuss:135,disp:[40,53,122,156,158,172],dispatch:166,dispatch_method:166,displai:[11,37,53,54,80,82,84,134,148,149,156,157,158,159,172,173],display1:122,display_driv:[40,41,42],display_event_menu:154,display_task_config:[53,150],displaydriv:[40,53,122,150],displayrot:[39,40],dissemin:56,distinguish:152,distribut:[21,55,120],divid:[33,59,121,139,143,164,165],divider_config:164,divis:164,dma:[0,6,53,122,143,150,156,158,164,172],dma_en:143,dnp:[4,9],doc:[16,39,135,141,143,145,164,169,171],document:[31,37,44,71,143,152,154,160],doe:[6,8,10,14,16,21,24,26,37,43,44,49,57,67,70,83,98,100,103,105,111,129,140,141,148,152,154,156,160,165,166],doesn:[4,9,21,53,57,122,150,156],don:[2,4,6,8,9,14,17,21,24,26,29,35,43,44,49,55,72,81,83,86,88,96,100,103,105,107,111,124,126,131,132,135,139,141,143,145,154,162,164,166],done:[21,29,55,98,109,113,129,131,132,137,138,156,162],dongl:80,dot:121,doubl:[39,154,158],double_buff:39,double_click:72,down:[29,30,32,35,75,91,103,111,113,126,129,131,132,139,141,154,156,162],down_left:75,down_right:75,download:134,doxygen:[135,141,145],doxygenfunct:[135,141,145],drain:[4,9],draw:[39,40,53,54,122,123,150,151,156,157,158,159,172,173],draw_circl:[53,122,150,156,158,172],drive:[4,17,18,41,55,71,72,74,100,103,126,127,143,144],driven:[70,74],driver:[14,15,17,18,19,39,42,53,71,73,74,78,80,81,83,85,87,88,91,92,95,96,97,101,111,122,126,141,145,146,148,150,156,158,162,172],driverconcept:17,drv2605:[12,74,80],drv:40,ds:[4,9,72],dsiplai:39,dsp:[59,63],dsprelat:[59,65],dt:145,dual:[35,134],dual_motor_fn:126,dual_motor_tim:126,dualconfig:35,due:21,dummycurrentsens:17,dump:[160,166],dupont:[5,10],durat:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],duration0:143,duration1:143,duration_m:21,dure:[135,139,154],duti:[16,109,126],duty_a:16,duty_b:16,duty_c:16,duty_perc:109,duty_resolut:109,dx:37,dynam:[17,26,70,117,135,139],dynamictask:162,e2:164,e792ec2ed4fb:149,e9f0ba2bcaf6:127,e:[17,21,24,32,49,57,72,111,115,117,126,134,138,143,154,155,164,165],each:[4,6,8,9,16,21,33,35,54,55,57,65,67,70,71,98,100,103,107,113,123,124,126,138,141,148,151,152,157,159,162],earli:[2,4,6,8,9,14,35,43,44,49,72,81,83,86,88,96,100,103,105,107,111,126,139,141,143,145,154,162,163,164],easili:[4,9,44,128,160,161,162],eastwood:160,ec:[2,4,9,12,14,29,35,44,49,55,57,72,78,81,83,86,88,93,96,100,103,105,135,137,141,145,148,152,162,166],eccentr:[72,73,74],ecm:72,ed:43,edg:[4,5,9,29,44,49,70,72,98,107,143],edit:31,edr:134,eeprom:135,efect:126,effect:[51,57,126],effici:[9,37],eh_ctrl:135,eight:2,eir:134,either:[29,35,43,98,124,126,151,164],el_angl:17,elaps:[2,4,9,29,72,98,109,113,122,135,139,158,162,164,166,172],electr:[17,18,71,160],element:[8,121],elif:150,elimin:14,els:[4,6,8,17,21,26,29,57,78,96,100,105,122,126,135,137,145,150,152,154,156,158,160,162,164,166,172],elsewher:17,em:[29,55],emb:160,embed:[25,160],embedded_t:160,emplace_back:135,empti:[24,72,111,134,148,162,166,169,171],empty_row:160,en:[16,57,59,60,65,113,129,131,132,134,135,141,143,145,164,169,171],enabl:[4,6,8,9,16,17,21,29,31,35,39,53,55,70,93,98,100,103,124,125,126,128,131,135,137,156,160,162,166,169,171],enable_if:121,enable_interrupt:[29,98,103],enable_reus:[129,131,132],enable_sound:53,encapsul:[41,135,137],encod:[11,17,18,45,50,70,71,80,90,122,126,127,148],encode_fn:143,encoded_symbol:143,encoder1:126,encoder2:126,encoder_count:122,encoder_input:85,encoder_spi_handl:49,encoder_typ:47,encoder_update_period:[44,49],encoder_valu:122,encodergo:[126,127],encoderinput:[11,85],encodertyp:[43,46],encrypt:134,end:[4,9,18,21,26,32,40,53,55,57,70,71,72,75,111,122,131,132,134,135,150,154,156,158,162,172],end_fram:111,endev:154,endif:[21,24,26,98,135,150,160],endl:[124,160],endpoint:[129,131,132],energi:134,enforc:[154,160],english:[100,134],enough:162,ensur:[12,17,53,55,63,98,120,122,137,141,143,150,156,162,166,169,171],enter:[4,9,14,21,78,91,109,154],enterpris:134,entri:[57,124,154],enumer:[2,4,9,21,29,35,49,53,72,75,86,98,100,103,105,107,111,113,134,141,164],eoi:148,epc:134,equal:[121,172],equat:[43,59,115,164],equip:14,equival:[31,37,100,103,160],eras:[137,138],erm:[72,73,74],erm_0:72,erm_1:72,erm_2:72,erm_3:72,erm_4:72,err0:162,err1:162,err:49,error:[2,4,9,12,14,24,26,29,35,44,49,51,53,55,57,72,75,78,81,83,86,88,93,96,98,100,103,105,113,122,135,137,139,141,143,145,148,150,156,158,162,164,166,172],error_cod:[2,4,9,12,14,29,35,44,49,55,57,72,78,81,83,86,88,93,96,100,103,105,135,137,141,145,148,152,162,166],error_rate_limit:113,escap:91,esp32:[0,3,5,6,10,15,16,30,35,41,45,53,54,57,63,70,79,80,82,84,87,89,96,97,99,101,104,110,112,122,135,141,143,145,146,148,149,150,155,156,158,160,165,169,171,173],esp32c3:156,esp32s2:6,esp32s3:[5,6,10,15,22,25,27,76,79,104,126,150,151,156,159],esp:[0,3,5,6,8,10,11,15,16,18,21,22,24,25,26,27,29,30,31,32,34,36,38,40,41,43,45,46,50,52,56,57,58,59,61,63,68,71,73,76,78,79,80,82,83,84,87,89,94,97,98,99,101,104,106,108,109,110,112,113,114,119,123,125,127,130,132,135,136,137,138,140,141,142,143,144,145,146,148,149,151,153,155,157,159,160,161,162,163,165,166,167,169,170,171,173],esp_bt_dev_get_address:135,esp_err_t:[40,49,143,162],esp_err_to_nam:162,esp_error_check:[40,49],esp_fail:162,esp_gap_ble_nc_req_evt:24,esp_gap_ble_sec_req_evt:24,esp_idf_vers:98,esp_idf_version_v:98,esp_intr_dump:98,esp_lcd_gc9a01:40,esp_lcd_ili9341:40,esp_lcd_touch_cst816:83,esp_littlef:58,esp_log:113,esp_ok:[49,143,162],esp_task_wdt_init:162,esp_task_wdt_reconfigur:162,esp_tim:166,esp_timer_dispatch_t:166,esp_timer_dump:166,esp_timer_get_tim:[122,158,172],esp_timer_task:166,espbox:[11,53,54],esphom:40,espp:[0,2,4,5,6,8,9,11,12,14,16,17,18,20,21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,39,40,43,44,45,46,49,50,51,52,53,54,55,57,60,65,67,69,70,71,72,75,76,78,81,83,85,86,88,91,92,93,95,96,98,99,100,103,105,106,107,109,110,111,112,113,115,117,120,121,122,123,124,126,127,129,131,132,134,135,136,137,139,140,141,143,144,145,148,149,150,151,152,154,156,157,158,159,162,164,166,169,170,171,172,173],espp_f:57,espp_logger_cursor_commands_en:113,espp_logger_debug_en:113,espp_logger_error_en:113,espp_logger_info_en:113,espp_logger_log_level_debug:113,espp_logger_log_level_error:113,espp_logger_log_level_info:113,espp_logger_log_level_non:113,espp_logger_log_level_warn:113,espp_logger_warn_en:113,esppp:76,espressif:[16,40,63,83,132,143,169,171],esptimercam:[11,51,52],estim:[14,160],etc:[18,55,57,71,77,91,100,103,105,111,139,143,152,156,165],evalu:[104,115,117],even:[26,120,135,152,160,162],evenli:70,event1:55,event1_cb:55,event2:55,event2_cb:55,event:[4,9,24,29,30,39,53,80,83,98,122,129,131,132,135,154,155,156,158,166,171,172],event_callback_fn:[29,55,98],event_count:4,event_flag:4,event_high_flag:4,event_low_flag:4,event_manag:55,event_queue_s:98,eventbas:154,eventdata:171,eventmanag:[11,29,55,56],everi:[21,24,26,39,44,49,53,113,122,126,150,156,158,172],exactli:[21,26,134],exampl:[7,19,28,31,33,42,62,67,80,118,128,168],exapand:106,exceed:171,excel:17,except:[31,36,57],exchang:134,execut:[55,125,154,155,162,166],exis:171,exist:[16,37,57,137,148,152,154,160,170],exit:[0,2,3,4,5,6,8,9,10,14,15,18,21,22,25,27,30,32,34,35,36,38,41,43,44,45,46,49,50,52,54,56,58,61,68,71,72,73,76,78,79,81,82,83,84,86,87,88,89,94,96,97,99,100,101,103,104,105,106,107,108,110,111,112,114,119,123,125,126,127,130,136,138,139,140,141,142,143,144,145,146,149,151,153,154,155,157,159,161,162,163,164,165,167,170,173],exitact:[21,78],exitchildren:154,exitselect:154,exp:[117,124],expand:[36,80,101,104],expans:[53,122,156,172],expect:[57,98,137],experi:24,expir:166,expiri:166,explicit:[2,4,6,8,9,14,16,17,20,21,23,24,26,29,33,35,39,43,44,49,60,63,64,65,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,129,131,132,134,135,137,139,141,143,145,148,154,162,164,166,169,171],explicitli:[31,120,162],expos:[31,34,37,113,160],ext:[24,26],extend:[21,24,26,134],extens:148,extern:[4,9,72,107,126,134,154,160],external_typ:134,extra:[143,148],extra_head:148,exttrigedg:72,exttriglvl:72,f1c5e0df:5,f4:134,f56b72ec1a0:101,f5fedec:112,f967:71,f:[32,57],f_0_25:103,f_0_5:103,f_0_75:103,f_1:103,f_cutoff:[60,63],f_sampl:[60,63],fa:134,facil:124,factor:[44,49,63,70,164],fade:109,fade_in:117,fade_out:117,fade_time_m:109,fahrenheit:164,fail:[17,24,29,51,53,72,78,86,96,100,103,105,122,135,137,141,150,152,156,158,171,172],failur:[21,137],fake:[140,162],fall:[4,5,9,29,98,135,143],falling_edg:[29,98],fals:[2,4,6,8,9,12,14,16,17,21,24,26,29,35,40,43,44,49,51,53,55,57,67,70,72,75,81,83,86,88,93,95,96,98,100,103,105,107,109,111,120,121,122,124,126,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,171,172],famili:[2,4,9],fashion:98,fast:[28,80,98,103,118,135],fast_co:116,fast_ln:116,fast_math:116,fast_sin:116,fast_sqrt:116,faster:156,fastest:[44,49],fault:16,fc2c:157,fc44:32,fclose:57,fd64e526:27,fe:134,featur:[4,26,51,53,103,122,150,156,158,172],feature_report:26,feedback:[70,71,72,74,140],feel:17,few:[31,40,55,75,98,154],ff:134,ffdaf68f13cb:5,fflush:137,fi:[169,171],field:[4,9,17,18,49,57,107,134,135,141,148],field_fal:135,field_ris:135,field_strength:49,figur:[37,57,152,154,160],file2:57,file:[54,69,80,101,104],file_byt:57,file_cont:57,file_entry_str:57,file_s:57,file_str:57,file_system:[57,58],file_time_to_str:57,filenam:37,filesystem:[11,58,67],fill:[40,59,63,95,107,129,131,132,135],filter1:126,filter2:126,filter:[0,6,8,17,29,43,44,45,49,50,66,80,98,126,164],filter_config:98,filter_cutoff_freq_hz:126,filter_cutoff_hz:[44,49],filter_fn:[17,44,49],filter_typ:[29,98],filterconfig:98,filtertyp:[29,98],find:[24,29,78,98],fine:70,fine_values_no_det:70,fine_values_with_det:70,finger563:154,finger:[53,122,150,156],finish:[21,70,143],finit:[80,154],firmwar:[23,24,54,156],firmware_vers:23,first:[4,17,24,29,55,57,72,111,131,132,134,135,138,148,150,164,165,166],first_row_is_head:37,fish:[21,78],fit:39,fix:[164,165],fixed_length_encod:152,fixed_resistance_ohm:164,flag:[4,9,14,21,24,26,40,41,49,55,134,135,137,143,148,162],flags_to_clear:14,flash:[2,4,6,8,9,14,17,21,24,26,29,31,33,35,37,40,43,44,49,51,53,55,57,67,70,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,122,124,126,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,172],flavor:126,flex:98,flex_glitch_filt:98,flexibl:98,flip:120,floatrangemapp:[107,120],floatraw_i:107,flush:[39,40,41,57],flush_callback:[39,40],flush_fn:39,fmod:109,fmt:[4,6,8,9,14,35,37,40,43,44,49,55,81,83,86,88,93,96,100,103,105,107,115,117,120,121,124,126,131,132,135,137,139,141,143,145,148,152,154,158,160,162,164,166,171,172],foc:[16,17,18,126],foc_typ:17,foctyp:17,folder:[7,19,31,37,42,43,107,113,124,128,137,139,152,154,160,162,166,168],follow:[0,4,9,17,18,20,23,24,41,51,53,56,59,70,71,72,111,116,122,124,134,135,143,146,150,154,156,158,164,172],font_align:160,font_background_color:160,font_color:160,font_styl:160,fontalign:160,fontstyl:160,fopen:57,forc:[16,39],force_refresh:39,forev:[51,53,150,156],form:[59,60,148,165],format:[3,4,5,9,10,26,33,37,39,40,45,50,55,57,80,114,115,124,134,148,149,158,160,162,164],formula:164,forum:134,forward:32,found:[2,4,9,12,14,29,44,49,72,78,81,83,86,88,93,96,98,100,103,105,126,134,135,137,141,145],found_address:78,four:2,fp:57,frac:[59,117,164],frag_typ:148,fragment:148,frame:[4,9,53,111,122,148,150,156,158,172],frame_buffer0:[53,122,150,156,158,172],frame_buffer1:[53,122,150,156,158,172],framer:149,framework:[24,25],fread:57,free:[20,21,23,24,26,29,39,57,98,109,137,143,160],free_spac:57,freebook:[59,65],freerto:[98,124,162,166],freertos_generate_run_time_stat:125,freertos_use_trace_facil:125,frequenc:[6,8,44,49,51,60,63,70,109,146],frequency_hz:109,frequent:[39,139],friendli:21,from:[2,3,4,5,6,8,9,10,12,15,16,17,20,21,23,26,29,30,31,32,33,35,39,40,44,45,46,49,50,53,55,57,61,62,68,70,71,72,74,75,78,79,80,81,83,86,88,92,93,94,95,96,98,100,103,105,107,108,109,113,117,120,121,122,129,131,132,134,135,137,138,139,141,143,145,148,150,152,154,155,156,160,162,164,165,171],from_sockaddr:129,fs:57,fseek:57,ft5x06:[12,80,90],ftell:57,ftm:135,ftp:[80,134,148],ftp_anon:134,ftp_client_sess:67,ftp_ftp:134,ftp_server:67,ftpclientsess:[11,67],ftpserver:[11,67,68],fuel:14,fulfil:[44,49],full:[3,5,10,15,16,18,22,25,27,30,32,34,36,38,41,45,46,50,52,53,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,98,99,100,101,104,106,108,110,111,112,114,119,122,123,125,127,130,136,138,140,142,144,146,148,149,150,151,153,155,156,157,158,159,161,163,165,167,170,172,173],fulli:[72,126,154,162],fun:55,further:[58,148],futur:[113,134,148,162],fwrite:57,g:[17,21,24,33,49,57,72,100,111,115,117,134,143,155,164,165],g_bright:100,g_down:100,g_led:100,g_up:100,gain:[2,70,139],game:134,gamepad:[26,27,36,75,76,134,135],gamepad_descriptor:75,gamepad_input_report:[26,75],gamepad_led_report:75,gamepad_leds_report:[26,75],gamepadinput:[26,75],gamepadinputreport:[26,75],gamepadl:[26,75],gamepadledoutputreport:[26,75],gamepadreport:[27,76],gamma:[109,117],gap:24,gate:16,gatt:[24,25,26,27,28,80],gaug:[14,15],gaussian:[51,80,109,118,126],gb:37,gbc:37,gc9a01:[122,150],gener:[4,26,27,44,49,61,62,75,129,134,143,148,169,171],generatedeventbas:154,generic_comput:21,generic_desktop:[26,75],generic_displai:24,generic_hid:134,geometr:33,gestur:86,get:[2,3,4,5,6,8,9,10,11,12,14,15,16,17,18,20,21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,49,50,51,52,53,54,55,56,57,58,61,64,67,68,70,71,72,73,75,76,78,79,81,82,83,84,85,86,87,88,89,91,92,93,94,95,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,113,114,117,119,122,123,124,125,126,127,129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,169,170,171,172,173],get_accumul:[44,49],get_active_st:[29,98],get_alert_statu:14,get_all_mv:[4,9],get_all_mv_map:[4,9],get_alpha:117,get_battery_charge_r:14,get_battery_level:20,get_battery_percentag:14,get_battery_voltag:[14,51],get_beta:117,get_bright:39,get_button_input_devic:85,get_button_st:141,get_camera_d0_pin:51,get_camera_d1_pin:51,get_camera_d2_pin:51,get_camera_d3_pin:51,get_camera_d4_pin:51,get_camera_d5_pin:51,get_camera_d6_pin:51,get_camera_d7_pin:51,get_camera_href_pin:51,get_camera_pclk_pin:51,get_camera_reset_pin:51,get_camera_scl_pin:51,get_camera_sda_pin:51,get_camera_vsync_pin:51,get_camera_xclk_freq_hz:51,get_camera_xclk_pin:51,get_celsiu:164,get_cent:120,get_center_deadband:120,get_chip_id:14,get_config:[117,139],get_connected_device_address:21,get_connected_device_info:[21,26],get_connected_device_nam:[21,26],get_connected_device_rssi:[21,26],get_connected_devices_rssi_valu:21,get_control:26,get_count:[43,44,49],get_csrc_count:148,get_current_id:162,get_cursor_object:92,get_dat:145,get_data:148,get_date_tim:145,get_degre:[43,44,49],get_descriptor:[26,75],get_digital_input_valu:[4,9],get_duti:109,get_electrical_angl:17,get_encoder_input_devic:85,get_error:139,get_event_data:4,get_event_flag:4,get_event_high_flag:4,get_event_low_flag:4,get_extens:148,get_external_i2c:126,get_fahrenheit:164,get_file_time_as_str:57,get_files_in_path:57,get_free_spac:57,get_ftm_length:135,get_gamma:117,get_head:148,get_height:148,get_home_button_input_devic:95,get_home_button_st:[83,88,96],get_id:[134,162],get_info:162,get_input_devic:91,get_integr:139,get_interrupt_captur:105,get_interrupt_statu:135,get_ipv4_info:[129,131,132],get_jpeg_data:148,get_kei:93,get_kelvin:164,get_latest_info_str:124,get_latest_info_t:124,get_lcd_dc_gpio:[53,122,150,156,158,172],get_led_breathing_period:51,get_led_bright:51,get_log_level:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],get_log_verbos:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],get_magnetic_field_strength:49,get_mark:148,get_maximum:120,get_mechanical_degre:[44,49],get_mechanical_radian:[44,49],get_min_queue_s:[29,98],get_minimum:120,get_mjpeg_head:148,get_mount_point:57,get_mute_pin:53,get_mv:[4,6,9,164],get_nam:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],get_num_q_t:148,get_num_touch_point:[81,83,86,88,96],get_offset:[40,148],get_offset_rot:40,get_or_set_var:137,get_output:[100,103],get_output_cent:120,get_output_max:120,get_output_min:120,get_output_rang:120,get_packet:148,get_pad:148,get_paired_devic:21,get_partition_label:57,get_passkei:24,get_passkey_callback:[21,24,26],get_passkey_callback_t:21,get_payload:148,get_payload_typ:148,get_period:166,get_pin:[100,103,105],get_pointer_input_devic:92,get_posit:70,get_power_supply_limit:16,get_protocol_mod:26,get_push_button:49,get_q:148,get_q_tabl:148,get_quantization_t:148,get_radian:[43,44,49],get_rang:120,get_range_deadband:120,get_rat:6,get_rate_limit:113,get_remote_info:131,get_report:[26,75],get_resist:164,get_revolut:43,get_root_path:57,get_rpm:[44,49],get_rpt_head:148,get_rtp_header_s:148,get_scan_data:148,get_sequence_numb:148,get_servic:[20,23],get_service_data:24,get_session_id:148,get_shaft_angl:[17,126],get_shaft_veloc:[17,126],get_siz:134,get_ssrc:148,get_stat:35,get_tag:113,get_tim:[113,145],get_time_const:64,get_timestamp:148,get_total_spac:57,get_touch_point:[81,83,86,88,96],get_touchpad_input_devic:95,get_tracking_statu:49,get_type_specif:148,get_used_spac:57,get_user_select:154,get_valu:[35,107],get_values_:107,get_values_fn:107,get_var:137,get_verbos:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],get_vers:[14,148],get_voltag:164,get_voltage_limit:16,get_watchdog_info:[162,166],get_width:148,getactivechild:154,getactiveleaf:154,getiniti:154,getparentst:154,getsecuritypasskei:[21,24,26],getsocknam:[129,131,132],getter:121,gettimerperiod:154,gettin:107,gfp:[28,80],gfps_characteristic_callback:24,gfps_servic:24,gfpsaccountkeycharacteristiccallback:24,gfpscharacteristiccallback:24,gfpskbpairingcharacteristiccallback:24,gfpsmodelidcharacteristiccallback:24,gfpspasskeycharacteristiccallback:24,gfpsservic:[11,24,25],gimbal:[18,70,71],github:[5,18,27,32,37,40,45,50,52,54,70,71,75,83,112,115,122,123,126,127,132,135,143,144,148,151,154,156,157,159,160],githubusercont:[32,101,110,149],give:[129,154,162],given:[2,4,9,12,14,24,29,44,49,55,60,72,81,83,86,88,93,96,98,100,103,105,135,141,145,148,154],glitch:[43,98],global:[6,100],gnd:[5,103],go:[5,18,21,51,52,55,57,71,137,154],goe:[4,9,162,166],gone:162,good:121,goodby:[21,78],googl:[28,80,135],got:[4,55,137,148,171],gotten:171,gpio0:99,gpio12:99,gpio18:5,gpio2:30,gpio40:5,gpio41:5,gpio:[4,5,14,16,29,30,35,39,41,43,45,53,98,99,100,103,105,109,110,122,143,146,150,156,158,172],gpio_a:35,gpio_a_h:[16,17],gpio_a_l:[16,17],gpio_b:35,gpio_b_h:[16,17],gpio_b_l:[16,17],gpio_c_h:[16,17],gpio_c_l:[16,17],gpio_config:4,gpio_config_t:4,gpio_down:35,gpio_en:[16,17],gpio_evt_queu:4,gpio_fault:[16,17],gpio_i:35,gpio_install_isr_servic:4,gpio_intr_negedg:4,gpio_isr_handl:4,gpio_isr_handler_add:4,gpio_joystick_select:35,gpio_left:35,gpio_mode_input:4,gpio_mode_output:93,gpio_num:[29,98,111,143,158,172],gpio_num_0:[29,98,158,172],gpio_num_10:93,gpio_num_12:[29,98],gpio_num_15:40,gpio_num_16:150,gpio_num_17:150,gpio_num_18:40,gpio_num_19:40,gpio_num_22:40,gpio_num_23:40,gpio_num_2:150,gpio_num_35:150,gpio_num_36:150,gpio_num_37:150,gpio_num_3:150,gpio_num_43:150,gpio_num_44:150,gpio_num_45:40,gpio_num_48:40,gpio_num_4:[40,150],gpio_num_5:[40,150],gpio_num_6:[40,150],gpio_num_7:[40,150],gpio_num_8:150,gpio_num_9:150,gpio_num_nc:[78,150],gpio_num_t:[2,4,9,14,29,35,39,40,44,49,51,72,78,81,83,86,88,93,96,100,103,105,135,141,145,150],gpio_pullup:35,gpio_pullup_dis:78,gpio_pullup_en:[4,78,81,83,86,88,96,103,145],gpio_pullup_t:78,gpio_right:35,gpio_select:35,gpio_set_direct:93,gpio_set_level:93,gpio_start:35,gpio_up:35,gpio_x:35,gpo:135,grab:107,gradient:33,grai:113,graphic:33,gravit:160,grb:111,greater:[107,113,121],green:[33,111,113,143,160],greengrass:160,grei:160,ground:35,group:[57,129,131,132,134],group_publ:134,grow:57,grow_on_mount:57,grown:57,gt911:[80,90],guarante:[111,137],guard:154,gui:[39,40,41,124],guid:[3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,169,170,171,173],h:[31,33,40,113,148,156],ha:[2,4,5,9,10,12,14,15,17,20,21,23,24,26,30,31,35,36,40,41,43,44,49,51,53,55,57,67,72,73,81,83,86,87,88,93,94,96,97,98,99,100,101,103,104,105,109,111,113,122,124,131,132,134,135,138,141,143,145,148,150,154,156,158,159,160,162,166,171,172],half:[44,49,59],hand:172,handheld:[14,149],handl:[14,21,29,30,31,41,67,98,100,103,105,111,131,132,137,138,143,154,162],handle_all_ev:154,handleev:154,handler:[4,5,24,29,39,98,131,132],handov:134,handover_vers:134,happen:[55,98],haptic:[73,80],haptic_config:70,haptic_motor:70,hapticconfig:70,hard:78,hardawr:109,hardwar:[0,4,9,14,17,21,23,24,26,29,35,39,40,43,44,49,51,53,63,70,72,75,78,81,83,86,88,92,93,96,98,100,103,105,107,109,111,122,126,135,140,141,143,145,148,150,156,158,164,172],hardware_custom:84,hardware_vers:23,harmless:166,hart:164,has_chsc6x:81,has_cst816:83,has_ev:154,has_gt911_14:88,has_gt911_5d:88,has_q_tabl:148,has_stop:154,has_valu:[6,8,35,107,109,164],hash:134,hat:[26,75],have:[2,4,5,6,8,9,11,12,14,16,17,20,21,23,24,26,29,30,31,35,37,39,43,44,49,51,53,55,57,59,63,67,70,71,72,73,78,81,83,84,85,86,87,88,91,92,93,95,96,97,98,100,103,105,107,109,111,113,120,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,160,162,164,166,169,171,172],hc:134,header:5,heart:17,height:[39,40,53,122,148,150,156,158,172],hello:[135,137],help:[29,98,134],helper:[78,129,162],henri:17,here:[14,18,21,24,31,37,44,45,50,55,72,78,83,100,103,105,135,137,139,154,160,162,166],hertz:78,hex:33,hfsm:80,hibern:14,hid:[28,80,134],hid_dev_mod:135,hid_info_flag:26,hid_servic:26,hid_service_exampl:26,hidden:159,hide_bord:160,hide_border_left:160,hide_border_right:160,hide_border_top:160,hidservic:[11,26,27],hierarchich:[80,154],high:[4,5,6,9,16,29,30,39,43,53,70,80,93,98,105,122,124,126,143,150,156,162,172],high_level:[29,98],high_limit:43,high_resolution_clock:[2,4,9,14,29,44,49,72,98,100,103,105,109,111,113,124,126,139,143,162,164],high_resolution_tim:166,high_resolution_timer2:166,high_threshold_mv:4,high_water_mark:124,higher:[55,59,63,156],highlight:160,highresolutiontim:[11,17,126,166],histori:[31,32,59,60,63,64,65,154],hmi:40,hold:[39,78,126,134,135],home:[53,54,83,85,88,89,95,96,123,135,141,145,157,159],home_press:[83,88],hop:[129,131,132],horizont:160,host:[4,9,26,28,40,49,100,134,169],hot:164,hour:[14,145],how:[2,4,6,8,9,14,17,21,24,26,29,31,33,35,37,39,40,43,44,49,51,53,55,57,67,70,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,172],howev:[59,156],hpp:[1,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,37,39,40,41,43,44,47,49,51,53,55,57,59,60,63,64,65,66,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],hr:[14,134],href:51,hs:134,hsfm:154,hsv:[33,34,111,135,141,143,145,158],html:[16,21,39,40,59,65,134,143,169,171],http:[4,5,9,14,16,17,18,21,24,27,32,37,39,40,44,45,50,52,54,57,59,60,65,70,71,72,75,83,100,101,110,112,113,115,122,123,126,127,129,131,132,134,135,143,144,148,149,151,154,156,157,159,160,164,169,171],http_www:134,https_www:134,hue:[33,111,143,158],human:[37,57,160],human_read:57,hz:[6,51,53,70],i2c0:126,i2c:[3,5,7,10,11,12,14,15,17,18,21,36,44,45,48,50,51,52,53,71,72,73,80,81,83,86,88,93,96,100,101,102,103,104,105,106,111,122,126,135,136,141,142,145,146,150,156],i2c_cmd_alive_interval_tick:78,i2c_menu:78,i2c_num_0:[9,14,49,78,81,83,86,88,93,96,105,135,141,145],i2c_num_1:[2,4,35,44,72,100,103],i2c_port_t:78,i2cmenu:[21,78],i:[4,9,17,21,26,29,37,43,49,57,80,87,102,106,111,117,124,126,135,139,152,154,160,162,164],i_gpio:43,ic:14,icon:92,id:[4,9,14,23,24,26,29,67,72,75,124,134,148,162,166],ident:[31,53,122,150,156],identifi:[23,72,134,148],idf:[0,3,5,6,8,10,15,16,18,22,25,27,29,30,32,34,36,38,41,45,46,50,52,54,56,57,58,61,68,71,73,76,78,79,80,82,84,87,89,94,97,98,99,101,104,106,108,109,110,112,113,114,119,123,125,127,130,132,136,138,140,142,143,144,146,149,151,153,155,157,159,161,163,165,166,167,169,170,171,173],idl:162,ifs:57,ifstream:57,ignor:[43,55,120,162],iir:63,il:134,illustr:36,imag:[32,92,101,110,148,149],imap:134,imax:100,imax_25:100,imax_50:100,imax_75:100,immedi:[21,154,162],imped:[16,160],impl:[60,65],implement:[4,9,12,14,16,17,19,20,21,23,24,26,28,31,33,49,57,59,60,63,64,65,67,69,70,75,98,115,116,117,121,126,134,137,148,154,166],implicit:[44,49],improv:14,impuls:63,inact:134,includ:[1,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,37,39,40,43,44,45,47,49,50,51,53,55,57,59,60,63,64,65,66,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,130,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],include_directori:57,include_tim:113,include_tx_pow:21,inclus:75,incom:131,incomplet:[75,134],increas:[43,98,113,139],increment:[4,9,43,85,100,117,120,138],increment_direct:126,increment_direction1:126,increment_direction2:126,incrementdirect:126,incur:39,independ:[107,121,160],index:[4,9,26,43,111,121,148,164],indic:[14,29,98,100,103,105,131,132,134,135,162],individu:[9,107,115,137],induct:17,infinit:63,info:[2,4,6,8,9,14,21,24,26,28,29,35,43,51,53,55,70,72,75,78,80,98,103,107,109,111,113,122,124,125,126,129,131,132,135,139,143,148,150,156,158,164,166,172],info_rate_limit:[113,166],inform:[14,20,21,23,24,26,33,39,44,45,49,50,60,65,68,71,75,83,100,103,105,107,111,115,122,124,126,129,131,132,134,135,143,154,155,156,162,164,169,171],infrar:143,inherit:31,init:[14,20,21,23,24,26,78,107,129,131,137],init_ipv4:129,init_low_level:135,init_motor_channel_1:126,init_motor_channel_2:126,initail:[6,164],initi:[4,6,8,9,11,14,16,17,20,21,23,24,26,29,39,40,43,44,49,51,52,53,54,63,64,72,78,85,91,92,93,95,100,103,105,107,109,117,120,122,123,126,127,129,131,132,135,137,138,143,150,151,154,156,157,158,159,162,166,169,171,172,173],initialize_button:122,initialize_displai:[53,122,150,156,158,172],initialize_encod:122,initialize_keyboard:156,initialize_l:[51,158],initialize_lcd:[53,122,150,156,158,172],initialize_rtc:51,initialize_sound:53,initialize_target:126,initialize_touch:[53,122,150,156],initialize_trackbal:156,inject:24,injectconfirmpasskei:[21,26],injectconfirmpin:21,inlin:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,40,43,44,49,51,53,55,57,59,60,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],inout:[4,137],input:[4,5,9,10,17,21,24,26,27,29,30,31,32,35,36,44,46,49,53,59,60,63,64,65,70,71,72,75,78,80,81,83,88,94,98,99,100,101,103,104,105,107,108,120,122,145,150,156,165],input_delay_n:[40,49],input_driv:[85,91,92,95],input_report:26,input_report_id:[26,75],input_valu:4,inquiri:134,insert:14,insid:[4,78],instal:[4,78,98,109],instanc:[2,4,9,12,14,21,44,49,51,53,55,57,72,81,83,86,88,93,96,100,103,105,122,126,135,141,145,150,156,158,160,172],instant:109,instantan:98,instanti:124,instead:[2,4,9,12,14,31,44,49,53,67,72,81,83,86,88,93,96,100,103,105,107,122,135,141,145,150,152,154,156,166],instruct:63,instrument:[4,9,72],int16_t:43,int32_t:137,int8_t:152,integ:[16,43,116,129,135],integr:[12,53,122,139,140,150,156],integrator_max:[17,139],integrator_min:[17,139],intend:[21,23,115,154,162],interact:[21,31,48,55,56,57,78,83,93,102,113,137,148],interest:[35,55],interfac:[11,12,13,14,16,19,28,32,36,39,48,49,51,53,57,67,70,71,72,77,78,80,81,83,88,93,100,102,103,105,111,122,126,137,141,143,148,150,156,158,172],interfer:70,intergatedcircuit:75,intermedi:134,intern:[4,14,24,26,29,31,35,40,43,51,53,59,60,63,64,65,72,100,103,105,122,129,150,154,156],internal_i2c:[51,53,122,150,156],interpol:[33,116],interpret:26,interrupt0:98,interrupt12:98,interrupt:[4,5,11,43,51,53,78,80,83,100,103,105,109,122,135,150,156,158,162,172],interrupt_config:[29,158,172],interrupt_typ:[29,98,158,172],interrupttyp:[29,103],interupt:98,interv:[21,93,156],interval_m:21,interval_ms_to_unit:21,interval_unit:21,interval_units_to_m:21,intr_typ:4,introduc:120,inttrig:72,inv_lerp:116,invalid:[21,26,33,98],invers:[103,109,116],invert:[35,53,95,100,103,105,109,120,122,150,156],invert_color:40,invert_i:95,invert_input:120,invert_output:120,invert_x:95,invoc:139,io0:98,io12:98,io:[21,26,39,40,57,80,101,104,115,134,159],io_cap:21,io_conf:4,io_num:4,ion:14,ip2str:171,ip:[67,129,131,132,148,159,171],ip_add_membership:[129,131,132],ip_address:[67,131,132,148],ip_callback:171,ip_event_got_ip_t:171,ip_evt:171,ip_info:171,ip_multicast_loop:[129,131,132],ip_multicast_ttl:[129,131,132],ipv4:129,ipv4_ptr:129,ipv6:129,ipv6_ptr:129,ir:143,iram:98,irdaobex:134,irq:83,is_0_act:98,is_12_act:98,is_a_press:35,is_act:[29,98,148],is_al:67,is_b_press:35,is_charg:55,is_clos:148,is_complet:148,is_connect:[21,26,67,131,148,171],is_dir:57,is_down_press:35,is_en:[16,17],is_fault:16,is_floating_point:121,is_grow_on_mount:57,is_left_press:35,is_mount_as_read_onli:57,is_multicast_endpoint:132,is_mut:53,is_oneshot:166,is_passive_data_connect:67,is_period:166,is_press:[29,35,126,141],is_right_press:35,is_run:[70,162,166],is_select_press:35,is_start:162,is_start_press:35,is_up_press:35,is_valid:[129,131,132],is_valid_fd:[129,131,132],isn:137,isr:[4,29,98,109],isr_core_id:[29,78,98,109],it_st:[135,141,145],ital:160,item:[37,57],iter:[8,40,55,57,131,132,162,166],its:[4,6,9,14,23,30,44,49,53,55,57,64,67,70,75,98,100,103,105,110,117,122,124,129,131,132,135,139,144,150,154,155,156,169],itself:[39,55,57,85,91,92,95,148,162],j1:5,j3:5,j5:5,j:160,jan:57,join:[129,131,132,162],josh:160,joybonnet:[2,35],joystick:[4,5,10,11,26,35,36,75,80,134],joystick_config:35,joystick_i:35,joystick_max:[26,75],joystick_min:[26,75],joystick_select:35,joystick_typ:75,joystick_x:35,jpeg:[148,149],jpeg_data:148,jpeg_fram:148,jpeg_frame_callback_t:148,jpeg_head:148,jpegfram:[148,149],jpeghead:148,jpg:37,js1:107,js2:107,jst:[5,10,126],jump:120,jumper:[5,165],june:160,just:[4,26,35,44,49,55,110,126,134,143,148,152,154,156,158,164,172],k:[32,164],k_bemf:17,kb:24,kbit:135,kd:[17,70,139],kd_factor_max:70,kd_factor_min:70,keep:[21,109,166],keepal:131,kei:[21,24,26,93,94,134,135,137,138,148,156],kelvin:164,kept:162,key_cb:[93,156],key_cb_fn:93,key_distribut:21,key_not_found:137,keyboard:[31,80,90,123,134,156,157,159],keyboard_interrupt:156,keypad:[80,90,93],keypad_input:91,keypadinput:[11,91],keypress_callback:156,keypress_callback_t:156,kg:160,ki:[17,139],kind:[47,154],kit:[41,80,104,165],know:[44,49,55,162],known:[134,154],kohm:[5,105],kp:[17,70,139],kp_factor:70,kts1622:[12,80,102],kts1622b:103,kts1622euaa:104,kv:17,kv_rate:17,l:32,lab:17,label:[40,53,57,122,150,156,158,172],label_btn:[53,122,150,156],label_btn_clear:150,lack:57,lambda:[113,162,164],landscap:[39,40],larg:148,larger:[6,148],last:[35,43,72,81,83,88,96,98,107,111,134,138,139,141,154],last_button_st:141,last_it_st:135,last_unus:35,latch:[103,143],later:[16,24,29,40,43,98,166],latest:[16,21,49,92,95,107,124,139,143,164,169,171],launch:[24,134],lazi:37,lcd:[40,49,53,122,150,156,158,159,172],lcd_backlight:150,lcd_c:150,lcd_dc:150,lcd_height:[53,122,150,156,158,172],lcd_send_lin:[40,41],lcd_spi_post_transfer_callback:40,lcd_spi_pre_transfer_callback:40,lcd_touch:83,lcd_wait_lin:41,lcd_width:[53,122,150,156,158,172],lcd_write:[40,41],le:134,le_rol:134,le_sc_confirm:134,le_sc_random:134,lead:[6,33],leaf:154,learn:[14,72,134],least:[18,43,71,111,131,141],leav:[4,9],led:[4,5,11,51,52,75,80,100,101,126,143,144,158,159],led_breathing_period:51,led_callback:109,led_channel0:126,led_channel1:126,led_channel:109,led_count:75,led_descriptor:75,led_encod:[111,143],led_encoder_st:143,led_fade_time_m:109,led_index:75,led_reset_cod:143,led_stip:143,led_strip:[111,143],led_task:[109,158],ledc:109,ledc_auto_clk:109,ledc_channel_5:109,ledc_channel_t:109,ledc_clk_cfg_t:109,ledc_low_speed_mod:109,ledc_mode_t:109,ledc_sleep_mode_keep_al:109,ledc_sleep_mode_t:109,ledc_timer_10_bit:109,ledc_timer_13_bit:109,ledc_timer_2:109,ledc_timer_bit_t:109,ledc_timer_t:109,ledc_use_rc_fast_clk:109,ledstrip:[11,111,112,158],left:[26,35,40,43,53,75,91,92,111,113,122,141,156,160],left_press:[92,156],legaci:[21,26,134],legend:[37,160],len:[2,49,111],length:[4,9,24,26,40,49,53,59,63,78,111,121,122,134,135,137,143,150,156,158,172],lerp:116,less:[16,98,107,121,134,135,162],let:[21,24,26,55,98,124,162],level0:143,level1:143,level:[2,4,6,8,9,11,12,13,14,16,17,19,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],leverag:63,lh:[135,141,145],li:14,lib:72,libarari:152,libfmt:[113,124,162],librari:[55,57,70,72,76,80,124,134,152,153,160],licens:160,life:152,lifecycl:39,lifetim:[29,98],light:[33,85,91,92,95,109,113,152,154,160,166],like:[55,98,122,129,137,166],lilygo:[80,89,90,157,159],limit:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],limit_voltag:[16,17],line:[29,32,45,51,53,80,83,98,113,122,124,150,156,158,172],line_input:31,linear:[46,72,73,74,116],lineinput:[31,32],link:[37,57,136],links_awaken:37,list:[4,9,21,26,29,57,72,98,134],list_directori:57,listconfig:57,listen:[67,131,148],lit:[4,9,72],lithium:14,littl:[21,51,55,109,162],littlef:[57,58],lk:[2,4,6,8,9,14,35,43,44,49,55,72,81,83,86,88,96,100,103,105,107,109,111,126,139,141,143,145,154,162,164],ll:[2,4,8,9,14,35,44,49,53,55,57,68,72,81,83,86,88,93,96,100,103,105,111,122,135,141,145,146,150,156,158,166,172],ln:164,load:[35,37,53,126,134,138],load_audio:53,local:[21,134],local_user_termin:21,locat:14,lock:[53,122,131,135,150,156,158,162,172],lock_guard:[53,122,150,156,158,172],log:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,80,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,114,115,122,124,126,129,131,132,135,137,138,139,141,143,145,148,149,150,154,156,158,162,164,166,169,171,172],log_level:[2,4,6,8,9,14,16,17,20,21,23,24,26,29,35,39,43,44,49,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,126,131,132,135,139,141,143,145,148,154,162,164,166,169,171],logger1:113,logger1_thread:113,logger2:113,logger2_thread:113,logger:[0,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,75,78,80,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],logger_:[21,39,107],logger_config:129,logger_fn:113,logging_fn:126,logging_task:126,logic:[4,9,29,30,35,98,132,134],long_local_nam:134,long_n:137,longer:[21,162],look:83,loop:[17,18,19,21,44,49,51,53,57,70,107,113,127,140,150,156,162],loop_foc:[17,126],loop_iter:113,loopback_en:[129,131,132],loos:55,lost:49,lot:[18,71,98,160,172],low:[4,5,8,9,14,16,17,19,21,29,30,35,43,53,55,75,98,105,122,126,129,134,143,150,156,158,172],low_level:[29,98],low_limit:43,low_threshold_mv:4,lower:[43,100,103,105,164],lowest:[162,166],lowpass:[62,80],lowpass_filt:63,lowpassfilt:[61,63],lra:[72,73,74],lsb:[4,9,100,103,105],lsit:57,lv_align_bottom_mid:150,lv_align_cent:[53,122,150,156,158,172],lv_align_top_left:[53,156],lv_align_top_mid:[122,150],lv_area_t:40,lv_btn_creat:[53,122,150,156],lv_color16_t:[53,122,150,156,158,172],lv_color_mak:[53,122,150,156,158,172],lv_color_t:40,lv_disp_set_rot:[53,122,156,158,172],lv_display_flush_cb_t:39,lv_display_rotation_0:[53,122,156,158,172],lv_display_rotation_t:[53,122,156,158,172],lv_display_t:[40,53,122,156,158,172],lv_event_press:[53,122,150,156],lv_image_dsc_t:92,lv_indev_t:[85,91,92,95],lv_label_cr:[53,122,150,156,158,172],lv_label_set_text:[53,122,150,156,158,172],lv_label_set_text_fmt:122,lv_obj_add_event_cb:[53,122,150,156],lv_obj_add_st:150,lv_obj_align:[53,122,150,156,158,172],lv_obj_clear_flag:[53,122,150,156],lv_obj_creat:[53,122,150,156,158,172],lv_obj_flag_scrol:[53,122,150,156],lv_obj_set_s:[53,122,150,156,158,172],lv_obj_set_scrollbar_mod:[53,122,150,156],lv_obj_set_style_bg_color:[53,122,150,156,158,172],lv_obj_set_style_text_align:[53,122,150,156,158,172],lv_obj_t:[53,92,122,150,156,158,172],lv_screen_act:[53,122,150,156,158,172],lv_scrollbar_mode_off:[53,122,150,156],lv_state_check:150,lv_symbol_refresh:[53,122,150,156],lv_symbol_trash:150,lv_task:[53,122,150,156,158,172],lv_task_handl:[53,122,150,156,158,172],lv_text_align_cent:[53,122,150,156,158,172],lv_tick_inc:39,lvgl:[39,40,41,53,54,85,91,92,95,122,123,150,151,156,157,158,159,172,173],lvgl_esp32_driv:40,lvgl_mutex:[53,122,150,156,158,172],lvgl_tft:40,lx:75,ly:75,m2:126,m5stack:[110,149],m:[2,4,6,8,9,11,14,35,43,44,49,53,55,70,72,81,83,86,88,96,100,103,105,107,109,111,113,122,126,131,135,139,141,143,145,150,154,156,158,160,162,164,172],m_pi:[26,44,49,75,124,126,158,172],m_pi_2:121,ma:164,mac:[134,135,171],mac_addr:134,mac_address:134,machin:80,made:[24,26,135],mag:121,magenta:160,magic_enum_no_check_support:154,magnet:[18,45,48,50,70,80,126,160],magnetic_det:70,magneticfieldstrength:49,magnitud:[107,121,139],magnitude_squar:121,mai:[4,5,6,9,12,21,29,36,70,98,111,134,135,137,154,162,166],mailbox:135,mailto:134,main:[17,39,41,101,104,143,149,156,162],mainli:39,maintain:[39,44,49,126,135],maintian:113,make:[0,2,4,9,14,17,18,21,26,35,44,49,55,57,71,72,73,78,81,83,86,88,93,96,98,100,103,105,107,110,120,126,129,134,135,141,145,148,150,154,158,164,166],make_alternative_carri:134,make_android_launch:[134,135],make_ev:154,make_handover_request:134,make_handover_select:[134,135],make_le_oob_pair:[134,135],make_multicast:[129,131,132],make_oob_pair:134,make_shar:[17,40],make_text:[134,135],make_uniqu:[2,4,9,35,72,109,124,131,132,143,162],make_uri:[134,135],make_wifi_config:[134,135],makeact:154,maker:160,makerfab:122,malloc_cap_8bit:39,malloc_cap_dma:39,man:21,manag:[8,11,14,20,21,22,23,24,25,26,27,33,35,37,39,41,57,58,77,80,98,100,103,105,108,109,131,132,134,135,137,166],mani:[17,21,43,55,56,98,131,132,171],manipul:34,manual:[4,9,17,21,29,31,49,70,98,148,154,155],manual_chid:[4,9],manufactur:23,manufacturer_nam:23,map:[4,9,26,35,77,107,108,120,148],mapped_mv:4,mapper:[80,107,118],mario:37,mark:[124,148,162],markdownexport:160,marker:148,mask:[100,103,105],maskaravivek:134,mass:[72,73,74],master:[40,83,132,143,156],match:[24,41,57,135,141,145],math:[80,115,117,120,121],matouch:[80,84],matouchrotarydisplai:[11,122,123],matrix:91,max17048:[14,15],max17049:14,max1704x:[12,13,80],max:[4,16,43,70,72,100,107,117,120,131,132,139,169],max_circl:[158,172],max_connect:131,max_data_s:148,max_glitch_n:43,max_interval_m:21,max_led_curr:100,max_num_byt:[131,132],max_number_of_st:169,max_pending_connect:131,max_receive_s:131,max_target:126,max_transfer_sz:[40,49],maxim:162,maximum:[16,21,35,44,49,100,107,120,126,131,132,139,148],maxledcurr:100,maybe_duti:109,maybe_mv:[6,8,164],maybe_r:6,maybe_unus:26,maybe_x_mv:[35,107],maybe_y_mv:[35,107],mb:[57,134],mb_ctrl:135,mbaud:52,mcp23017:106,mcp23x17:[12,80,102],mcpwm:[16,70],me:134,mean:[16,26,33,44,49,59,98,103,107,113,120,124,143,152,162,166],meant:21,measur:[6,8,14,17,18,43,44,49,51,71,107,121,139,164],mechan:[6,17,44,49,55,67],media:134,mega_man:37,megaman1:37,megaman:37,member:[2,4,6,8,9,12,14,16,17,21,23,29,33,35,39,43,44,49,57,60,63,64,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,124,129,131,132,134,135,139,141,143,145,148,150,162,164,166,169,171,172],memori:[20,21,23,24,26,39,53,59,63,98,103,109,122,135,138,143,150,156,158,160,162,172],memset:[4,40,49],mention:[18,31,41],menu:[21,26,78],menuconfig:[15,18,41,57,68,79,82,84,89,125,149,162,166,170],mere:16,messag:[2,4,5,9,21,29,35,51,55,57,72,96,100,103,105,134,135,137,141,145,148,152,154,162,166],message_begin:134,message_end:134,method:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,115,117,122,124,126,129,131,132,135,137,139,141,143,145,148,150,152,156,158,162,164,166,169,171,172],metroid1:37,metroid:37,mhz:49,mice:92,micro:[40,122,158],microcontrol:14,microphon:53,micropow:14,micros_per_sec:143,microsecond:[122,126,129,131,132,158,166,172],microsoft:26,middel:150,middl:[21,134,150],middle_i:[158,172],middle_x:[158,172],might:[71,162,166],millisecond:[2,4,9,12,14,21,44,49,72,78,81,83,86,88,93,96,100,103,105,109,113,135,141,145,156,162],millivolt:164,mime_media:134,min:[4,70,107,120],min_interval_m:21,min_queue_s:98,mini:80,minimum:[21,29,35,98,107,120,139],minu:148,minut:[44,49,145],mireq:40,mirror:105,mirror_i:40,mirror_x:40,miso:150,miso_io_num:[40,49],miss:98,mit:160,mitm:[21,26],mix:33,mjepg:148,mjpeg:[148,149],mkdir:57,mmev01:104,mode:[4,6,9,10,14,24,26,40,49,70,72,100,103,109,134,135,166],model:[14,23,24,33,122,154],model_numb:23,modelgaug:14,moder:8,modern:160,modif:17,modifi:[40,71,100,148,149],modul:[53,122,126,149,150,156,158,172],modulo:[44,49],moment:148,monitor:[0,3,5,10,13,15,18,22,25,27,30,32,34,36,38,41,45,46,50,51,52,54,56,58,61,68,71,73,76,79,80,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,162,163,165,167,170,173],month:145,more:[4,6,9,21,24,26,31,33,39,45,50,60,62,65,71,72,83,98,99,107,109,111,113,117,122,126,129,131,132,134,143,149,154,155,156,162,164,166],mosi:[40,150],mosi_io_num:[40,49],most:[6,17,35,44,49,53,58,99,107,122,139,150,156],motion:[17,70,126],motion_control_typ:[17,126],motioncontroltyp:[17,126],motoion:17,motor1:126,motor1_current_u_amp:126,motor1_current_w_amp:126,motor1_driv:126,motor2:126,motor2_current_u_amp:126,motor2_current_w_amp:126,motor2_driv:126,motor:[16,18,19,44,49,70,71,73,74,80,126,127],motor_task_fn:17,motor_tim:17,motor_typ:72,motorconcept:70,motorgo:80,motorgo_mini:126,motorgomini:[11,126,127],motortyp:72,mount:[18,57,71],mount_point:57,mous:134,move:[17,32,64,111,113,124,126,143,156,162],move_down:[86,113],move_left:86,move_right:86,move_to:113,move_to_start:113,move_up:[21,51,86,113],movement:31,movi:160,mp4:[32,101,110,149],ms:[21,39],msb:[4,9,100,103,105],msb_first:143,msg:154,mt6701:[12,17,18,46,48,71,80],mt6701interfac:[11,49],mt_displai:122,mtro128g:122,much:[59,160],multi:70,multi_byte_charact:160,multi_rev_no_det:70,multicast:[129,130,131],multicast_address:[129,131,132],multicast_group:[129,131,132],multipl:[6,8,17,21,35,56,70,72,74,98,113,136,139,148],multipli:[70,121,139],must:[4,8,9,17,18,20,21,23,25,41,43,49,55,57,63,71,92,93,120,124,126,129,131,132,134,135,137,150,152,154,156,162,169,171],mutabl:[121,162],mutat:162,mute:[4,53],mutex:[2,4,6,8,9,12,14,35,43,44,49,53,55,72,81,83,86,88,96,100,103,105,107,109,111,122,126,131,135,139,141,143,145,150,154,156,158,162,164,172],mutual:96,mux:[4,9],mv:[2,4,6,8,9,107,164],my:24,mynewt:21,mystruct:152,n:[4,6,8,9,14,21,32,35,37,43,44,49,55,57,59,65,66,78,81,83,86,88,93,96,100,103,105,107,115,117,120,121,124,126,131,132,135,137,139,141,143,145,148,152,154,158,160,162,164,166,171,172],name:[0,2,3,4,5,6,8,9,10,11,12,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,32,34,35,36,37,38,39,41,43,44,45,46,49,50,51,52,53,54,55,56,57,58,61,67,68,70,71,72,73,76,78,79,81,82,83,84,85,86,87,88,89,91,92,93,94,95,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,114,119,122,123,124,125,126,127,129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,169,170,171,172,173],namespac:[2,4,9,26,35,57,72,75,137,160],nanosecond:[16,43,98],navig:31,nby:160,ncharact:160,ncustom:160,ndef:[80,133,135],ndeflib:134,ndefmessag:134,ne:[36,37,141,142],nearbi:[24,25],nearby_fp_characterist:24,nearest:[21,70,116],necessari:[17,162],need:[2,4,5,6,8,9,10,12,14,18,24,26,29,31,44,49,53,55,57,59,68,70,71,72,75,81,83,86,88,93,96,98,100,103,105,113,121,122,134,135,139,141,143,145,146,149,150,154,156,162,165,166],needs_zero_search:[44,49],neg:[14,111,120,121,139,156,164,165,166],negat:[35,121],nencod:122,neo_bff_io:111,neo_bff_num_l:111,neopixel:112,neopixel_writ:111,nest:160,net:126,network:[21,80,131,132,134,149,169,170],never:26,new_address:141,new_button_st:126,new_data:[81,83,88,96],new_duti:109,new_object:152,new_target:17,newer:162,newli:162,newlib:58,newlin:124,newtonian:160,next:[32,70,72,137,143,158,172],nf:134,nfault:17,nfc:[80,134,135,136],nfcforum:134,nice:[53,122,124,156,160,172],nicer:113,nimbl:[21,24,26],nimbleaddress:21,nimbleadvertis:21,nimblecharacterist:[24,26],nimblecharacteristiccallback:24,nimbleconninfo:[21,24,26],nimbledevic:[20,21,23,24,26],nimbleextadvertis:21,nimbleextadvertisingcallback:21,nimblehiddevic:26,nimbleserv:[20,21,23,24,26],nimbleservercallback:21,nimbleservic:[20,23,24,26],nimbleuuid:[20,23,24,26],nm:17,no_pul:103,no_timeout:162,node:[129,131,132,154],noexcept:109,nois:120,nomin:164,nominal_resistance_ohm:164,non:[6,21,41,68,70,120,135,137,138],nonallocatingconfig:39,none:[4,9,10,75,86,98,113,134,135,141,145,154],nopen:137,norm:121,normal:[2,4,9,12,14,39,44,49,55,59,72,81,83,86,88,93,96,100,103,105,121,135,141,145,154],normalizd:[60,63],normalized_cutoff_frequ:[44,49,60,63,126],note:[2,4,5,6,8,9,10,12,14,17,18,21,24,25,26,31,35,36,43,44,49,52,53,55,57,67,70,71,72,75,78,81,83,86,87,88,96,100,103,105,107,109,111,113,115,121,122,125,126,131,132,137,139,141,143,145,146,149,150,152,154,156,160,162,164,166],noth:[16,29,98,124,162,166],notif:24,notifi:[4,20,24,26,148],now:[2,4,9,14,17,21,24,26,29,37,44,49,55,57,70,72,78,81,83,86,88,93,96,98,100,103,105,107,109,111,113,124,126,131,132,135,137,138,139,141,143,145,156,162,164,166],npress:[53,122,156],ns_name:137,ntc:[9,164,165],ntc_smd_standard_series_0402:164,ntcg103jf103ft1:164,nthe:171,nto:158,nullopt:[109,132],nullptr:[12,17,21,39,44,49,53,57,96,107,121,122,131,132,135,150,154,156,166,171],num:148,num_button:[26,75],num_byt:[53,162],num_connect_retri:171,num_incr:117,num_l:[26,75,111,158],num_periods_to_run:109,num_pole_pair:17,num_publish:55,num_receiv:55,num_seconds_to_run:[109,113,139,162],num_seconds_to_wait:21,num_steps_per_iter:162,num_task:[124,162],num_touch:95,num_touch_point:[53,81,83,86,88,96,122,150,156,172],number:[4,6,9,17,23,29,39,40,43,44,49,53,57,59,63,70,75,79,81,83,86,88,95,96,98,109,111,113,116,122,129,131,132,134,135,138,143,148,150,156,158,159,164,169,171,172],number_of_link:57,nv:[11,80],nvs_commit:137,nvs_flash:[21,24,26],nvs_flash_init:[169,171],nvs_handle_espp:137,nvserrc:137,nvshandl:[11,80],o:[4,9,21,26,80,102,106],object:[14,17,21,23,24,26,29,31,33,36,37,41,53,55,64,78,92,98,109,111,113,117,122,124,126,134,137,141,143,148,150,152,153,154,156,162,164,166,172],occur:[4,9,14,55,57,81,83,88,93,96,98,100,103,105,129,131,132,135,137,148,154,162],octob:160,off:[4,5,21,43,70,100,113,126,134,148,156,164],offset:[17,18,40,71,135,148],offset_i:40,offset_x:40,ofs:57,ofstream:57,ohm:[17,164],ok:148,older:162,on_button_press:122,on_clear_press:150,on_connect:171,on_disconnect:171,on_gfps_read:24,on_gfps_writ:24,on_got_ip:171,on_jpeg_fram:148,on_off_strong_det:70,on_pairing_request:24,on_receive_callback:132,on_response_callback:[131,132],on_rotate_press:150,on_touch:122,onc:[9,18,35,43,44,49,55,71,126,148,166],once_flag:55,one:[4,5,10,12,26,31,32,36,41,44,49,55,56,67,71,99,109,111,113,131,132,135,143,154,155,160,166,167],ones:78,oneshot:[7,80],oneshot_adc:8,oneshotadc:[0,8,11,35,36,107,126],ongo:[53,122,150,156,158,172],onli:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,36,37,39,43,44,45,49,51,53,55,57,59,67,70,71,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,149,150,152,154,156,158,160,162,164,166,169,171,172],onread:24,onwrit:24,oob:[134,135],open:[4,9,17,18,19,57,70,131,134,136,137,138,169,171],open_drain:[4,9,100,103],oper:[2,4,9,12,14,33,44,49,51,57,60,61,63,64,65,72,81,83,86,88,93,96,100,103,105,115,117,121,135,137,139,140,141,145,149,164,172],operation_not_support:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],oppos:33,opposit:109,optim:[17,59,116],option:[4,6,8,9,16,17,21,26,31,35,39,40,44,49,68,78,84,85,95,103,107,109,111,113,120,124,129,131,132,134,148,149,152,162,166],order:[4,9,21,24,59,60,62,66,80,111,113,126,131,150],orderli:98,oreilli:134,oresp32:89,org:[21,59,60,65,129,131,132,134,164],orient:[17,18],origin:[14,45,50,57,71,103,121],oscil:[4,120],osr_128:[4,9],osr_16:[4,9],osr_2:[4,9],osr_32:[4,9],osr_4:[4,9],osr_64:[4,9],osr_8:[4,9],ostringstream:37,other:[4,9,17,21,31,33,39,55,75,82,84,89,94,97,98,109,110,121,122,126,129,131,132,135,137,139,141,145,152,154,162,169],otherwis:[5,16,17,18,21,24,29,35,49,51,53,55,67,70,71,75,81,83,88,93,98,105,107,109,121,122,124,131,132,134,137,143,148,150,154,156,158,162,166,171,172],ouput:120,our:[49,109,129,131,132,162],ourselv:[21,24],out:[21,31,36,37,51,57,78,92,98,107,113,124,129,131,132,134,137,143,152,154,160,162,164,166],output:[2,4,6,8,9,14,17,19,21,24,26,29,31,33,36,37,41,43,44,46,49,51,53,55,57,59,60,63,64,65,67,70,73,75,78,81,83,86,88,93,95,96,98,100,103,105,106,107,109,111,113,117,120,122,124,126,135,137,139,141,143,145,148,150,153,154,156,158,160,162,164,166,170,172],output_cent:120,output_drive_mod:103,output_drive_mode_p0:100,output_invert:109,output_max:[17,120,139],output_min:[17,120,139],output_mod:[4,9],output_rang:120,output_report:26,output_report_id:[26,75],outputdrivemod:103,outputdrivemodep0:100,outputdrivestrength:103,outputmod:[4,9],outsid:[4,31,33],over:[4,14,16,29,36,48,57,73,98,102,109,128,131,132,137,148,149,162,173],overflow:[43,59],overhead:[39,55],overload:57,overrid:[24,154],oversampl:[4,9,10],oversampling_ratio:[4,9],oversamplingratio:[4,9,10],overstai:113,overth:[4,9],overview:126,overvoltag:5,overwrit:[51,100,103,148,166],own:[6,14,25,39,44,49,67,71,98,100,103,105,126,129,131,132,155,169],owner:57,p0:[100,103,115],p0_0:[100,103],p0_1:[100,103],p0_2:100,p0_3:100,p0_5:100,p0_7:103,p1:[100,103,115],p1_0:[100,103],p1_1:100,p1_5:100,p1_6:100,p1_7:[100,103],p1_8:100,p2:115,p3:115,p:[0,3,4,5,9,10,15,18,22,25,27,30,32,34,36,37,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,139,140,142,144,146,149,151,153,155,157,159,160,161,163,165,167,170,173],pa_0:105,pack:35,packag:[11,14,134],packet:[129,131,132,134,148,149],packet_:148,pad:[26,35,75,148],padding_bottom:160,padding_left:160,padding_right:160,padding_top:160,page:[26,57,75,134,137,164],pair:[17,21,28,29,80,98,134,135,136,137],panel:95,panic:162,panic_on_timeout:162,panic_on_watchdog_timeout:[162,166],param:[2,4,9,12,14,17,21,44,49,55,72,81,83,86,88,92,93,95,96,100,103,105,107,111,129,131,132,135,141,143,145,150,162,171],paramet:[2,4,6,8,9,11,12,13,14,16,17,20,21,23,24,26,29,33,35,39,40,43,44,47,49,51,53,55,57,59,60,63,64,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],parent:154,pars:[37,124,148],part:[16,21,36,40,70,95,164,165],parti:[24,152],partit:[57,137],partition_label:57,pass:[4,9,21,40,53,55,67,71,113,120,122,150,156,158,172],passiv:67,passkei:[21,24,26],password:[67,134,169,171],pasv:67,pat:134,path:[57,67,148],pattern:56,paul:160,paus:[39,148],payload:[134,135,148],payload_id:135,payload_s:148,payload_typ:148,pb_7:105,pclk:51,pdf:[4,9,14,44,72,100,134,135,143,164],pend:131,per:[2,4,6,9,14,17,26,44,49],perceiv:33,percent:[53,109],percentag:[14,53,70,75,109,122,126,150,156,158,172],perform:[4,6,8,9,12,21,26,33,57,107,108,140,149,153,162],perhipher:109,period:[3,5,10,14,17,35,39,44,45,49,50,51,53,55,81,83,86,88,96,98,100,103,105,122,124,126,135,141,145,150,154,156,158,172,173],period_u:166,perioic:166,peripher:[2,3,4,5,9,10,14,16,18,20,22,23,25,26,27,28,43,44,49,70,71,72,74,76,79,80,81,83,86,88,93,96,100,103,105,109,111,122,126,134,135,141,143,144,145,156],peripheral_centr:134,peripheral_onli:[134,135],peripheral_pow:156,peripheral_power_pin:156,perm:57,permeabl:160,permiss:57,permitt:160,person:[24,134],perturb:61,phase:[16,17,126],phase_induct:17,phase_resist:17,phillip:160,phone:[134,135],photo:135,php:134,physic:30,pi:121,pick:43,pico:[15,79],pictur:17,pid:[11,17,21,24,26,70,80],pid_config:139,piecewis:116,piecewise_linear:116,pihat:36,pin:[2,4,5,9,14,15,16,17,29,30,35,39,40,51,53,72,78,79,84,93,98,99,100,101,103,104,105,109,122,124,126,143,150,156,158,162,166,172],pin_bit_mask:4,pin_config:150,pin_glitch_filt:[29,98],pin_mask:[103,105],pinconfig:[29,98,135,141,145,150,158,172],pinout:17,pixel:[11,39,40,53,111,122,148,150,156,158,172],pixel_buffer_s:[39,40,53,122,150,156,158,172],place:[55,70,98],placehold:[4,9,14,17,35,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],plai:[23,53,54,71,72,148,160],plan:164,planck:160,platform:[113,162,166],play_audio:53,play_click:53,play_hapt:70,playback:72,pleas:[31,33,37,65,72,150,154,160],plot:[4,9,45,50],plotter:[45,50],plu:103,plug:[5,23],pn532:134,pnp:23,pnp_id:23,pnpid:23,point:[18,21,33,43,53,57,59,63,70,71,80,81,83,86,88,95,96,109,113,115,116,121,122,131,132,134,135,150,156,168,170,171,172],pointer:[21,26,39,40,51,53,59,63,70,78,80,90,95,107,111,122,129,131,135,143,148,150,154,156,158,162,171,172],pointer_input:[92,156],pointerdata:[135,141,145,156],pointerinput:[11,92,156],pokemon:37,pokemon_blu:37,pokemon_r:37,pokemon_yellow:37,polar:[103,105],pole:17,poll:[14,35,41,44,49,81,83,86,88,93,96,100,103,105,126,135,141,145,156],poll_interv:156,polling_interv:93,pomax:115,pop:134,popul:132,port0:[100,103,105],port1:[100,103,105],port:[0,2,3,4,5,9,10,14,15,17,18,22,25,27,30,32,34,35,36,38,39,41,44,45,46,49,50,52,54,56,58,61,67,68,71,72,73,76,78,79,81,82,83,84,86,87,88,89,93,94,96,97,99,100,101,103,104,105,106,108,110,112,114,119,123,125,127,129,130,131,132,135,136,138,140,141,142,144,145,146,148,149,151,153,155,157,159,161,163,165,167,170,173],port_0_direction_mask:[100,103,105],port_0_interrupt_mask:[100,103,105],port_1_direction_mask:[100,103,105],port_1_interrupt_mask:[100,103,105],port_a:105,port_b:105,portabl:14,portmax_delai:4,portrait:40,pos_typ:57,posit:[14,17,18,26,40,43,44,45,49,50,70,71,92,95,96,103,107,113,120],posix:[58,128,129],possibl:[4,9,16,21,26,75,78,120,134],post:[41,134],post_cb:40,poster:134,potenti:[6,18,59,71,135,141,145],power:[4,9,14,16,17,18,21,53,71,93,103,111,126,134,156],power_ctrl:93,power_st:134,power_supply_voltag:[16,17],pr:[45,50,71],pranav:37,pre:[25,40,41,79,98,139,143,170],pre_cb:40,precis:[113,143],preconfigur:72,predefin:71,predetermin:[4,9],predic:162,prefer:134,prefix:[4,9,57],prepend:113,present:[78,96,134,148],preset:72,press:[4,5,29,30,35,49,53,54,75,83,88,92,93,94,95,96,122,123,126,127,141,150,156,157,159,172],pretti:[124,126,161],prevent:[29,39,98,139],previou:[32,51,100,103,109,166],previous:[16,21,120],previous_touchpad_data:[53,122,150,156],primari:[78,143],primarili:[12,162],primary_data:143,print:[3,4,5,6,8,9,10,14,18,21,31,35,37,43,44,45,49,50,51,55,71,78,81,83,86,88,93,96,98,100,103,105,107,113,115,117,120,121,124,125,126,131,132,135,137,139,141,142,143,145,148,152,154,158,160,161,162,164,166,171,172],prior:[135,169,171],prioriti:[6,29,39,53,55,98,113,122,124,150,156,158,162,166,172],probe:[2,4,9,12,14,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],probe_devic:[78,81,83,88,93],probe_fn:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],process:[21,98,109,131,132,162],processor:[4,9,63,162],produc:[33,71],product:[23,100,121,143,154,164],product_id:23,product_vers:[21,23,24,26],profil:70,program:[49,138],programm:4,programmed_data:135,project:[0,3,5,10,15,16,17,22,25,27,30,32,34,36,38,40,45,46,50,52,54,56,58,61,67,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,124,127,130,135,136,138,140,141,142,143,144,145,146,148,151,153,155,157,159,161,163,165,167,169,171,173],proper:[33,53,63,122,137,150,154,156],properli:[8,83,148,162],proport:[139,140],protect:[5,12,21,29,137],protocol:[12,26,67,111,131,132,143,149],prototyp:[55,92,95],provid:[2,4,6,7,8,9,11,12,13,14,16,17,18,19,20,21,23,24,25,26,27,28,29,31,33,34,35,37,39,40,42,43,44,46,48,49,51,53,55,57,59,60,62,63,64,65,66,69,70,71,74,75,76,77,78,80,81,83,85,88,91,92,93,95,98,100,102,103,105,107,109,111,113,115,116,117,119,120,121,122,124,126,128,129,130,131,132,134,135,137,139,141,143,145,148,149,150,152,154,156,158,160,162,164,166,168,170,171,172],prt:129,pseudost:154,psram:160,pub:[55,56],publish:[29,55],pull:[4,5,9,29,30,45,50,71,100,103,105],pull_down:103,pull_up:103,pull_up_en:4,pulldown:[29,98],pulldown_en:[29,98,158,172],pullresistor:103,pullup:[29,78,98],pullup_en:[29,98,158,172],puls:[4,9,43,98,143],pulsed_high:[4,9],pulsed_low:[4,9],pulsing_strong_1:72,pulsing_strong_2:72,pure:[43,154],push:[4,9,49,122],push_back:[78,120,160],push_button:49,push_pul:[4,9,100,103],put:135,pwm:[16,17,19,49,72,109],pwmanalog:72,py:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],pyqtgraph:115,python:[124,149],q0:148,q0_tabl:148,q1:148,q1_tabl:148,q:[17,63,148],q_current_filt:17,q_factor:63,qt:104,qtpy:[0,5,10,15,79,104,112,150,151,165],qtpys3:150,qtpys3config:150,qtypi:150,quadhd_io_num:[40,49],quadratur:[43,46],quadwp_io_num:[40,49],qualiti:63,quantiti:160,quantiz:148,queri:166,question:[31,37,109,135,160],queu:[41,143],queue:[4,29,53,98,122,143,150,156,158,172],queue_siz:[40,49],quickli:[98,154],quit:135,quit_test:[35,44,49,105,135,141],quote_charact:37,qwiic:[5,10,104,126,141],qwiicn:[12,80,135,145],r0:164,r1:[4,9,164],r25:164,r2:[4,9,164],r:[33,57,100,111,120,134,143,164],r_0:164,r_bright:100,r_down:100,r_led:100,r_scale:164,r_up:100,race:109,rad:17,radian:[17,43,44,49,121,126],radio:[134,135],radio_mac_addr:135,radiu:[92,107,158,172],rads1:126,rads2:126,rads_to_rpm:126,rainbow:[111,143],ram:39,ranav:[37,160],random:[5,61,134],random_valu:134,rang:[2,16,20,26,33,44,49,51,57,60,63,70,74,75,80,107,117,118,164,169],range_deadband:[107,120],range_deadzon:107,range_mapp:120,rangemapp:[107,120],rare:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],rate:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],rate_limit:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],ratio:[4,9],ration:115,rational_bezi:115,raw:[2,4,5,8,9,10,17,29,35,36,44,45,49,50,53,98,107,115,122,129,134,135,141,150,156],raw_descriptor:[26,75],raw_i:107,raw_x:107,rb:57,rdf:[26,75],rdf_descriptor:75,re:[31,35,44,49,53,55,71,72,98,122,126,129,131,132,137,143,150,154,156,162,164],reach:[72,131,135,154],read:[0,2,3,4,5,6,8,9,10,12,14,17,20,23,24,29,31,35,36,38,44,45,49,50,53,54,57,71,72,78,79,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,122,123,129,131,132,135,136,137,138,141,142,145,150,151,156,157,159,164],read_address:141,read_all_mv:8,read_at_regist:[72,78,86,105,141],read_at_register_vector:78,read_button_accumul:141,read_current_st:141,read_data:78,read_fn:[2,4,9,12,14,44,49,72,81,83,85,86,88,91,92,93,96,100,103,105,135,141,145],read_gestur:86,read_joystick:[35,107],read_kei:[93,156],read_mv:[8,35,107,164],read_mv_fn:164,read_nvs_fail:137,read_onli:57,read_raw:8,read_regist:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],read_register_fn:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],read_siz:78,read_valu:37,read_vector:78,readabl:[37,57,160],reader:[6,8,107,158],readi:[93,166],readm:160,readthedoc:134,real:[51,55,72,140,149,155],realli:[37,137,152,154,160],realtim:72,reason:[21,24,26,98,152,162],rebuild:45,receic:55,receiv:[4,21,24,29,40,98,129,131,132,135,148,149],receive_callback_fn:[129,131,132],receive_config:132,receiveconfig:132,recent:[4,6,17,35,44,49,53,107,122,139,150,156],recharg:75,recogn:[24,53,122,150,156],recommend:[11,44,49,52,55,98,107],reconfigur:[39,71,101,104],record:[134,135,136],record_data:135,recurs:[57,154],recursive_directory_iter:57,recursive_mutex:[53,122,150,156],recvfrom:[129,132],red:[33,37,111,113,126,143,150,158,160],red_l:126,redraw:39,reenabl:[29,98],reepres:148,refer:80,reference_wrapp:[21,70,78],refresh:39,reg_addr:78,regard:[44,49],regardless:[29,98],region:[4,9],regist:[2,4,9,12,14,25,29,44,49,55,72,78,79,81,83,85,86,88,91,92,93,95,96,98,100,103,105,122,135,141,145,148,162],register_address:78,registeraddresstyp:[11,12],registr:55,registri:55,reinit:131,reiniti:131,reistor:[100,103],reject:[21,24],rel:[14,18,71],relat:[26,31,109],releas:[29,53,122,126,150,156,160,162,172],relev:[57,164],reli:154,reliabl:[44,49,131,153],remain:[14,113,122,166],remot:[21,80,131,132,134],remote_control:134,remote_device_termin:21,remote_info:132,remote_user_termin:21,remount:[18,71],remov:[16,26,29,36,55,57,98],remove_al:[29,98],remove_cont:57,remove_feature_report:26,remove_input_report:26,remove_interrupt:[29,98],remove_output_report:26,remove_publish:55,remove_subscrib:55,renam:57,render:[39,53,122,124,150,156,158,172],repeat:[166,167],repeatedli:[143,162,166],replac:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],report:[20,26,27,75,77,135],report_char:26,report_id:[26,75],report_map:26,report_map_len:26,repositori:149,repres:[21,33,44,49,67,109,113,121,134,135,137,139,141,143,148],represent:[33,134,154,160],reprogramm:136,request:[4,9,21,24,67,129,131,132,134,135,148],requir:[4,9,11,14,17,21,24,26,29,35,40,43,44,49,51,53,70,72,75,78,81,83,86,88,93,96,98,100,103,105,107,109,111,122,126,135,141,143,145,148,150,156,158,160,164,172],rescal:33,reserv:134,reset:[4,9,26,40,43,51,63,64,75,135,137,138,139,143,159],reset_count:137,reset_fn:143,reset_pin:40,reset_st:139,reset_tick:143,reset_valu:40,resist:[17,164,165],resistor:[5,14,29,30,98,100,103,126,164,165],resistordividerconfig:164,resiz:[32,57,124,148,162],resolut:[80,109,143],resolution_hz:[111,143],resolv:[135,141,145],reson:[72,73,74],resourc:[8,21,129,131,132,135,143],respect:[7,148,154],respond:[78,83,98,129,131,132],respons:[20,21,23,24,26,39,57,63,67,134,139,148,162],response_callback_fn:[129,131,132],response_s:[131,132],response_timeout:[131,132],rest:30,restart:[137,138,154,166],restart_count:[137,138],restartselect:154,restrict:[44,49],result0:162,result1:162,result:[4,6,9,33,107,121,148],resum:39,ret:[40,49],ret_stat:143,retri:[148,171],retriev:[6,21,35,95,107,162],return_to_center_with_det:70,return_to_center_with_detents_and_multiple_revolut:70,reusabl:[31,80],rev:70,revers:[131,132],revis:24,revolut:[43,44,49,70],rf:135,rf_activ:135,rf_get_msg:135,rf_intterupt:135,rf_put_msg:135,rf_user:135,rf_write:135,rfc:[134,148],rfid:[134,135],rgb:[33,34,101,111,112,135,141,143,145,158,159],rh:[33,121,135,141,145,172],right:[17,26,35,57,67,75,91,92,111,135,141,156,160,172],right_press:[92,156],rise:[29,72,98,135,143],rising_edg:[29,98],risk:59,rm2:120,rm3:120,rm4:120,rm:120,rmdir:57,rmt:[11,80,111],rmt_bytes_encoder_config_t:143,rmt_channel_handle_t:143,rmt_clk_src_default:143,rmt_clock_source_t:143,rmt_encod:143,rmt_encode_state_t:143,rmt_encoder_handle_t:143,rmt_encoder_t:143,rmt_encoding_complet:143,rmt_encoding_mem_ful:143,rmt_encoding_reset:143,rmt_symbol_word_t:143,rmtencod:[111,143,144],robot:126,robust:[113,153],robustli:120,role:134,root:[57,67,154],root_list:57,root_path:57,rotari:[70,71,80,84],rotaryip:122,rotat:[17,39,40,44,46,49,53,70,72,73,74,111,121,122,143,150,156,158,172],rotation_callback:[39,40],rotation_fn:39,round:[21,75,80,82,116],round_displai:150,routin:[18,29,71,107],row:[37,160],row_index:37,row_t:160,rp:[27,77,80],rpm1:126,rpm2:126,rpm:[17,44,49,126],rpm_to_rad:[17,126],rssi:[21,26],rstp:134,rt_fmt_str:113,rtc:[51,52,80,145,146,150],rtcp:148,rtcp_packet:148,rtcp_port:148,rtcppacket:148,rtd:134,rtp:[72,148,149],rtp_header_s:148,rtp_jpeg_packet:148,rtp_packet:148,rtp_port:148,rtpjpegpacket:148,rtppacket:148,rtsp:[80,134],rtsp_client:148,rtsp_path:148,rtsp_port:148,rtsp_server:148,rtsp_session:148,rtspclient:[11,148,149],rtspserver:[11,148,149],rtspsession:[11,148],rule:160,run:[0,3,5,6,10,15,17,18,21,22,25,27,29,30,32,34,36,38,39,41,44,45,46,49,50,52,53,54,55,56,58,61,67,68,70,71,73,76,78,79,82,84,87,89,93,94,97,99,101,104,106,108,109,110,112,113,114,119,123,124,125,126,127,130,136,138,140,142,144,146,149,151,153,155,157,159,160,161,163,165,166,167,170,173],run_on_cor:162,run_on_core_non_block:162,run_sensor_upd:17,run_task:49,runner:[135,141,145],runtim:113,rwxrwxrwx:57,rx:75,rx_buffer:49,rx_data:49,rxlength:49,ry:75,s2:[6,40],s3:[0,6,35,41,45,51,53,54,80,87,89,96,97,101,104,112,122,149,150,151,156,165],s:[0,4,9,11,12,14,17,18,19,21,23,24,25,26,27,29,31,33,36,37,44,49,53,55,67,70,71,83,98,100,103,105,107,109,111,113,120,124,126,132,137,141,143,152,154,160,162,164,167],s_isdir:57,safe:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,109,135,139,141,145],same:[4,8,9,17,24,26,55,98,121,134,139,156,166],sampl:[2,4,6,9,17,18,44,49,53,59,60,63,64,65,71,73,98,135,139,164],sample_freq_hz:126,sample_mv:[2,35],sample_r:[2,53],sample_rate_hz:[6,164],sandbox:57,sar:[4,9],sarch:[44,49],satisfi:154,satur:[33,139],save:[107,113,137,138],scalar:121,scale:[17,107,121,139,164],scan:[4,9,21,78,148,171],scan_data:148,scan_request_callback:21,scan_request_callback_t:21,scan_request_whitelist:21,scan_respons:21,scan_response_data:21,scenario:[155,169,171],schedul:166,schemat:[17,126],scheme:[17,18],sck:150,scl:[4,5,9,51,78,79,103,146,150,159],scl_io_num:[2,4,9,14,35,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],scl_pullup_en:[78,81,83,86,88,96,103,145],sclk:40,sclk_io_num:[40,49],scope:[137,162,166],scottbez1:70,screen:[32,40,41,53,113,122,123,150,156,157,158,159,172,173],screenshot:[17,149],scren:[54,151],scroll:[53,122,150,156],sd:[122,158],sda:[5,51,78,79,103,146,150,159],sda_io_num:[2,4,9,14,35,44,49,72,78,81,83,86,88,93,96,100,103,105,135,141,145],sda_pullup_en:[78,81,83,86,88,96,103,145],sdkconfig:[113,125],sdp:148,se:75,search:[44,49],second:[2,4,6,14,17,21,24,26,29,44,49,51,60,62,78,80,98,100,103,105,109,113,121,126,138,145,148,149,162,164,165,166],secondari:39,seconds_per_minut:[44,49],seconds_since_start:124,section:[33,60,62,80],sectionimpl:65,secur:[21,24,26,134,169,171],secure_connect:[21,26],security_manager_flag:134,security_manager_tk:134,see:[3,4,5,9,10,15,17,18,21,22,24,25,26,27,30,31,32,33,34,36,37,38,39,40,41,43,45,46,50,52,54,56,58,59,60,61,65,68,71,72,73,76,79,82,84,87,89,94,97,99,101,104,106,107,108,110,112,114,115,119,122,123,124,125,127,129,130,131,132,134,135,136,138,140,142,143,144,146,149,151,153,154,155,156,157,159,160,161,163,164,165,166,167,169,170,171,173],seeed:[80,82],seek_end:57,seek_set:57,seekg:57,seem:[26,57,148],segment:39,sel:[4,5],select:[4,5,6,15,35,41,67,71,72,79,84,111,129,131,132,134,141,150,154],select_bit_mask:4,select_librari:[72,73],select_press:4,select_valu:4,self:96,send:[26,39,40,67,75,78,111,131,132,135,143,148,155],send_bright:111,send_command:40,send_config:[131,132],send_data:40,send_fram:148,send_request:148,send_rtcp_packet:148,send_rtp_packet:148,sendconfig:132,sender:[129,131,132],sender_info:[129,131,132],sendto:129,sens:[14,17,96,126],sensit:[156,165],sensor:[17,44,45,49,50,96,164],sensor_direct:17,sensorconcept:17,sensordirect:17,sent:[4,9,21,26,40,67,111,131,132,143,148],sentenc:160,separ:[2,4,9,12,14,35,37,39,44,49,72,81,83,86,88,93,96,98,100,103,105,124,135,141,145],separate_write_then_read_delai:12,separt:98,septemb:160,sequenc:[4,9,55,72,124,134,135,148,154],sequence_numb:148,seri:[0,5,14,65,98,148,164],serial:[0,3,5,10,15,18,22,23,25,27,29,30,32,34,36,38,41,45,46,48,50,52,54,55,56,58,61,68,71,72,73,75,76,79,80,82,84,87,89,93,94,97,99,100,101,102,103,104,105,106,108,110,112,114,119,123,125,127,130,134,135,136,138,140,142,144,146,148,149,151,155,157,159,161,163,165,167,170,173],serial_numb:23,serializa:152,series_second_order_sect:[59,65],serizalizt:37,server:[20,23,24,25,26,27,28,68,69,80,128,129,130,149],server_address:[131,132,148],server_config:132,server_port:148,server_socket:[131,132],server_task:131,server_task_config:[131,132],server_task_fn:131,server_uri:148,servic:[4,21,28,29,80,98,109,134],session:[67,143,148],session_st:143,set:[0,2,4,5,6,8,9,10,11,12,14,16,17,18,20,21,23,24,26,29,31,35,39,40,43,44,49,51,53,55,57,63,64,67,70,71,72,75,78,81,82,83,84,85,86,88,89,91,92,93,95,96,98,100,103,105,107,109,110,111,113,116,117,120,122,124,126,129,131,132,134,135,137,139,141,143,145,146,148,150,154,156,158,162,164,166,169,171,172],set_acceler:[26,75],set_address:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_advertise_on_disconnect:[21,24,26],set_advertisement_data:[21,24,26],set_al:111,set_alpha:117,set_analog_alert:4,set_ap_mac:171,set_battery_level:[20,21,24,26,75],set_beta:117,set_brak:[26,75],set_bright:39,set_button:[26,75],set_cable_connect:75,set_calibr:107,set_callback:[21,24,26],set_center_deadband:120,set_center_deadzone_radiu:107,set_charg:[26,75],set_config:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,117,135,139,141,145],set_csrc_count:148,set_cursor:92,set_dat:145,set_date_tim:145,set_device_info:23,set_device_nam:21,set_digital_alert:4,set_digital_output_mod:[4,9],set_digital_output_valu:[4,9],set_direct:[100,103,105],set_drawing_area:40,set_duti:109,set_encod:[111,143],set_error:75,set_extens:148,set_fade_with_tim:109,set_firmware_vers:[21,23,24,26],set_gamma:117,set_grow_on_mount:57,set_hardware_vers:[21,23,24,26],set_hat:[26,75],set_id:[134,135],set_include_tim:113,set_info:26,set_init_key_distribut:[21,26],set_input_latch:103,set_input_polar:105,set_interrupt:100,set_interrupt_mirror:105,set_interrupt_on_chang:105,set_interrupt_on_valu:105,set_interrupt_polar:105,set_io_cap:[21,26],set_l:75,set_label:40,set_led_breathing_period:51,set_led_bright:51,set_left_joystick:[26,75],set_log_callback:154,set_log_level:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_log_rate_limit:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_log_tag:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_log_verbos:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_manufacturer_nam:[21,23,24,26],set_mark:148,set_met:40,set_mod:72,set_model_numb:[21,23,24,26],set_motion_control_typ:[17,126],set_mount_as_read_onli:57,set_offset:40,set_pad:148,set_passkei:[21,24],set_payload:148,set_payload_typ:148,set_period:166,set_phase_st:16,set_phase_voltag:17,set_pin:[100,103,105],set_pin_config:150,set_pixel:111,set_pnp_id:[21,23,24,26],set_polarity_invers:103,set_port_output_drive_mod:103,set_prob:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_pull_resistor_for_pin:103,set_pull_up:105,set_pwm:16,set_range_deadband:120,set_range_deadzon:107,set_rate_limit:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_read:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_read_regist:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_receive_timeout:[129,131,132],set_recharg:[26,75],set_record:135,set_red_led_duti:126,set_report_map:26,set_resp_key_distribut:[21,26],set_right_joystick:[26,75],set_scan_response_data:21,set_secur:[21,26],set_separate_write_then_read_delai:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_sequence_numb:148,set_serial_numb:[21,23,24,26],set_session_log_level:148,set_software_vers:[21,23,24,26],set_ssrc:148,set_tag:113,set_text:160,set_tim:145,set_time_const:64,set_timestamp:148,set_trackball_sensit:156,set_typ:107,set_var:137,set_verbos:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],set_vers:148,set_voltag:16,set_waveform:72,set_writ:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_write_then_read:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],set_yellow_led_duti:126,setactivechild:154,setappear:[21,24,26],setcolor:[21,78],setdeephistori:154,setflag:[21,24,26],setinputhistorys:[21,78],setnam:[21,24,26],setparentst:154,setpartialservices16:26,setpoint:[17,70,126],setsecuritypasskei:[21,24],setservicedata:24,setshallowhistori:154,setter:121,setup:[4,32,148],sever:[48,62,102],sftp:134,sgn:116,sh:[5,10,126],shaft:[17,44,49],shallow:154,shallow_history_st:154,shallowhistoryst:154,shamelessli:160,share:[24,51,53,122,134,150,156,158,172],shared_ptr:[17,51,53,122,150,156,158,172],sharp_click:72,sheet:[4,9],shield:[35,36],shift:[111,141,158],shift_bi:111,shift_left:111,shift_right:111,shop:[100,143],short_local_nam:134,shortcut:156,shorten:134,shorter:98,shot:[166,167],should:[2,4,5,9,12,14,16,17,20,21,22,23,24,25,26,27,33,35,36,39,40,44,45,49,50,53,57,59,63,72,75,76,81,83,86,88,93,96,98,100,101,103,104,105,107,109,111,121,122,127,129,131,132,134,135,139,141,143,145,148,150,154,156,162,166,170],shouldn:[57,113],show:[0,3,5,10,15,18,21,22,25,26,27,30,32,34,36,38,41,45,46,50,52,54,55,56,58,61,71,73,75,76,79,82,84,89,94,99,101,104,106,108,110,111,112,114,123,125,130,136,138,140,144,146,149,151,153,154,155,157,159,161,162,163,165,166,167,170,173],showcas:[46,55,68,119],shown:[10,113],shut:162,side:[14,16,69,172],sig:[20,23],sign:[43,116,120],signal:[4,29,35,53,59,60,61,63,64,65,72,98,111,122,139,143,150,156,158,172],signatur:[93,162],signific:141,similar:143,simpl:[1,8,11,41,53,55,57,62,66,67,78,80,93,98,113,122,134,137,139,150,152,156,158,162,164,172],simple_button:29,simple_lowpass_filt:64,simpleconfig:29,simplefoc:17,simplelowpassfilt:[61,64],simpler:[109,143,162],simpli:[4,6,9,18,21,29,31,44,53,61,71,98,122,140,150,156,165],simplif:21,simplifi:[26,29,137,148],simultan:[134,149],sin:[26,75,124,158,172],sinc:[4,17,20,21,23,24,26,43,44,49,53,55,57,93,98,100,103,113,122,126,138,141,143,148,150,156,162,164,166,170],singl:[4,8,9,14,43,70,75,85,98,111,113,124],single_unit_1:[6,164],single_unit_2:6,singleton:[51,53,55,57,122,126,150,156,158,172],sinusoid:17,sip:134,situat:98,sixteen:2,size:[21,26,29,39,53,55,57,75,78,79,98,113,122,124,131,132,134,135,143,148,150,152,156,158,162,164,166,172],size_t:[2,6,17,24,26,29,37,39,40,43,49,53,55,57,59,60,63,65,75,78,98,109,111,113,122,124,126,129,131,132,143,148,150,152,156,158,160,162,166,171,172],sizeof:[4,40,49,143,148],sk6085:143,sk6805:[112,143],sk6805_10mhz_bytes_encoder_config:143,sk6805_freq_hz:111,sk6812:111,skip:166,skip_unhandled_ev:166,sku:24,sleep:[2,4,6,8,9,14,21,24,26,35,43,44,49,55,72,81,83,86,88,96,100,103,105,107,109,111,113,122,124,126,139,141,143,145,154,162,164,166],sleep_for:[6,29,40,51,53,55,93,98,109,111,113,122,124,126,131,132,139,148,150,154,156,158,162,166,171,172],sleep_mod:109,sleep_until:[21,24,26,162],slope:117,slot:[72,150],slow:8,small:[29,70,98,117,126],smart:134,smartknob:[41,70],smb:134,snap:70,snprintf:162,so:[2,4,5,8,9,14,17,18,21,24,26,29,30,31,35,37,40,43,44,45,49,52,53,55,57,62,67,70,71,72,75,80,87,96,98,100,103,105,107,111,120,122,124,126,135,139,143,148,150,154,156,160,162,164,165,166],so_recvtimeo:[129,131,132],so_reuseaddr:[129,131,132],so_reuseport:[129,131,132],soc:14,sock_type_t:[129,131,132],sockaddr:129,sockaddr_in6:129,sockaddr_in:129,sockaddr_storag:[129,131,132],socket:[11,67,80,128,148],socket_fd:[129,131,132],soft_bump:72,soft_fuzz:72,softwar:[4,9,23,39,55],software_rotation_en:39,software_vers:23,some:[5,10,11,12,17,18,21,24,26,28,31,41,45,46,48,50,55,56,57,62,70,71,83,98,101,104,113,116,119,122,124,129,134,135,143,150,154,162,163,166,167],someth:[39,162],somewhat:[70,76],sophist:14,sos_filt:65,sosfilt:[60,65],sound:[53,54,70],sourc:[23,109,132,143],source_address:129,sp:134,sp_hash_c192:134,sp_hash_c256:134,sp_hash_r256:134,sp_random_r192:134,space:[17,29,33,57,70,98,111,143,156,160],space_vector_pwm:17,spaceship:121,sparignli:120,sparkfun:[35,36,141],spawn:[44,49,67,148,154,155,162],spawn_endevent_ev:154,spawn_event1_ev:154,spawn_event2_ev:154,spawn_event3_ev:154,spawn_event4_ev:154,speaker:53,spec:24,specfici:2,special:[47,72,100,143],specif:[12,24,26,33,45,50,70,74,78,85,87,91,92,95,113,137,148,154,162,165,166],specifi:[4,9,12,21,29,44,49,57,70,78,98,109,113,132,148,166],speed:[17,44,49,78,98,109,126,131,160],speed_mod:109,spi2_host:[40,49,126],spi:[12,40,41,44,53,105,122,150,156,158,172],spi_bus_add_devic:[40,49],spi_bus_config_t:[40,49],spi_bus_initi:[40,49],spi_device_handle_t:49,spi_device_interface_config_t:[40,49],spi_device_transmit:49,spi_dma_ch_auto:[40,49],spi_num:[40,49],spi_queue_s:40,spi_trans_use_rxdata:49,spi_transaction_t:49,spibus_read:49,spic:40,spics_io_num:[40,49],spike:117,spiram:[53,122,150,156,158,172],sporad:8,spot:17,sps128:2,sps1600:2,sps16:2,sps2400:2,sps250:2,sps32:2,sps3300:2,sps475:2,sps490:2,sps64:2,sps860:2,sps8:2,sps920:2,spuriou:162,squar:[107,116,121],sr:134,ssid:[134,135,169,171],ssrc:148,ssrounddisplai:[11,80,151],st25dv04k:135,st25dv:[80,133,141,145],st26dv16k:136,st7735:159,st7789:53,st7789_defin:40,st7789v_8h_sourc:40,st:[57,135],st_mode:57,st_size:57,sta:[80,168],stabl:134,stack:[21,55,124,162,166],stack_size_byt:[2,4,9,14,29,35,39,44,49,53,55,72,98,100,103,105,111,122,124,126,131,132,135,143,150,156,158,162,166,172],stackoverflow:[57,135,160],stand:17,standalon:[48,102],standard:[11,20,21,23,26,57,68,113,120,148],star:72,start:[2,3,4,5,6,8,9,10,14,15,18,20,21,22,23,24,25,26,27,29,30,32,34,35,36,38,39,40,41,43,44,45,46,49,50,51,52,53,54,55,56,58,61,67,68,70,71,72,73,76,78,79,81,82,83,84,86,87,88,89,93,94,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,113,114,119,121,122,123,124,125,126,127,128,130,131,132,135,136,138,139,140,141,142,143,144,145,146,148,149,150,151,153,154,155,156,157,158,159,161,162,163,164,165,167,170,172,173],start_advertis:[21,24,26],start_breath:126,start_fast_transfer_mod:135,start_fram:111,start_led_breath:51,start_receiv:132,start_servic:[21,24,26],start_task:156,start_watchdog:[162,166],startup:[18,44,49,71],starv:98,stat:[57,124,166],state:[14,16,18,20,26,29,30,35,44,49,53,54,55,59,60,63,64,65,72,75,80,81,83,86,88,95,96,98,100,103,105,122,123,124,126,127,134,135,139,141,142,143,145,150,151,156,157,159,172],state_a:16,state_b:16,state_bas:154,state_c:16,state_machin:154,state_of_charg:55,statebas:154,static_cast:[4,53,113,122,137,143,156,158,172],station:[80,168,169,170],statist:4,statistics_en:4,statu:[4,13,14,49,75,103,135],std:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,35,37,39,40,43,44,49,51,53,55,58,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,128,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],stdby:17,stdin:154,stdout:[98,137,154,166],steady_clock:[21,24,26],steinhart:164,stemma:104,step:[3,5,10,15,17,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,162,163,165,167,170,173],still:[14,98,162],stop:[2,4,6,8,9,14,17,21,26,35,39,43,44,49,51,55,67,70,72,78,81,83,86,88,93,96,100,103,105,107,109,111,124,126,131,132,135,139,141,143,145,148,154,163,164,166,167,171],stop_advertis:21,stop_breath:126,stop_fast_transfer_mod:135,stop_led_breath:51,stop_request:162,stop_watchdog:[162,166],storag:[129,137,138],store:[21,24,26,35,40,57,64,66,78,117,134,135,148,164],stori:160,str:[37,137],strcutur:40,stream:[37,148,149],streamer:[148,149],strength:[49,70],strictli:152,string:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,35,37,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,162,164,166,169,171,172],string_view:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,40,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],strip:[80,143,158],strong:[49,70],strong_buzz:72,strong_click:72,strongli:152,struct:[2,4,6,8,9,12,14,16,17,21,23,29,33,35,39,43,44,49,55,57,60,63,64,66,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,124,129,131,132,134,135,139,141,143,145,148,150,152,162,164,166,169,171,172],structur:[2,4,9,17,35,39,40,55,72,85,91,92,93,95,100,103,105,107,109,115,117,124,129,131,132,134,139,145,150,154,169,171,172],studio:[80,82],sub:[55,56,57],sub_dir:57,sub_fil:57,sub_fp:57,sub_of:57,subclass:[11,12,24,65,98,129,148,154],subdirectori:57,subfil:57,submodul:31,subscib:55,subscrib:[29,55],subscript:55,subsequ:[4,55,134,138],subset:35,substat:154,subsystem:[6,8,39,51,53,54,109,123,151,156,157,158,159,172,173],subtract:121,subystem:171,success:[4,9,24,78,137,148],successfulli:[21,43,51,53,55,57,122,129,131,132,143,148,150,152,156,158,166,172],sucess:137,suffix:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,135,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],suggest:143,suit:33,sulli:160,super_mario_1:37,super_mario_3:37,super_mario_bros_1:37,super_mario_bros_3:37,suppli:[16,18,71,164],supply_mv:164,support:[0,4,9,17,21,24,25,26,31,32,33,35,43,45,47,49,51,56,57,72,75,79,86,96,98,100,103,109,111,113,126,128,134,135,148,150,162],sure:[0,17,18,71,73,109,110,148],swap:[95,126],swap_xi:95,sweet:126,symlink:[4,9,72],symmetr:117,synchron:41,syst_address:135,system:[14,31,37,55,80,109,113,124,135,137,138,152,154,160,162,164],sytl:152,t5t:135,t:[2,4,6,8,9,11,14,17,21,24,26,29,35,37,40,41,43,44,49,53,55,57,72,80,81,83,86,88,89,90,96,100,103,105,107,109,111,113,115,117,120,121,122,123,124,126,131,132,134,135,137,139,141,143,145,150,154,162,164,166],t_0:164,t_keyboard:93,ta:35,tabl:[4,5,9,57,124,134,148,160,161,164],tabul:80,tag:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,122,124,126,129,131,132,134,135,136,137,139,141,143,145,148,150,156,158,162,164,166,169,171,172],take:[8,21,57,78,160,162],taken:57,talk:[100,103,111],target1:126,target2:126,target:[0,17,18,45,126,171],target_delta:126,target_is_angl:126,target_task:126,target_task_fn:126,tarnsact:49,task1:55,task2:55,task:[0,2,3,4,5,6,8,9,10,11,14,17,18,29,35,39,41,43,44,45,49,50,53,55,56,67,70,72,80,81,83,86,88,93,96,98,100,103,105,107,109,111,122,125,126,131,132,135,139,141,143,145,148,150,154,155,156,158,164,166,172],task_1_fn:55,task_2_fn:55,task_callback:124,task_config:[2,4,6,8,9,14,29,35,39,43,44,49,53,55,72,81,83,86,88,96,98,100,103,105,107,109,111,122,124,126,131,132,135,139,141,143,145,150,154,156,158,162,164,166,172],task_fn2:162,task_fn3:162,task_fn:[6,8,14,35,43,44,49,72,81,83,86,88,96,100,103,105,107,111,124,135,139,141,143,145,154,162,164],task_id:124,task_id_t:162,task_info:124,task_iter:162,task_monitor:124,task_nam:[124,162],task_notifi:162,task_prior:6,task_stack_size_byt:124,task_tabl:124,taskinfo:124,taskmonitor:[11,124],tb:35,tcp:[80,128,148],tcp_socket:131,tcpclientsess:131,tcpobex:134,tcpserver:131,tcpsocket:[129,130,131,148],tdata:152,tdeck:[11,156,157],tdfn:14,tdk:164,tdongl:158,tdongles3:[11,158,159],tdown:35,tear:[129,131,132,162],teardown:148,tel:134,tell:[26,111,143],tellg:57,telnet:134,temp:164,temperatur:[14,164,165],temperature_celsiu:55,templat:[12,17,39,43,47,49,57,60,65,70,75,76,113,115,120,121,137,162],temporari:134,termin:[21,32,154,160,162],test2:57,test:[6,10,15,17,18,21,36,71,78,87,104,120,137,155,162,170],test_dir:57,test_fil:57,test_start:162,texa:[4,9,72],text:[53,122,134,136,150,156,158,172],tf:159,tflite:40,tft:159,tft_driver:40,tft_espi:40,tftp:134,th:[39,66],than:[16,39,98,107,113,121,135,148,162,166],thank:[21,78],thei:[8,13,29,31,35,53,70,98,121,148,154,156,162],them:[3,4,9,14,21,24,26,33,35,55,57,117,143,148,154,158,162,172],therefor:[5,6,8,31,33,44,49,72,120,162],thermistor:[11,80],thermistor_ntcg_en:164,thi:[0,2,3,4,5,6,8,9,10,11,12,14,15,16,17,18,20,21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,49,50,51,52,53,54,55,56,57,58,59,61,67,68,70,71,72,73,75,76,78,79,80,81,82,83,84,85,86,87,88,89,91,92,93,94,95,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,113,114,115,119,120,121,122,123,124,125,126,127,129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,169,170,171,172,173],thin:117,thing:[75,124],third:152,this_thread:[6,21,24,26,29,40,51,53,55,93,98,109,111,113,122,124,126,131,132,139,148,150,154,156,158,162,166,171,172],those:[36,45,55,100,113,124,127,154],though:[55,98,151,162],thread:[2,4,9,12,14,44,49,53,55,67,70,72,78,81,83,86,88,93,96,100,103,105,109,122,124,131,132,135,139,141,145,148,150,155,156,158,162,172],threshold:[4,9,98],through:[4,9,17,18,24,26,53,70,71,72,111,120,122,143,150,154,156],throughput:6,thu:14,thumb:[5,10],ti:[4,9,72],tick:154,tickselect:154,time:[4,8,9,12,14,18,21,29,35,44,49,51,54,55,57,64,71,72,83,98,100,103,105,109,111,113,122,123,124,126,132,135,137,138,139,141,143,145,146,149,150,151,154,157,159,162,164,166,171],time_const:64,time_point:57,time_t:57,time_to_l:[129,131,132],timeout:[21,78,129,131,132,162,166],timeout_m:[78,81,83,88,162],timeout_u:166,timer2_fn:166,timer:[11,17,80,109,110,126,149,154,162],timer_cam:51,timer_fn:166,timer_isr:166,timer_task:166,timercam:[52,80,146],timestamp:[148,149],tini:[14,18,71],tinypico:0,tinys3:[0,17,18,71,143,144],tk:134,tkeyboard:[12,93,156],tkip:134,tla2528:[7,12,80],tla:9,tla_read_task_fn:9,tla_task:9,tleft:35,tloz_links_awaken:37,tloz_links_awakening_dx:37,tm:124,tmc6300:[17,18,71,126],tname:152,tnf:134,to_str:[57,154,160],to_time_t:57,togeth:[18,25,27,71],toggl:[93,127,137],toi:160,toler:164,tone:111,too:[29,49,98,148,160],too_strong:49,too_weak:49,tool:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],top:[53,113,122,150,154,156,165],topic:[29,55],torqu:17,torque_control:17,torquecontroltyp:17,total:[43,57],total_spac:57,touch:[53,54,80,82,84,87,89,90,95,122,123,150,151,156,157,159,172],touch_callback:[53,150,156],touch_callback_t:[53,122,150,156],touch_cb:156,touch_interrupt:150,touch_invert_i:[53,122,150,156],touch_invert_x:[53,122,150,156],touchdriv:150,touchpad:[53,54,80,81,83,88,90,96,122,123,134,150,151,156,157,159,172],touchpad_convert:[53,122,150,156],touchpad_data:[53,122,150,156],touchpad_input:[53,95,122,150,156],touchpad_read:[53,95,122,150,156],touchpad_read_fn:95,touchpaddata:[53,122,135,141,145,150,156,172],touchpadinput:[11,53,95,122,150,156],touchscreen:[51,53,122,150,156],tp:57,tpd_commercial_ntc:164,trace:[124,155],track:[14,49,139],trackbal:156,trackball_btn_gpio:156,trackball_callback:156,trackball_callback_t:156,trackball_cb:156,trackball_data:156,trackball_down_gpio:156,trackball_left_gpio:156,trackball_read:156,trackball_right_gpio:156,trackball_up_gpio:156,tracking_statu:49,trackingstatu:49,tradit:14,transact:[53,122,143,150,156,158,172],transaction_queue_depth:143,transceiv:80,transfer:[40,41,62,69,80,135],transfer_funct:66,transferfunct:[65,66],transform:[17,21,26,55,131,132],transit:154,transition_click_1:72,transition_hum_1:72,transmiss:[131,143],transmit:[41,55,111,129,131,132,134],transmit_config:131,transmitconfig:131,transmitt:143,transport:148,tree:[83,132,143,154,156],trigger:[4,8,9,26,70,72,75,98,103,105,135,162,166],trigger_max:[26,75],trigger_min:[26,75],trigger_typ:75,tright:35,trim_polici:37,trim_whitespac:37,triple_click:72,troubleshoot:[17,70],ts:72,tselect:35,tstart:35,tt1535109:160,tt1979376:160,tt21100:[12,80,90],tt3263904:160,ttgo:41,tthi:57,ttl:[129,131,132],tup:35,tupl:164,turn:[4,5,21,26,39,113,126,134],tvalu:152,two:[2,3,5,10,14,29,33,35,39,53,75,100,103,105,113,116,121,122,124,126,127,143,150,156,158,172],twothird:2,tx:[21,134],tx_buffer:49,tx_power_level:134,txt:57,type:[0,2,3,4,5,7,9,10,12,14,15,17,18,21,22,25,27,29,30,32,34,35,36,38,39,41,43,44,45,46,48,49,50,52,53,54,55,56,57,58,61,62,68,70,71,72,73,75,76,79,80,81,82,83,84,86,87,88,89,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,119,121,122,123,125,126,127,130,131,132,134,135,136,138,140,141,142,143,144,145,146,148,149,150,151,152,153,155,156,157,158,159,161,162,163,164,165,166,167,170,171,172,173],type_specif:148,typedef:[2,4,9,12,14,17,21,29,39,44,49,55,72,81,83,86,88,92,93,95,96,98,100,103,105,107,111,129,131,132,135,141,143,145,162,164,166,171],typenam:[39,57,75,113,115,120,121,137],typic:91,u16:12,u8:12,u:[121,126,134],ua:16,uart:[31,45,50],uart_serial_plott:[4,9],ub:16,uc:16,ud:17,udp:[80,128,148],udp_multicast:132,udp_socket:132,udpserv:132,udpsocket:[129,130,132],uic:[134,135],uint16_t:[2,11,14,21,23,24,26,39,40,53,67,75,81,83,86,88,95,96,100,103,105,122,134,135,143,145,150,156,158,172],uint32_t:[4,21,24,26,33,35,39,40,53,78,98,109,122,124,134,148,150,152,156,158,162,172],uint64_t:[16,126,134,135,166],uint8_t:[2,4,9,11,12,14,20,21,23,24,26,29,40,44,49,53,55,72,75,78,81,83,86,88,93,95,96,98,100,103,105,111,113,121,122,129,131,132,134,135,137,141,143,145,148,150,152,156,158,169,171,172],uint:143,uk:134,unabl:[135,141,145],unbound:70,unbounded_no_det:70,uncalibr:[35,107],uncent:120,unchang:134,under:[43,57],underflow:43,underlin:160,understand:134,unencrypt:[20,24],unexpect:137,unhandl:166,unicast:[130,132],uninstal:109,uninstall_isr:109,uniqu:[21,78,131,148,162],unique_lock:[2,4,6,8,9,14,35,43,44,49,53,55,72,81,83,86,88,96,100,103,105,107,109,111,122,126,131,135,139,141,143,145,150,154,156,158,162,164,172],unique_ptr:[21,78,124,131,148,162],unit:[1,6,8,14,17,21,35,43,57,59,107,121,164],unittest:156,universal_const:160,unknown:[17,21,53,134,171],unless:[53,55,122,150,156,158,162,166,172],unlink:57,unmap:[107,120],unmut:53,unord:[4,9,132],unordered_map:[4,9,148],unpair:21,unpair_al:21,unregist:[85,91,92,95],unreli:132,until:[4,9,21,55,57,70,72,78,98,109,111,131,132,143,154,162,166],unus:[35,43,70,96,107],unweight:115,unwind:154,up:[4,5,6,21,29,31,32,35,39,43,51,52,57,72,75,86,91,93,96,98,100,103,105,109,113,117,126,131,135,138,139,141,148,154,156,162,166],up_left:75,up_right:75,upat:39,updat:[11,14,16,17,18,21,24,26,35,39,40,41,44,49,53,59,60,63,64,65,70,73,75,81,83,88,93,96,100,103,105,107,109,113,117,120,121,122,126,129,137,138,139,141,150,154,156,158,172],update_address:141,update_detent_config:70,update_period:[17,39,44,49],update_period_m:[53,122,150,156,158,172],update_target:126,upgrad:162,upload:138,upper:[40,164],uq:17,uri:[134,148],urn:134,urn_epc:134,urn_epc_id:134,urn_epc_pat:134,urn_epc_raw:134,urn_epc_tag:134,urn_nfc:134,us:[2,4,6,8,9,11,12,14,16,17,19,20,21,23,24,26,29,31,33,35,37,39,40,43,44,47,49,51,53,55,57,59,60,64,67,69,70,72,74,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,120,122,124,126,128,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],usag:[26,31,37,56,75,160],usage_pag:[26,75],usb:[23,24,26,51,158,159],usd:[150,159],usd_c:150,use_individual_funct:8,useaddress:[2,4,9,11,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],used_spac:57,user:[4,6,8,9,18,19,21,29,31,32,40,43,44,49,52,53,70,71,72,78,94,98,100,101,103,105,110,122,143,148,149,150,151,156,157,158,162,172],user_data:[53,122,150,156,158,172],usernam:67,ust:55,usual:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],util:[57,113,116,121,124,129,134,135,156,162],uuid:[20,23,24,26,134],uuids_128_bit_complet:134,uuids_128_bit_parti:134,uuids_16_bit_complet:134,uuids_16_bit_parti:134,uuids_32_bit_complet:134,uuids_32_bit_parti:134,uvw:49,v1:126,v2:121,v5:57,v8:121,v8_2:121,v:[14,17,33,51,103,117,120,121],v_in:164,vacuum:160,val:120,val_mask:105,valid:[67,72,92,111,124,129,131,132,148],valu:[0,2,4,5,6,8,9,12,14,18,21,23,24,29,33,35,37,39,41,43,44,45,49,50,53,57,63,64,70,72,75,81,83,86,88,98,100,103,105,107,109,111,113,115,116,117,120,121,122,126,134,137,138,139,141,143,145,148,150,152,156,160,162,164],valus:107,vari:[14,70],variabl:[40,107,113,137,138,162],variant:[87,162],varieti:[4,9],variou:[21,28,34,36,41,71,111,113,163,167],vcc:[5,103],ve:[24,26,41,57,162],vector2d:[80,115,118,135,141,145],vector2f:[107,115,121],vector2u8:121,vector:[4,6,8,9,17,21,24,26,29,35,37,53,55,57,63,75,78,98,107,109,111,120,121,124,129,131,132,134,135,148,152,162,164],veloc:[17,18,44,45,49,50,126,127],velocity_filt:[17,44,49],velocity_filter_fn:[44,49],velocity_limit:17,velocity_openloop:[17,126],velocity_pid_config:17,veloicti:17,vendor:23,vendor_id:23,vendor_id_sourc:23,vendor_sourc:[21,24,26],veolciti:[44,49],verbos:[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,35,39,43,44,49,51,53,55,57,67,70,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,122,124,126,129,131,132,135,137,139,141,143,145,148,150,154,156,158,162,164,166,169,171,172],veri:[41,98,149],version:[9,14,23,26,53,121,134,137,148],via:[5,9,15,18,45,50,57,71,72,79,100,101,103,104,105,106,126,136,142,146,166],vibe:72,vibrat:[70,72],vid:[21,24,26],video:[4,17,39,101,148],view:[0,3,5,10,15,18,21,22,25,26,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,131,132,134,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],vio:17,virtual:[35,148,154],visual:124,volatil:[137,138],volt:[4,9,16,51],voltag:[2,4,6,8,9,14,16,17,19,51,55,164,165],voltage_limit:16,volum:53,vram0:[39,53,122,150,156,158,172],vram1:[39,53,122,150,156,158,172],vram:[39,53,122,150,156,158,172],vram_size_byt:39,vram_size_px:39,vsync:51,vtaskgetinfo:124,w0:115,w1:115,w2:115,w3:115,w:[57,72,113,120,126],wa:[4,6,8,15,16,18,21,24,29,35,36,40,43,44,49,51,53,55,57,67,71,86,93,96,98,107,122,129,131,132,137,138,141,143,148,150,154,156,158,162,166,172],wafer:14,wai:[2,4,6,8,9,12,14,21,29,31,35,37,43,44,49,57,70,72,81,83,86,88,96,98,100,103,105,107,111,126,134,139,141,143,145,152,154,160,162,163,164,167],wait:[4,21,55,70,93,129,131,132,135,162,163],wait_for:[2,6,8,14,35,43,44,49,53,55,72,81,83,86,88,96,100,103,105,107,109,111,122,126,131,135,139,141,143,145,150,154,156,158,162,172],wait_for_respons:[131,132],wait_until:[4,9,126,162,164],wake:[98,162],wakeup:162,want:[2,4,5,6,8,9,14,17,21,24,25,31,35,36,39,43,44,49,53,55,70,72,75,98,100,103,105,107,109,110,111,122,124,126,131,132,135,139,143,150,154,156,162,164,166,170],warn:[2,4,6,8,9,14,16,17,18,20,21,23,24,26,29,35,39,43,44,49,55,57,71,72,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,126,131,132,135,139,141,143,145,148,162,164,166,169,171],warn_rate_limit:113,was_connect:[21,26],watch:134,watchdog_info:[162,166],water:[124,162],wav:[53,54],wav_siz:53,wave:117,waveform:[16,51,72],we:[2,4,5,8,9,14,16,17,21,24,26,35,44,49,53,55,57,70,72,78,81,83,86,88,93,96,100,103,105,107,109,111,122,126,129,131,132,135,141,143,145,150,154,156,158,162,164,166,172],weak:[49,70],web:136,webcamera:51,webgm:[154,155],week:145,weekdai:145,weight:115,weightedconfig:115,weirdli:[53,122,150,156],welcom:113,well:[0,4,12,24,35,48,49,51,53,55,62,65,72,75,101,117,124,131,134,135,148,154,155,162,163,167],well_known:134,wep:134,were:[4,8,9,16,21,26,57,78,96,107,129,131,132,139,154,162],what:[8,9,16,24,55,143,154],whatev:[14,100,103,105],whe:171,when:[0,2,4,5,6,8,9,14,17,18,21,24,29,35,40,41,43,44,47,49,53,55,70,71,72,81,83,86,88,93,96,98,100,103,105,107,109,111,120,122,126,129,131,132,135,137,139,141,143,145,148,150,151,152,154,156,162,164,166,171],whenev:154,where:[19,43,54,70,98,107,115,123,124,132,151,154,157,159,164],whether:[6,14,21,29,35,39,44,49,57,75,92,93,98,109,111,113,120,129,131,132,143,148,156,162,171],which:[2,4,5,6,8,9,14,15,17,18,19,21,26,30,31,33,35,37,39,41,44,46,49,53,55,56,57,59,60,62,63,70,71,72,73,74,75,76,78,81,83,84,85,86,88,91,93,94,97,98,99,100,101,102,103,104,105,107,109,111,113,115,116,120,121,122,124,126,127,131,132,134,135,141,143,146,148,150,154,156,158,159,160,162,164,166,169,170,171,172],white:[21,160],who:40,whole:[137,148,154],whose:98,wi:[169,171],wide:14,width:[39,40,53,70,98,122,148,150,156,158,160,172],wifi:[68,80,134,149,159],wifi_ap:169,wifi_sta:171,wifiap:[11,169,170],wifiauthenticationtyp:134,wificonfig:134,wifiencryptiontyp:134,wifista:[11,170,171],wiki:[59,60,65,129,131,132,164],wikipedia:[43,59,60,65,129,131,132,164],wind:139,window:98,window_size_byt:[6,164],window_threshold_n:98,window_width_n:98,windup:139,wire:[5,10,143,156,165],wireless:135,wish:[31,35,36,45,68,110,124],witdth:43,within:[17,18,21,33,41,44,48,49,55,70,71,76,78,98,107,113,120,132,137,160,162,163,164],without:[4,6,31,70,124,135,137,143,148],wlp:14,wole:137,word:160,work:[9,10,17,18,31,55,57,70,71,97,124,135,141,145,146,148,162],world:155,worri:164,would:[43,55,98,154,162],wpa2:134,wpa2_enterpris:134,wpa2_person:134,wpa:134,wpa_enterpris:134,wpa_person:134,wpa_wpa2_person:134,wrap:[16,43,55,58,100,143,153,160],wrapper:[6,8,31,37,39,57,75,78,85,91,92,95,107,109,113,115,117,143,152,154,160],write:[2,4,9,12,14,17,24,35,38,39,40,44,49,53,57,63,72,78,81,83,86,88,93,96,100,103,105,111,122,135,136,137,141,145,150,156,158,172],write_data:78,write_fn:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,111,135,141,145],write_lcd:[53,122,150,156,158,172],write_lcd_fram:[53,122,150,156,158,172],write_lcd_lin:[53,122,150,156,158,172],write_read:[44,78,100,103,145],write_read_vector:78,write_row:37,write_s:78,write_then_read:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],write_then_read_fn:[2,4,9,12,14,44,49,72,81,83,86,88,93,96,100,103,105,135,141,145],write_vector:78,written:[24,53,111,122,134,135,137,150,154,156,158,172],wrote:[37,57],wrover:[0,41,80,165],wroverkit:[11,172,173],ws2811:111,ws2812:[111,144],ws2812_10mhz_bytes_encoder_config:143,ws2812_freq_hz:143,ws2812b:143,ws2813:111,www:[4,9,59,65,72,134,135],x1:121,x2:121,x:[4,5,9,14,35,36,40,53,59,75,81,83,86,88,92,95,96,100,103,105,107,113,115,116,121,122,124,135,148,150,156,158,172],x_calibr:[35,107],x_mv:[2,4,35,107],xbox:[26,75],xboxbatteryinputreport:[26,75],xclk:51,xe:[40,53,122,150,156,158,172],xiao:[150,151],xiaos3:150,xiaos3config:150,xinyuan:156,xml:[135,141,145],xml_in:[135,141,145],xout:5,xportgetcoreid:162,xqueuecreat:4,xqueuerec:4,xs:[40,53,122,150,156,158,172],y1:121,y2:121,y:[4,5,9,35,36,40,53,59,75,81,83,86,88,92,95,96,107,113,115,117,121,122,124,148,150,156,158,162,166,169,171,172],y_calibr:[35,107],y_mv:[2,4,35,107],ye:[40,53,122,150,156,158,171,172],year:145,yellow:[37,113,126,160],yellow_l:126,yet:[17,44,49,69,137,138,162],yield:143,you:[0,2,4,5,6,9,10,12,14,17,18,21,24,25,26,31,35,36,37,39,41,43,44,45,49,50,53,54,55,57,68,71,72,73,75,78,81,83,84,86,88,93,96,98,100,103,105,107,109,110,111,113,117,120,122,123,124,127,135,139,141,143,145,146,148,149,150,151,152,154,156,157,159,160,162,165,166,169,170,171],your:[18,25,53,55,71,113,122,124,150,156,160],yourself:154,yout:5,ys:[40,53,122,150,156,158,172],z:43,zelda1:37,zelda2:37,zelda:37,zelda_2:37,zero:[17,18,21,43,63,71,111,120,135,164],zero_electric_offset:17,zero_electrical_offset:[18,71],zone:16,zoom_in:86,zoom_out:86},titles:["ADC Example","ADC Types","ADS1x15 I2C ADC","Ads1x15 Example","ADS7138 I2C ADC","Ads7138 Example","Continuous ADC","ADC APIs","Oneshot ADC","TLA2528 I2C ADC","Tla2528 Example","Base Compoenent","Base Peripheral","Battery APIs","MAX1704X","MAX1704X Example","BLDC Driver","BLDC Motor","BldcMotor Example","BLDC APIs","Battery Service","BLE GATT Server","BLE GATT Server Example","Device Info Service","Google Fast Pair Service (GFPS) Service","Google Fast Pair Service (GFPS) Service Example","HID Service","BLE HID Service Example","BLE APIs","Button APIs","Button Example","Command Line Interface (CLI) APIs","Cli Example","Color APIs","Color Example","Controller APIs","Controller Example","CSV APIs","CSV Example","Display","Display Drivers","Display Drivers Example","Display APIs","ABI Encoder","AS5600 Magnetic Encoder","As5600 Example","Encoder Example","Encoder Types","Encoder APIs","MT6701 Magnetic Encoder","Mt6701 Example","ESP32 TimerCam","ESP32-TIMER-CAM Example","ESP BOX","ESP-BOX Example","Event Manager APIs","Event Manager Example","File System APIs","File System Example","Biquad Filter","Butterworth Filter","Filters Example","Filter APIs","Lowpass Filter","Simple Lowpass Filter","Second Order Sections (SoS) Filter","Transfer Function API","FTP Server","FTP Example","FTP APIs","BLDC Haptics","BLDC Haptics Example","DRV2605 Haptic Motor Driver","Drv2605 Example","Haptics APIs","HID-RP","HID-RP Example","HID APIs","I2C","I2C Example","ESPP Documentation","CHSC6X Touch Controller","CHSC6X Example","CST816 Touch Controller","CST816 Example","Encoder Input","FT5x06 Touch Controller","FT5x06 Example","GT911 Touch Controller","GT911 Example","Input APIs","Keypad Input","Pointer Input","LilyGo T-Keyboard","LilyGo T-Keyboard Example","Touchpad Input","TT21100 Touch Controller","TT21100 Example","Interrupt APIs","Interrupt Example","AW9523 I/O Expander","AW9523 Example","IO Expander APIs","KTS1622 I/O Expander","KTS1622 Example","MCP23x17 I/O Expander","MCP23x17 Example","Joystick APIs","Joystick Example","LED APIs","LED Example","LED Strip APIs","LED Strip Example","Logging APIs","Logger Example","Bezier","Fast Math","Gaussian","Math APIs","Math Example","Range Mapper","Vector2d","MaTouch Rotary Display","Matouch-Rotary-Display Example","Monitoring APIs","Monitor Example","MotorGo Mini","MotorGo-Mini Example","Network APIs","Sockets","Socket Example","TCP Sockets","UDP Sockets","NFC APIs","NDEF","ST25DV","St25dv Example","NVS APIs","NVS Example","PID APIs","PID Example","QwiicNES","QwiicNES Example","Remote Control Transceiver (RMT)","RMT Example","BM8563","BM8563 Example","RTC APIs","RTSP APIs","RTSP Example","Seeed Studio Round Display","Seeed Studio Round Display Example","Serialization APIs","Serialization Example","State Machine APIs","Hierarchichal Finite State Machine (HFSM) Example","LilyGo T-Deck","T-Deck Example","LilyGo T-Dongle S3","T-Dongle-S3 Example","Tabulate APIs","Tabulate Example","Task APIs","Task Example","Thermistor APIs","Thermistor Example","Timer APIs","Timer Example","WiFi APIs","WiFi Access Point (AP)","WiFi Example","WiFi Station (STA)","ESP32-WROVER-KIT","Wrover-Kit Example"],titleterms:{"1":[70,111,143,166],"2":70,"class":[2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,33,35,37,39,40,43,44,49,51,53,55,57,59,60,63,64,65,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],"function":[66,135,141,145],"long":162,In:117,No:29,On:71,Then:166,With:29,abi:43,abiencod:43,access:169,adc:[0,1,2,4,6,7,8,9,107,164],ads1x15:[2,3],ads7138:[4,5],advancedconfig:166,again:166,alpaca:152,analog:35,ap:169,apa102:111,api:[1,2,4,6,7,8,9,11,12,13,14,16,17,19,20,21,23,24,26,28,29,31,33,35,37,39,40,42,43,44,47,48,49,51,53,55,57,59,60,62,63,64,65,66,67,69,70,72,74,75,77,78,81,83,85,86,88,90,91,92,93,95,96,98,100,102,103,105,107,109,111,113,115,116,117,118,120,121,122,124,126,128,129,131,132,133,134,135,137,139,141,143,145,147,148,150,152,154,156,158,160,162,164,166,168,169,171,172],appropri:18,as5600:[44,45],aw9523:[100,101],base:[11,12],basic:[70,107,113,124,139,162],batteri:[13,20],bench:154,best:71,bezier:115,biquad:59,bldc:[16,17,19,70,71],bldcmotor:18,ble:[21,22,27,28],block:162,bm8563:[145,146],board:18,box:[40,53,54],breakdown:[18,41,71],breath:109,build:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],butterworth:60,button:[29,30],buzz:70,callback:29,cam:[51,52],cancel:166,chsc6x:[81,82],circular:107,cli:[31,32],click:70,client:[131,132,148],coars:71,color:[33,34],command:[31,113],complex:[37,139,152,154,160],compoen:11,config:40,configur:[18,41,68,82,84,89,125,149,159,170],consol:18,continu:6,control:[35,36,81,83,86,88,96,143],core:162,cst816:[83,84],csv:[37,38],cursor:113,data:143,de:152,deck:[156,157],definit:129,delai:166,detent:71,devic:[23,154],digit:35,displai:[39,40,41,42,122,123,150,151],document:80,dongl:[158,159],driver:[16,40,41,72],drv2605:[72,73],e:18,encod:[43,44,46,47,48,49,85,143],esp32:[40,51,52,172],esp:[53,54],espp:80,event:[55,56],exampl:[0,2,3,4,5,6,8,9,10,14,15,17,18,21,22,24,25,26,27,29,30,32,34,35,36,37,38,40,41,43,44,45,46,49,50,51,52,53,54,55,56,57,58,61,68,70,71,72,73,75,76,78,79,81,82,83,84,86,87,88,89,93,94,96,97,98,99,100,101,103,104,105,106,107,108,109,110,111,112,113,114,115,117,119,120,121,122,123,124,125,126,127,130,131,132,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,169,170,171,172,173],expand:[100,102,103,105],fade:117,fast:[24,25,116],file:[1,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,37,39,40,43,44,47,49,51,53,55,57,58,59,60,63,64,65,66,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],filesystem:57,filter:[59,60,61,62,63,64,65],finit:155,flash:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],format:113,ft5x06:[86,87],ftp:[67,68,69],g:18,gatt:[21,22],gaussian:117,gc9a01:40,gener:154,get_latest_info_:124,get_latest_info_vector:124,gfp:[24,25],googl:[24,25],gt911:[88,89],haptic:[70,71,72,74],hardwar:[5,10,15,18,22,25,27,30,36,41,45,46,50,52,54,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,123,127,136,142,144,146,149,151,157,159,165,173],header:[1,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,37,39,40,43,44,47,49,51,53,55,57,59,60,63,64,65,66,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],hfsm:[154,155],hid:[26,27,75,76,77],hierarchich:155,high:166,how:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],i2c:[2,4,9,35,49,78,79],i:[100,103,105],ili9341:40,info:[23,57,162],input:[85,90,91,92,95],interfac:31,interrupt:[29,98,99],io:102,itself:166,joystick:[107,108],keyboard:[93,94],keypad:91,kit:[40,172,173],kts1622:[103,104],lab:18,led:[109,110,111,112],lilygo:[93,94,156,158],line:31,linear:[43,109],log:[18,113],logger:[113,114],lowpass:[63,64],machin:[154,155],macro:[37,113,152,154,160],magnet:[44,49,71],manag:[55,56],mani:162,mapper:120,markdown:160,math:[116,118,119],matouch:[122,123],max1704x:[14,15],mcp23x17:[105,106],mini:[126,127],monitor:[124,125],motor:[17,72],motorgo:[126,127],mt6701:[49,50],multi:71,multicast:132,ndef:134,network:128,newlib:57,nfc:133,non:162,notifi:162,nv:[137,138],nvshandl:[137,138],o:[100,103,105],off:71,oneshot:[8,166],order:65,out:117,output:[0,3,5,10,15,18,22,25,27,30,32,34,38,45,50,52,54,56,58,61,68,71,76,79,82,84,87,89,94,97,99,101,104,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,155,157,159,161,163,165,167,173],pair:[24,25],period:166,peripher:12,pictur:18,pid:[139,140],pin:159,plai:70,point:169,pointer:92,posix:57,project:[18,41,68,125,149,170],qwiicn:[141,142],rang:120,reader:37,real:154,recommend:162,rectangular:107,refer:[1,2,4,6,8,9,11,12,14,16,17,20,21,23,24,26,29,31,33,35,37,39,40,43,44,47,49,51,53,55,57,59,60,63,64,65,66,67,70,72,75,78,81,83,85,86,88,91,92,93,95,96,98,100,103,105,107,109,111,113,115,116,117,120,121,122,124,126,129,131,132,134,135,137,139,141,143,145,148,150,152,154,156,158,160,162,164,166,169,171,172],remot:143,request:162,requir:[5,10,15,18,22,25,27,30,36,41,45,46,50,52,54,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,123,127,136,142,144,146,149,151,157,159,165,173],resolut:166,respons:[131,132],rev:71,rmt:[143,144],rotari:[122,123],rotat:43,round:[150,151],rp:[75,76],rtc:147,rtsp:[148,149],run:[154,162],s3:[40,158,159],schemat:18,screenshot:18,second:65,section:65,seeed:[150,151],serial:[152,153],server:[21,22,67,131,132,148],servic:[20,23,24,25,26,27],simpl:[29,64],smartknob:40,so:65,socket:[129,130,131,132],sound:71,spi:[49,111],ssi:49,ssrounddisplai:150,st25dv:[135,136],st7789:40,sta:171,start:166,state:[154,155],station:171,std:57,stop:162,strip:[111,112],strong:71,structur:152,studio:[150,151],system:[57,58],t:[93,94,156,157,158,159],tabul:[160,161],task:[124,162,163],tcp:131,test:154,thermistor:[164,165],thread:113,timer:[51,52,166,167],timercam:51,tla2528:[9,10],touch:[81,83,86,88,96],touchpad:95,transceiv:143,transfer:66,transmit:143,troubleshoot:[18,71],tt21100:[96,97],ttgo:40,type:[1,47,129],udp:132,union:[134,135,141],updat:166,us:[0,3,5,10,15,18,22,25,27,30,32,34,36,38,41,45,46,50,52,54,56,58,61,68,71,73,76,79,82,84,87,89,94,97,99,101,104,106,108,110,112,114,119,123,125,127,130,136,138,140,142,144,146,149,151,153,155,157,159,161,163,165,167,170,173],usag:[17,70],valid:164,valu:71,vector2d:121,verbos:113,via:111,video:[5,18],watchdog:[162,166],wifi:[168,169,170,171],writer:37,wrover:[40,172,173],ws2812:143}}) \ No newline at end of file diff --git a/seeed_studio_round_display.html b/seeed_studio_round_display.html new file mode 100644 index 000000000..066069504 --- /dev/null +++ b/seeed_studio_round_display.html @@ -0,0 +1,1017 @@ + + + + + + + Seeed Studio Round Display - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Seeed Studio Round Display

+
+

SsRoundDisplay

+

The Seeed Studio Round Display is a development board containing a 240x240 round +display with touchscreen, RTC, battery charger, and uSD card slot. It support +connection to a QtyPy or a XIAO module.

+

The espp::SsRoundDisplay component provides a singleton hardware abstraction +for initializing the display and touchscreen components for the Seeed Studio +Round Display.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class SsRoundDisplay : public espp::BaseComponent
+

The SsRoundDisplay class provides an interface to the Seeed Studio Round Display development board.

+

The class provides access to the following features:

+

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
#if CONFIG_EXAMPLE_HARDWARE_XIAOS3
+  logger.info("Using XiaoS3 hardware configuration");
+  espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::XiaoS3Config);
+#elif CONFIG_EXAMPLE_HARDWARE_QTPYS3
+  logger.info("Using QtpyS3 hardware configuration");
+  espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::QtpyS3Config);
+#else
+#error "Please select a hardware configuration"
+#endif
+  espp::SsRoundDisplay &round_display = espp::SsRoundDisplay::get();
+
+  auto touch_callback = [&](const auto &touch) {
+    // NOTE: since we're directly using the touchpad data, and not using the
+    // TouchpadInput + LVGL, we'll need to ensure the touchpad data is
+    // converted into proper screen coordinates instead of simply using the
+    // raw values.
+    static auto previous_touchpad_data = round_display.touchpad_convert(touch);
+    auto touchpad_data = round_display.touchpad_convert(touch);
+    if (touchpad_data != previous_touchpad_data) {
+      logger.info("Touch: {}", touchpad_data);
+      previous_touchpad_data = touchpad_data;
+      // if the button is pressed, clear the circles
+      if (touchpad_data.btn_state) {
+        clear_circles();
+      }
+      // if there is a touch point, draw a circle
+      if (touchpad_data.num_touch_points > 0) {
+        draw_circle(touchpad_data.x, touchpad_data.y, 10);
+      }
+    }
+  };
+
+  // initialize the LCD
+  if (!round_display.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // set the pixel buffer to be 50 lines high
+  static constexpr size_t pixel_buffer_size = round_display.lcd_width() * 50;
+  espp::Task::BaseConfig display_task_config = {
+      .name = "Display",
+      .stack_size_bytes = 6 * 1024,
+      .priority = 10,
+      .core_id = 0,
+  };
+  // initialize the LVGL display for the seeed-studio-round-display
+  if (!round_display.initialize_display(pixel_buffer_size, display_task_config)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+  // initialize the touchpad
+  if (!round_display.initialize_touch(touch_callback)) {
+    logger.error("Failed to initialize touchpad!");
+    return;
+  }
+
+  // set the background color to black
+  lv_obj_t *bg = lv_obj_create(lv_screen_active());
+  lv_obj_set_size(bg, round_display.lcd_width(), round_display.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Touch the screen!");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // add a button in the top middel which (when pressed) will rotate the display
+  // through 0, 90, 180, 270 degrees
+  lv_obj_t *btn = lv_btn_create(lv_screen_active());
+  lv_obj_set_size(btn, 50, 50);
+  lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 0);
+  lv_obj_t *label_btn = lv_label_create(btn);
+  lv_label_set_text(label_btn, LV_SYMBOL_REFRESH);
+  lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_add_event_cb(btn, on_rotate_pressed, LV_EVENT_PRESSED, nullptr);
+
+  // add a button in the bottom middle which (when pressed) will clear the
+  // circles
+  lv_obj_t *btn_clear = lv_btn_create(lv_screen_active());
+  lv_obj_set_size(btn_clear, 50, 50);
+  lv_obj_align(btn_clear, LV_ALIGN_BOTTOM_MID, 0, 0);
+  lv_obj_add_state(btn_clear, LV_STATE_CHECKED); // make the button red
+  lv_obj_t *label_btn_clear = lv_label_create(btn_clear);
+  lv_label_set_text(label_btn_clear, LV_SYMBOL_TRASH);
+  lv_obj_align(label_btn_clear, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_add_event_cb(btn_clear, on_clear_pressed, LV_EVENT_PRESSED, nullptr);
+
+  // disable scrolling on the screen (so that it doesn't behave weirdly when
+  // rotated and drawing with your finger)
+  lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF);
+  lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                      }});
+  lv_task.start();
+
+  // set the display brightness to be 75%
+  round_display.brightness(75.0f);
+
+  // loop forever
+  while (true) {
+    std::this_thread::sleep_for(1s);
+  }
+
+
+
+
+

Note

+

You must call set_pin_config() before calling get() for the first time, in order to provide the appropriate pin configuration for the controller board connected to the display. Some pin configuration structures are provided for convenience.

+
+
+

Public Types

+
+
+using Pixel = lv_color16_t
+

Alias for the type of pixel the display uses.

+
+ +
+
+using DisplayDriver = espp::Gc9a01
+

Alias for the display driver.

+
+ +
+
+using TouchDriver = espp::Chsc6x
+

Alias for the touch driver.

+
+ +
+
+using TouchpadData = espp::TouchpadData
+

Alias for the touchpad data.

+
+ +
+
+using touch_callback_t = std::function<void(const TouchpadData&)>
+

The touch callback function type

+
+
Param data
+

The touchpad data

+
+
+
+ +
+
+

Public Functions

+
+
+espp::I2c &internal_i2c()
+

Get a reference to the internal I2C bus

+
+
Returns
+

A reference to the internal I2C bus

+
+
+
+ +
+
+espp::Interrupt &interrupts()
+

Get a reference to the interrupts

+
+
Returns
+

A reference to the interrupts

+
+
+
+ +
+
+bool initialize_touch(const touch_callback_t &callback = nullptr)
+

Initialize the touchpad

+
+

Note

+

This will configure the touchpad interrupt pin which will automatically call the touch callback function when the touchpad is touched

+
+
+

Warning

+

This method should be called after the display has been initialized if you want the touchpad to be recognized and used with LVGL and its objects.

+
+
+
Parameters
+

callback – The touchpad callback

+
+
Returns
+

true if the touchpad was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<TouchpadInput> touchpad_input() const
+

Get the touchpad input

+
+
Returns
+

A shared pointer to the touchpad input

+
+
+
+ +
+
+TouchpadData touchpad_data() const
+

Get the most recent touchpad data

+
+
Returns
+

The touchpad data

+
+
+
+ +
+
+void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)
+

Get the most recent touchpad data

+

See also

+

touchpad_data()

+
+

+
+

Note

+

This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the touchpad_data() method

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points

  • +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • btn_state – The button state (0 = button released, 1 = button pressed)

  • +
+
+
+
+ +
+
+TouchpadData touchpad_convert(const TouchpadData &data) const
+

Convert touchpad data from raw reading to display coordinates

+
+

Note

+

Uses the touch_invert_x and touch_invert_y settings to determine if the x and y coordinates should be inverted

+
+
+
Parameters
+

data – The touchpad data to convert

+
+
Returns
+

The converted touchpad data

+
+
+
+ +
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline void set_pin_config(const PinConfig &pin_config)
+

Set the pin configuration for the controller board connected to the display.

+
+
Parameters
+

pin_config – The pin configuration for the controller board

+
+
+
+ +
+
+static inline SsRoundDisplay &get()
+

Access the singleton instance of the SsRoundDisplay class.

+
+

Note

+

This method must be called after set_pin_config() has been called

+
+
+
Returns
+

Reference to the singleton instance of the SsRoundDisplay class

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static constexpr PinConfig XiaoS3Config  = {.sda = GPIO_NUM_5,.scl = GPIO_NUM_6,.usd_cs = GPIO_NUM_3,.lcd_cs = GPIO_NUM_2,.lcd_dc = GPIO_NUM_4,.lcd_backlight = GPIO_NUM_43,.miso = GPIO_NUM_8,.mosi = GPIO_NUM_9,.sck = GPIO_NUM_7,.touch_interrupt = GPIO_NUM_44,}
+

The default pin configuration for the Seeed Studio Round Display connected to the Xiao ESP32-S3.

+
+ +
+
+static constexpr PinConfig QtpyS3Config  = {.sda = GPIO_NUM_7,.scl = GPIO_NUM_6,.usd_cs = GPIO_NUM_9,.lcd_cs = GPIO_NUM_17,.lcd_dc = GPIO_NUM_8,.lcd_backlight = GPIO_NUM_5,.miso = GPIO_NUM_37,.mosi = GPIO_NUM_35,.sck = GPIO_NUM_36,.touch_interrupt = GPIO_NUM_16,}
+

The default pin configuration for the Seeed Studio Round Display connected to the Qtpy Esp32S3.

+
+ +
+
+
+struct PinConfig
+

The pin configuration structure.

+
+

Public Members

+
+
+gpio_num_t sda = GPIO_NUM_NC
+

I2C data.

+
+ +
+
+gpio_num_t scl = GPIO_NUM_NC
+

I2C clock.

+
+ +
+
+gpio_num_t usd_cs = GPIO_NUM_NC
+

uSD card chip select

+
+ +
+
+gpio_num_t lcd_cs = GPIO_NUM_NC
+

LCD chip select.

+
+ +
+
+gpio_num_t lcd_dc = GPIO_NUM_NC
+

LCD data/command.

+
+ +
+
+gpio_num_t lcd_backlight = GPIO_NUM_NC
+

LCD backlight.

+
+ +
+
+gpio_num_t miso = GPIO_NUM_NC
+

SPI MISO.

+
+ +
+
+gpio_num_t mosi = GPIO_NUM_NC
+

SPI MOSI.

+
+ +
+
+gpio_num_t sck = GPIO_NUM_NC
+

SPI SCK.

+
+ +
+
+gpio_num_t touch_interrupt = GPIO_NUM_NC
+

Touch interrupt.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/seeed_studio_round_display_example.html b/seeed_studio_round_display_example.html new file mode 100644 index 000000000..f535c241c --- /dev/null +++ b/seeed_studio_round_display_example.html @@ -0,0 +1,238 @@ + + + + + + + Seeed Studio Round Display Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Seeed Studio Round Display Example

+

This example shows how to use the espp::SsRoundDisplay hardware abstraction +component to initialize the hardware components on the Seeed Studio Round +Display when used with +either the XIAO S3 or the QtPy ESP32S3.

+

It initializes the touch and display subsystems. It reads the touchpad state and +each time you touch the scren it uses LVGL to draw a circle where you touch.

+

https://github.com/user-attachments/assets/4cac7882-2a79-4c7c-a139-d36e39322660

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on either the QtPy ESP32S3 or the XIAO S3, +though the espp::SsRoundDisplay can be used with custom hardware.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-08-26 at 08 24 22

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/serialization.html b/serialization.html new file mode 100644 index 000000000..6555fdbae --- /dev/null +++ b/serialization.html @@ -0,0 +1,358 @@ + + + + + + + Serialization APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Serialization APIs

+
+

Alpaca

+

The serialization library is a light wrapper around the third-party alpaca serialization library.

+
+
+

Serialization

+

The Serialization component provides a simple wrapper with reasonable default +options around the Alpaca libarary. The default +serialization/deserialization options are configured such that messages / types +can be distinguished from each other.

+

Code examples for the serialization API are provided in the serialization +example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Macros

+
+
+__gnu_linux__
+
+ +
+
+

Classes

+
+
+class __serialization_documentation__
+

Serialization convenience wrapper for espp, providing methods for serializaing structures / classes into containers (such as c-sytle arrays, std::arrays, std::vectors, etc.). and for deserializing such containers into structures / classes.

+
+

(De-)Serialization Example

+
    struct MyStruct {
+      uint8_t value; // NOTE: you cannot use int, you must use strongly sized types.
+    };
+    std::error_code ec;
+    MyStruct object{5};
+    {
+      uint8_t buffer[10];
+      auto bytes_written = alpaca::serialize(object, buffer);
+      fmt::print("Serialized {}B to c-array (alpaca)\n", bytes_written);
+      auto new_object = alpaca::deserialize<MyStruct>(buffer, bytes_written, ec);
+      if (!ec && new_object.value == object.value) {
+        fmt::print("Deserialized successfully!\n");
+      } else {
+        fmt::print("Deserialization failed: {}\n", ec.message());
+      }
+    }
+    {
+      uint8_t buffer[10];
+      auto bytes_written = espp::serialize(object, buffer);
+      fmt::print("Serialized {}B to c-array (espp wrapper)\n", bytes_written);
+      auto new_object = espp::deserialize<MyStruct>(buffer, bytes_written, ec);
+      if (!ec && new_object.value == object.value) {
+        fmt::print("Deserialized successfully!\n");
+      } else {
+        fmt::print("Deserialization failed: {}\n", ec.message());
+      }
+    }
+    {
+      std::array<uint8_t, 5> buffer;
+      auto bytes_written = espp::serialize(object, buffer);
+      fmt::print("Serialized {}B to std::array\n", bytes_written);
+      auto new_object = espp::deserialize<MyStruct>(buffer, ec);
+      if (!ec && new_object.value == object.value) {
+        fmt::print("Deserialized successfully!\n");
+      } else {
+        fmt::print("Deserialization failed: {}\n", ec.message());
+      }
+    }
+    {
+      std::vector<uint8_t> buffer;
+      auto bytes_written = espp::serialize(object, buffer);
+      fmt::print("Serialized {}B to std::vector\n", bytes_written);
+      auto new_object = espp::deserialize<MyStruct>(buffer, ec);
+      if (!ec && new_object.value == object.value) {
+        fmt::print("Deserialized successfully!\n");
+      } else {
+        fmt::print("Deserialization failed: {}\n", ec.message());
+      }
+    }
+    {
+      std::array<uint8_t, 15> buffer;
+      constexpr auto OPTIONS = alpaca::options::fixed_length_encoding;
+      auto bytes_written = espp::serialize<OPTIONS>(object, buffer);
+      fmt::print("Serialized {}B to std::arary with custom options\n", bytes_written);
+      auto new_object = espp::deserialize<OPTIONS, MyStruct>(buffer, ec);
+      if (!ec && new_object.value == object.value) {
+        fmt::print("Deserialized successfully!\n");
+      } else {
+        fmt::print("Deserialization failed: {}\n", ec.message());
+      }
+    }
+
+
+
+
+

Complex Structure (De-)Serialization Example

+
    struct MyStruct {
+      uint8_t value;
+      std::vector<uint32_t> data;
+      std::string name;
+    };
+    std::error_code ec;
+    MyStruct object{42, {1, 3, 3, 7}, "the meaning of life"};
+    std::vector<uint8_t> buffer;
+    auto bytes_written = espp::serialize(object, buffer);
+    fmt::print("Serialized {}B to std::vector\n", bytes_written);
+    auto new_object = espp::deserialize<MyStruct>(buffer, ec);
+    if (!ec && new_object.value == object.value) {
+      fmt::print("Deserialized successfully!\n");
+      fmt::print("\tvalue: {}\n"
+                 "\tdata:  {}\n"
+                 "\tname:  {}\n",
+                 new_object.value, new_object.data, new_object.name);
+    } else {
+      fmt::print("Deserialization failed: {}\n", ec.message());
+    }
+
+
+
+
+

Note

+

When defining types to be serialized, you MUST use strictly sized types, such as uint8_t / int8_t or uint32_t or int8_t instead of just int or even size_t.

+
+
+

Note

+

This class does not really exist or do anything, but it’s the only way I could figure out how to get this documentation built into the system :(

+
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/serialization_example.html b/serialization_example.html new file mode 100644 index 000000000..3d9f06b0a --- /dev/null +++ b/serialization_example.html @@ -0,0 +1,224 @@ + + + + + + + Serialization Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Serialization Example

+

This example shows the use of the serialization component (and the alpaca +library it wraps) to perform robust and reliable binary serialization and +deserialization of arbitrary objects.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/state_machine.html b/state_machine.html new file mode 100644 index 000000000..4c4111a48 --- /dev/null +++ b/state_machine.html @@ -0,0 +1,900 @@ + + + + + + + State Machine APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

State Machine APIs

+

The state_machine component is a light wrapper around the webgme-hfsm static generated code. It is +designed to be used as the component that one or more specific hfsms (manually written or +generated from webgme-hfsm) can depend on.

+

Code examples for the state_machine API are provided in the state_machine +example folder.

+

The example runs the generated code for the following example hsfm (which is +provided and for which the code was generated from webgme-hfsm):

+"Complex" example HFSM showing the many of the UML formalisms supported. + +
+

API Reference

+
+

Header File

+ +
+
+

Macros

+
+
+MAGIC_ENUM_NO_CHECK_SUPPORT
+
+ +
+
+

Classes

+
+
+class __state_machine_documentation__
+

State machine convenience wrapper for espp. Including state_machine.hpp provides access to all the base classes that the generated code relies on as well as what you would need to subclass yourself for a manually written hfsm. Please see https://github.com/finger563/webgme-hfsm for more information about modeling, generating, and developing HFSMs.

+
+

State Machine / HFSM Example with the generated Complex example hfsm

+
    const espp::state_machine::Complex::GeneratedEventBase *e = nullptr;
+    bool handled = false;
+
+    // create the HFSM
+    espp::state_machine::Complex::Root complex_root;
+
+    // set the log callback to print to stdout
+    complex_root.set_log_callback([](std::string_view msg) { fmt::print("{}\n", msg); });
+
+    // initialize the HFSM
+    complex_root.initialize();
+
+    // start a task to run the hfsm
+    auto task_fn = [&complex_root](std::mutex &m, std::condition_variable &cv) {
+      // execute the state machine
+      complex_root.handle_all_events();
+      complex_root.tick();
+      // NOTE: if we call tick above, then we need to call handle_all_events()
+      //      again to handle any events that were spawned by the tick()
+      complex_root.handle_all_events();
+      // get the active state period (the state may have changed from handling
+      // events, so we always need to get the active leaf)
+      auto current_hfsm_period = complex_root.getActiveLeaf()->getTimerPeriod();
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, std::chrono::duration<float>(current_hfsm_period));
+      }
+      // stop the task if the hfsm has stopped (reached its end state)
+      return complex_root.has_stopped();
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "HFSM"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+
+    // from other contexts you can spawn events into the HFSM. the functions are
+    // generated based on the event names from the model, and the data
+    // structures are generated into <state machine name>_event_data.hpp so that
+    // you can enforce that events must have certain data. The sequence below
+    // should transition the HFSM through a few states until it gets to a state
+    // where the ENDEVENT will cause the whole HFSM to terminate.
+    complex_root.spawn_EVENT4_event({});
+    complex_root.spawn_EVENT1_event({});
+    complex_root.spawn_EVENT2_event({});
+    complex_root.spawn_EVENT3_event({});
+    complex_root.spawn_EVENT1_event({});
+    complex_root.spawn_ENDEVENT_event({});
+
+    // give the hfsm some time to handle the events before we fully exit
+    std::this_thread::sleep_for(1s);
+
+
+
+
+

Running the HFSM Test Bench on a Real Device:

+
    // NOTE: we need to configure stdin/stdout to use std::cin for
+    //       get_user_selection() function.
+    espp::Cli::configure_stdin_stdout();
+
+    const espp::state_machine::Complex::GeneratedEventBase *e = nullptr;
+
+    // create the HFSM
+    espp::state_machine::Complex::Root complex_root;
+
+    // set the log callback to print to stdout
+    complex_root.set_log_callback([](std::string_view msg) { fmt::print("{}\n", msg); });
+
+    // initialize the HFSM
+    complex_root.initialize();
+
+    // start a task to run the hfsm
+    auto task_fn = [&complex_root](std::mutex &m, std::condition_variable &cv) {
+      // execute the state machine
+      complex_root.handle_all_events();
+
+      // NOTE: we would normally call the tick() function here, but we want to
+      //       be able to manually tick the HFSM from the test bench and we
+      //       don't want to clutter the log with the tick() messages.
+      // complex_root.tick();
+
+      // NOTE: if we call tick above, then we need to call handle_all_events()
+      //       again to handle any events that were spawned by the tick()
+      //       function
+      // complex_root.handle_all_events();
+
+      // get the active state period (the state may have changed from handling
+      // events, so we always need to get the active leaf)
+      auto current_hfsm_period = complex_root.getActiveLeaf()->getTimerPeriod();
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, std::chrono::duration<float>(current_hfsm_period));
+      }
+      // stop the task if the hfsm has stopped (reached its end state)
+      return complex_root.has_stopped();
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "HFSM"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+
+    // NOTE: this is just a copy of the HFSM code from the generated test bench,
+    //       and is not intended to show how to actually run the HFSM in
+    //       production.
+    while (!complex_root.has_stopped()) {
+      do {
+        std::this_thread::sleep_for(100ms);
+      } while (complex_root.has_events());
+      display_event_menu();
+      int selection = get_user_selection();
+      if (selection == ExitSelection) {
+        complex_root.terminate();
+        break;
+      } else if (selection == RestartSelection) {
+        complex_root.restart();
+      } else if (selection == TickSelection) {
+        complex_root.tick();
+      } else {
+        make_event(complex_root, selection);
+      }
+    }
+
+
+
+
+

Note

+

This class does not really exist or do anything, but it’s the only way I could figure out how to get this documentation built into the system :(

+
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class EventBase
+
+

Public Functions

+
+
+inline virtual ~EventBase()
+

Default constructor.

+
+ +
+
+virtual std::string to_string() const = 0
+

Returns a string representation of the event.

+
+ +
+
+ +
+
+class StateBase
+

States contain other states and can consume generic EventBase objects if they have internal or external transitions on those events and if those transitions’ guards are satisfied. Only one transition can consume an event in a given state machine.

+

There is also a different kind of Event, the tick event, which is not consumed, but instead executes from the top-level state all the way to the curently active leaf state.

+

Entry and Exit actions also occur whenever a state is entered or exited, respectively.

+

Subclassed by espp::state_machine::DeepHistoryState, espp::state_machine::ShallowHistoryState

+
+

Public Functions

+
+
+StateBase()
+

Default constructor.

+
+ +
+
+explicit StateBase(StateBase *parent)
+

Constructor that sets the parent state.

+
+
Parameters
+

parent[in] Pointer to parent state

+
+
+
+ +
+
+virtual ~StateBase(void)
+

Destructor.

+
+ +
+
+virtual void initialize(void)
+

Will be generated to call entry() then handle any child initialization. Finally calls makeActive on the leaf.

+
+ +
+
+virtual void entry(void)
+

Will be generated to run the entry() function defined in the model.

+
+ +
+
+virtual void exit(void)
+

Will be generated to run the exit() function defined in the model.

+
+ +
+
+virtual bool handleEvent(EventBase *event)
+

Calls handleEvent on the activeLeaf.

+
+
Parameters
+

event[in] Event needing to be handled

+
+
Returns
+

true if event is consumed, false otherwise

+
+
+
+ +
+
+virtual void tick(void)
+

Will be generated to run the tick() function defined in the model and then call _activeState->tick().

+
+ +
+
+virtual double getTimerPeriod(void)
+

Returns the timer period for the state.

+
+ +
+
+virtual StateBase *getInitial(void)
+

Will be known from the model so will be generated in derived classes to immediately return the correct initial state pointer for quickly transitioning to the proper state during external transition handling.

+
+
Returns
+

Pointer to initial substate

+
+
+
+ +
+
+void exitChildren(void)
+

Recurses down to the leaf state and calls the exit actions as it unwinds.

+
+ +
+
+StateBase *getActiveChild(void)
+

Will return _activeState if it exists, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active substate

+
+
+
+ +
+
+StateBase *getActiveLeaf(void)
+

Will return the active leaf state, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active leaf state.

+
+
+
+ +
+
+virtual void makeActive(void)
+

Make this state the active substate of its parent and then recurse up through the tree to the root.

+
+

Note

+

Should only be called on leaf nodes!

+
+
+ +
+
+void setActiveChild(StateBase *childState)
+

Update the active child state.

+
+ +
+
+void setShallowHistory(void)
+

Sets the currentlyActive state to the last active state and re-initializes them.

+
+ +
+
+void setDeepHistory(void)
+

Go to the last active leaf of this state. If none exists, re-initialize.

+
+ +
+
+void setParentState(StateBase *parent)
+

Will set the parent state.

+
+
Parameters
+

parent[in] Pointer to parent state

+
+
+
+ +
+
+StateBase *getParentState(void)
+

Will return the parent state.

+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class ShallowHistoryState : public espp::state_machine::StateBase
+

Shallow History Pseudostates exist purely to re-implement the makeActive() function to actually call _parentState->setShallowHistory()

+
+

Public Functions

+
+
+inline ShallowHistoryState()
+

Default constructor.

+
+ +
+
+inline explicit ShallowHistoryState(StateBase *_parent)
+

Constructor.

+
+
Parameters
+

_parent – The parent state

+
+
+
+ +
+
+inline virtual void makeActive() override
+

Calls _parentState->setShallowHistory().

+
+ +
+
+virtual void initialize(void)
+

Will be generated to call entry() then handle any child initialization. Finally calls makeActive on the leaf.

+
+ +
+
+virtual void entry(void)
+

Will be generated to run the entry() function defined in the model.

+
+ +
+
+virtual void exit(void)
+

Will be generated to run the exit() function defined in the model.

+
+ +
+
+virtual bool handleEvent(EventBase *event)
+

Calls handleEvent on the activeLeaf.

+
+
Parameters
+

event[in] Event needing to be handled

+
+
Returns
+

true if event is consumed, false otherwise

+
+
+
+ +
+
+virtual void tick(void)
+

Will be generated to run the tick() function defined in the model and then call _activeState->tick().

+
+ +
+
+virtual double getTimerPeriod(void)
+

Returns the timer period for the state.

+
+ +
+
+virtual StateBase *getInitial(void)
+

Will be known from the model so will be generated in derived classes to immediately return the correct initial state pointer for quickly transitioning to the proper state during external transition handling.

+
+
Returns
+

Pointer to initial substate

+
+
+
+ +
+
+void exitChildren(void)
+

Recurses down to the leaf state and calls the exit actions as it unwinds.

+
+ +
+
+StateBase *getActiveChild(void)
+

Will return _activeState if it exists, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active substate

+
+
+
+ +
+
+StateBase *getActiveLeaf(void)
+

Will return the active leaf state, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active leaf state.

+
+
+
+ +
+
+void setActiveChild(StateBase *childState)
+

Update the active child state.

+
+ +
+
+void setShallowHistory(void)
+

Sets the currentlyActive state to the last active state and re-initializes them.

+
+ +
+
+void setDeepHistory(void)
+

Go to the last active leaf of this state. If none exists, re-initialize.

+
+ +
+
+void setParentState(StateBase *parent)
+

Will set the parent state.

+
+
Parameters
+

parent[in] Pointer to parent state

+
+
+
+ +
+
+StateBase *getParentState(void)
+

Will return the parent state.

+
+ +
+
+ +
+
+

Header File

+ +
+
+

Classes

+
+
+class DeepHistoryState : public espp::state_machine::StateBase
+

Deep History Pseudostates exist purely to re-implement the makeActive() function to actually call _parentState->setDeepHistory()

+
+

Public Functions

+
+
+inline DeepHistoryState()
+

Construct a new Deep History State object.

+
+ +
+
+inline explicit DeepHistoryState(StateBase *_parent)
+

Construct a new Deep History State object.

+
+
Parameters
+

_parent – The parent state of this state

+
+
+
+ +
+
+inline virtual void makeActive() override
+

Calls _parentState->setDeepHistory()

+
+ +
+
+virtual void initialize(void)
+

Will be generated to call entry() then handle any child initialization. Finally calls makeActive on the leaf.

+
+ +
+
+virtual void entry(void)
+

Will be generated to run the entry() function defined in the model.

+
+ +
+
+virtual void exit(void)
+

Will be generated to run the exit() function defined in the model.

+
+ +
+
+virtual bool handleEvent(EventBase *event)
+

Calls handleEvent on the activeLeaf.

+
+
Parameters
+

event[in] Event needing to be handled

+
+
Returns
+

true if event is consumed, false otherwise

+
+
+
+ +
+
+virtual void tick(void)
+

Will be generated to run the tick() function defined in the model and then call _activeState->tick().

+
+ +
+
+virtual double getTimerPeriod(void)
+

Returns the timer period for the state.

+
+ +
+
+virtual StateBase *getInitial(void)
+

Will be known from the model so will be generated in derived classes to immediately return the correct initial state pointer for quickly transitioning to the proper state during external transition handling.

+
+
Returns
+

Pointer to initial substate

+
+
+
+ +
+
+void exitChildren(void)
+

Recurses down to the leaf state and calls the exit actions as it unwinds.

+
+ +
+
+StateBase *getActiveChild(void)
+

Will return _activeState if it exists, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active substate

+
+
+
+ +
+
+StateBase *getActiveLeaf(void)
+

Will return the active leaf state, otherwise will return nullptr.

+
+
Returns
+

Pointer to last active leaf state.

+
+
+
+ +
+
+void setActiveChild(StateBase *childState)
+

Update the active child state.

+
+ +
+
+void setShallowHistory(void)
+

Sets the currentlyActive state to the last active state and re-initializes them.

+
+ +
+
+void setDeepHistory(void)
+

Go to the last active leaf of this state. If none exists, re-initialize.

+
+ +
+
+void setParentState(StateBase *parent)
+

Will set the parent state.

+
+
Parameters
+

parent[in] Pointer to parent state

+
+
+
+ +
+
+StateBase *getParentState(void)
+

Will return the parent state.

+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/state_machine_example.html b/state_machine_example.html new file mode 100644 index 000000000..f246eb2d1 --- /dev/null +++ b/state_machine_example.html @@ -0,0 +1,234 @@ + + + + + + + Hierarchichal Finite State Machine (HFSM) Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Hierarchichal Finite State Machine (HFSM) Example

+

This example shows an example of running the below HFSM on an ESP32 in a +real-world scenario (e.g. spawning events from one or more threads and running +the HFSM in its own thread) as well as in a test-bench scenario (e.g. running a +CLI to manually spawn events and trace the execution). For more information, see +webgme-hfsm.

+

hfsm

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

Running the HFSM in a task and sending events to it: +CleanShot 2023-04-10 at 10 55 19

+

Running the test bench: +CleanShot 2023-04-10 at 10 55 43

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/t_deck.html b/t_deck.html new file mode 100644 index 000000000..f4754f44a --- /dev/null +++ b/t_deck.html @@ -0,0 +1,1181 @@ + + + + + + + LilyGo T-Deck - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LilyGo T-Deck

+
+

T-Deck

+

The LilyGo T-Deck is a development board for the ESP32-S3 module. It features a +nice touchscreen display and expansion headers.

+

The espp::TDeck component provides a singleton hardware abstraction for +initializing the touch and display subsystems.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TDeck : public espp::BaseComponent
+

The TDeck class provides an interface to the LilyGo T-Deck ESP32-S3 development board.

+

The class provides access to the following features:

+

+

For more information, see https://github.com/Xinyuan-LilyGO/T-Deck/tree/master and https://github.com/Xinyuan-LilyGO/T-Deck/blob/master/examples/UnitTest/utilities.h

+

+The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::TDeck &tdeck = espp::TDeck::get();
+  tdeck.set_log_level(espp::Logger::Verbosity::INFO);
+
+  static auto rotation = LV_DISPLAY_ROTATION_0;
+
+  auto keypress_callback = [&](uint8_t key) {
+    logger.info("Key pressed: {}", key);
+    if (key == 8) {
+      std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+      clear_circles();
+    } else if (key == ' ') {
+      std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+      clear_circles();
+      rotation = static_cast<lv_display_rotation_t>((static_cast<int>(rotation) + 1) % 4);
+      lv_display_t *disp = _lv_refr_get_disp_refreshing();
+      lv_disp_set_rotation(disp, rotation);
+    }
+  };
+
+  auto touch_callback = [&](const auto &touch) {
+    // NOTE: since we're directly using the touchpad data, and not using the
+    // TouchpadInput + LVGL, we'll need to ensure the touchpad data is
+    // converted into proper screen coordinates instead of simply using the
+    // raw values.
+    static auto previous_touchpad_data = tdeck.touchpad_convert(touch);
+    auto touchpad_data = tdeck.touchpad_convert(touch);
+    if (touchpad_data != previous_touchpad_data) {
+      logger.info("Touch: {}", touchpad_data);
+      previous_touchpad_data = touchpad_data;
+      // if there is a touch point, draw a circle
+      if (touchpad_data.num_touch_points > 0) {
+        std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+        draw_circle(touchpad_data.x, touchpad_data.y, 10);
+      }
+    }
+  };
+
+  auto trackball_callback = [&](const auto &trackball) {
+    logger.debug("Trackball: {}", trackball);
+  };
+
+  // initialize the Keyboard
+  bool start_task = true;
+  if (!tdeck.initialize_keyboard(start_task, keypress_callback)) {
+    logger.error("Failed to initialize Keyboard!");
+    return;
+  }
+  // initialize the LCD
+  if (!tdeck.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // set the pixel buffer to be 50 lines high
+  static constexpr size_t pixel_buffer_size = tdeck.lcd_width() * 50;
+  // initialize the LVGL display for the T-Deck
+  if (!tdeck.initialize_display(pixel_buffer_size)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+  // initialize the touchpad
+  if (!tdeck.initialize_touch(touch_callback)) {
+    logger.error("Failed to initialize touchpad!");
+    return;
+  }
+  // initialize the trackball
+  if (!tdeck.initialize_trackball(trackball_callback)) {
+    logger.error("Failed to initialize trackball!");
+    return;
+  }
+
+  // set the background color to black
+  lv_obj_t *bg = lv_obj_create(lv_screen_active());
+  lv_obj_set_size(bg, tdeck.lcd_width(), tdeck.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Touch the screen!\nPress the delete key to clear circles.\nPress the "
+                           "space key to rotate the display.");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // add a button in the top left which (when pressed) will rotate the display
+  // through 0, 90, 180, 270 degrees
+  lv_obj_t *btn = lv_btn_create(lv_screen_active());
+  lv_obj_set_size(btn, 50, 50);
+  lv_obj_align(btn, LV_ALIGN_TOP_LEFT, 0, 0);
+  lv_obj_t *label_btn = lv_label_create(btn);
+  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<std::recursive_mutex> lock(lvgl_mutex);
+        clear_circles();
+        rotation = static_cast<lv_display_rotation_t>((static_cast<int>(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)
+  lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF);
+  lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                      }});
+  lv_task.start();
+
+  // set the display brightness to be 75%
+  tdeck.brightness(75.0f);
+
+  // now just loop forever
+  while (true) {
+    std::this_thread::sleep_for(1s);
+  }
+
+
+
+
+

Note

+

They keyboard has a backlight, which you can control with the shortcut alt + b. The keyboard backlight is off by default.

+
+
+

Public Types

+
+
+using Pixel = lv_color16_t
+

Alias for the pixel type used by the TDeck display.

+
+ +
+
+

Public Functions

+
+
+I2c &internal_i2c()
+

Get a reference to the internal I2C bus

+
+

Note

+

The internal I2C bus is used for the touchscreen

+
+
+
Returns
+

A reference to the internal I2C bus

+
+
+
+ +
+
+espp::Interrupt &interrupts()
+

Get a reference to the interrupts

+
+
Returns
+

A reference to the interrupts

+
+
+
+ +
+
+void peripheral_power(bool on)
+

Enable or disable power to the peripherals

+
+
Parameters
+

on – Whether to enable or disable power to the peripherals

+
+
+
+ +
+
+bool peripheral_power() const
+

Get the state of the peripheral power

+
+
Returns
+

true if power is enabled, false otherwise

+
+
+
+ +
+
+bool initialize_keyboard(bool start_task = true, const keypress_callback_t &key_cb = nullptr, std::chrono::milliseconds poll_interval = std::chrono::milliseconds(10))
+

Initialize the keyboard

+

See also

+

TKeyboard

+
+
+

See also

+

keyboard()

+
+

+
+

Note

+

The Keyboard has an interrupt pin connected from it (the esp32c3) to the main esp32s3. However, the default firmware on the keyboard (esp32c3) does not use this interrupt pin. Instead, the main esp32s3 must poll the keyboard to get key presses. This is done by the keyboard task. If you update the firmware on the keyboard to use the interrupt pin, you can set start_task to false and wire up the interrupt to the keyboard()->read_key() method.

+
+
+
Parameters
+
    +
  • start_task – Whether to start the keyboard task

  • +
  • key_cb – The key callback function, called when a key is pressed if not null and the keyboard task is started

  • +
  • poll_interval – The interval at which to poll the keyboard

  • +
+
+
Returns
+

true if the keyboard was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<TKeyboard> keyboard() const
+

Get the keyboard

+
+

Note

+

The keyboard is only available if it was successfully initialized

+
+
+
Returns
+

A shared pointer to the keyboard

+
+
+
+ +
+
+bool initialize_trackball(const trackball_callback_t &trackball_cb = nullptr, int sensitivity = 10)
+

Initialize the trackball

+

See also

+

trackball()

+
+
+

See also

+

trackball_data()

+
+
+

See also

+

trackball_read()

+
+ +

+
+
Parameters
+
    +
  • trackball_cb – The trackball callback function, called when the trackball is moved if not null

  • +
  • sensitivity – The sensitivity of the trackball. The higher the sensitivity, the faster the trackball will move

  • +
+
+
Returns
+

true if the trackball was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<PointerInput> trackball() const
+

Get the trackball

+
+

See also

+

trackball_data()

+
+
+

See also

+

trackball_read()

+
+

+
+

Note

+

The trackball is only available if it was successfully initialized

+
+
+

Note

+

This is the same as the pointer_input() method

+
+
+
Returns
+

A shared pointer to the trackball

+
+
+
+ +
+
+void set_trackball_sensitivity(int sensitivity)
+

Set the trackball sensitivity

+
+

Note

+

The sensitivity can be negative, which will invert the direction of the trackball

+
+
+
Parameters
+

sensitivity – The sensitivity of the trackball. The higher the sensitivity, the faster the trackball will move

+
+
+
+ +
+
+std::shared_ptr<PointerInput> pointer_input() const
+

Get the pointer input for the trackball

+
+
Returns
+

A shared pointer to the pointer input for the trackball

+
+
+
+ +
+
+espp::PointerData trackball_data() const
+

Get the most recent trackball data

+
+
Returns
+

The trackball data

+
+
+
+ +
+
+void trackball_read(int &x, int &y, bool &left_pressed, bool &right_pressed)
+

Get the most recent trackball data

+
+

Note

+

This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the trackball_data() method

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • left_pressed – Whether the left button is pressed

  • +
  • right_pressed – Whether the right button is pressed

  • +
+
+
+
+ +
+
+bool initialize_touch(const touch_callback_t &touch_cb = nullptr)
+

Initialize the touchpad

+
+

Note

+

This will configure the touchpad interrupt pin which will automatically call the touch callback function when the touchpad is touched

+
+
+

Warning

+

This method should be called after the display has been initialized if you want the touchpad to be recognized and used with LVGL and its objects.

+
+
+
Parameters
+

touch_cb – The touch callback function, called when the touchpad is touched if not null

+
+
Returns
+

true if the touchpad was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<TouchpadInput> touchpad_input() const
+

Get the touchpad input

+
+
Returns
+

A shared pointer to the touchpad input

+
+
+
+ +
+
+espp::TouchpadData touchpad_data() const
+

Get the most recent touchpad data

+
+
Returns
+

The touchpad data

+
+
+
+ +
+
+void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)
+

Get the most recent touchpad data

+

See also

+

touchpad_data()

+
+

+
+

Note

+

This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the touchpad_data() method

+
+
+
Parameters
+
    +
  • num_touch_points – The number of touch points

  • +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • btn_state – The button state (0 = button released, 1 = button pressed)

  • +
+
+
+
+ +
+
+espp::TouchpadData touchpad_convert(const espp::TouchpadData &data) const
+

Convert touchpad data from raw reading to display coordinates

+
+

Note

+

Uses the touch_invert_x and touch_invert_y settings to determine if the x and y coordinates should be inverted

+
+
+
Parameters
+

data – The touchpad data to convert

+
+
Returns
+

The converted touchpad data

+
+
+
+ +
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline TDeck &get()
+

Access the singleton instance of the TDeck class.

+
+
Returns
+

Reference to the singleton instance of the TDeck class

+
+
+
+ +
+
+static inline constexpr auto peripheral_power_pin()
+

Get the GPIO pin for the peripheral power

+
+

Note

+

This pin is used to enable/disable power to the peripherals, such as the keyboard, screen, etc.

+
+
+
Returns
+

The GPIO pin for the peripheral power

+
+
+
+ +
+
+static inline constexpr auto keyboard_interrupt()
+

Get the GPIO pin for the keyboard interrupt

+
+

Note

+

This pin is used to detect when a key is pressed on the keyboard and is connected to the main esp32s3, however the default firmware on the keyboard does not use this pin

+
+
+
Returns
+

The GPIO pin for the keyboard interrupt

+
+
+
+ +
+
+static inline constexpr auto trackball_up_gpio()
+

Get the GPIO pin for the trackball up button

+
+
Returns
+

The GPIO pin for the trackball up button

+
+
+
+ +
+
+static inline constexpr auto trackball_down_gpio()
+

Get the GPIO pin for the trackball down button

+
+
Returns
+

The GPIO pin for the trackball down button

+
+
+
+ +
+
+static inline constexpr auto trackball_left_gpio()
+

Get the GPIO pin for the trackball left button

+
+
Returns
+

The GPIO pin for the trackball left button

+
+
+
+ +
+
+static inline constexpr auto trackball_right_gpio()
+

Get the GPIO pin for the trackball right button

+
+
Returns
+

The GPIO pin for the trackball right button

+
+
+
+ +
+
+static inline constexpr auto trackball_btn_gpio()
+

Get the GPIO pin for the trackball button

+
+
Returns
+

The GPIO pin for the trackball button

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/t_deck_example.html b/t_deck_example.html new file mode 100644 index 000000000..4b9226f22 --- /dev/null +++ b/t_deck_example.html @@ -0,0 +1,239 @@ + + + + + + + T-Deck Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

T-Deck Example

+

This example shows how to use the espp::TDeck hardware abstraction component +initialize the components on the LilyGo T-Deck.

+

It initializes the touch, display, and t-keyboard subsystems. It reads the +touchpad state and each time you touch the screen it uses LVGL to draw a circle +where you touch. If you press the home button on the display, it will clear the +circles.

+

https://github.com/user-attachments/assets/5d7e7086-fc2c-4477-8948-07b5bab3e51f

+

https://github.com/esp-cpp/espp/assets/213467/dc476c3d-dd9e-4b65-8c2d-9eda3ff3f33f

+

image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the LilyGo T-Deck.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-05 at 23 43 27@2x

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/t_dongle_s3.html b/t_dongle_s3.html new file mode 100644 index 000000000..c39f5a46d --- /dev/null +++ b/t_dongle_s3.html @@ -0,0 +1,854 @@ + + + + + + + LilyGo T-Dongle S3 - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LilyGo T-Dongle S3

+
+

T-Dongle S3

+

The LilyGo T-Dongle S3 is a development board for the ESP32-S3 module. It +features a USB-A connector which doubles as a micro-SD card reader, a color LCD, +an RGB LED, and a button.

+

The espp::TDongleS3 component provides a singleton hardware abstraction for +initializing the display and LED subsystems.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class TDongleS3 : public espp::BaseComponent
+

The TDongleS3 class provides an interface to the LilyGo T-Dongle-S3 ESP32-S3 development board.

+

The class provides access to the following features:

+

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::TDongleS3 &tdongle = espp::TDongleS3::get();
+  tdongle.set_log_level(espp::Logger::Verbosity::INFO);
+
+  // initialize the LED
+  if (!tdongle.initialize_led()) {
+    logger.error("Failed to initialize led!");
+    return;
+  }
+  // initialize the LCD
+  if (!tdongle.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // set the pixel buffer to be a full screen buffer
+  static constexpr size_t pixel_buffer_size = tdongle.lcd_width() * tdongle.lcd_height();
+  // initialize the LVGL display for the T-Dongle-S3
+  if (!tdongle.initialize_display(pixel_buffer_size)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+
+  // 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<std::mutex> lock(lvgl_mutex);
+                                             static auto rotation = LV_DISPLAY_ROTATION_0;
+                                             rotation = static_cast<lv_display_rotation_t>(
+                                                 (static_cast<int>(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);
+  float brightness = 5.0f; // 5% brightness
+  tdongle.led(hsv, brightness);
+
+  // set the background color to black
+  lv_obj_t *bg = lv_obj_create(lv_screen_active());
+  lv_obj_set_size(bg, tdongle.lcd_width(), tdongle.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Drawing circles\nto the screen.");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          // lock the display mutex
+                          std::lock_guard<std::mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                          .core_id = 1,
+                      }});
+  lv_task.start();
+
+  // set the display brightness to be 75%
+  tdongle.brightness(75.0f);
+
+  // make a task to constantly shift the hue of the LED
+  espp::Task led_task({.callback = [&](std::mutex &m, std::condition_variable &cv) -> bool {
+                         static float hue = 0.0f;
+                         hue += 1.0f;
+                         if (hue >= 360.0f) {
+                           hue = 0.0f;
+                         }
+                         espp::Hsv hsv(hue, 1.0f, 1.0f);
+                         espp::TDongleS3::get().led(hsv, brightness);
+                         std::unique_lock<std::mutex> lock(m);
+                         cv.wait_for(lock, 25ms);
+                         return false;
+                       },
+                       .task_config = {
+                           .name = "led_task",
+                       }});
+  led_task.start();
+
+  while (true) {
+    auto start = esp_timer_get_time();
+    // if there are 10 circles on the screen, clear them
+    static constexpr int max_circles = 10;
+    if (circles.size() >= max_circles) {
+      // lock the lvgl mutex
+      std::lock_guard<std::mutex> lock(lvgl_mutex);
+      clear_circles();
+    } else {
+      // draw a circle of circles on the screen (just draw the next circle)
+      static constexpr int middle_x = tdongle.lcd_width() / 2;
+      static constexpr int middle_y = tdongle.lcd_height() / 2;
+      static constexpr int radius = 30;
+      float angle = circles.size() * 2.0f * M_PI / max_circles;
+      int x = middle_x + radius * cos(angle);
+      int y = middle_y + radius * sin(angle);
+      // lock the lvgl mutex
+      std::lock_guard<std::mutex> lock(lvgl_mutex);
+      draw_circle(x, y, 5);
+    }
+    auto end = esp_timer_get_time();
+    auto elapsed = end - start;
+    std::this_thread::sleep_for(100ms - std::chrono::microseconds(elapsed));
+  }
+
+
+
+
+

Public Types

+
+
+using Pixel = lv_color16_t
+

Alias for the pixel type used by the T-Dongle-S3 display.

+
+ +
+
+

Public Functions

+
+
+bool initialize_led()
+

Initialize the RGB LED

+
+
Returns
+

true if the RGB LED was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<LedStrip> led() const
+

Get a shared pointer to the RGB LED

+
+
Returns
+

A shared pointer to the RGB LED

+
+
+
+ +
+
+bool led(const Hsv &hsv, float brightness = 100.0f)
+

Set the color of the LED

+
+
Parameters
+
    +
  • hsv – The color of the LED in HSV format

  • +
  • brightness – The brightness of the LED as a percentage (0 - 100)

  • +
+
+
Returns
+

true if the color was successfully set, false otherwise

+
+
+
+ +
+
+bool led(const Rgb &rgb, float brightness = 100.0f)
+

Set the color of the LED

+
+
Parameters
+
    +
  • rgb – The color of the LED in RGB format

  • +
  • brightness – The brightness of the LED as a percentage (0 - 100)

  • +
+
+
Returns
+

true if the color was successfully set, false otherwise

+
+
+
+ +
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline TDongleS3 &get()
+

Access the singleton instance of the TDongleS3 class.

+
+
Returns
+

Reference to the singleton instance of the TDongleS3 class

+
+
+
+ +
+
+static inline constexpr size_t num_leds()
+

Get the number of LEDs in the strip

+
+
Returns
+

The number of LEDs in the strip

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/t_dongle_s3_example.html b/t_dongle_s3_example.html new file mode 100644 index 000000000..e08337696 --- /dev/null +++ b/t_dongle_s3_example.html @@ -0,0 +1,317 @@ + + + + + + + T-Dongle-S3 Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

T-Dongle-S3 Example

+

This example shows how to use the espp::TDongleS3 hardware abstraction component +initialize the components on the LilyGo T-Dongle-S3.

+

It initializes the touch, display, and t-keyboard subsystems. It reads the +touchpad state and each time you touch the screen it uses LVGL to draw a circle +where you touch. If you press the home button on the display, it will clear the +circles.

+

https://github.com/esp-cpp/espp/assets/213467/15f57640-d3bc-4a40-932c-d9309337301f

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the LilyGo T-Dongle +S3 dev board which has:

+
    +
  • WiFi / BLE

  • +
  • uSD card (hidden in the USB A connector!)

  • +
  • RGB LED

  • +
  • Color TFT LCD (ST7735, 80x160 0.96” IPS LCD)

  • +
+
+

T-Dongle S3 Pin Configuration

+ + + + + + + + + + + + + + +

LED Pin

ESP32S3 IO Pin Number

Data

40

Clock

39

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

LCD Pin

ESP32S3 IO Pin Number

CS

4

SDA

3

SCL

5

DC

2

Reset

1

Backlight

38

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

TF / uSD Card Pin

ESP32S3 IO Pin Number

D0

14

D1

17

D2

21

D3

18

CLK

12

CMD

16

+
+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-06 at 20 12 35@2x

+

image

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/tabulate.html b/tabulate.html new file mode 100644 index 000000000..e7e0b87c1 --- /dev/null +++ b/tabulate.html @@ -0,0 +1,553 @@ + + + + + + + Tabulate APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Tabulate APIs

+

The tabulate.hpp header provides a convenience include / wrapper around +p-ranav/tabulate. It also exposes +tabulate’s include folder, so including tabulate.hpp is completely +equivalent to including both tabulate/table.hpp. Please see the documentation +for tabulate if you have any questions about usage beyond the examples provided +here.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Macros

+
+
+__unix__
+
+ +
+
+

Classes

+
+
+class __tabulate_documentation__
+

Table maker for modern c++ convenience wrapper around p-ranav/tabulate which exposes tabulate::Table for creating human-readable tables in console/terminal applications.

+
+

Tabulate Example

+
  using namespace tabulate;
+  using Row_t = Table::Row_t;
+
+  Table universal_constants;
+
+  universal_constants.add_row({"Quantity", "Value"});
+  universal_constants.add_row({"Characteristic impedance of vacuum", "376.730 313 461... Ω"});
+  universal_constants.add_row(
+      {"Electric constant (permittivity of free space)", "8.854 187 817... × 10⁻¹²F·m⁻¹"});
+  universal_constants.add_row({"Magnetic constant (permeability of free space)",
+                               "4π × 10⁻⁷ N·A⁻² = 1.2566 370 614... × 10⁻⁶ N·A⁻²"});
+  universal_constants.add_row({"Gravitational constant (Newtonian constant of gravitation)",
+                               "6.6742(10) × 10⁻¹¹m³·kg⁻¹·s⁻²"});
+  universal_constants.add_row({"Planck's constant", "6.626 0693(11) × 10⁻³⁴ J·s"});
+  universal_constants.add_row({"Dirac's constant", "1.054 571 68(18) × 10⁻³⁴ J·s"});
+  universal_constants.add_row({"Speed of light in vacuum", "299 792 458 m·s⁻¹"});
+
+  universal_constants.format()
+      .font_style({FontStyle::bold})
+      .border_top(" ")
+      .border_bottom(" ")
+      .border_left(" ")
+      .border_right(" ")
+      .corner(" ");
+
+  universal_constants[0]
+      .format()
+      .padding_top(1)
+      .padding_bottom(1)
+      .font_align(FontAlign::center)
+      .font_style({FontStyle::underline})
+      .font_background_color(Color::red);
+
+  universal_constants.column(1).format().font_color(Color::yellow);
+
+  universal_constants[0][1].format().font_background_color(Color::blue).font_color(Color::white);
+
+  std::cout << universal_constants << std::endl << std::endl;
+
+
+
+
+

Tabulate to Markdown Example

+
  using namespace tabulate;
+  Table movies;
+  movies.add_row({"S/N", "Movie Name", "Director", "Estimated Budget", "Release Date"});
+  movies.add_row({"tt1979376", "Toy Story 4", "Josh Cooley", "$200,000,000", "21 June 2019"});
+  movies.add_row({"tt3263904", "Sully", "Clint Eastwood", "$60,000,000", "9 September 2016"});
+  movies.add_row(
+      {"tt1535109", "Captain Phillips", "Paul Greengrass", "$55,000,000", " 11 October 2013"});
+
+  // center align 'Director' column
+  movies.column(2).format().font_align(FontAlign::center);
+
+  // right align 'Estimated Budget' column
+  movies.column(3).format().font_align(FontAlign::right);
+
+  // right align 'Release Date' column
+  movies.column(4).format().font_align(FontAlign::right);
+
+  // Color header cells
+  for (size_t i = 0; i < 5; ++i) {
+    movies[0][i].format().font_color(Color::yellow).font_style({FontStyle::bold});
+  }
+
+  // Export to Markdown
+  fmt::print("Exporting to Markdown...\n");
+  MarkdownExporter exporter;
+  auto markdown = exporter.dump(movies);
+
+  // tabulate::table
+  std::cout << "Tabulate movie table:\n";
+  std::cout << movies << "\n\n";
+
+  // Exported Markdown
+  std::cout << "Markdown movie table:\n";
+  std::cout << markdown << std::endl << std::endl;
+
+
+
+
+

Complex Tabulate Example

+
  using namespace tabulate;
+  using Row_t = Table::Row_t;
+
+  Table readme;
+  readme.format().border_color(Color::yellow);
+
+  readme.add_row(Row_t{"🔥tabulate for Modern C++🔥"});
+  readme[0].format().font_align(FontAlign::center).font_color(Color::yellow);
+
+  readme.add_row(Row_t{"https://github.com/p-ranav/tabulate"});
+  readme[1]
+      .format()
+      .font_align(FontAlign::center)
+      .font_style({FontStyle::underline, FontStyle::italic})
+      .font_color(Color::white)
+      .hide_border_top();
+
+  readme.add_row(Row_t{"Tabulate is a header-only library for printing aligned, formatted, and "
+                       "colorized tables in Modern C++"});
+  readme[2].format().font_style({FontStyle::italic}).font_color(Color::magenta);
+
+  Table highlights;
+  highlights.add_row(Row_t{"Header-only Library", "Requires C++17", "MIT License"});
+  readme.add_row(Row_t{highlights});
+  readme[3].format().font_align(FontAlign::center).hide_border_top();
+
+  Table empty_row;
+  empty_row.format().hide_border();
+  readme.add_row(Row_t{empty_row});
+  readme[4].format().hide_border_left().hide_border_right();
+
+  readme.add_row(Row_t{"Easily format and align content within cells"});
+  readme[5].format().font_align(FontAlign::center);
+
+  Table format;
+  format.add_row(Row_t{"Horizontal Alignment", "Left aligned", "Center aligned", "Right aligned"});
+  format[0].format().font_align(FontAlign::center);
+  format[0][0].format().font_color(Color::green).column_separator(":");
+
+  format.column(1).format().width(25).font_align(FontAlign::left);
+  format.column(2).format().width(25).font_align(FontAlign::center);
+  format.column(3).format().width(25).font_align(FontAlign::right);
+
+  format.add_row({"Word-Wrapping algorithm taking shamelessly from StackOverflow",
+                  "Long sentences automatically word-wrap based on the width of the "
+                  "column",
+                  "Word-wrapping also plays nicely with alignment rules. For instance, "
+                  "this cell is center "
+                  "aligned.",
+                  "Enforce \ncustom word-wrapping \nby embedding '\\n' \ncharacters in "
+                  "your cell\n content."});
+  format[1][0].format().font_align(FontAlign::center);
+  format[1][2].format().font_align(FontAlign::center);
+  format[1][3].format().font_align(FontAlign::right);
+
+  format.column(0).format().width(23);
+  format.column(1).format().border_left(":");
+
+  readme.add_row(Row_t{format});
+
+  readme[5]
+      .format()
+      .border_color(Color::green)
+      .font_color(Color::cyan)
+      .font_style({FontStyle::underline})
+      .padding_top(0)
+      .padding_bottom(0);
+
+  readme[6].format().hide_border_top().padding_top(0);
+
+  readme.add_row(Row_t{empty_row});
+  readme[7].format().hide_border_left().hide_border_right();
+
+  Table embedded_table;
+  embedded_table.add_row(
+      {"You can even\n embed tables...",
+       Table().add_row({"within tables",
+                        Table().add_row({"within tables",
+                                         Table().add_row(Row_t{
+                                             "within tables",
+                                             Table().add_row(Row_t{"within tables.. "})})})})});
+
+  readme.add_row(Row_t{"Nested Representations"});
+  readme[8].format().font_align(FontAlign::center);
+
+  readme.add_row(Row_t{embedded_table});
+
+  readme[9].format().hide_border_top().border_color(Color::white).font_color(Color::yellow);
+
+  readme.add_row(Row_t{"ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ "
+                       "ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ "
+                       "ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ"});
+  readme[10]
+      .format()
+      .font_background_color(Color::red)
+      .hide_border_top()
+      .multi_byte_characters(true);
+
+  // Print the table
+  std::cout << readme << "\n\n";
+
+// NOTE: the below chart / table takes too much memory to run on the ESP32
+// because it has a lot of rows and columns. Enable the below code to run it on
+// an ESP system which has external PSRAM enabled.
+#if 0
+  Table chart;
+  chart.format()
+      .font_color(Color::white)
+      .padding_left(0)
+      .padding_right(0)
+      .column_separator("")
+      .hide_border();
+
+  for (size_t i = 0; i < 9; ++i) {
+    Row_t row;
+    row.push_back(std::to_string(90 - i * 10));
+    for (size_t j = 0; j <= 50; ++j) {
+      row.push_back(" ");
+    }
+    chart.add_row(row);
+  }
+
+  Row_t row;
+  for (int i = 0; i <= 12; ++i) {
+    if ((i + 1) % 4 == 0) {
+      row.push_back(std::to_string(i + 1));
+    } else {
+      row.push_back(" ");
+    }
+  }
+  chart.add_row(row);
+  chart.add_row(Row_t{});
+
+  chart.column(0).format().padding_left(1).padding_right(1).border_left(" ");
+
+  for (size_t i = 1; i <= 18; ++i) {
+    chart.column(i).format().width(2);
+  }
+
+  chart.column(2).format().border_color(Color::white).border_left("|").border_top("-");
+  chart.column(2)[8].format().background_color(Color::red);
+  chart.column(2)[7].format().background_color(Color::red);
+
+  chart.column(3)[8].format().background_color(Color::yellow);
+  chart.column(3)[7].format().background_color(Color::yellow);
+  chart.column(3)[6].format().background_color(Color::yellow);
+
+  chart.column(6)[8].format().background_color(Color::red);
+  chart.column(6)[7].format().background_color(Color::red);
+  chart.column(6)[6].format().background_color(Color::red);
+  chart.column(6)[5].format().background_color(Color::red);
+
+  chart.column(7)[8].format().background_color(Color::yellow);
+  chart.column(7)[7].format().background_color(Color::yellow);
+  chart.column(7)[6].format().background_color(Color::yellow);
+  chart.column(7)[5].format().background_color(Color::yellow);
+  chart.column(7)[4].format().background_color(Color::yellow);
+
+  chart.column(10)[8].format().background_color(Color::red);
+  chart.column(10)[7].format().background_color(Color::red);
+  chart.column(10)[6].format().background_color(Color::red);
+  chart.column(10)[5].format().background_color(Color::red);
+  chart.column(10)[4].format().background_color(Color::red);
+  chart.column(10)[3].format().background_color(Color::red);
+
+  chart.column(11)[8].format().background_color(Color::yellow);
+  chart.column(11)[7].format().background_color(Color::yellow);
+  chart.column(11)[6].format().background_color(Color::yellow);
+  chart.column(11)[5].format().background_color(Color::yellow);
+  chart.column(11)[4].format().background_color(Color::yellow);
+  chart.column(11)[3].format().background_color(Color::yellow);
+  chart.column(11)[2].format().background_color(Color::yellow);
+  chart.column(11)[1].format().background_color(Color::yellow);
+
+  chart[2][15].format().background_color(Color::red);
+  chart[2][16].set_text("Batch 1");
+  chart.column(16).format().padding_left(1).width(20);
+
+  chart[4][15].format().background_color(Color::yellow);
+  chart[4][16].set_text("Batch 2");
+
+  Table legend;
+  legend.add_row(Row_t{"Batch 1", "10", "40", "50", "20", "10", "50"});
+  legend.add_row(Row_t{"Batch 2", "30", "60", "(70)", "50", "40", "30"});
+
+  legend[0].format().font_align(FontAlign::center);
+  legend[1].format().font_align(FontAlign::center);
+
+  legend.column(0)
+      .format()
+      .font_align(FontAlign::right)
+      .font_color(Color::green)
+      .font_background_color(Color::grey);
+
+  legend.column(2).format().font_color(Color::white).font_background_color(Color::red);
+
+  legend[1][3].format().font_style({FontStyle::italic}).font_color(Color::yellow);
+
+  chart.column(17).format().width(50);
+
+  chart[4][17].set_text("Cells, rows, and columns");
+  chart[5][17].set_text("can be independently formatted.");
+  chart[7][17].set_text("This cell is green and italic");
+  chart[7][17].format().color(Color::green).font_style({FontStyle::italic});
+
+  chart[8][17].set_text("This one's yellow and right-aligned");
+  chart[8][17].format().color(Color::yellow).font_align(FontAlign::right);
+
+  chart[9][17].set_text("This one's on 🔥🔥🔥");
+
+  std::cout << chart;
+  std::cout << legend << "\n\n";
+#endif
+
+
+
+
+

Note

+

This class does not really exist or do anything, but it’s the only way I could figure out how to get this documentation built into the system :(

+
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/tabulate_example.html b/tabulate_example.html new file mode 100644 index 000000000..afcb6d585 --- /dev/null +++ b/tabulate_example.html @@ -0,0 +1,227 @@ + + + + + + + Tabulate Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Tabulate Example

+

This example shows the use of the tabulate component to easily create and +pretty print tables to the console.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

image

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/task.html b/task.html new file mode 100644 index 000000000..c0f8e07c6 --- /dev/null +++ b/task.html @@ -0,0 +1,1114 @@ + + + + + + + Task APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Task APIs

+
+

Task

+

The Task component provides a cross-platform API around std::thread with +some additional configuration of stack size, priority, and core affinity for +FreeRTOS / ESP, as well as providing a callback API which enables interruptible +sleeps and termination of the task.

+

Code examples for the task API are provided in the task example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Task : public espp::BaseComponent
+

Task provides an abstraction over std::thread which optionally includes memory / priority configuration on ESP systems. It allows users to easily stop the task, and will automatically stop itself if destroyed.

+

There is also a utility function which can be used to get the info for the task of the current context, or for a provided Task object.

+

There is also a helper function to run a lambda on a specific core, which can be used to run a specific function on a specific core, as you might want to do when registering an interrupt driver on a specific core.

+
+

Basic Task Example

+
    espp::Task::configure_task_watchdog(1000ms);
+    auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
+      static size_t task_iterations{0};
+      fmt::print("Task: #iterations = {}\n", task_iterations);
+      task_iterations++;
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Task 1"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+    task.start_watchdog(); // start the watchdog timer for this task
+    std::this_thread::sleep_for(num_seconds_to_run * 1s);
+    task.stop_watchdog(); // stop the watchdog timer for this task
+    // show explicitly stopping the task (though the destructor called at the
+    // end of this scope would do it for us)
+    task.stop();
+    std::error_code ec;
+    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
+    if (ec) {
+      fmt::print("Error getting watchdog info: {}\n", ec.message());
+    } else if (!watchdog_info.empty()) {
+      fmt::print("Watchdog info: {}\n", watchdog_info);
+    } else {
+      fmt::print("No watchdog info available\n");
+    }
+
+
+
+
+

Task Watchdog Example

+
    static constexpr bool panic_on_watchdog_timeout = false;
+    espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);
+    auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
+      static size_t task_iterations{0};
+      fmt::print("Task: #iterations = {}\n", task_iterations);
+      task_iterations++;
+      std::unique_lock<std::mutex> lk(m);
+      // note our sleep here is longer than the watchdog timeout, so we should
+      // trigger the watchdog timeout
+      cv.wait_for(lk, 500ms);
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Task 1"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+    task.start_watchdog(); // start the watchdog timer for this task
+    std::this_thread::sleep_for(500ms);
+    std::error_code ec;
+    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
+    if (ec) {
+      fmt::print("Error getting watchdog info: {}\n", ec.message());
+    } else if (!watchdog_info.empty()) {
+      fmt::print("Watchdog info: {}\n", watchdog_info);
+    } else {
+      fmt::print("No watchdog info available\n");
+    }
+    // NOTE: the task and the watchdog will both automatically get stopped when
+    // the task goes out of scope and is destroyed.
+
+
+
+
+

Many Task Example

+
    std::vector<std::unique_ptr<espp::Task>> tasks;
+    size_t num_tasks = 10;
+    logger.info("Many task example: spawning {} tasks!", num_tasks);
+    tasks.resize(num_tasks);
+    auto start = std::chrono::high_resolution_clock::now();
+    for (size_t i = 0; i < num_tasks; i++) {
+      size_t iterations{0};
+      // copy the loop variables and indicate that we intend to mutate them!
+      auto task_fn = [i, iterations](std::mutex &m, std::condition_variable &cv) mutable {
+        fmt::print("Task {}: #iterations = {}\n", i, iterations);
+        iterations++;
+        // NOTE: sleeping in this way allows the sleep to exit early when the
+        // task is being stopped / destroyed
+        {
+          std::unique_lock<std::mutex> lk(m);
+          cv.wait_for(lk, 1s);
+        }
+        // we don't want to stop, so return false
+        return false;
+      };
+      std::string task_name = fmt::format("Task {}", i);
+      auto task =
+          espp::Task::make_unique({.callback = task_fn, .task_config = {.name = task_name}});
+      tasks[i] = std::move(task);
+      tasks[i]->start();
+    }
+    fmt::print("Tasks spawned, waiting for {} seconds!\n", num_seconds_to_run);
+    std::this_thread::sleep_until(start + num_seconds_to_run * 1s);
+
+
+
+
+

Long Running Task Example

+
    auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
+      static size_t task_iterations{0};
+      const size_t num_steps_per_iteration = 10;
+      fmt::print("Task processing iteration {}...\n", task_iterations);
+      for (size_t i = 0; i < num_steps_per_iteration; i++) {
+        // NOTE: sleeping in this way allows the sleep to exit early when the
+        // task is being stopped / destroyed
+        {
+          std::unique_lock<std::mutex> lk(m);
+          // NOTE: using the return value from the cv.wait_for() allows us to
+          // know if the task was asked to stop, for which we can handle and
+          // return early.
+          auto cv_retval = cv.wait_for(lk, std::chrono::milliseconds(100));
+          if (cv_retval == std::cv_status::no_timeout) {
+            // if there was no timeout, then we were notified, therefore we need
+            // to shut down.
+            fmt::print("Task stopping early (step {}/{}) on iteration {}\n", i,
+                       num_steps_per_iteration, task_iterations);
+            // NOTE: use this_thread::sleep_for() to fake cleaning up work that
+            // we would do
+            std::this_thread::sleep_for(10ms);
+            // now that we've (fake) cleaned-up our work, return from the task
+            // function so the task can fully destruct.
+            return false;
+          }
+        }
+      }
+      fmt::print("Task processing iteration {} complete\n", task_iterations);
+      task_iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Complex Task"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+
+
+
+
+

Long Running Task Notified Example (Recommended)

+
    auto task_fn = [](std::mutex &m, std::condition_variable &cv, bool &task_notified) {
+      static size_t task_iterations{0};
+      const size_t num_steps_per_iteration = 10;
+      fmt::print("Task processing iteration {}...\n", task_iterations);
+      for (size_t i = 0; i < num_steps_per_iteration; i++) {
+        // NOTE: sleeping in this way allows the sleep to exit early when the
+        // task is being stopped / destroyed
+        {
+          std::unique_lock<std::mutex> lk(m);
+          // NOTE: using the return value from the cv.wait_for() allows us to
+          // know if the task was asked to stop, for which we can handle and
+          // return early.
+          auto stop_requested = cv.wait_for(lk, std::chrono::milliseconds(100),
+                                            [&task_notified] { return task_notified; });
+          if (stop_requested) {
+            fmt::print("Task was notified, stopping early (step {}/{}) on iteration {}\n", i,
+                       num_steps_per_iteration, task_iterations);
+            // NOTE: use this_thread::sleep_for() to fake cleaning up work that
+            // we would do
+            std::this_thread::sleep_for(10ms);
+            // now that we've (fake) cleaned-up our work, return from the task
+            // function so the task can fully destruct.
+            return false;
+          }
+        }
+      }
+      fmt::print("Task processing iteration {} complete\n", task_iterations);
+      task_iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "Notified Complex Task"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+
+
+
+
+

Task Info Example

+
    auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
+      static size_t task_iterations{0};
+      task_iterations++;
+      // allocate stack
+      size_t num_bytes = 256 * task_iterations;
+      char buffer[num_bytes];
+      // do something with the bufer (which also uses stack)
+      snprintf(buffer, num_bytes, "%.06f\n", (float)task_iterations);
+      fmt::print("{}\n", espp::Task::get_info());
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 500ms);
+      }
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "DynamicTask"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+    auto now = std::chrono::high_resolution_clock::now();
+    auto elapsed = std::chrono::duration<float>(now - test_start).count();
+    while (elapsed < num_seconds_to_run) {
+      std::this_thread::sleep_for(200ms);
+      now = std::chrono::high_resolution_clock::now();
+      elapsed = std::chrono::duration<float>(now - test_start).count();
+    }
+    fmt::print("Final: {}\n", espp::Task::get_info(task));
+
+
+
+
+

Task Request Stop Example

+
    auto task_fn = [&num_seconds_to_run](std::mutex &m, std::condition_variable &cv) {
+      static auto begin = std::chrono::high_resolution_clock::now();
+      auto now = std::chrono::high_resolution_clock::now();
+      auto elapsed = std::chrono::duration<float>(now - begin).count();
+      if (elapsed > num_seconds_to_run) {
+        // we've gone long enough, time to stop our task!
+        return true;
+      }
+      // NOTE: sleeping in this way allows the sleep to exit early when the
+      // task is being stopped / destroyed
+      {
+        std::unique_lock<std::mutex> lk(m);
+        cv.wait_for(lk, 10ms);
+      }
+      // we don't want to stop yet, so return false
+      return false;
+    };
+    auto task = espp::Task({.callback = task_fn,
+                            .task_config = {.name = "AutoStop Task"},
+                            .log_level = espp::Logger::Verbosity::DEBUG});
+    task.start();
+    while (task.is_started()) {
+      std::this_thread::sleep_for(10ms);
+    }
+
+
+
+
+

Run on Core Example

+
    logger.info("espp::task::run_on_core example: main thread core ID: {}", xPortGetCoreID());
+    // NOTE: in these examples, because we're logging with libfmt in the
+    // function to be run, we need a little more than the default 2k stack size,
+    // so we're using 3k.
+
+    // test running a function that returns void on a specific core
+    auto task_fn = []() -> void { fmt::print("Void Task running on core {}\n", xPortGetCoreID()); };
+    espp::task::run_on_core(task_fn, 0, 3 * 1024);
+    fmt::print("Void Function returned\n");
+    espp::task::run_on_core(task_fn, 1, 3 * 1024);
+    fmt::print("Void Function returned\n");
+
+    // test running a function that returns bool on a specific core
+    auto task_fn2 = []() -> bool {
+      auto core_id = xPortGetCoreID();
+      fmt::print("Bool Task running on core {}\n", core_id);
+      return core_id == 1;
+    };
+    auto result0 = espp::task::run_on_core(task_fn2, 0, 3 * 1024);
+    fmt::print("Bool Function returned {}\n", result0);
+    auto result1 = espp::task::run_on_core(
+        task_fn2, {.name = "test", .stack_size_bytes = 3 * 1024, .core_id = 1});
+    fmt::print("Bool Function returned {}\n", result1);
+
+    // test running a function that returns esp_err_t on a specific core
+    auto task_fn3 = []() -> esp_err_t {
+      auto core_id = xPortGetCoreID();
+      fmt::print("esp_err_t Task running on core {}\n", core_id);
+      return core_id == 1 ? ESP_OK : ESP_FAIL;
+    };
+    auto err0 = espp::task::run_on_core(task_fn3, 0, 3 * 1024);
+    fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err0));
+    auto err1 = espp::task::run_on_core(task_fn3, 1, 3 * 1024);
+    fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err1));
+
+
+
+
+

Run on Core (Non-Blocking) Example

+
    logger.info("espp::task::run_on_core non-blocking example: main thread core ID: {}",
+                xPortGetCoreID());
+    // NOTE: in these examples, because we're logging with libfmt in the
+    // function to be run, we need a little more than the default 2k stack size,
+    // so we're using 3k.
+
+    // test running a function which takes a while to complete
+    auto task_fn = []() -> void {
+      fmt::print("[{0}] Task running on core {0}\n", xPortGetCoreID());
+      std::this_thread::sleep_for(1s);
+      fmt::print("[{0}] Task done!\n", xPortGetCoreID());
+    };
+    espp::task::run_on_core_non_blocking(task_fn, 0, 3 * 1024);
+    espp::task::run_on_core_non_blocking(task_fn, {.name = "test", .core_id = 1});
+    fmt::print("Started tasks on cores 0 and 1\n");
+
+    // sleep for a bit to let the tasks run
+    std::this_thread::sleep_for(2s);
+
+
+
+
+

Public Types

+
+
+typedef std::function<bool(std::mutex &m, std::condition_variable &cv, bool &notified)> callback_m_cv_notified_fn
+

Task callback function signature.

+
+

Note

+

The callback is run repeatedly within the Task, therefore it MUST return, and also SHOULD have a sleep to give the processor over to other tasks. For this reason, the callback is provided a std::condition_variable (and associated mutex) which the callback can use when they need to wait. If the cv.wait_for / cv.wait_until return false, no action is necessary (as the timeout properly occurred / the task was not notified). If they return true, then the callback function should return immediately since the task is being stopped (optionally performing any task-specific tear-down).

+
+
+
Param m
+

mutex associated with the condition variable (should be locked before calling cv.wait_for() or cv.wait_until())

+
+
Param cv
+

condition variable the callback can use to perform an interruptible wait. Use the notified parameter as the predicate for the wait to ensure spurious wake-ups are properly ignored.

+
+
Param notified
+

Whether or not the task has been notified to stop. This is a reference to the task’s notified member, and is intended to be used with the condition variable parameter cv when waiting to avoid spurious wakeups. The task function is responsible for clearing this flag after each wait. Do not release the lock on the mutex m until the notified flag has been checked and cleared.

+
+
Return
+

Whether or not the callback’s thread / task should stop - True to stop, false to continue running.

+
+
+
+ +
+
+typedef std::function<bool(std::mutex &m, std::condition_variable &cv)> callback_m_cv_fn
+

Task callback function signature.

+
+

Note

+

The callback is run repeatedly within the Task, therefore it MUST return, and also SHOULD have a sleep to give the processor over to other tasks. For this reason, the callback is provided a std::condition_variable (and associated mutex) which the callback can use when they need to wait. If the cv.wait_for / cv.wait_until return std::cv_status::timeout, no action is necessary, but if they return std::cv_status::no_timeout, then the function should return immediately since the task is being stopped (optionally performing any task-specific tear-down).

+
+
+

Warning

+

This is an older callback function signature, and is kept for backwards compatibility. It is recommended to use the newer callback signature (callback_m_cv_notified_fn) which includes the notified parameter, enabling the task callback function to wait on the condition variable and ignore spurious wakeups.

+
+
+
Param m
+

mutex associated with the condition variable (should be locked before calling cv.wait_for() or cv.wait_until())

+
+
Param cv
+

condition variable the callback can use to perform an interruptible wait.

+
+
Return
+

Whether or not the callback’s thread / task should stop - True to stop, false to continue running.

+
+
+
+ +
+
+typedef std::function<bool()> callback_no_params_fn
+

Simple callback function signature.

+
+

Note

+

The callback is run repeatedly within the Task, therefore it MUST return, and also SHOULD have a sleep to give the processor over to other tasks.

+
+
+
Return
+

True to stop the task, false to continue running.

+
+
+
+ +
+
+typedef std::variant<callback_m_cv_notified_fn, callback_m_cv_fn, callback_no_params_fn> callback_variant
+

Variant of the callback function for the task.

+

+This is primarily used to enable simpler API upgrades in the future and maximize backwards compatibility.

+
+

Note

+

This is a std::variant of the different callback function signatures that can be used with the Task. This allows the Task to be configured with a callback function that takes no parameters, a callback function that takes a mutex and condition variable, or a callback function that takes a mutex, condition variable, and a bool reference to the notified flag.

+
+
+ +
+
+

Public Functions

+
+
+explicit Task(const espp::Task::Config &config)
+

Construct a new Task object using the Config struct.

+
+
Parameters
+

configConfig struct to initialize the Task with.

+
+
+
+ +
+
+~Task()
+

Destroy the task, stopping it if it was started.

+
+ +
+
+bool start()
+

Start executing the task.

+
+
Returns
+

true if the task started, false if it was already started.

+
+
+
+ +
+
+bool stop()
+

Stop the task execution.

+

This will request the task to stop, notify the condition variable, and (if this calling context is not the task context) join the thread.

+
+
Returns
+

true if the task stopped, false if it was not started / already stopped.

+
+
+
+ +
+
+bool is_started() const
+

Has the task been started or not?

+
+
Returns
+

true if the task is started / running, false otherwise.

+
+
+
+ +
+
+bool is_running() const
+

Is the task running?

+
+
Returns
+

true if the task is running, false otherwise.

+
+
+
+ +
+
+bool start_watchdog()
+

Start the task watchdog for this task.

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

true if the watchdog was started, false otherwise.

+
+
+
+ +
+
+bool stop_watchdog()
+

Stop the task watchdog for this task.

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

true if the watchdog was stopped, false otherwise.

+
+
+
+ +
+
+inline task_id_t get_id() const
+

Get the ID for this Task’s thread / task context.

+
+
Returns
+

ID for this Task’s thread / task context.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static std::unique_ptr<Task> make_unique(const espp::Task::Config &config)
+

Get a unique pointer to a new task created with config. Useful to not have to use templated std::make_unique (less typing).

+
+
Parameters
+

configConfig struct to initialize the Task with.

+
+
Returns
+

std::unique_ptr<Task> pointer to the newly created task.

+
+
+
+ +
+
+static bool configure_task_watchdog(uint32_t timeout_ms, bool panic_on_timeout = true)
+

Initialize/Configure the task watchdog for the current task.

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+

Note

+

This function will not monitor the idle tasks.

+
+
+

Note

+

If the watchdog has not been configured, then this function will call esp_task_wdt_init, otherwise it will then call esp_task_wdt_reconfigure.

+
+
+
Parameters
+
    +
  • timeout_ms – Timeout in milliseconds for the watchdog.

  • +
  • panic_on_timeout – Whether or not to panic on timeout.

  • +
+
+
Returns
+

true if the watchdog was initialized, false otherwise.

+
+
+
+ +
+
+static bool configure_task_watchdog(const std::chrono::milliseconds &timeout, bool panic_on_timeout = true)
+

Initialize/Configure the task watchdog for the current task.

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+

Note

+

This function will not monitor the idle tasks.

+
+
+

Note

+

If the watchdog has not been configured, then this function will call esp_task_wdt_init, otherwise it will then call esp_task_wdt_reconfigure.

+
+
+
Parameters
+
    +
  • timeout – The timeout for the watchdog.

  • +
  • panic_on_timeout – Whether or not to panic on timeout.

  • +
+
+
Returns
+

true if the watchdog was initialized, false otherwise.

+
+
+
+ +
+
+static std::string get_watchdog_info(std::error_code &ec)
+

Retrieve the info about tasks / users which triggered the task watchdog timeout.

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+

Note

+

This function will only return info for tasks which are still registered with the watchdog. If you call this after you have called stop_watchdog() for a task, then even if the task triggered the watchdog timeout you will not get that information.

+
+
+
Parameters
+

ec – Error code to set if there was an error retrieving the info.

+
+
Returns
+

std::string containing the task watchdog info, or an empty string if there was no timeout or there was an error retrieving the info.

+
+
+
+ +
+
+static std::string get_info()
+

Get the info (as a string) for the task of the current context.

+
+

Note

+

This function is only available on ESP

+
+
+
Returns
+

std::string containing name, core ID, priority, and stack high water mark (B)

+
+
+
+ +
+
+static std::string get_info(const Task &task)
+

Get the info (as a string) for the provided task.

+
+

Note

+

This function is only available on ESP

+
+
+
Parameters
+

task – Reference to the task for which you want the information.

+
+
Returns
+

std::string containing name, core ID, priority, and stack high water mark (B)

+
+
+
+ +
+
+static inline task_id_t get_current_id()
+

Get the ID for the current thread / task context.

+
+
Returns
+

ID for the current thread / task context.

+
+
+
+ +
+
+
+struct BaseConfig
+

Base configuration struct for the Task.

+
+

Note

+

This is designed to be used as a configuration struct in other classes that may have a Task as a member.

+
+
+

Public Members

+
+
+std::string name
+

Name of the task

+
+ +
+
+size_t stack_size_bytes = {4096}
+

Stack Size (B) allocated to the task.

+
+ +
+
+size_t priority = {0}
+

Priority of the task, 0 is lowest priority on ESP / FreeRTOS.

+
+ +
+
+int core_id = {-1}
+

Core ID of the task, -1 means it is not pinned to any core.

+
+ +
+
+ +
+
+struct Config
+

Configuration struct for the Task. Can be initialized with any of the supported callback function signatures.

+
+

Public Members

+
+
+espp::Task::callback_variant callback
+

Callback function

+
+ +
+
+espp::Task::BaseConfig task_config
+

Base configuration for the task.

+
+ +
+
+espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}
+

Log verbosity for the task.

+
+ +
+
+ +
+ +
+
+

Header File

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/task_example.html b/task_example.html new file mode 100644 index 000000000..6d0610fa0 --- /dev/null +++ b/task_example.html @@ -0,0 +1,228 @@ + + + + + + + Task Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Task Example

+

This example shows some various different ways of starting and stopping tasks, +as well as examples of how to wait, block, exit early, and run long-running +computations within tasks using the task component.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-11-19 at 16 21 48

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/thermistor.html b/thermistor.html new file mode 100644 index 000000000..78a4113f2 --- /dev/null +++ b/thermistor.html @@ -0,0 +1,684 @@ + + + + + + + Thermistor APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Thermistor APIs

+

The Thermistor APIs provide a set of functions to read the temperature from a +thermistor. The thermistor stores the relevant information (from the datasheet) +such as the B value, the nominal resistance, circuit configuration (upper or +lower part of the voltage divider), the fixed resistor value, and the supply +voltage.

+

It uses these data to compute the measured resistance of the thermistor, from +which the temperature can then be calculated using the Steinhart-Hart equation. +See the Wikipedia article for more +information.

+

Using the Steinhart-Hart equation, the temperature can be calculated using the +following formula:

+
+\[\begin{split}T = \frac{1}{\frac{1}{T_0} + \frac{1}{B} \\ln \frac{R}{R_0}}\end{split}\]
+

where:

+
    +
  • \(T\) is the temperature in Kelvin

  • +
  • \(T_0\) is the nominal temperature in Kelvin (e.g. 298.15 K, 25 °C)

  • +
  • \(B\) is the B (beta) value of the thermistor (e.g. 3950 K)

  • +
  • \(R\) is the resistance of the thermistor, measured in Ohm

  • +
  • \(R_0\) is the nominal resistance of the thermistor (e.g. 10000 Ohm at 25 °C)

  • +
+

Note: the thermistor component assumes that the thermistor is used within a +voltage divider circuit, with a fixed resistor. The component can be configured +so that either the thermistor or the fixed resistor is the upper part of the +voltage divider.

+ +
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Thermistor : public espp::BaseComponent
+

Thermistor class.

+

Reads voltage from a thermistor and converts it to temperature using the Steinhart-Hart equation. This class is designed to be used with a NTC (negative temperature coefficient) thermistor in a voltage divider configuration.

+

+
+

Validation Example

+
    // create a lambda function for getting the voltage from the thermistor
+    // this is just a simple voltage divider
+    auto compute_voltage = [](float r1, float r2 = 10000, float v_in = 3300.0) -> float {
+      return v_in * (r2 / (r1 + r2));
+    };
+
+    // create a table of datasheet info for the thermistor
+    // this is used to calculate the temperature
+    // the first value is the temperature in C
+    // the second value is the resistance scale factor (R/R0)
+    // This data is from the datasheet for the thermistor
+    // https://product.tdk.com/system/files/dam/doc/product/sensor/ntc/chip-ntc-thermistor/data_sheet/50/db/ntc/ntc_smd_standard_series_0402.pdf
+    // we chose a 10k NTC, which corresponds to the 8502 series column on
+    // page 5 of the datasheet
+    auto datasheet_info = std::vector<std::tuple<float, float>>{
+        {0, 3.2657},  {10, 1.9907}, {20, 1.2494}, {25, 1},        {30, .80552},
+        {40, .53229}, {50, .35981}, {75, .14763}, {100, .067488},
+    };
+
+    int i = 0;
+    // create a lambda function for getting the voltage from the thermistor
+    // using the datasheet info, this will return the voltage for the
+    // current temperature (based on the index)
+    auto get_voltage = [&compute_voltage, &i, &datasheet_info]() -> float {
+      auto [temp, r_scale] = datasheet_info[i];
+      return compute_voltage(r_scale * 10000);
+    };
+
+    // create a thermistor object
+    espp::Thermistor thermistor({.divider_config = espp::Thermistor::ResistorDividerConfig::UPPER,
+                                 .beta = 3940, // 25/50C beta since we're not planning on hot temps
+                                 .nominal_resistance_ohms = 10000,
+                                 .fixed_resistance_ohms = 10000,
+                                 .supply_mv = 3300,
+                                 .read_mv = get_voltage,
+                                 .log_level = espp::Logger::Verbosity::INFO});
+
+    // see how bad the error is
+    for (i = 0; i < datasheet_info.size(); i++) {
+      auto [actual_celsius, r_scale] = datasheet_info[i];
+      auto actual_kelvin = actual_celsius + 273.15;
+      // read the temperature
+      auto kelvin = thermistor.get_kelvin();
+      auto celsius = thermistor.get_celsius();
+      // use kelvin for calculating error so we don't have to worry about division by zero
+      auto error = std::abs(kelvin - actual_kelvin);
+      logger.info("measured voltage: {:.2f} mV, calculated resistance: {:.2f} Ohm, calculated "
+                  "temp: {:.2f} C, actual: {:.2f} C; error: {:.2f} C",
+                  get_voltage(), thermistor.get_resistance(), celsius, actual_celsius, error);
+    }
+
+
+
+
+

ADC Example

+
  // create a continuous ADC which will sample and filter the thermistor
+  // voltage on ADC1 channel 7
+  std::vector<espp::AdcConfig> channels{
+      {.unit = ADC_UNIT_1, .channel = ADC_CHANNEL_7, .attenuation = ADC_ATTEN_DB_11}};
+  // this initailizes the DMA and filter task for the continuous adc
+  espp::ContinuousAdc adc(
+      {.sample_rate_hz = 20 * 1000,
+       .channels = channels,
+       .convert_mode = ADC_CONV_SINGLE_UNIT_1, // or BOTH_UNIT, ALTER_UNIT, SINGLE_UNIT_1
+       .window_size_bytes = 1024,
+       .log_level = espp::Logger::Verbosity::WARN});
+  adc.start();
+
+  // make a lambda function for getting the latest voltage from the adc
+  auto get_voltage = [&adc, &channels]() -> float {
+    auto maybe_mv = adc.get_mv(channels[0]);
+    if (maybe_mv.has_value()) {
+      return maybe_mv.value();
+    } else {
+      return 0;
+    }
+  };
+
+  // create a thermistor object (based on the datasheet from
+  // https://product.tdk.com/system/files/dam/doc/product/sensor/ntc/chip-ntc-thermistor/catalog/tpd_commercial_ntc-thermistor_ntcg_en.pdf
+  // From the table (page 7):
+  // clang-format off
+  // Part Number.    | R25(Ω) | Tolerance | B25/50(Κ) | B25/75(Κ) | B25/85(Κ) | B25/100(K) | Current (mA) | Operating Temp Range
+  // NTCG103JF103FT1 | 10,000 |   +/–1%   | 3380      | 3422      | 3435      | 3453 +/–1% | 0.31         | –40 to 152
+  // clang-format on
+  espp::Thermistor thermistor({.divider_config = espp::Thermistor::ResistorDividerConfig::UPPER,
+                               .beta = 3380,
+                               .nominal_resistance_ohms = 10000,
+                               .fixed_resistance_ohms = 10000,
+                               .supply_mv = 3300,
+                               .read_mv = get_voltage,
+                               .log_level = espp::Logger::Verbosity::INFO});
+
+  fmt::print("% time(s), temp(C)\n");
+  auto task_fn = [&thermistor](std::mutex &m, std::condition_variable &cv) {
+    static auto start = std::chrono::high_resolution_clock::now();
+    auto now = std::chrono::high_resolution_clock::now();
+    float elapsed = std::chrono::duration<float>(now - start).count();
+
+    // read the temperature
+    auto temp = thermistor.get_celsius();
+
+    // print out the temperature
+    fmt::print("{:.3f}, {}\n", elapsed, temp);
+
+    // NOTE: sleeping in this way allows the sleep to exit early when the
+    // task is being stopped / destroyed
+    {
+      std::unique_lock<std::mutex> lk(m);
+      cv.wait_until(lk, now + 10ms);
+    }
+    // don't want to stop the task
+    return false;
+  };
+  auto task = espp::Task({.callback = task_fn,
+                          .task_config = {.name = "Read Thermistor"},
+                          .log_level = espp::Logger::Verbosity::INFO});
+  task.start();
+
+
+
+
+

Public Types

+
+
+enum class ResistorDividerConfig
+

Enum for resistor divider configuration.

+

Values:

+
+
+enumerator LOWER
+

Thermistor is the lower resistor.

+
+ +
+
+enumerator UPPER
+

Thermistor is the upper resistor.

+
+ +
+ +
+
+typedef std::function<float(void)> read_mv_fn
+

Function type for reading voltage.

+
+
Return
+

Voltage in millivolts

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit Thermistor(const Config &config)
+

Constructor.

+
+
Parameters
+

config – Configuration struct

+
+
+
+ +
+
+inline float get_resistance()
+

Get resistance of the thermistor.

+

+Reads the voltage from the thermistor and converts it to resistance

+
+
Returns
+

Resistance of the thermistor in ohms

+
+
+
+ +
+
+inline float get_kelvin()
+

Get the temperature in Kelvin.

+

+Reads the voltage from the thermistor and converts it to temperature using the Steinhart-Hart equation.

+
+
Returns
+

Temperature in Kelvin

+
+
+
+ +
+
+inline float get_celsius()
+

Get the temperature in Celsius.

+

+Reads the voltage from the thermistor and converts it to temperature using the Steinhart-Hart equation. The temperature is converted from Kelvin to Celsius.

+

See also

+

get_kelvin()

+
+

+
+
Returns
+

Temperature in Celsius

+
+
+
+ +
+
+inline float get_fahrenheit()
+

Get the temperature in Fahrenheit.

+

+Reads the voltage from the thermistor and converts it to temperature using the Steinhart-Hart equation. The temperature is converted from Kelvin to Fahrenheit.

+

See also

+

get_kelvin()

+
+

+
+
Returns
+

Temperature in Fahrenheit

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration struct for Thermistor.

+
+

Public Members

+
+
+ResistorDividerConfig divider_config
+

Resistor divider configuration.

+
+ +
+
+float beta
+

Beta coefficient of the thermistor at 25C, e.g. 3950.

+
+ +
+
+float nominal_resistance_ohms
+

Resistance of the thermistor (in ohms) at 25C, e.g. 10000.

+
+ +
+
+float fixed_resistance_ohms
+

Resistance of the fixed resistor in the voltage divider (in ohms), e.g. 10000

+
+ +
+
+float supply_mv
+

Supply voltage of the voltage divider (in mv), e.g. 3300.

+
+ +
+
+read_mv_fn read_mv
+

Function for reading voltage.

+
+ +
+
+Logger::Verbosity log_level = Logger::Verbosity::WARN
+

Log level for this class.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/thermistor_example.html b/thermistor_example.html new file mode 100644 index 000000000..6bfcfec93 --- /dev/null +++ b/thermistor_example.html @@ -0,0 +1,248 @@ + + + + + + + Thermistor Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Thermistor Example

+

This example shows how to use the thermistor component to compute the +temperature from a temperature sensitive resistor (thermistor) - specifically +negative temperature coefficient (NTC) thermistors.

+

The first part of the example does not need any hardware and simply shows how +to use the component to compute the temperature from the resistance of the +thermistor. The second part of the example shows how to use the component with +an ESP32 to compute the temperature from the voltage divider formed by the +thermistor and a fixed resistor.

+
+

How to use example

+
+
+

Hardware Required

+

To run this example, you need:

+
    +
  • An ESP32 dev board (e.g. ESP32-WROVER Kit, ESP32-S3-BOX, QtPy ESP32, etc.)

  • +
  • A thermistor (the NTC), such as this 10k NTC

  • +
  • A 10k resistor

  • +
  • A breadboard

  • +
  • Jumper wires

  • +
+

The example is configured so that the NTC is the top resistor in a voltage +divider, with the 10k resistor on the bottom. The voltage divider is connected +to the ADC1 channel 0 input of the ESP32.

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2023-06-08 at 09 26 27

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/timer.html b/timer.html new file mode 100644 index 000000000..4d1daf883 --- /dev/null +++ b/timer.html @@ -0,0 +1,1358 @@ + + + + + + + Timer APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Timer APIs

+
+

Timer

+

The Timer component provides a cross-platform API for executing callback +functions with a specified period. The timer can be started, stopped, and +restarted, and the timer can have an optional initial delay before the first +callback is executed. The timer can be configured to run once or repeatedly.

+

The timer API is implemented using the Task component, and the timer callback +is executed in the context of the timer task.

+

Code examples for the task API are provided in the timer example folder.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class Timer : public espp::BaseComponent
+

A timer that can be used to schedule tasks to run at a later time.

+

A timer can be used to schedule a task to run at a later time. The timer will run in the background and will call the task when the time is up. The timer can be canceled at any time. A timer can be configured to run once or to repeat.

+

The timer uses a task to run in the background. The task will sleep until the timer is ready to run. When the timer is ready to run, the task will call the callback function. The callback function can return true to cancel the timer or false to keep the timer running. If the timer is configured to repeat, then the callback function will be called again after the period has elapsed. If the timer is configured to run once, then the callback function will only be called once.

+

The timer can be configured to start automatically when it is constructed. If the timer is not configured to start automatically, then the timer can be started by calling start(). The timer can be canceled at any time by calling cancel().

+
+

Timer Example 1

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 500ms,
+                              .callback = timer_fn,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+
+
+
+
+

Timer Watchdog Example

+
    static constexpr bool panic_on_watchdog_timeout = false;
+    espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);
+    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 500ms,
+                              .callback = timer_fn,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+    timer.start_watchdog(); // start the watchdog timer for this timer
+    std::this_thread::sleep_for(500ms);
+    std::error_code ec;
+    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
+    if (ec) {
+      fmt::print("Error getting watchdog info: {}\n", ec.message());
+    } else if (!watchdog_info.empty()) {
+      fmt::print("Watchdog info: {}\n", watchdog_info);
+    } else {
+      fmt::print("No watchdog info available\n");
+    }
+    // NOTE: the timer and the watchdog will both automatically get stopped when
+    // the task goes out of scope and is destroyed.
+
+
+
+
+

Timer Delay Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer =
+        espp::Timer({.name = "Timer 1",
+                     .period = 500ms,
+                     .delay = 500ms,
+                     .callback = timer_fn,
+                     .auto_start = false, // don't start the timer automatically, we'll call start()
+                     .log_level = espp::Logger::Verbosity::DEBUG});
+    timer.start();
+    std::this_thread::sleep_for(2s);
+    logger.info("Cancelling timer for 2 seconds");
+    timer.cancel();
+    std::this_thread::sleep_for(2s);
+    timer.start();
+    std::this_thread::sleep_for(2s);
+    logger.info("Cancelling timer for 2 seconds");
+    timer.cancel();
+    std::this_thread::sleep_for(2s);
+    timer.start(1s);
+
+
+
+
+

Oneshot Timer Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 0ms, // one shot timer
+                              .delay = 500ms,
+                              .callback = timer_fn,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+
+
+
+
+

Timer Cancel Itself Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // cancel the timer after 3 iterations
+      if (iterations == 3) {
+        fmt::print("[{:.3f}] auto-cancelling timer\n", elapsed());
+        return true;
+      }
+      return false;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 500ms,
+                              .callback = timer_fn,
+                              .stack_size_bytes = 6192,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+
+
+
+
+

Oneshot Timer Cancel Itself Then Start again with Delay Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we want to stop, so return true
+      return true;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 0ms, // one shot timer
+                              .delay = 500ms,
+                              .callback = timer_fn,
+                              .stack_size_bytes = 4096,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+    std::this_thread::sleep_for(2s);
+    timer.cancel();  // it will have already been cancelled by here, but this should be harmless
+    timer.start(1s); // restart the timer with a 1 second delay
+
+
+
+
+

Timer Update Period Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer = espp::Timer({.name = "Timer 1",
+                              .period = 500ms,
+                              .callback = timer_fn,
+                              .stack_size_bytes = 4096,
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+    std::this_thread::sleep_for(2s);
+    logger.info("Updating period to 100ms");
+    timer.set_period(100ms);
+
+
+
+
+

Timer AdvancedConfig Example

+
    auto timer_fn = []() {
+      static size_t iterations{0};
+      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
+      iterations++;
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto timer = espp::Timer({.period = 500ms,
+                              .callback = timer_fn,
+                              .task_config =
+                                  {
+                                      .name = "Advanced Config Timer",
+                                      .stack_size_bytes = 4096,
+                                      .priority = 10,
+                                      .core_id = 1,
+                                  },
+                              .log_level = espp::Logger::Verbosity::DEBUG});
+
+
+
+
+

Note

+

The timer uses a task to run in the background, so the timer callback function will be called in the context of the task. The timer callback function should not block for a long time because it will block the task. If the timer callback function blocks for a long time, then the timer will not be able to keep up with the period.

+
+
+

Public Types

+
+
+typedef std::function<bool()> callback_fn
+

The callback function type. Return true to cancel the timer.

+
+ +
+
+

Public Functions

+
+
+explicit Timer(const Config &config)
+

Construct a new Timer object.

+
+
Parameters
+

config – The configuration for the timer.

+
+
+
+ +
+
+explicit Timer(const AdvancedConfig &config)
+

Construct a new Timer object.

+
+
Parameters
+

config – The configuration for the timer.

+
+
+
+ +
+
+~Timer()
+

Destroy the Timer object.

+

Cancels the timer if it is running.

+
+ +
+
+void start()
+

Start the timer.

+

Starts the timer. Does nothing if the timer is already running.

+
+ +
+
+void start(const std::chrono::duration<float> &delay)
+

Start the timer with a delay.

+

Starts the timer with a delay. If the timer is already running, this will cancel the timer and start it again with the new delay. If the timer is not running, this will start the timer with the delay. Overwrites any previous delay that might have been set.

+
+
Parameters
+

delay – The delay before the first execution of the timer callback.

+
+
+
+ +
+
+void stop()
+

Stop the timer, same as cancel().

+

Stops the timer, same as cancel().

+
+ +
+
+void cancel()
+

Cancel the timer.

+

Cancels the timer.

+
+ +
+
+bool start_watchdog()
+

Start the task watchdog for the timer.

+

+

See also

+

stop_watchdog()

+
+ +
+

See also

+

Task::stop_watchdog()

+
+

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

true if the watchdog was started, false otherwise.

+
+
+
+ +
+
+bool stop_watchdog()
+

Stop the task watchdog for the timer.

+

+

See also

+

start_watchdog()

+
+ +
+

See also

+

Task::stop_watchdog()

+
+

+
+

Note

+

This function is only available on ESP

+
+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

true if the watchdog was stopped, false otherwise.

+
+
+
+ +
+
+void set_period(const std::chrono::duration<float> &period)
+

Set the period of the timer.

+

Sets the period of the timer.

+
+

Note

+

If the period is 0, the timer will run once.

+
+
+

Note

+

If the period is negative, the period will not be set / updated.

+
+
+

Note

+

If the timer is running, the period will be updated after the current period has elapsed.

+
+
+
Parameters
+

period – The period of the timer.

+
+
+
+ +
+
+bool is_running() const
+

Check if the timer is running.

+

Checks if the timer is running.

+
+
Returns
+

true if the timer is running, false otherwise.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct AdvancedConfig
+

Advanced configuration for the timer.

+
+

Public Members

+
+
+std::chrono::duration<float> period
+

The period of the timer. If 0, the timer callback will only be called once.

+
+ +
+
+std::chrono::duration<float> delay = std::chrono::duration<float>(0)
+

The delay before the first execution of the timer callback after start() is called.

+
+ +
+
+espp::Timer::callback_fn callback
+

The callback function to call when the timer expires.

+
+ +
+
+bool auto_start = {true}
+

If true, the timer will start automatically when constructed.

+
+ +
+
+espp::Task::BaseConfig task_config
+

The task configuration for the timer.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The log level for the timer.

+
+ +
+
+ +
+
+struct Config
+

The configuration for the timer.

+
+

Public Members

+
+
+std::string_view name
+

The name of the timer.

+
+ +
+
+std::chrono::duration<float> period
+

The period of the timer. If 0, the timer callback will only be called once.

+
+ +
+
+std::chrono::duration<float> delay = std::chrono::duration<float>(0)
+

The delay before the first execution of the timer callback after start() is called.

+
+ +
+
+espp::Timer::callback_fn callback
+

The callback function to call when the timer expires.

+
+ +
+
+bool auto_start = {true}
+

If true, the timer will start automatically when constructed.

+
+ +
+
+size_t stack_size_bytes = {4096}
+

The stack size of the task that runs the timer.

+
+ +
+
+size_t priority = {0}
+

Priority of the timer, 0 is lowest priority on ESP / FreeRTOS.

+
+ +
+
+int core_id = {-1}
+

Core ID of the timer, -1 means it is not pinned to any core.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

The log level for the timer.

+
+ +
+
+ +
+ +
+
+
+

High Resolution Timer

+

The HighResolutionTimer component provides an esp-idf specific API to create +managed high resolution timer objects using the esp_timer API. The timer can be +started, stopped, and restarted, and it can be configured as a one-shot timer +or a periodic timer.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class HighResolutionTimer : public espp::BaseComponent
+

High resolution timer This class provides a high resolution timer using the ESP-IDF esp_timer API. The timer can be started in oneshot or periodic mode. The timer period can be set and queried. The timer can be started, stopped, and restarted. The timer can be queried to check if it is running.

+
+

High Resolution Timer Example

+
    logger.set_rate_limit(100ms);
+    auto timer_fn = [&]() {
+      static size_t iterations{0};
+      iterations++;
+      logger.info_rate_limited("High resolution timer callback: {}", iterations);
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto high_resolution_timer =
+        espp::HighResolutionTimer({.name = "High Resolution Timer",
+                                   .callback = timer_fn,
+                                   .log_level = espp::Logger::Verbosity::DEBUG});
+    uint64_t period_us = 100;
+    bool started = high_resolution_timer.start(period_us);
+    logger.info("High resolution timer started: {}", started);
+
+    std::this_thread::sleep_for(500ms);
+    logger.info("Updating period to 100ms");
+    period_us = 1000 * 100;
+    high_resolution_timer.set_period(period_us);
+    logger.info("Periodic timer period: {}us", high_resolution_timer.get_period());
+
+    // NOTE: only if CONFIG_ESP_TIMER_PROFILING is enabled will this show more
+    //       than address, period and alarm.
+    esp_timer_dump(stdout); // dump timer stats
+
+    std::this_thread::sleep_for(500ms);
+    logger.info("High resolution timer is running: {}", high_resolution_timer.is_running());
+    logger.info("Stopping timer");
+    high_resolution_timer.stop();
+
+    std::this_thread::sleep_for(500ms);
+    logger.info("Starting oneshot to expire in 100ms");
+    started = high_resolution_timer.oneshot(period_us);
+    logger.info("Oneshot timer started: {}", started);
+    logger.info("Oneshot timer expiry: {}us", high_resolution_timer.get_period());
+
+
+
+
+

High Resolution Timer Watchdog Example

+
    logger.set_rate_limit(100ms);
+    auto timer_fn = [&]() {
+      static size_t iterations{0};
+      iterations++;
+      logger.info_rate_limited("High resolution timer callback: {}", iterations);
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto high_resolution_timer =
+        espp::HighResolutionTimer({.name = "High Resolution Timer 1",
+                                   .callback = timer_fn,
+                                   .log_level = espp::Logger::Verbosity::DEBUG});
+    uint64_t period_us = 100;
+    bool started = high_resolution_timer.start(period_us);
+    logger.info("High resolution timer 1 started: {}", started);
+
+    // make another HighResolutionTimer
+    auto timer2_fn = [&]() {
+      // sleep here to ensure watchdog triggers
+      std::this_thread::sleep_for(350ms);
+      // we don't want to stop, so return false
+      return false;
+    };
+    auto high_resolution_timer2 =
+        espp::HighResolutionTimer({.name = "High Resolution Timer 2",
+                                   .callback = timer2_fn,
+                                   .log_level = espp::Logger::Verbosity::DEBUG});
+
+    // configure the task watchdog
+    static constexpr bool panic_on_watchdog_timeout = false;
+    espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);
+
+    // start the watchdog timer for this timer
+    high_resolution_timer2.start_watchdog();
+
+    // ensure we can run the watchdog on a oneshot timer which is started after
+    // we start the watchdog
+    period_us = 1000 * 100;
+    started = high_resolution_timer2.oneshot(period_us);
+    logger.info("High resolution timer 2 started: {}", started);
+
+    std::this_thread::sleep_for(400ms);
+
+    std::error_code ec;
+    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
+    if (ec) {
+      fmt::print("Error getting watchdog info: {}\n", ec.message());
+    } else if (!watchdog_info.empty()) {
+      fmt::print("Watchdog info: {}\n", watchdog_info);
+    } else {
+      fmt::print("No watchdog info available\n");
+    }
+
+    // now stop the watchdog timer
+    high_resolution_timer2.stop_watchdog();
+
+    // delay some more so we can see the watchdog timer has stopped
+    std::this_thread::sleep_for(500ms);
+
+
+
+
+

Note

+

Since this uses the esp-timer API, you cannot set different stack sizes for differnt timers like you can with espp::Timer and espp::Task. Instead, you may need to adjust the stack size via the menuconfig CONFIG_ESP_TIMER_TASK_STACK_SIZE.

+
+
+

Public Types

+
+
+typedef std::function<void()> Callback
+

Callback type for the timer.

+
+ +
+
+

Public Functions

+
+
+explicit HighResolutionTimer(const Config &config)
+

Constructor

+
+
Parameters
+

config – Configuration of the timer

+
+
+
+ +
+
+~HighResolutionTimer()
+

Destructor.

+
+ +
+
+bool start(uint64_t period_us = 0, bool oneshot = false)
+

Start the timer

+
+
Parameters
+
    +
  • period_us – Period of the timer in microseconds, or timeout if oneshot is true

  • +
  • oneshot – True if the timer should be oneshot, false if periodic

  • +
+
+
Returns
+

True if the timer was started successfully, false otherwise

+
+
+
+ +
+
+bool oneshot(uint64_t timeout_us = 0)
+

Start the timer in oneshot mode

+
+
Parameters
+

timeout_us – Timeout of the timer in microseconds

+
+
Returns
+

True if the timer was started successfully, false otherwise

+
+
+
+ +
+
+bool periodic(uint64_t period_us = 0)
+

Start the timer in periodic mode

+
+
Parameters
+

period_us – Period of the timer in microseconds

+
+
Returns
+

True if the timer was started successfully, false otherwise

+
+
+
+ +
+
+void stop()
+

Stop the timer.

+
+ +
+
+bool start_watchdog()
+

Start the watchdog timer

+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

True if the watchdog timer was started successfully, false otherwise

+
+
+
+ +
+
+bool stop_watchdog()
+

Stop the watchdog timer

+
+

Note

+

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

+
+
+
Returns
+

True if the watchdog timer was stopped successfully, false otherwise

+
+
+
+ +
+
+bool is_running() const
+

Check if the timer is running

+
+
Returns
+

True if the timer is running, false otherwise

+
+
+
+ +
+
+bool is_oneshot() const
+

Is the timer oneshot?

+
+
Returns
+

True if the timer is a oneshot timer, false if it is perioic.

+
+
+
+ +
+
+bool is_periodic() const
+

Is the timer periodic?

+
+
Returns
+

True if the timer is a periodic timer, false if it is oneshot.

+
+
+
+ +
+
+void set_period(uint64_t period_us)
+

Set the period of the timer in microseconds

+
+

Note

+

This function will restart the timer if it is running

+
+
+
Parameters
+

period_us – Period of the timer in microseconds

+
+
+
+ +
+
+uint64_t get_period()
+

Get the period of the timer in microseconds

+
+

Note

+

This function will return 0 if the timer is not running

+
+
+

Note

+

This function will return the period of the timer, not the remaining time

+
+
+
Returns
+

Period of the timer in microseconds

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+

Configuration of the timer.

+
+

Public Members

+
+
+std::string name
+

Name of the timer.

+
+ +
+
+Callback callback = {nullptr}
+

Callback to be called when the timer expires.

+
+ +
+
+bool skip_unhandled_events = {false}
+

Skip unhandled events. If true, will skip unhandled events in light sleep for periodic timers.

+
+ +
+
+esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK
+

Dispatch method, TIMER_TASK or TIMER_ISR.

+
+ +
+
+espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN
+

Log level.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/timer_example.html b/timer_example.html new file mode 100644 index 000000000..f645409be --- /dev/null +++ b/timer_example.html @@ -0,0 +1,237 @@ + + + + + + + Timer Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Timer Example

+

This example shows some various different ways of starting and stopping timers, +as well as some different examples of ways the timers can be configured, such as +repeating or one-shot, and how to use the timer’s callback function.

+
+

How to use example

+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-11-19 at 16 19 32

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/wifi/index.html b/wifi/index.html new file mode 100644 index 000000000..085d8d439 --- /dev/null +++ b/wifi/index.html @@ -0,0 +1,209 @@ + + + + + + + WiFi APIs - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wifi/wifi_ap.html b/wifi/wifi_ap.html new file mode 100644 index 000000000..162abea06 --- /dev/null +++ b/wifi/wifi_ap.html @@ -0,0 +1,429 @@ + + + + + + + WiFi Access Point (AP) - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

WiFi Access Point (AP)

+

The WiFi access point enables the ESP to host its own WiFi network to which +other devices can connect.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class WifiAp : public espp::BaseComponent
+

WiFi Access Point (AP)

+

see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#esp32-wi-fi-ap-general-scenario

+
+

WiFi Access Point Example

+
    espp::WifiAp wifi_ap({.ssid = CONFIG_ESP_WIFI_SSID, .password = CONFIG_ESP_WIFI_PASSWORD});
+
+
+
+
+

Note

+

If CONFIG_ESP32_WIFI_NVS_ENABLED is set to y (which is the default), then you must ensure that you call nvs_flash_init() prior to creating the WiFi Access Point.

+
+
+

Public Functions

+
+
+inline explicit WifiAp(const Config &config)
+

Initialize the WiFi Access Point (AP)

+
+
Parameters
+

configWifiAp::Config structure with initialization information.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+
+

Public Members

+
+
+std::string ssid
+

SSID for the access point.

+
+ +
+
+std::string password
+

Password for the access point. If empty, the AP will be open / have no security.

+
+ +
+
+uint8_t channel = {1}
+

WiFi channel, range [1,13].

+
+ +
+
+uint8_t max_number_of_stations = {4}
+

Max number of connected stations to this AP.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Verbosity of WifiAp logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/wifi/wifi_example.html b/wifi/wifi_example.html new file mode 100644 index 000000000..e585e3981 --- /dev/null +++ b/wifi/wifi_example.html @@ -0,0 +1,234 @@ + + + + + + + WiFi Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

WiFi Example

+

This example shows the use of the espp::WifiSta for connecting to existing +wifi networks, and the espp::WifiAp for creating a wifi access point, both of +which are provided by the wifi component.

+
+

How to use example

+
+

Configure the project

+
idf.py menuconfig
+
+
+

Since this example tests the espp::WifiSta which acts as a station and +connects to a pre-existing WiFi network, you should configure the wifi network +you want to connect to.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/wifi/wifi_sta.html b/wifi/wifi_sta.html new file mode 100644 index 000000000..4acf65005 --- /dev/null +++ b/wifi/wifi_sta.html @@ -0,0 +1,513 @@ + + + + + + + WiFi Station (STA) - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

WiFi Station (STA)

+

The WiFi station enables the ESP to scan for and connect to an exising WiFi +access point.

+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class WifiSta : public espp::BaseComponent
+

WiFi Station (STA)

+

see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#esp32-wi-fi-station-general-scenario

+
+

WiFi Station Example

+
    espp::WifiSta wifi_sta({.ssid = CONFIG_ESP_WIFI_SSID,
+                            .password = CONFIG_ESP_WIFI_PASSWORD,
+                            .num_connect_retries = CONFIG_ESP_MAXIMUM_RETRY,
+                            .on_connected = nullptr,
+                            .on_disconnected = nullptr,
+                            .on_got_ip = [](ip_event_got_ip_t *eventdata) {
+                              fmt::print("got IP: {}.{}.{}.{}\n", IP2STR(&eventdata->ip_info.ip));
+                            }});
+
+    while (!wifi_sta.is_connected()) {
+      std::this_thread::sleep_for(100ms);
+    }
+
+
+
+
+

Note

+

If CONFIG_ESP32_WIFI_NVS_ENABLED is set to y (which is the default), then you must ensure that you call nvs_flash_init() prior to creating the WiFi Station.

+
+
+

Public Types

+
+
+typedef std::function<void(void)> connect_callback
+

called when the WiFi station connects to an access point.

+
+ +
+
+typedef std::function<void(void)> disconnect_callback
+

Called when the WiFi station is disconnected from the access point and has exceeded the configured Config::num_connect_retries.

+
+ +
+
+typedef std::function<void(ip_event_got_ip_t *ip_evt)> ip_callback
+

Called whe nthe WiFi station has gotten an IP from the access point.

+
+
Param ip_evt
+

Pointer to IP Event data structure (contains ip address).

+
+
+
+ +
+
+

Public Functions

+
+
+inline explicit WifiSta(const Config &config)
+

Initialize the WiFi Station (STA)

+
+
Parameters
+

configWifiSta::Config structure with initialization information.

+
+
+
+ +
+
+inline ~WifiSta()
+

Stop the WiFi station and deinit the wifi subystem.

+
+ +
+
+inline bool is_connected() const
+

Whether the station is connected to an access point.

+
+
Returns
+

true if it is currently connected, false otherwise.

+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+
+struct Config
+
+

Public Members

+
+
+std::string ssid
+

SSID for the access point.

+
+ +
+
+std::string password
+

Password for the access point. If empty, the AP will be open / have no security.

+
+ +
+
+size_t num_connect_retries{0}
+

Number of times to retry connecting to the AP before stopping. After this many retries, on_disconnected will be called.

+
+ +
+
+connect_callback on_connected{nullptr}
+

Called when the station connects, or fails to connect.

+
+ +
+
+disconnect_callback on_disconnected = {nullptr}
+

Called when the station disconnects.

+
+ +
+
+ip_callback on_got_ip = {nullptr}
+

Called when the station gets an IP address.

+
+ +
+
+uint8_t channel = {0}
+

Channel of target AP; set to 0 for unknown.

+
+ +
+
+bool set_ap_mac = {false}
+

Whether to check MAC address of the AP (generally no). If yes, provide ap_mac.

+
+ +
+
+uint8_t ap_mac[6] = {0}
+

MAC address of the AP to check if set_ap_mac is set to true.

+
+ +
+
+Logger::Verbosity log_level = {Logger::Verbosity::WARN}
+

Verbosity of WifiSta logger.

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/wrover_kit.html b/wrover_kit.html new file mode 100644 index 000000000..cf90f2c08 --- /dev/null +++ b/wrover_kit.html @@ -0,0 +1,802 @@ + + + + + + + ESP32-WROVER-KIT - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ESP32-WROVER-KIT

+
+

Wrover-Kit

+

The ESP32-WROVER-KIT is a development board for the ESP32-WROVER module. It +features a nice display and a lot of expansion headers.

+

The espp::WroverKit component provides a singleton hardware abstraction for +initializing the display subsystems.

+ +
+
+

API Reference

+
+

Header File

+ +
+
+

Classes

+
+
+class WroverKit : public espp::BaseComponent
+

The WroverKit class provides an interface to the ESP32-WROVER-KIT ESP32 development board.

+

The class provides access to the following features:

+

+

The class is a singleton and can be accessed using the get() method.

+
+

Example

+
  espp::WroverKit &wrover = espp::WroverKit::get();
+  wrover.set_log_level(espp::Logger::Verbosity::INFO);
+
+  // initialize the LCD
+  if (!wrover.initialize_lcd()) {
+    logger.error("Failed to initialize LCD!");
+    return;
+  }
+  // set the pixel buffer to be 50 lines high
+  static constexpr size_t pixel_buffer_size = wrover.lcd_width() * 50;
+  // initialize the LVGL display for the wrover-kit
+  if (!wrover.initialize_display(pixel_buffer_size)) {
+    logger.error("Failed to initialize display!");
+    return;
+  }
+
+  logger.info("Adding LVGL objects to the screen.");
+
+  // 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<std::mutex> lock(lvgl_mutex);
+                                             static auto rotation = LV_DISPLAY_ROTATION_0;
+                                             rotation = static_cast<lv_display_rotation_t>(
+                                                 (static_cast<int>(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());
+  lv_obj_set_size(bg, wrover.lcd_width(), wrover.lcd_height());
+  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
+
+  // add text in the center of the screen
+  lv_obj_t *label = lv_label_create(lv_screen_active());
+  lv_label_set_text(label, "Drawing circles to the screen.");
+  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
+
+  // start a simple thread to do the lv_task_handler every 16ms
+  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
+                        {
+                          std::lock_guard<std::mutex> lock(lvgl_mutex);
+                          lv_task_handler();
+                        }
+                        std::unique_lock<std::mutex> lock(m);
+                        cv.wait_for(lock, 16ms);
+                        return false;
+                      },
+                      .task_config = {
+                          .name = "lv_task",
+                      }});
+  lv_task.start();
+
+  // set the display brightness to be 75%
+  wrover.brightness(75.0f);
+
+  while (true) {
+    auto start = esp_timer_get_time();
+    // if there are 10 circles on the screen, clear them
+    static constexpr int max_circles = 10;
+    if (circles.size() >= max_circles) {
+      std::lock_guard<std::mutex> lock(lvgl_mutex);
+      clear_circles();
+    } else {
+      // draw a circle of circles on the screen (just draw the next circle)
+      static constexpr int middle_x = wrover.lcd_width() / 2;
+      static constexpr int middle_y = wrover.lcd_height() / 2;
+      static constexpr int radius = 50;
+      float angle = circles.size() * 2.0f * M_PI / max_circles;
+      int x = middle_x + radius * cos(angle);
+      int y = middle_y + radius * sin(angle);
+      std::lock_guard<std::mutex> lock(lvgl_mutex);
+      draw_circle(x, y, 10);
+    }
+    auto end = esp_timer_get_time();
+    auto elapsed = end - start;
+    std::this_thread::sleep_for(100ms - std::chrono::microseconds(elapsed));
+  }
+
+
+
+
+

Public Types

+
+
+using Pixel = lv_color16_t
+

Alias for the pixel type used by the wrover-kit display.

+
+ +
+
+

Public Functions

+
+
+bool initialize_lcd()
+

Initialize the LCD (low level display driver)

+
+
Returns
+

true if the LCD was successfully initialized, false otherwise

+
+
+
+ +
+
+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)
+

Initialize the display (lvgl display driver)

+
+

Note

+

This will also allocate two full frame buffers in the SPIRAM

+
+
+
Parameters
+
    +
  • pixel_buffer_size – The size of the pixel buffer

  • +
  • task_config – The task configuration for the display task

  • +
  • update_period_ms – The update period of the display task

  • +
+
+
Returns
+

true if the display was successfully initialized, false otherwise

+
+
+
+ +
+
+std::shared_ptr<Display<Pixel>> display() const
+

Get a shared pointer to the display

+
+
Returns
+

A shared pointer to the display

+
+
+
+ +
+
+void brightness(float brightness)
+

Set the brightness of the backlight

+
+
Parameters
+

brightness – The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+float brightness() const
+

Get the brightness of the backlight

+
+
Returns
+

The brightness of the backlight as a percentage (0 - 100)

+
+
+
+ +
+
+Pixel *vram0() const
+

Get the VRAM 0 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 0 pointer

+
+
+
+ +
+
+Pixel *vram1() const
+

Get the VRAM 1 pointer (DMA memory used by LVGL)

+
+

Note

+

This is the memory used by LVGL for rendering

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The VRAM 1 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer0() const
+

Get the frame buffer 0 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 0 pointer

+
+
+
+ +
+
+uint8_t *frame_buffer1() const
+

Get the frame buffer 1 pointer

+
+

Note

+

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

+
+
+

Note

+

This is null unless initialize_display() has been called

+
+
+
Returns
+

The frame buffer 1 pointer

+
+
+
+ +
+
+void write_lcd(const uint8_t *data, size_t length, uint32_t user_data)
+

Write data to the LCD

+
+

Note

+

This method is designed to be used by the display driver

+
+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • data – The data to write

  • +
  • length – The length of the data

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)
+

Write a frame to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • x – The x coordinate

  • +
  • y – The y coordinate

  • +
  • width – The width of the frame, in pixels

  • +
  • height – The height of the frame, in pixels

  • +
  • data – The data to write

  • +
+
+
+
+ +
+
+void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
+

Write lines to the LCD

+
+

Note

+

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

+
+
+
Parameters
+
    +
  • xs – The x start coordinate

  • +
  • ys – The y start coordinate

  • +
  • xe – The x end coordinate

  • +
  • ye – The y end coordinate

  • +
  • data – The data to write

  • +
  • user_data – User data to pass to the spi transaction callback

  • +
+
+
+
+ +
+
+inline const std::string &get_name() const
+

Get the name of the component

+
+

Note

+

This is the tag of the logger

+
+
+
Returns
+

A const reference to the name of the component

+
+
+
+ +
+
+inline void set_log_tag(const std::string_view &tag)
+

Set the tag for the logger

+
+
Parameters
+

tag – The tag to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_level() const
+

Get the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_level(espp::Logger::Verbosity level)
+

Set the log level for the logger

+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline void set_log_verbosity(espp::Logger::Verbosity level)
+

Set the log verbosity for the logger

+

See also

+

set_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::set_verbosity

+
+

+
+

Note

+

This is a convenience method that calls set_log_level

+
+
+
Parameters
+

level – The verbosity level to use for the logger

+
+
+
+ +
+
+inline espp::Logger::Verbosity get_log_verbosity() const
+

Get the log verbosity for the logger

+

See also

+

get_log_level

+
+
+

See also

+

Logger::Verbosity

+
+
+

See also

+

Logger::get_verbosity

+
+

+
+

Note

+

This is a convenience method that calls get_log_level

+
+
+
Returns
+

The verbosity level of the logger

+
+
+
+ +
+
+inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
+

Set the rate limit for the logger

+

+
+

Note

+

Only calls to the logger that have _rate_limit suffix will be rate limited

+
+
+
Parameters
+

rate_limit – The rate limit to use for the logger

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline WroverKit &get()
+

Access the singleton instance of the WroverKit class.

+
+
Returns
+

Reference to the singleton instance of the WroverKit class

+
+
+
+ +
+
+static inline constexpr size_t lcd_width()
+

Get the width of the LCD in pixels

+
+
Returns
+

The width of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr size_t lcd_height()
+

Get the height of the LCD in pixels

+
+
Returns
+

The height of the LCD in pixels

+
+
+
+ +
+
+static inline constexpr auto get_lcd_dc_gpio()
+

Get the GPIO pin for the LCD data/command signal

+
+
Returns
+

The GPIO pin for the LCD data/command signal

+
+
+
+ +
+
+
+struct TouchpadData
+

The data structure for the touchpad.

+
+

Public Functions

+
+
+bool operator==(const TouchpadData &rhs) const = default
+

Compare two TouchpadData objects for equality.

+
+
Parameters
+

rhs – The right hand side of the comparison

+
+
Returns
+

true if the two TouchpadData objects are equal, false otherwise

+
+
+
+ +
+
+

Public Members

+
+
+uint8_t num_touch_points = 0
+

The number of touch points.

+
+ +
+
+uint16_t x = 0
+

The x coordinate.

+
+ +
+
+uint16_t y = 0
+

The y coordinate.

+
+ +
+
+uint8_t btn_state = 0
+

The button state (0 = button released, 1 = button pressed)

+
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/wrover_kit_example.html b/wrover_kit_example.html new file mode 100644 index 000000000..0fcf1f745 --- /dev/null +++ b/wrover_kit_example.html @@ -0,0 +1,233 @@ + + + + + + + Wrover-Kit Example - ESP32 - — ESPP main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Wrover-Kit Example

+

This example shows how to use the espp::WroverKit hardware abstraction component +to initialize the ESP32-WROVER-KIT.

+

It initializes the display subsystem and periodically draws 10 circles to the +screen before clearing and starting over using LVGL.

+

image

+
+

How to use example

+
+

Hardware Required

+

This example is designed to run on the ESP32-WROVER-KIT.

+
+
+

Build and Flash

+

Build the project and flash it to the board, then run monitor tool to view +serial output:

+
idf.py -p PORT flash monitor
+
+
+

(Replace PORT with the name of the serial port to use.)

+

(To exit the serial monitor, type Ctrl-].)

+

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

+
+
+
+

Example Output

+

CleanShot 2024-07-05 at 23 57 31@2x

+
+
+ + +
+
+ +
+
+
+
+ + + + + \ No newline at end of file