SensESP 3.3.0
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
digital_pcnt_input.cpp
Go to the documentation of this file.
2
3#include "esp_log.h"
4
5#if ESP_ARDUINO_VERSION_MAJOR < 3
6#warning "The Pulse Counter API is only available in ESP32 Arduino Core 3.0.0 and later"
7#else
8#include "driver/pulse_cnt.h"
9
10namespace sensesp {
11
12DigitalInputPcntCounter::DigitalInputPcntCounter(uint8_t pin, int pin_mode,
13 int interrupt_type,
14 unsigned int read_delay,
15 String config_path)
16 : DigitalInput(pin, pin_mode),
17 Sensor(config_path),
18 read_delay_(read_delay),
19 interrupt_type_(interrupt_type) {
20 load();
21
22 ESP_ERROR_CHECK(configurePcnt(interrupt_type));
23
24 event_loop()->onRepeat(read_delay_, [this]() {
25 // Note: there is a small TOCTOU window between pcnt_unit_get_count and
26 // pcnt_unit_clear_count where pulses can be lost. noInterrupts() does not
27 // help because PCNT is a hardware counter that counts independently.
28 int count = 0;
29 ESP_ERROR_CHECK(pcnt_unit_get_count(pcnt_unit_, &count));
30 ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit_));
31 output_ = count;
32 notify();
33 });
34}
35
36DigitalInputPcntCounter::~DigitalInputPcntCounter() {
37 esp_err_t err;
38 if (pcnt_channel_) {
39 err = pcnt_del_channel(pcnt_channel_);
40 if (err != ESP_OK) {
41 ESP_LOGE("PCNT", "Failed to delete PCNT channel: %s", esp_err_to_name(err));
42 }
43 }
44 if (pcnt_unit_) {
45 err = pcnt_unit_stop(pcnt_unit_);
46 if (err != ESP_OK) {
47 ESP_LOGE("PCNT", "Failed to stop PCNT unit: %s", esp_err_to_name(err));
48 }
49 err = pcnt_unit_disable(pcnt_unit_);
50 if (err != ESP_OK) {
51 ESP_LOGE("PCNT", "Failed to disable PCNT unit: %s", esp_err_to_name(err));
52 }
53 err = pcnt_del_unit(pcnt_unit_);
54 if (err != ESP_OK) {
55 ESP_LOGE("PCNT", "Failed to delete PCNT unit: %s", esp_err_to_name(err));
56 }
57 }
58}
59
60esp_err_t DigitalInputPcntCounter::configurePcnt(int interrupt_mode) {
61 pcnt_unit_config_t unit_config = {
62 .low_limit = -1,
63 .high_limit = INT16_MAX,
64 };
65
66 ESP_ERROR_CHECK(pcnt_new_unit(&unit_config, &pcnt_unit_));
67
68 pcnt_chan_config_t chan_config = {.edge_gpio_num = pin_,
69 .level_gpio_num = -1,
70 .flags = {.invert_edge_input = false,
71 .invert_level_input = false,
72 .virt_edge_io_level = 0,
73 .virt_level_io_level = 0,
74 .io_loop_back = false}};
75
76 ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit_, &chan_config, &pcnt_channel_));
77
78 pcnt_channel_edge_action_t edge_action_pos =
79 (interrupt_mode == RISING || interrupt_mode == CHANGE)
80 ? PCNT_CHANNEL_EDGE_ACTION_INCREASE
81 : PCNT_CHANNEL_EDGE_ACTION_HOLD;
82 pcnt_channel_edge_action_t edge_action_neg =
83 (interrupt_mode == FALLING || interrupt_mode == CHANGE)
84 ? PCNT_CHANNEL_EDGE_ACTION_INCREASE
85 : PCNT_CHANNEL_EDGE_ACTION_HOLD;
86 ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_channel_, edge_action_pos,
87 edge_action_neg));
88
89 ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit_));
90 ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit_));
91
92 return pcnt_unit_start(pcnt_unit_);
93}
94
95bool DigitalInputPcntCounter::to_json(JsonObject& root) {
96 root["read_delay"] = read_delay_;
97 return true;
98}
99
100bool DigitalInputPcntCounter::from_json(const JsonObject& config) {
101 String const expected[] = {"read_delay"};
102 for (auto str : expected) {
103 if (!config[str].is<JsonVariant>()) {
104 return false;
105 }
106 }
107 read_delay_ = config["read_delay"];
108 return true;
109}
110
111const String ConfigSchema(const DigitalInputPcntCounter& obj) {
112 return R"###({"type":"object","properties":{"read_delay":{"title":"Read delay","type":"number","description":"The time, in milliseconds, between each read of the input"}} })###";
113}
114
115bool ConfigRequiresRestart(const DigitalInputPcntCounter& obj) { return true; }
116
117} // namespace sensesp
118
119#endif // ESP_ARDUINO_VERSION_MAJOR < 3
DigitalInput is the base class for reading a digital GPIO pin.
Sensor template class for any sensor producing actual values.
Definition sensor.h:42
const String ConfigSchema(const SmartSwitchController &obj)
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
bool ConfigRequiresRestart(const HTTPServer &obj)