esp-idf/examples/cxx/experimental/experimental_cpp_component/include/gpio_cxx.hpp
Jakob Hasse ce7cdeffb4 bugfix (cxx)!: added missing explicit for some strong value types
BREAKING CHANGE: Users who have been using the GPIO and SPI classes
                 may need to revisit their code as it's now not allowed
                 anymore to pass raw numbers for classes like MOSI
                 or GPIONum.
2021-11-19 16:07:32 +08:00

403 lines
12 KiB
C++

/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#if __cpp_exceptions
#include "esp_exception.hpp"
#include "system_cxx.hpp"
namespace idf {
/**
* @brief Exception thrown for errors in the GPIO C++ API.
*/
struct GPIOException : public ESPException {
/**
* @param error The IDF error representing the error class of the error to throw.
*/
GPIOException(esp_err_t error);
};
/**
* Check if the numeric pin number is valid on the current hardware.
*/
esp_err_t check_gpio_pin_num(uint32_t pin_num) noexcept;
/**
* Check if the numeric value of a drive strength is valid on the current hardware.
*/
esp_err_t check_gpio_drive_strength(uint32_t strength) noexcept;
/**
* This is a "Strong Value Type" class for GPIO. The GPIO pin number is checked during construction according to
* the hardware capabilities. This means that any GPIONumBase object is guaranteed to contain a valid GPIO number.
* See also the template class \c StrongValue.
*/
template<typename GPIONumFinalType>
class GPIONumBase final : public StrongValueComparable<uint32_t> {
public:
/**
* @brief Create a numerical pin number representation and make sure it's correct.
*
* @throw GPIOException if the number does not reflect a valid GPIO number on the current hardware.
*/
explicit GPIONumBase(uint32_t pin) : StrongValueComparable<uint32_t>(pin)
{
esp_err_t pin_check_result = check_gpio_pin_num(pin);
if (pin_check_result != ESP_OK) {
throw GPIOException(pin_check_result);
}
}
using StrongValueComparable<uint32_t>::operator==;
using StrongValueComparable<uint32_t>::operator!=;
/**
* Retrieves the valid numerical representation of the GPIO number.
*/
uint32_t get_num() const { return get_value(); };
};
/**
* This is a TAG type whose sole purpose is to create a distinct type from GPIONumBase.
*/
class GPIONumType;
/**
* A GPIO number type used for general GPIOs, in contrast to specific GPIO pins like e.g. SPI_SCLK.
*/
using GPIONum = GPIONumBase<class GPIONumType>;
/**
* Level of an input GPIO.
*/
enum class GPIOLevel {
HIGH,
LOW
};
/**
* Represents a valid pull up configuration for GPIOs.
* It is supposed to resemble an enum type, hence it has static creation methods and a private constructor.
* This class is a "Strong Value Type", see also the template class \c StrongValue for more properties.
*/
class GPIOPullMode final : public StrongValueComparable<uint32_t> {
private:
/**
* Constructor is private since it should only be accessed by the static creation methods.
*
* @param pull_mode A valid numerical respresentation of the pull up configuration. Must be valid!
*/
explicit GPIOPullMode(uint32_t pull_mode) : StrongValueComparable<uint32_t>(pull_mode) { }
public:
/**
* Create a representation of a floating pin configuration.
* For more information, check the driver and HAL files.
*/
static GPIOPullMode FLOATING();
/**
* Create a representation of a pullup configuration.
* For more information, check the driver and HAL files.
*/
static GPIOPullMode PULLUP();
/**
* Create a representation of a pulldown configuration.
* For more information, check the driver and HAL files.
*/
static GPIOPullMode PULLDOWN();
using StrongValueComparable<uint32_t>::operator==;
using StrongValueComparable<uint32_t>::operator!=;
/**
* Retrieves the valid numerical representation of the pull mode.
*/
uint32_t get_pull_mode() const { return get_value(); };
};
/**
* @brief Represents a valid wakup interrupt type for GPIO inputs.
*
* This class is a "Strong Value Type", see also the template class \c StrongValue for more properties.
* It is supposed to resemble an enum type, hence it has static creation methods and a private constructor.
* For a detailed mapping of interrupt types to numeric values, please refer to the driver types and implementation.
*/
class GPIOWakeupIntrType final: public StrongValueComparable<uint32_t> {
private:
/**
* Constructor is private since it should only be accessed by the static creation methods.
*
* @param pull_mode A valid numerical respresentation of a possible interrupt level to wake up. Must be valid!
*/
explicit GPIOWakeupIntrType(uint32_t interrupt_level) : StrongValueComparable<uint32_t>(interrupt_level) { }
public:
static GPIOWakeupIntrType LOW_LEVEL();
static GPIOWakeupIntrType HIGH_LEVEL();
/**
* Retrieves the valid numerical representation of the pull mode.
*/
uint32_t get_level() const noexcept { return get_value(); };
};
/**
* Class representing a valid drive strength for GPIO outputs.
* This class is a "Strong Value Type", see also the template class \c StrongValue for more properties.
* For a detailed mapping for values to drive strengths, please refer to the datasheet of the chip you are using.
* E.g. for ESP32, the values in general are the following:
* - WEAK: 5mA
* - STRONGER: 10mA
* - DEFAULT/MEDIUM: 20mA
* - STRONGEST: 40mA
*/
class GPIODriveStrength final : public StrongValueComparable<uint32_t> {
public:
/**
* @brief Create a drive strength representation and checks its validity.
*
* After construction, this class should have a guaranteed valid strength representation.
*
* @param strength the numeric value mapping for a particular strength. For possible ranges, look at the
* static creation functions below.
* @throws GPIOException if the supplied number is out of the hardware capable range.
*/
explicit GPIODriveStrength(uint32_t strength) : StrongValueComparable<uint32_t>(strength)
{
esp_err_t strength_check_result = check_gpio_drive_strength(strength);
if (strength_check_result != ESP_OK) {
throw GPIOException(strength_check_result);
}
}
/**
* Create a representation of the default drive strength.
* For more information, check the datasheet and driver and HAL files.
*/
static GPIODriveStrength DEFAULT();
/**
* Create a representation of the weak drive strength.
* For more information, check the datasheet and driver and HAL files.
*/
static GPIODriveStrength WEAK();
/**
* Create a representation of the less weak drive strength.
* For more information, check the datasheet and driver and HAL files.
*/
static GPIODriveStrength LESS_WEAK();
/**
* Create a representation of the medium drive strength.
* For more information, check the datasheet and driver and HAL files.
*/
static GPIODriveStrength MEDIUM();
/**
* Create a representation of the strong drive strength.
*/
static GPIODriveStrength STRONGEST();
using StrongValueComparable<uint32_t>::operator==;
using StrongValueComparable<uint32_t>::operator!=;
/**
* Retrieves the valid numerical representation of the drive strength.
*/
uint32_t get_strength() const { return get_value(); };
};
/**
* @brief Implementations commonly used functionality for all GPIO configurations.
*
* Some functionality is only for specific configurations (set and get drive strength) but is necessary here
* to avoid complicating the inheritance hierarchy of the GPIO classes.
* Child classes implementing any GPIO configuration (output, input, etc.) are meant to intherit from this class
* and possibly make some of the functionality publicly available.
*/
class GPIOBase {
protected:
/**
* @brief Construct a GPIO.
*
* This constructor will only reset the GPIO but leaves the actual configuration (input, output, etc.) to
* the sub class.
*
* @param num GPIO pin number of the GPIO to be configured.
*
* @throws GPIOException
* - if the underlying driver function fails
*/
GPIOBase(GPIONum num);
/**
* @brief Enable gpio pad hold function.
*
* The gpio pad hold function works in both input and output modes, but must be output-capable gpios.
* If pad hold enabled:
* in output mode: the output level of the pad will be force locked and can not be changed.
* in input mode: the input value read will not change, regardless the changes of input signal.
*
* @throws GPIOException if the underlying driver function fails.
*/
void hold_en();
/**
* @brief Disable gpio pad hold function.
*
* @throws GPIOException if the underlying driver function fails.
*/
void hold_dis();
/**
* @brief Configure the drive strength of the GPIO.
*
* @param strength The drive strength. Refer to \c GPIODriveStrength for more details.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_drive_strength(GPIODriveStrength strength);
/**
* @brief Return the current drive strength of the GPIO.
*
* @return The currently configured drive strength. Refer to \c GPIODriveStrength for more details.
*
* @throws GPIOException if the underlying driver function fails.
*/
GPIODriveStrength get_drive_strength();
/**
* @brief The number of the configured GPIO pin.
*/
GPIONum gpio_num;
};
/**
* @brief This class represents a GPIO which is configured as output.
*/
class GPIO_Output : public GPIOBase {
public:
/**
* @brief Construct and configure a GPIO as output.
*
* @param num GPIO pin number of the GPIO to be configured.
*
* @throws GPIOException
* - if the underlying driver function fails
*/
GPIO_Output(GPIONum num);
/**
* @brief Set GPIO to high level.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_high();
/**
* @brief Set GPIO to low level.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_low();
using GPIOBase::set_drive_strength;
using GPIOBase::get_drive_strength;
};
/**
* @brief This class represents a GPIO which is configured as input.
*/
class GPIOInput : public GPIOBase {
public:
/**
* @brief Construct and configure a GPIO as input.
*
* @param num GPIO pin number of the GPIO to be configured.
*
* @throws GPIOException
* - if the underlying driver function fails
*/
GPIOInput(GPIONum num);
/**
* @brief Read the current level of the GPIO.
*
* @return The GPIO current level of the GPIO.
*/
GPIOLevel get_level() const noexcept;
/**
* @brief Configure the internal pull-up and pull-down restors.
*
* @param mode The pull-up/pull-down configuration see \c GPIOPullMode.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_pull_mode(GPIOPullMode mode);
/**
* @brief Configure the pin as wake up pin.
*
* @throws GPIOException if the underlying driver function fails.
*/
void wakeup_enable(GPIOWakeupIntrType interrupt_type);
/**
* @brief Disable wake up functionality for this pin if it was enabled before.
*
* @throws GPIOException if the underlying driver function fails.
*/
void wakeup_disable();
};
/**
* @brief This class represents a GPIO which is configured as open drain output and input at the same time.
*
* This class facilitates bit-banging for single wire protocols.
*/
class GPIO_OpenDrain : public GPIOInput {
public:
/**
* @brief Construct and configure a GPIO as open drain output as well as input.
*
* @param num GPIO pin number of the GPIO to be configured.
*
* @throws GPIOException
* - if the underlying driver function fails
*/
GPIO_OpenDrain(GPIONum num);
/**
* @brief Set GPIO to floating level.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_floating();
/**
* @brief Set GPIO to low level.
*
* @throws GPIOException if the underlying driver function fails.
*/
void set_low();
using GPIOBase::set_drive_strength;
using GPIOBase::get_drive_strength;
};
}
#endif