Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/button/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
idf_component_register(
INCLUDE_DIRS "include"
REQUIRES driver event_manager logger serialization task)
REQUIRES driver logger task)
2 changes: 1 addition & 1 deletion components/button/example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ set(EXTRA_COMPONENT_DIRS

set(
COMPONENTS
"main esptool_py button"
"main esptool_py button event_manager serialization"
CACHE STRING
"List of components to include"
)
Expand Down
2 changes: 1 addition & 1 deletion components/button/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui

## Example Output

![CleanShot 2023-06-21 at 16 28 24](https://github.com/esp-cpp/espp/assets/213467/47b18733-2999-41ac-a5c6-a50c27f6643b)
![CleanShot 2023-06-22 at 16 23 59](https://github.com/esp-cpp/espp/assets/213467/cc2a131c-7c78-4ec7-8bff-1f629137a41b)
27 changes: 22 additions & 5 deletions components/button/example/main/button_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "button.hpp"
#include "event_manager.hpp"
#include "serialization.hpp"

using namespace std::chrono_literals;

Expand All @@ -18,28 +19,44 @@ extern "C" void app_main(void) {
// create a button on GPIO 2
espp::Button button({
.gpio_num = GPIO_NUM_2,
.topic = button_topic,
.component_name = button_component_name,
.callback =
[&](const espp::Button::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.pressed);
// 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::Button::ActiveLevel::HIGH,
.interrupt_type = espp::Button::InterruptType::ANY_EDGE,
.pullup_enabled = false,
.pulldown_enabled = false,
.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::string &data) {
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::Button::Event>(data, ec);
if (!ec) {
logger.info("[{:.3f}]: button {} state changed to: {}", elapsed, state.gpio_num,
state.pressed);
logger.info("[Subscriber][{:.3f}]: button {} state changed to: {}", elapsed,
state.gpio_num, state.pressed);
} else {
logger.error("Failed to deserialize button state: {}", ec.message());
}
Expand Down
53 changes: 27 additions & 26 deletions components/button/include/button.hpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
#pragma once

#include <atomic>
#include <functional>

#include <driver/gpio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"

#include "event_manager.hpp"
#include "logger.hpp"
#include "serialization.hpp"
#include "task.hpp"

namespace espp {
/// \brief A class to handle a button connected to a GPIO
/// \details This class uses the ESP-IDF GPIO interrupt handler to detect
/// button presses and releases. It then publishes events to the
/// event manager with the topic specified in the config. The events
/// are "pressed" and "released".
/// button presses and releases. It then calls the callback function
/// with the event.
///
/// \section button_ex1 Button Example
/// \snippet button_example.cpp button example
Expand All @@ -44,12 +42,12 @@ class Button {
HIGH_LEVEL = GPIO_INTR_HIGH_LEVEL, ///< Interrupt on high level
};

typedef std::function<void(const Event &)> event_callback_fn; ///< The callback for the event

/// \brief The configuration for the button
struct Config {
int gpio_num; ///< GPIO number to use for the button
std::string topic; ///< Topic to publish events to via the event manager, e.g. "button/state"
std::string
component_name; ///< Name of the component for logging and event manager, e.g. "button"
int gpio_num; ///< GPIO number to use for the button
event_callback_fn callback; ///< Callback for the button event
ActiveLevel active_level; ///< Active level of the GPIO
InterruptType interrupt_type = InterruptType::ANY_EDGE; ///< Interrupt type to use for the GPIO
bool pullup_enabled = false; ///< Whether to enable the pullup resistor
Expand All @@ -60,14 +58,11 @@ class Button {
/// \brief Construct a button
/// \param config The configuration for the button
explicit Button(const Config &config)
: gpio_num_(config.gpio_num), topic_(config.topic),
logger_({.tag = config.component_name, .level = config.log_level}) {
: gpio_num_(config.gpio_num), callback_(config.callback), active_level_(config.active_level),
logger_({.tag = "Button", .level = config.log_level}) {
// make the event queue
event_queue_ = xQueueCreate(10, sizeof(EventData));

// register with the event manager that we want to publish events
espp::EventManager::get().add_publisher(topic_, config.component_name);

// configure the GPIO for an interrupt
gpio_config_t io_conf;
memset(&io_conf, 0, sizeof(io_conf));
Expand All @@ -79,8 +74,7 @@ class Button {
gpio_config(&io_conf);

// set the initial state of the button
pressed_ =
gpio_get_level(static_cast<gpio_num_t>(gpio_num_)) == static_cast<int>(config.active_level);
update();

// install the isr handler
handler_args_ = {
Expand Down Expand Up @@ -126,6 +120,17 @@ class Button {
int gpio_num;
};

bool update() {
auto new_state =
gpio_get_level(static_cast<gpio_num_t>(gpio_num_)) == static_cast<int>(active_level_);
logger_.debug("Button new state: {}", new_state);
if (new_state != pressed_) {
pressed_ = new_state;
return true;
}
return false;
}

static void isr_handler(void *arg) {
HandlerArgs *handler_args = static_cast<HandlerArgs *>(arg);
EventData event_data = {
Expand All @@ -141,30 +146,26 @@ class Button {
logger_.error("Received event for wrong GPIO");
return false;
}
pressed_ = !pressed_;
logger_.debug("Button state: {}", pressed_);
bool updated = update();
logger_.debug("ISR Notify, button state: {}, was updated: {}", pressed_, updated);
Event event = {
.gpio_num = static_cast<uint8_t>(gpio_num_),
.pressed = pressed_,
};
std::vector<uint8_t> buffer;
auto bytes_written = espp::serialize(event, buffer);
if (bytes_written) {
std::string data(buffer.begin(), buffer.end());
espp::EventManager::get().publish(topic_, data);
} else {
logger_.error("Failed to serialize event data");
if (callback_) {
callback_(event);
}
}
// we don't want to stop the task, so return false
return false;
}

int gpio_num_;
event_callback_fn callback_;
ActiveLevel active_level_;
QueueHandle_t event_queue_;
HandlerArgs handler_args_;
std::atomic<bool> pressed_{false};
std::string topic_;
std::unique_ptr<espp::Task> task_;
espp::Logger logger_;
};
Expand Down
2 changes: 1 addition & 1 deletion components/event_manager/example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ set(EXTRA_COMPONENT_DIRS

set(
COMPONENTS
"main esptool_py format event_manager"
"main esptool_py logger event_manager serialization"
CACHE STRING
"List of components to include"
)
Expand Down
2 changes: 1 addition & 1 deletion components/event_manager/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui

## Example Output

![output](https://user-images.githubusercontent.com/213467/231610256-73cd92e1-168d-43cd-8c92-49b5e7e79dbf.png)
![CleanShot 2023-06-22 at 16 25 55](https://github.com/esp-cpp/espp/assets/213467/93679c9c-8322-4c21-99d1-b1ab323c7ee4)
Loading