1 /* 2 * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #pragma once 8 9 #if __cpp_exceptions 10 11 #include "esp_exception.hpp" 12 #include "system_cxx.hpp" 13 14 namespace idf { 15 16 /** 17 * @brief Exception thrown for errors in the GPIO C++ API. 18 */ 19 struct GPIOException : public ESPException { 20 /** 21 * @param error The IDF error representing the error class of the error to throw. 22 */ 23 GPIOException(esp_err_t error); 24 }; 25 26 /** 27 * Check if the numeric pin number is valid on the current hardware. 28 */ 29 esp_err_t check_gpio_pin_num(uint32_t pin_num) noexcept; 30 31 /** 32 * Check if the numeric value of a drive strength is valid on the current hardware. 33 */ 34 esp_err_t check_gpio_drive_strength(uint32_t strength) noexcept; 35 36 /** 37 * This is a "Strong Value Type" class for GPIO. The GPIO pin number is checked during construction according to 38 * the hardware capabilities. This means that any GPIONumBase object is guaranteed to contain a valid GPIO number. 39 * See also the template class \c StrongValue. 40 */ 41 template<typename GPIONumFinalType> 42 class GPIONumBase final : public StrongValueComparable<uint32_t> { 43 public: 44 /** 45 * @brief Create a numerical pin number representation and make sure it's correct. 46 * 47 * @throw GPIOException if the number does not reflect a valid GPIO number on the current hardware. 48 */ GPIONumBase(uint32_t pin)49 GPIONumBase(uint32_t pin) : StrongValueComparable<uint32_t>(pin) 50 { 51 esp_err_t pin_check_result = check_gpio_pin_num(pin); 52 if (pin_check_result != ESP_OK) { 53 throw GPIOException(pin_check_result); 54 } 55 } 56 57 using StrongValueComparable<uint32_t>::operator==; 58 using StrongValueComparable<uint32_t>::operator!=; 59 60 /** 61 * Retrieves the valid numerical representation of the GPIO number. 62 */ get_num() const63 uint32_t get_num() const { return get_value(); }; 64 }; 65 66 /** 67 * This is a TAG type whose sole purpose is to create a distinct type from GPIONumBase. 68 */ 69 class GPIONumType; 70 71 /** 72 * A GPIO number type used for general GPIOs, in contrast to specific GPIO pins like e.g. SPI_SCLK. 73 */ 74 using GPIONum = GPIONumBase<class GPIONumType>; 75 76 /** 77 * Level of an input GPIO. 78 */ 79 enum class GPIOLevel { 80 HIGH, 81 LOW 82 }; 83 84 /** 85 * Represents a valid pull up configuration for GPIOs. 86 * It is supposed to resemble an enum type, hence it has static creation methods and a private constructor. 87 * This class is a "Strong Value Type", see also the template class \c StrongValue for more properties. 88 */ 89 class GPIOPullMode final : public StrongValueComparable<uint32_t> { 90 private: 91 /** 92 * Constructor is private since it should only be accessed by the static creation methods. 93 * 94 * @param pull_mode A valid numerical respresentation of the pull up configuration. Must be valid! 95 */ GPIOPullMode(uint32_t pull_mode)96 GPIOPullMode(uint32_t pull_mode) : StrongValueComparable<uint32_t>(pull_mode) { } 97 98 public: 99 /** 100 * Create a representation of a floating pin configuration. 101 * For more information, check the driver and HAL files. 102 */ 103 static GPIOPullMode FLOATING(); 104 105 /** 106 * Create a representation of a pullup configuration. 107 * For more information, check the driver and HAL files. 108 */ 109 static GPIOPullMode PULLUP(); 110 111 /** 112 * Create a representation of a pulldown configuration. 113 * For more information, check the driver and HAL files. 114 */ 115 static GPIOPullMode PULLDOWN(); 116 117 using StrongValueComparable<uint32_t>::operator==; 118 using StrongValueComparable<uint32_t>::operator!=; 119 120 /** 121 * Retrieves the valid numerical representation of the pull mode. 122 */ get_pull_mode() const123 uint32_t get_pull_mode() const { return get_value(); }; 124 }; 125 126 /** 127 * @brief Represents a valid wakup interrupt type for GPIO inputs. 128 * 129 * This class is a "Strong Value Type", see also the template class \c StrongValue for more properties. 130 * It is supposed to resemble an enum type, hence it has static creation methods and a private constructor. 131 * For a detailed mapping of interrupt types to numeric values, please refer to the driver types and implementation. 132 */ 133 class GPIOWakeupIntrType final: public StrongValueComparable<uint32_t> { 134 private: 135 /** 136 * Constructor is private since it should only be accessed by the static creation methods. 137 * 138 * @param pull_mode A valid numerical respresentation of a possible interrupt level to wake up. Must be valid! 139 */ GPIOWakeupIntrType(uint32_t interrupt_level)140 GPIOWakeupIntrType(uint32_t interrupt_level) : StrongValueComparable<uint32_t>(interrupt_level) { } 141 142 public: 143 static GPIOWakeupIntrType LOW_LEVEL(); 144 static GPIOWakeupIntrType HIGH_LEVEL(); 145 146 /** 147 * Retrieves the valid numerical representation of the pull mode. 148 */ get_level() const149 uint32_t get_level() const noexcept { return get_value(); }; 150 }; 151 152 /** 153 * Class representing a valid drive strength for GPIO outputs. 154 * This class is a "Strong Value Type", see also the template class \c StrongValue for more properties. 155 * For a detailed mapping for values to drive strengths, please refer to the datasheet of the chip you are using. 156 * E.g. for ESP32, the values in general are the following: 157 * - WEAK: 5mA 158 * - STRONGER: 10mA 159 * - DEFAULT/MEDIUM: 20mA 160 * - STRONGEST: 40mA 161 */ 162 class GPIODriveStrength final : public StrongValueComparable<uint32_t> { 163 public: 164 /** 165 * @brief Create a drive strength representation and checks its validity. 166 * 167 * After construction, this class should have a guaranteed valid strength representation. 168 * 169 * @param strength the numeric value mapping for a particular strength. For possible ranges, look at the 170 * static creation functions below. 171 * @throws GPIOException if the supplied number is out of the hardware capable range. 172 */ GPIODriveStrength(uint32_t strength)173 GPIODriveStrength(uint32_t strength) : StrongValueComparable<uint32_t>(strength) 174 { 175 esp_err_t strength_check_result = check_gpio_drive_strength(strength); 176 if (strength_check_result != ESP_OK) { 177 throw GPIOException(strength_check_result); 178 } 179 } 180 181 /** 182 * Create a representation of the default drive strength. 183 * For more information, check the datasheet and driver and HAL files. 184 */ 185 static GPIODriveStrength DEFAULT(); 186 187 /** 188 * Create a representation of the weak drive strength. 189 * For more information, check the datasheet and driver and HAL files. 190 */ 191 static GPIODriveStrength WEAK(); 192 193 /** 194 * Create a representation of the less weak drive strength. 195 * For more information, check the datasheet and driver and HAL files. 196 */ 197 static GPIODriveStrength LESS_WEAK(); 198 199 /** 200 * Create a representation of the medium drive strength. 201 * For more information, check the datasheet and driver and HAL files. 202 */ 203 static GPIODriveStrength MEDIUM(); 204 205 /** 206 * Create a representation of the strong drive strength. 207 */ 208 static GPIODriveStrength STRONGEST(); 209 210 using StrongValueComparable<uint32_t>::operator==; 211 using StrongValueComparable<uint32_t>::operator!=; 212 213 /** 214 * Retrieves the valid numerical representation of the drive strength. 215 */ get_strength() const216 uint32_t get_strength() const { return get_value(); }; 217 218 }; 219 220 /** 221 * @brief Implementations commonly used functionality for all GPIO configurations. 222 * 223 * Some functionality is only for specific configurations (set and get drive strength) but is necessary here 224 * to avoid complicating the inheritance hierarchy of the GPIO classes. 225 * Child classes implementing any GPIO configuration (output, input, etc.) are meant to intherit from this class 226 * and possibly make some of the functionality publicly available. 227 */ 228 class GPIOBase { 229 protected: 230 /** 231 * @brief Construct a GPIO. 232 * 233 * This constructor will only reset the GPIO but leaves the actual configuration (input, output, etc.) to 234 * the sub class. 235 * 236 * @param num GPIO pin number of the GPIO to be configured. 237 * 238 * @throws GPIOException 239 * - if the underlying driver function fails 240 */ 241 GPIOBase(GPIONum num); 242 243 /** 244 * @brief Enable gpio pad hold function. 245 * 246 * The gpio pad hold function works in both input and output modes, but must be output-capable gpios. 247 * If pad hold enabled: 248 * in output mode: the output level of the pad will be force locked and can not be changed. 249 * in input mode: the input value read will not change, regardless the changes of input signal. 250 * 251 * @throws GPIOException if the underlying driver function fails. 252 */ 253 void hold_en(); 254 255 /** 256 * @brief Disable gpio pad hold function. 257 * 258 * @throws GPIOException if the underlying driver function fails. 259 */ 260 void hold_dis(); 261 262 /** 263 * @brief Configure the drive strength of the GPIO. 264 * 265 * @param strength The drive strength. Refer to \c GPIODriveStrength for more details. 266 * 267 * @throws GPIOException if the underlying driver function fails. 268 */ 269 void set_drive_strength(GPIODriveStrength strength); 270 271 /** 272 * @brief Return the current drive strength of the GPIO. 273 * 274 * @return The currently configured drive strength. Refer to \c GPIODriveStrength for more details. 275 * 276 * @throws GPIOException if the underlying driver function fails. 277 */ 278 GPIODriveStrength get_drive_strength(); 279 280 /** 281 * @brief The number of the configured GPIO pin. 282 */ 283 GPIONum gpio_num; 284 }; 285 286 /** 287 * @brief This class represents a GPIO which is configured as output. 288 */ 289 class GPIO_Output : public GPIOBase { 290 public: 291 /** 292 * @brief Construct and configure a GPIO as output. 293 * 294 * @param num GPIO pin number of the GPIO to be configured. 295 * 296 * @throws GPIOException 297 * - if the underlying driver function fails 298 */ 299 GPIO_Output(GPIONum num); 300 301 /** 302 * @brief Set GPIO to high level. 303 * 304 * @throws GPIOException if the underlying driver function fails. 305 */ 306 void set_high(); 307 308 /** 309 * @brief Set GPIO to low level. 310 * 311 * @throws GPIOException if the underlying driver function fails. 312 */ 313 void set_low(); 314 315 using GPIOBase::set_drive_strength; 316 using GPIOBase::get_drive_strength; 317 }; 318 319 /** 320 * @brief This class represents a GPIO which is configured as input. 321 */ 322 class GPIOInput : public GPIOBase { 323 public: 324 /** 325 * @brief Construct and configure a GPIO as input. 326 * 327 * @param num GPIO pin number of the GPIO to be configured. 328 * 329 * @throws GPIOException 330 * - if the underlying driver function fails 331 */ 332 GPIOInput(GPIONum num); 333 334 /** 335 * @brief Read the current level of the GPIO. 336 * 337 * @return The GPIO current level of the GPIO. 338 */ 339 GPIOLevel get_level() const noexcept; 340 341 /** 342 * @brief Configure the internal pull-up and pull-down restors. 343 * 344 * @param mode The pull-up/pull-down configuration see \c GPIOPullMode. 345 * 346 * @throws GPIOException if the underlying driver function fails. 347 */ 348 void set_pull_mode(GPIOPullMode mode); 349 350 /** 351 * @brief Configure the pin as wake up pin. 352 * 353 * @throws GPIOException if the underlying driver function fails. 354 */ 355 void wakeup_enable(GPIOWakeupIntrType interrupt_type); 356 357 /** 358 * @brief Disable wake up functionality for this pin if it was enabled before. 359 * 360 * @throws GPIOException if the underlying driver function fails. 361 */ 362 void wakeup_disable(); 363 }; 364 365 /** 366 * @brief This class represents a GPIO which is configured as open drain output and input at the same time. 367 * 368 * This class facilitates bit-banging for single wire protocols. 369 */ 370 class GPIO_OpenDrain : public GPIOInput { 371 public: 372 /** 373 * @brief Construct and configure a GPIO as open drain output as well as input. 374 * 375 * @param num GPIO pin number of the GPIO to be configured. 376 * 377 * @throws GPIOException 378 * - if the underlying driver function fails 379 */ 380 GPIO_OpenDrain(GPIONum num); 381 382 /** 383 * @brief Set GPIO to floating level. 384 * 385 * @throws GPIOException if the underlying driver function fails. 386 */ 387 void set_floating(); 388 389 /** 390 * @brief Set GPIO to low level. 391 * 392 * @throws GPIOException if the underlying driver function fails. 393 */ 394 void set_low(); 395 396 using GPIOBase::set_drive_strength; 397 using GPIOBase::get_drive_strength; 398 }; 399 400 } 401 402 #endif 403