1 /*
2 * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #if __cpp_exceptions
8
9 #include <array>
10 #include "driver/gpio.h"
11 #include "gpio_cxx.hpp"
12
13 namespace idf {
14
15 #define GPIO_CHECK_THROW(err) CHECK_THROW_SPECIFIC((err), GPIOException)
16
17 namespace {
18 #if CONFIG_IDF_TARGET_LINUX
19 constexpr std::array<uint32_t, 1> INVALID_GPIOS = {24};
20 #elif CONFIG_IDF_TARGET_ESP32
21 constexpr std::array<uint32_t, 1> INVALID_GPIOS = {24};
22 #elif CONFIG_IDF_TARGET_ESP32S2
23 constexpr std::array<uint32_t, 4> INVALID_GPIOS = {22, 23, 24, 25};
24 #elif CONFIG_IDF_TARGET_ESP32S3
25 constexpr std::array<uint32_t, 4> INVALID_GPIOS = {22, 23, 24, 25};
26 #elif CONFIG_IDF_TARGET_ESP32C3
27 constexpr std::array<uint32_t, 0> INVALID_GPIOS = {};
28 #else
29 #error "No GPIOs defined for the current target"
30 #endif
31
gpio_to_driver_type(const GPIONum & gpio_num)32 gpio_num_t gpio_to_driver_type(const GPIONum &gpio_num)
33 {
34 return static_cast<gpio_num_t>(gpio_num.get_num());
35 }
36
37 }
38
GPIOException(esp_err_t error)39 GPIOException::GPIOException(esp_err_t error) : ESPException(error) { }
40
check_gpio_pin_num(uint32_t pin_num)41 esp_err_t check_gpio_pin_num(uint32_t pin_num) noexcept
42 {
43 if (pin_num >= GPIO_NUM_MAX) {
44 return ESP_ERR_INVALID_ARG;
45 }
46
47 for (auto num: INVALID_GPIOS)
48 {
49 if (pin_num == num) {
50 return ESP_ERR_INVALID_ARG;
51 }
52 }
53
54 return ESP_OK;
55 }
56
check_gpio_drive_strength(uint32_t strength)57 esp_err_t check_gpio_drive_strength(uint32_t strength) noexcept
58 {
59 if (strength >= GPIO_DRIVE_CAP_MAX) {
60 return ESP_ERR_INVALID_ARG;
61 }
62
63 return ESP_OK;
64 }
65
FLOATING()66 GPIOPullMode GPIOPullMode::FLOATING()
67 {
68 return GPIOPullMode(GPIO_FLOATING);
69 }
70
PULLUP()71 GPIOPullMode GPIOPullMode::PULLUP()
72 {
73 return GPIOPullMode(GPIO_PULLUP_ONLY);
74 }
75
PULLDOWN()76 GPIOPullMode GPIOPullMode::PULLDOWN()
77 {
78 return GPIOPullMode(GPIO_PULLDOWN_ONLY);
79 }
80
LOW_LEVEL()81 GPIOWakeupIntrType GPIOWakeupIntrType::LOW_LEVEL()
82 {
83 return GPIOWakeupIntrType(GPIO_INTR_LOW_LEVEL);
84 }
85
HIGH_LEVEL()86 GPIOWakeupIntrType GPIOWakeupIntrType::HIGH_LEVEL()
87 {
88 return GPIOWakeupIntrType(GPIO_INTR_HIGH_LEVEL);
89 }
90
DEFAULT()91 GPIODriveStrength GPIODriveStrength::DEFAULT()
92 {
93 return MEDIUM();
94 }
95
WEAK()96 GPIODriveStrength GPIODriveStrength::WEAK()
97 {
98 return GPIODriveStrength(GPIO_DRIVE_CAP_0);
99 }
100
LESS_WEAK()101 GPIODriveStrength GPIODriveStrength::LESS_WEAK()
102 {
103 return GPIODriveStrength(GPIO_DRIVE_CAP_1);
104 }
105
MEDIUM()106 GPIODriveStrength GPIODriveStrength::MEDIUM()
107 {
108 return GPIODriveStrength(GPIO_DRIVE_CAP_2);
109 }
110
STRONGEST()111 GPIODriveStrength GPIODriveStrength::STRONGEST()
112 {
113 return GPIODriveStrength(GPIO_DRIVE_CAP_3);
114 }
115
GPIOBase(GPIONum num)116 GPIOBase::GPIOBase(GPIONum num) : gpio_num(num)
117 {
118 GPIO_CHECK_THROW(gpio_reset_pin(gpio_to_driver_type(gpio_num)));
119 }
120
hold_en()121 void GPIOBase::hold_en()
122 {
123 GPIO_CHECK_THROW(gpio_hold_en(gpio_to_driver_type(gpio_num)));
124 }
125
hold_dis()126 void GPIOBase::hold_dis()
127 {
128 GPIO_CHECK_THROW(gpio_hold_dis(gpio_to_driver_type(gpio_num)));
129 }
130
set_drive_strength(GPIODriveStrength strength)131 void GPIOBase::set_drive_strength(GPIODriveStrength strength)
132 {
133 GPIO_CHECK_THROW(gpio_set_drive_capability(gpio_to_driver_type(gpio_num),
134 static_cast<gpio_drive_cap_t>(strength.get_strength())));
135 }
136
GPIO_Output(GPIONum num)137 GPIO_Output::GPIO_Output(GPIONum num) : GPIOBase(num)
138 {
139 GPIO_CHECK_THROW(gpio_set_direction(gpio_to_driver_type(gpio_num), GPIO_MODE_OUTPUT));
140 }
141
set_high()142 void GPIO_Output::set_high()
143 {
144 GPIO_CHECK_THROW(gpio_set_level(gpio_to_driver_type(gpio_num), 1));
145 }
146
set_low()147 void GPIO_Output::set_low()
148 {
149 GPIO_CHECK_THROW(gpio_set_level(gpio_to_driver_type(gpio_num), 0));
150 }
151
get_drive_strength()152 GPIODriveStrength GPIOBase::get_drive_strength()
153 {
154 gpio_drive_cap_t strength;
155 GPIO_CHECK_THROW(gpio_get_drive_capability(gpio_to_driver_type(gpio_num), &strength));
156 return GPIODriveStrength(static_cast<uint32_t>(strength));
157 }
158
GPIOInput(GPIONum num)159 GPIOInput::GPIOInput(GPIONum num) : GPIOBase(num)
160 {
161 GPIO_CHECK_THROW(gpio_set_direction(gpio_to_driver_type(gpio_num), GPIO_MODE_INPUT));
162 }
163
get_level() const164 GPIOLevel GPIOInput::get_level() const noexcept
165 {
166 int level = gpio_get_level(gpio_to_driver_type(gpio_num));
167 if (level) {
168 return GPIOLevel::HIGH;
169 } else {
170 return GPIOLevel::LOW;
171 }
172 }
173
set_pull_mode(GPIOPullMode mode)174 void GPIOInput::set_pull_mode(GPIOPullMode mode)
175 {
176 GPIO_CHECK_THROW(gpio_set_pull_mode(gpio_to_driver_type(gpio_num),
177 static_cast<gpio_pull_mode_t>(mode.get_pull_mode())));
178 }
179
wakeup_enable(GPIOWakeupIntrType interrupt_type)180 void GPIOInput::wakeup_enable(GPIOWakeupIntrType interrupt_type)
181 {
182 GPIO_CHECK_THROW(gpio_wakeup_enable(gpio_to_driver_type(gpio_num),
183 static_cast<gpio_int_type_t>(interrupt_type.get_level())));
184 }
185
wakeup_disable()186 void GPIOInput::wakeup_disable()
187 {
188 GPIO_CHECK_THROW(gpio_wakeup_disable(gpio_to_driver_type(gpio_num)));
189 }
190
GPIO_OpenDrain(GPIONum num)191 GPIO_OpenDrain::GPIO_OpenDrain(GPIONum num) : GPIOInput(num)
192 {
193 GPIO_CHECK_THROW(gpio_set_direction(gpio_to_driver_type(gpio_num), GPIO_MODE_INPUT_OUTPUT_OD));
194 }
195
set_floating()196 void GPIO_OpenDrain::set_floating()
197 {
198 GPIO_CHECK_THROW(gpio_set_level(gpio_to_driver_type(gpio_num), 1));
199 }
200
set_low()201 void GPIO_OpenDrain::set_low()
202 {
203 GPIO_CHECK_THROW(gpio_set_level(gpio_to_driver_type(gpio_num), 0));
204 }
205
206 }
207
208 #endif
209