From bd2353fea83ac30d3f2073eb4c5e69d73e559442 Mon Sep 17 00:00:00 2001
From: William Emfinger
Date: Mon, 12 Feb 2024 12:32:26 -0600
Subject: [PATCH] Feature/base peripheral (#150)
* feat(base_peripheral): added base peripheral class
* doc: include base peripheral in doc
* feat: update peripherals
* Update peripheral classes to use new base_peripheral as the base class
* doc: rebuild
* fix: fix bldc_motor and bldc_haptics example for breaking change to mt6701 config (read -> read_register)
* fix(bldc_driver): ensure configuration structs are zeroed out
* example(tla2528): update
* Updated tla2528 example to test all analog input channels
* fix(max1704x): fix u8 read to make it u16 so it reads the right values
* fix: typo
* doc: rebuild
* fix(gt911): fix reading / writing 16bit register addresses
---
components/ads1x15/CMakeLists.txt | 2 +-
.../ads1x15/example/main/ads1x15_example.cpp | 9 +-
components/ads1x15/include/ads1x15.hpp | 83 +---
components/ads1x15/src/ads1x15.cpp | 14 +-
components/ads7138/CMakeLists.txt | 2 +-
components/ads7138/include/ads7138.hpp | 148 +++----
components/as5600/CMakeLists.txt | 2 +-
.../as5600/example/main/as5600_example.cpp | 7 +-
components/as5600/include/as5600.hpp | 56 +--
components/aw9523/CMakeLists.txt | 2 +-
.../aw9523/example/main/aw9523_example.cpp | 5 +-
components/aw9523/include/aw9523.hpp | 122 ++----
components/base_peripheral/CMakeLists.txt | 3 +
.../include/base_peripheral.hpp | 382 ++++++++++++++++++
.../bldc_driver/include/bldc_driver.hpp | 2 +
.../example/main/bldc_haptics_example.cpp | 5 +-
.../example/main/bldc_motor_example.cpp | 5 +-
components/bm8563/CMakeLists.txt | 2 +-
.../bm8563/example/main/bm8563_example.cpp | 5 +-
components/bm8563/include/bm8563.hpp | 60 +--
components/drv2605/CMakeLists.txt | 2 +-
.../drv2605/example/main/drv2605_example.cpp | 10 +-
components/drv2605/include/drv2605.hpp | 99 ++---
components/ft5x06/CMakeLists.txt | 2 +-
.../ft5x06/example/main/ft5x06_example.cpp | 6 +-
components/ft5x06/include/ft5x06.hpp | 87 +---
components/gt911/CMakeLists.txt | 2 +-
.../gt911/example/main/gt911_example.cpp | 10 +-
components/gt911/include/gt911.hpp | 80 ++--
components/max1704x/CMakeLists.txt | 2 +-
components/max1704x/include/max1704x.hpp | 103 +----
components/mcp23x17/CMakeLists.txt | 2 +-
.../example/main/mcp23x17_example.cpp | 5 +-
components/mcp23x17/include/mcp23x17.hpp | 99 ++---
components/mt6701/CMakeLists.txt | 2 +-
.../mt6701/example/main/mt6701_example.cpp | 16 +-
components/mt6701/include/mt6701.hpp | 58 +--
components/ndef/include/ndef.hpp | 8 +-
components/qwiicnes/CMakeLists.txt | 2 +-
.../example/main/qwiicnes_example.cpp | 13 +-
components/qwiicnes/include/qwiicnes.hpp | 71 ++--
components/st25dv/CMakeLists.txt | 2 +-
.../st25dv/example/main/st25dv_example.cpp | 21 +-
components/st25dv/example/sdkconfig.defaults | 2 +-
components/st25dv/include/st25dv.hpp | 139 ++++---
components/t_keyboard/CMakeLists.txt | 2 +-
components/t_keyboard/include/t_keyboard.hpp | 61 +--
components/tla2528/CMakeLists.txt | 2 +-
.../tla2528/example/main/tla2528_example.cpp | 31 +-
components/tla2528/include/tla2528.hpp | 162 +++-----
components/tt21100/CMakeLists.txt | 2 +-
components/tt21100/include/tt21100.hpp | 56 ++-
doc/Doxyfile | 1 +
doc/en/base_peripheral.rst | 20 +
doc/en/index.rst | 1 +
docs/_sources/index.rst.txt | 1 +
docs/adc/adc_types.html | 3 +-
docs/adc/ads1x15.html | 195 +++++++--
docs/adc/ads7138.html | 186 ++++++++-
docs/adc/continuous_adc.html | 5 +-
docs/adc/index.html | 3 +-
docs/adc/oneshot_adc.html | 5 +-
docs/adc/tla2528.html | 213 ++++++++--
docs/base_component.html | 11 +-
docs/base_peripheral.html | 269 +++++++++++-
docs/battery/bldc_driver.html | 5 +-
docs/battery/bldc_motor.html | 14 +-
docs/battery/index.html | 7 +-
docs/battery/max1704x.html | 178 +++++++-
docs/bldc/bldc_driver.html | 5 +-
docs/bldc/bldc_motor.html | 14 +-
docs/bldc/index.html | 3 +-
docs/button.html | 5 +-
docs/cli.html | 7 +-
docs/color.html | 5 +-
docs/controller.html | 5 +-
docs/csv.html | 5 +-
docs/display/display.html | 5 +-
docs/display/display_drivers.html | 7 +-
docs/display/index.html | 3 +-
docs/encoder/abi_encoder.html | 5 +-
docs/encoder/as5600.html | 208 ++++++++--
docs/encoder/encoder_types.html | 3 +-
docs/encoder/index.html | 3 +-
docs/encoder/mt6701.html | 213 ++++++++--
docs/event_manager.html | 5 +-
docs/file_system.html | 5 +-
docs/filters/biquad.html | 5 +-
docs/filters/butterworth.html | 5 +-
docs/filters/index.html | 3 +-
docs/filters/lowpass.html | 5 +-
docs/filters/sos.html | 5 +-
docs/filters/transfer_function.html | 3 +-
docs/ftp/ftp_server.html | 7 +-
docs/ftp/index.html | 3 +-
docs/genindex.html | 297 +++++++++++++-
docs/haptics/bldc_haptics.html | 9 +-
docs/haptics/drv2605.html | 195 +++++++--
docs/haptics/index.html | 3 +-
docs/i2c.html | 5 +-
docs/index.html | 7 +-
docs/input/encoder_input.html | 5 +-
docs/input/ft5x06.html | 189 +++++++--
docs/input/gt911.html | 180 ++++++++-
docs/input/index.html | 3 +-
docs/input/keypad_input.html | 5 +-
docs/input/t_keyboard.html | 192 +++++++--
docs/input/touchpad_input.html | 5 +-
docs/input/tt21100.html | 180 ++++++++-
docs/io_expander/aw9523.html | 190 +++++++--
docs/io_expander/index.html | 3 +-
docs/io_expander/mcp23x17.html | 191 +++++++--
docs/joystick.html | 5 +-
docs/led.html | 5 +-
docs/led_strip.html | 5 +-
docs/logger.html | 5 +-
docs/math/bezier.html | 5 +-
docs/math/fast_math.html | 3 +-
docs/math/gaussian.html | 5 +-
docs/math/index.html | 3 +-
docs/math/range_mapper.html | 5 +-
docs/math/vector2d.html | 5 +-
docs/monitor.html | 5 +-
docs/network/index.html | 3 +-
docs/network/socket.html | 5 +-
docs/network/tcp_socket.html | 5 +-
docs/network/udp_socket.html | 5 +-
docs/nfc/index.html | 3 +-
docs/nfc/ndef.html | 5 +-
docs/nfc/st25dv.html | 200 +++++++--
docs/objects.inv | Bin 64792 -> 66081 bytes
docs/pid.html | 5 +-
docs/qwiicnes.html | 208 ++++++++--
docs/rmt.html | 7 +-
docs/rtc/bm8563.html | 188 +++++++--
docs/rtc/index.html | 3 +-
docs/rtsp.html | 19 +-
docs/search.html | 1 +
docs/searchindex.js | 2 +-
docs/serialization.html | 5 +-
docs/state_machine.html | 11 +-
docs/tabulate.html | 5 +-
docs/task.html | 5 +-
docs/thermistor.html | 5 +-
docs/timer.html | 5 +-
docs/wifi/index.html | 3 +-
docs/wifi/wifi_ap.html | 5 +-
docs/wifi/wifi_sta.html | 5 +-
148 files changed, 4414 insertions(+), 1738 deletions(-)
create mode 100644 components/base_peripheral/CMakeLists.txt
create mode 100644 components/base_peripheral/include/base_peripheral.hpp
create mode 100644 doc/en/base_peripheral.rst
diff --git a/components/ads1x15/CMakeLists.txt b/components/ads1x15/CMakeLists.txt
index eaba5c0af..3616d6e54 100644
--- a/components/ads1x15/CMakeLists.txt
+++ b/components/ads1x15/CMakeLists.txt
@@ -1,5 +1,5 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
- REQUIRES "logger" "pthread"
+ REQUIRES "base_peripheral" "pthread"
)
diff --git a/components/ads1x15/example/main/ads1x15_example.cpp b/components/ads1x15/example/main/ads1x15_example.cpp
index 255ad24ed..d49047f71 100644
--- a/components/ads1x15/example/main/ads1x15_example.cpp
+++ b/components/ads1x15/example/main/ads1x15_example.cpp
@@ -24,10 +24,11 @@ extern "C" void app_main(void) {
// make the actual ads class
espp::Ads1x15 ads(espp::Ads1x15::Ads1015Config{
.device_address = espp::Ads1x15::DEFAULT_ADDRESS,
- .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
- .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3)});
+ .write = [&i2c](uint8_t addr, const uint8_t *data,
+ size_t len) { return i2c.write(addr, data, len); },
+ .read = [&i2c](uint8_t addr, uint8_t *data,
+ size_t len) { return i2c.read(addr, data, len); },
+ });
// make the task which will get the raw data from the I2C ADC
auto ads_read_task_fn = [&ads](std::mutex &m, std::condition_variable &cv) {
static auto start = std::chrono::high_resolution_clock::now();
diff --git a/components/ads1x15/include/ads1x15.hpp b/components/ads1x15/include/ads1x15.hpp
index d2bd596fc..d855587fb 100644
--- a/components/ads1x15/include/ads1x15.hpp
+++ b/components/ads1x15/include/ads1x15.hpp
@@ -2,10 +2,9 @@
#include
#include
-#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -14,28 +13,10 @@ namespace espp {
* \section ads1x15_ex1 ADS1X15 Example
* \snippet ads1x15_example.cpp ads1x15 example
*/
-class Ads1x15 {
+class Ads1x15 : public espp::BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = (0x48); ///< I2C address of the ADS1x15 chips.
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if the write was successful.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful.
- */
- typedef std::function read_fn;
-
/**
* @brief Gain values for the ADC conversion.
*/
@@ -80,8 +61,8 @@ class Ads1x15 {
*/
struct Ads1015Config {
uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address of the device.
- write_fn write; ///< Function to write to the ADC
- read_fn read; ///< Function to read from the ADC
+ BasePeripheral::write_fn write; ///< Function to write to the ADC
+ BasePeripheral::read_fn read; ///< Function to read from the ADC
Gain gain{Gain::TWOTHIRDS}; ///< Gain for the ADC
Ads1015Rate sample_rate{Ads1015Rate::SPS1600}; ///< Sample rate for the ADC
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< Verbosity for the logger.
@@ -92,8 +73,8 @@ class Ads1x15 {
*/
struct Ads1115Config {
uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address of the device.
- write_fn write; ///< Function to write to the ADC
- read_fn read; ///< Function to read from the ADC
+ BasePeripheral::write_fn write; ///< Function to write to the ADC
+ BasePeripheral::read_fn read; ///< Function to read from the ADC
Gain gain{Gain::TWOTHIRDS}; ///< Gain for the ADC
Ads1115Rate sample_rate{Ads1115Rate::SPS128}; ///< Sample rate for the ADC
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< Verbosity for the logger.
@@ -104,18 +85,24 @@ class Ads1x15 {
* @param config Configuration structure.
*/
explicit Ads1x15(const Ads1015Config &config)
- : gain_(config.gain), ads1015rate_(config.sample_rate), bit_shift_(4),
- address_(config.device_address), write_(config.write), read_(config.read),
- logger_({.tag = "Ads1015", .level = config.log_level}) {}
+ : BasePeripheral(
+ {.address = config.device_address, .write = config.write, .read = config.read},
+ "Ads1015", config.log_level)
+ , gain_(config.gain)
+ , ads1015rate_(config.sample_rate)
+ , bit_shift_(4) {}
/**
* @brief Construct Ads1x15 specficially for ADS1115.
* @param config Configuration structure.
*/
explicit Ads1x15(const Ads1115Config &config)
- : gain_(config.gain), ads1115rate_(config.sample_rate), bit_shift_(0),
- address_(config.device_address), write_(config.write), read_(config.read),
- logger_({.tag = "Ads1115", .level = config.log_level}) {}
+ : BasePeripheral(
+ {.address = config.device_address, .write = config.write, .read = config.read},
+ "Ads1115", config.log_level)
+ , gain_(config.gain)
+ , ads1115rate_(config.sample_rate)
+ , bit_shift_(0) {}
/**
* @brief Communicate with the ADC to sample the channel and return the
@@ -165,35 +152,6 @@ class Ads1x15 {
return raw * (fsRange / (32768 >> bit_shift_));
}
- uint16_t read_two_(uint8_t reg_addr, std::error_code &ec) {
- // lock the mutex so that we don't have multiple threads trying to read
- // from the device at the same time
- std::lock_guard lock(mutex_);
- // write the reg addr we want to read from
- bool success = write_(address_, ®_addr, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- // then read the two bytes
- uint8_t data[2];
- success = read_(address_, data, 2);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return (data[0] << 8) | data[1];
- }
-
- void write_two_(uint8_t reg_addr, uint16_t value, std::error_code &ec) {
- uint8_t total_len = 3;
- uint8_t data[total_len] = {reg_addr, (uint8_t)(value >> 8), (uint8_t)(value & 0xFF)};
- bool success = write_(address_, data, total_len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
enum class Register : uint8_t {
POINTER_CONVERT = 0x00, ///< Conversion
POINTER_CONFIG = 0x01, ///< Configuration
@@ -208,10 +166,5 @@ class Ads1x15 {
uint16_t rate_;
};
int bit_shift_;
- uint8_t address_;
- write_fn write_;
- read_fn read_;
- std::mutex mutex_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/ads1x15/src/ads1x15.cpp b/components/ads1x15/src/ads1x15.cpp
index 08756b58d..8566e4e66 100644
--- a/components/ads1x15/src/ads1x15.cpp
+++ b/components/ads1x15/src/ads1x15.cpp
@@ -51,10 +51,6 @@ static constexpr uint16_t REG_CONFIG_CQUE_NONE =
(0x0003); ///< Disable the comparator and put ALERT/RDY in high state (default)
int16_t Ads1x15::sample_raw(int channel, std::error_code &ec) {
- if (!write_ || !read_) {
- logger_.error("Write / read functions not properly configured, cannot sample!");
- return 0;
- }
// Start with default values
uint16_t config = REG_CONFIG_MODE_SINGLE;
// This is equivalent to the below (since the rest are 0x0000):
@@ -72,17 +68,17 @@ int16_t Ads1x15::sample_raw(int channel, std::error_code &ec) {
config |= REG_CONFIG_OS_SINGLE;
// configure to read from mux 0
logger_.debug("configuring conversion for channel {}", channel);
- write_two_((uint8_t)Register::POINTER_CONFIG, config, ec);
+ write_u16_to_register((uint8_t)Register::POINTER_CONFIG, config, ec);
if (ec) {
logger_.error("error configuring conversion for channel {}", channel);
return 0;
}
- write_two_((uint8_t)Register::POINTER_HITHRESH, 0x8000, ec);
+ write_u16_to_register((uint8_t)Register::POINTER_HITHRESH, 0x8000, ec);
if (ec) {
logger_.error("error configuring hi threshold for channel {}", channel);
return 0;
}
- write_two_((uint8_t)Register::POINTER_LOWTHRESH, 0x0000, ec);
+ write_u16_to_register((uint8_t)Register::POINTER_LOWTHRESH, 0x0000, ec);
if (ec) {
logger_.error("error configuring low threshold for channel {}", channel);
return 0;
@@ -97,7 +93,7 @@ int16_t Ads1x15::sample_raw(int channel, std::error_code &ec) {
return 0;
}
logger_.debug("reading conversion result for channel {}", channel);
- uint16_t val = read_two_((uint8_t)Register::POINTER_CONVERT, ec) >> bit_shift_;
+ uint16_t val = read_u16_from_register((uint8_t)Register::POINTER_CONVERT, ec) >> bit_shift_;
if (ec) {
logger_.error("error reading conversion result for channel {}", channel);
return 0;
@@ -112,7 +108,7 @@ int16_t Ads1x15::sample_raw(int channel, std::error_code &ec) {
}
bool Ads1x15::conversion_complete(std::error_code &ec) {
- auto val = read_two_((uint8_t)Register::POINTER_CONFIG, ec);
+ auto val = read_u16_from_register((uint8_t)Register::POINTER_CONFIG, ec);
if (ec) {
logger_.error("error reading config register");
return false;
diff --git a/components/ads7138/CMakeLists.txt b/components/ads7138/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/ads7138/CMakeLists.txt
+++ b/components/ads7138/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/ads7138/include/ads7138.hpp b/components/ads7138/include/ads7138.hpp
index 100c7f92a..6667c2e24 100644
--- a/components/ads7138/include/ads7138.hpp
+++ b/components/ads7138/include/ads7138.hpp
@@ -8,7 +8,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -25,30 +25,12 @@ namespace espp {
* @section ads7138_ex1 ADS7138 Example
* @snippet ads7138_example.cpp ads7138 example
*/
-class Ads7138 {
+class Ads7138 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS =
(0x10); ///< Default I2C address of the device (when both R1 and R2 are DNP) (see data sheet
///< Table 2, p. 16)
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if successful, false otherwise.
- */
- typedef std::function read_fn;
-
/// @brief Possible oversampling ratios, see data sheet Table 15 (p. 34)
enum class OversamplingRatio : uint8_t {
NONE = 0, ///< No oversampling
@@ -167,8 +149,8 @@ class Ads7138 {
///< mode.
OversamplingRatio oversampling_ratio = OversamplingRatio::NONE; ///< Oversampling ratio to use.
bool statistics_enabled = true; ///< Enable statistics collection (min, max, recent)
- write_fn write; ///< Function to write to the ADC
- read_fn read; ///< Function to read from the ADC
+ BasePeripheral::write_fn write; ///< Function to write to the ADC
+ BasePeripheral::read_fn read; ///< Function to read from the ADC
bool auto_init = true; ///< Automatically initialize the ADC on construction. If false,
///< initialize() must be called before any other functions.
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< Verbosity for the logger.
@@ -179,15 +161,19 @@ class Ads7138 {
* @param config Configuration structure.
*/
explicit Ads7138(const Config &config)
- : config_(config), mode_(config.mode), avdd_mv_(config.avdd_volts * 1000.0f) // Convert to mV
- ,
- data_format_(config.oversampling_ratio == OversamplingRatio::NONE ? DataFormat::RAW
- : DataFormat::AVERAGED),
- statistics_enabled_(config.statistics_enabled), analog_inputs_(config.analog_inputs),
- digital_inputs_(config.digital_inputs), digital_outputs_(config.digital_outputs),
- oversampling_ratio_(config.oversampling_ratio), address_(config.device_address),
- write_(config.write), read_(config.read),
- logger_({.tag = "Ads7138", .level = config.log_level}) {
+ : BasePeripheral(
+ {.address = config.device_address, .write = config.write, .read = config.read},
+ "Ads7138", config.log_level)
+ , config_(config)
+ , mode_(config.mode)
+ , avdd_mv_(config.avdd_volts * 1000.0f) // Convert to mV
+ , data_format_(config.oversampling_ratio == OversamplingRatio::NONE ? DataFormat::RAW
+ : DataFormat::AVERAGED)
+ , statistics_enabled_(config.statistics_enabled)
+ , analog_inputs_(config.analog_inputs)
+ , digital_inputs_(config.digital_inputs)
+ , digital_outputs_(config.digital_outputs)
+ , oversampling_ratio_(config.oversampling_ratio) {
// initialize the ADC
if (config.auto_init) {
std::error_code ec;
@@ -525,6 +511,8 @@ class Ads7138 {
/// @param ec Error code to set if an error occurs.
/// @note This will reset all registers to their default values (converting
/// all channels to analog inputs and disabling all events).
+ /// @note If the write is successful, the function will wait for the reset
+ /// to complete before returning
void reset(std::error_code &ec) {
std::lock_guard lock(mutex_);
// reset the device
@@ -1052,7 +1040,7 @@ class Ads7138 {
logger_.info("Reading recent values for all channels");
std::vector values(analog_inputs_.size());
uint8_t raw_values[16];
- read_many_(Register::RECENT_CH0_LSB, raw_values, 16, ec);
+ read_block_(Register::RECENT_CH0_LSB, raw_values, 16, ec);
if (ec)
return {};
int analog_index = 0;
@@ -1077,7 +1065,7 @@ class Ads7138 {
logger_.info("Reading recent mapped values for all channels");
std::unordered_map values;
uint8_t raw_values[16];
- read_many_(Register::RECENT_CH0_LSB, raw_values, 16, ec);
+ read_block_(Register::RECENT_CH0_LSB, raw_values, 16, ec);
if (ec)
return {};
// only pull out the ones that were configured as analog inputs
@@ -1121,7 +1109,7 @@ class Ads7138 {
std::vector values(analog_inputs_.size());
uint8_t raw_values[16];
int analog_index = 0;
- read_many_(Register::MAX_CH0_LSB, raw_values, 16, ec);
+ read_block_(Register::MAX_CH0_LSB, raw_values, 16, ec);
if (ec)
return {};
// only pull out the ones that were configured as analog inputs
@@ -1164,7 +1152,7 @@ class Ads7138 {
std::vector values(analog_inputs_.size());
uint8_t raw_values[16];
int analog_index = 0;
- read_many_(Register::MIN_CH0_LSB, raw_values, 16, ec);
+ read_block_(Register::MIN_CH0_LSB, raw_values, 16, ec);
if (ec)
return {};
// only pull out the ones that were configured as analog inputs
@@ -1405,8 +1393,9 @@ class Ads7138 {
// low threshold register contains 8 msb of low threshold
static_cast(low_threshold >> 4)};
// write the data to the registers
- write_many_(static_cast(static_cast(Register::HYSTERESIS_CH0) + channel * 4),
- data, sizeof(data), ec);
+ write_block_(
+ static_cast(static_cast(Register::HYSTERESIS_CH0) + channel * 4), data,
+ sizeof(data), ec);
}
bool is_digital_input(Channel channel) {
@@ -1423,20 +1412,15 @@ class Ads7138 {
return std::find(analog_inputs_.begin(), analog_inputs_.end(), channel) != analog_inputs_.end();
}
+ // NOTE: this chip has specific read and write operation commands that are
+ // used, so we don't use the subclass's read_* and write_* methods directly
+
uint8_t read_one_(Register reg, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
+ uint8_t data = 0;
uint8_t read_one_command[] = {OP_READ_ONE, (uint8_t)reg};
- bool success = write_(address_, read_one_command, sizeof(read_one_command));
- if (!success) {
- logger_.error("Failed to write read one command");
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- uint8_t data;
- success = read_(address_, &data, 1);
- if (!success) {
- logger_.error("Failed to read one byte");
- ec = std::make_error_code(std::errc::io_error);
+ write_then_read(read_one_command, sizeof(read_one_command), &data, 1, ec);
+ if (ec) {
return 0;
}
return data;
@@ -1444,82 +1428,52 @@ class Ads7138 {
uint16_t read_two_(Register reg, std::error_code &ec) {
uint8_t data[2];
- read_many_(reg, data, 2, ec);
- if (ec)
+ read_block_(reg, data, 2, ec);
+ if (ec) {
return 0;
+ }
// NOTE: registers are little endian (LSB first, then MSB) so if we want
// to read the value of a 16 bit register we need to read the LSB first,
// then the MSB and combine them into a 16 bit value
return (data[1] << 8) | data[0];
}
- void read_many_(Register reg, uint8_t *data, uint8_t len, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ void read_block_(Register reg, uint8_t *data, uint8_t len, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
uint8_t read_block_command[] = {OP_READ_BLOCK, (uint8_t)reg};
- bool success = write_(address_, read_block_command, sizeof(read_block_command));
- if (!success) {
- logger_.error("Failed to write read block command");
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
- success = read_(address_, data, len);
- if (!success) {
- logger_.error("Failed to read {} bytes", len);
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_then_read(read_block_command, sizeof(read_block_command), data, len, ec);
}
void set_bits_(Register reg, uint8_t bit, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_SET_BITS, (uint8_t)reg, bit};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- logger_.error("Failed to write set bits command");
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void clear_bits_(Register reg, uint8_t bit, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_CLR_BITS, (uint8_t)reg, bit};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- logger_.error("Failed to write clear bits command");
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void write_one_(Register reg, uint8_t value, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_WRITE_ONE, (uint8_t)reg, value};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- logger_.error("Failed to write write one command");
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void write_two_(Register reg, uint16_t value, std::error_code &ec) {
- write_many_(reg, (uint8_t *)&value, 2, ec);
+ write_block_(reg, (uint8_t *)&value, 2, ec);
}
- void write_many_(Register reg, const uint8_t *data, uint8_t len, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ void write_block_(Register reg, const uint8_t *data, uint8_t len, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
uint8_t total_len = len + 2;
uint8_t data_with_header[total_len];
data_with_header[0] = OP_WRITE_BLOCK;
data_with_header[1] = (uint8_t)reg;
memcpy(data_with_header + 2, data, len);
- bool success = write_(address_, data_with_header, total_len);
- if (!success) {
- logger_.error("Failed to write write block command");
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data_with_header, total_len, ec);
}
Config config_;
@@ -1534,11 +1488,7 @@ class Ads7138 {
std::vector digital_inputs_;
std::vector digital_outputs_;
OversamplingRatio oversampling_ratio_;
- uint8_t address_;
- write_fn write_;
- read_fn read_;
std::recursive_mutex mutex_; ///< mutex for thread safety
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/as5600/CMakeLists.txt b/components/as5600/CMakeLists.txt
index a244e0474..f7698dd56 100644
--- a/components/as5600/CMakeLists.txt
+++ b/components/as5600/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger" "task"
+ REQUIRES "base_peripheral" "task"
)
diff --git a/components/as5600/example/main/as5600_example.cpp b/components/as5600/example/main/as5600_example.cpp
index e4f34b4ea..0964695cc 100644
--- a/components/as5600/example/main/as5600_example.cpp
+++ b/components/as5600/example/main/as5600_example.cpp
@@ -32,10 +32,9 @@ extern "C" void app_main(void) {
// now make the as5600 which decodes the data
espp::As5600 as5600(
- {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ {.write_then_read =
+ std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
.velocity_filter = filter_fn,
.update_period = std::chrono::duration(encoder_update_period),
.log_level = espp::Logger::Verbosity::WARN});
diff --git a/components/as5600/include/as5600.hpp b/components/as5600/include/as5600.hpp
index 7ad19480c..7548f86f3 100644
--- a/components/as5600/include/as5600.hpp
+++ b/components/as5600/include/as5600.hpp
@@ -4,7 +4,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
#include "task.hpp"
namespace espp {
@@ -28,30 +28,10 @@ namespace espp {
* \section as5600_ex1 As5600 Example
* \snippet as5600_example.cpp as5600 example
*/
-class As5600 {
+class As5600 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = (0b0110110); ///< I2C address of the AS5600
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if the write was successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param reg_addr Register address to read from.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* @brief Filter the input raw velocity and return it.
* @param raw Most recent raw velocity measured.
@@ -76,9 +56,9 @@ class As5600 {
* @brief Configuration information for the As5600.
*/
struct Config {
- uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address for this device.
- write_fn write; ///< Function to write to the device.
- read_fn read; ///< Function to read from the device.
+ uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address for this device.
+ BasePeripheral::write_then_read_fn
+ write_then_read; ///< Function to write then read from the device.
velocity_filter_fn velocity_filter{nullptr}; ///< Function to filter the veolcity. @note Will be
///< called once every update_period seconds.
std::chrono::duration update_period{
@@ -94,9 +74,11 @@ class As5600 {
* @brief Construct the As5600 and start the update task.
*/
explicit As5600(const Config &config)
- : address_(config.device_address), write_(config.write), read_(config.read),
- velocity_filter_(config.velocity_filter), update_period_(config.update_period),
- logger_({.tag = "As5600", .level = config.log_level}) {
+ : BasePeripheral(
+ {.address = config.device_address, .write_then_read = config.write_then_read}, "As5600",
+ config.log_level)
+ , velocity_filter_(config.velocity_filter)
+ , update_period_(config.update_period) {
logger_.info("Initializing. Fastest measurable velocity will be {:.3f} RPM",
// half a rotation in one update period is the fastest we can
// measure
@@ -180,11 +162,11 @@ class As5600 {
int read_count(std::error_code &ec) {
logger_.info("read_count");
// read the angle count registers
- uint8_t angle_h = read_one_((uint8_t)Registers::ANGLE_H, ec);
+ uint8_t angle_h = read_u8_from_register((uint8_t)Registers::ANGLE_H, ec);
if (ec) {
return 0;
}
- uint8_t angle_l = read_one_((uint8_t)Registers::ANGLE_L, ec) >> 2;
+ uint8_t angle_l = read_u8_from_register((uint8_t)Registers::ANGLE_L, ec) >> 2;
if (ec) {
return 0;
}
@@ -304,25 +286,11 @@ class As5600 {
static constexpr int MAGNET_LOW = (1 << 4); ///< For use with the STATUS register
static constexpr int MAGNET_DETECTED = (1 << 5); ///< For use with the STATUS register
- uint8_t read_one_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data;
- bool success = read_(address_, reg_addr, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
- uint8_t address_;
- write_fn write_;
- read_fn read_;
velocity_filter_fn velocity_filter_{nullptr};
std::chrono::duration update_period_;
std::atomic count_{0};
std::atomic accumulator_{0};
std::atomic velocity_rpm_{0};
std::unique_ptr task_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/aw9523/CMakeLists.txt b/components/aw9523/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/aw9523/CMakeLists.txt
+++ b/components/aw9523/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/aw9523/example/main/aw9523_example.cpp b/components/aw9523/example/main/aw9523_example.cpp
index 408dab408..2d7db00e8 100644
--- a/components/aw9523/example/main/aw9523_example.cpp
+++ b/components/aw9523/example/main/aw9523_example.cpp
@@ -36,8 +36,9 @@ extern "C" void app_main(void) {
.port_1_direction_mask = 0b00000011,
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .write_then_read =
+ std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
.log_level = espp::Logger::Verbosity::WARN});
std::error_code ec;
aw9523.initialize(ec); // Initialized separately from the constructor.
diff --git a/components/aw9523/include/aw9523.hpp b/components/aw9523/include/aw9523.hpp
index bae93505f..b573d4fed 100644
--- a/components/aw9523/include/aw9523.hpp
+++ b/components/aw9523/include/aw9523.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -14,30 +14,10 @@ namespace espp {
* \section aw9523_ex1 AW9523 Example
* \snippet aw9523_example.cpp aw9523 example
*/
-class Aw9523 {
+class Aw9523 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = 0x58; ///< Lower 2 bits are AD1, AD0 pins on the chip.
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param reg_addr Register address to read from.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* The two GPIO ports the Aw9523 has.
*/
@@ -74,11 +54,12 @@ class Aw9523 {
uint8_t port_1_direction_mask = 0x00; ///< Direction mask (1 = input) for port 1.
uint8_t port_1_interrupt_mask = 0x00; ///< Interrupt mask (1 = disable interrupt) for port 1.
OutputDriveModeP0 output_drive_mode_p0 =
- OutputDriveModeP0::OPEN_DRAIN; ///< Output drive mode for Port 0
- MaxLedCurrent max_led_current = MaxLedCurrent::IMAX; ///< Max current allowed on each LED.
- write_fn write; ///< Function to write to the device.
- read_fn read; ///< Function to read from the device.
- bool auto_init = true; ///< Automatically initialize the device.
+ OutputDriveModeP0::OPEN_DRAIN; ///< Output drive mode for Port 0
+ MaxLedCurrent max_led_current = MaxLedCurrent::IMAX; ///< Max current allowed on each LED.
+ BasePeripheral::write_fn write; ///< Function to write to the device.
+ BasePeripheral::write_then_read_fn
+ write_then_read; ///< Function to write then read from the device.
+ bool auto_init = true; ///< Automatically initialize the device.
Logger::Verbosity log_level{Logger::Verbosity::WARN}; ///< Log verbosity for the component.
};
@@ -87,8 +68,11 @@ class Aw9523 {
* @param config Config structure for configuring the AW9523
*/
explicit Aw9523(const Config &config)
- : config_(config), address_(config.device_address), write_(config.write), read_(config.read),
- logger_({.tag = "Aw9523", .level = config.log_level}) {
+ : BasePeripheral({.address = config.device_address,
+ .write = config.write,
+ .write_then_read = config.write_then_read},
+ "Aw9523", config.log_level)
+ , config_(config) {
if (config.auto_init) {
std::error_code ec;
initialize(ec);
@@ -112,7 +96,7 @@ class Aw9523 {
*/
uint8_t get_pins(Port port, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::INPORT0 : Registers::INPORT1;
- return read_one_((uint8_t)addr, ec);
+ return read_u8_from_register((uint8_t)addr, ec);
}
/**
@@ -121,10 +105,10 @@ class Aw9523 {
* @return The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).
*/
uint16_t get_pins(std::error_code &ec) {
- uint16_t p0 = read_one_((uint8_t)Registers::INPORT0, ec);
+ uint16_t p0 = read_u8_from_register((uint8_t)Registers::INPORT0, ec);
if (ec)
return 0;
- uint16_t p1 = read_one_((uint8_t)Registers::INPORT1, ec);
+ uint16_t p1 = read_u8_from_register((uint8_t)Registers::INPORT1, ec);
if (ec)
return 0;
return (p1 << 8) | p0;
@@ -140,7 +124,7 @@ class Aw9523 {
*/
void output(Port port, uint8_t value, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::OUTPORT0 : Registers::OUTPORT1;
- write_one_((uint8_t)addr, value, ec);
+ write_u8_to_register((uint8_t)addr, value, ec);
}
/**
@@ -181,11 +165,11 @@ class Aw9523 {
*/
void clear_pins(Port port, uint8_t mask, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::OUTPORT0 : Registers::OUTPORT1;
- auto data = read_one_((uint8_t)addr, ec);
+ auto data = read_u8_from_register((uint8_t)addr, ec);
if (ec)
return;
data &= ~mask;
- write_one_((uint8_t)addr, data, ec);
+ write_u8_to_register((uint8_t)addr, data, ec);
}
/**
@@ -224,11 +208,11 @@ class Aw9523 {
*/
void set_pins(Port port, uint8_t mask, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::OUTPORT0 : Registers::OUTPORT1;
- auto data = read_one_((uint8_t)addr, ec);
+ auto data = read_u8_from_register((uint8_t)addr, ec);
if (ec)
return;
data |= mask;
- write_one_((uint8_t)addr, data, ec);
+ write_u8_to_register((uint8_t)addr, data, ec);
}
/**
@@ -266,7 +250,7 @@ class Aw9523 {
*/
uint8_t get_output(Port port, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::OUTPORT0 : Registers::OUTPORT1;
- return read_one_((uint8_t)addr, ec);
+ return read_u8_from_register((uint8_t)addr, ec);
}
/**
@@ -275,10 +259,10 @@ class Aw9523 {
* @return The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).
*/
uint16_t get_output(std::error_code &ec) {
- uint16_t p0 = read_one_((uint8_t)Registers::OUTPORT0, ec);
+ uint16_t p0 = read_u8_from_register((uint8_t)Registers::OUTPORT0, ec);
if (ec)
return 0;
- uint16_t p1 = read_one_((uint8_t)Registers::OUTPORT1, ec);
+ uint16_t p1 = read_u8_from_register((uint8_t)Registers::OUTPORT1, ec);
if (ec)
return 0;
return (p1 << 8) | p0;
@@ -293,7 +277,7 @@ class Aw9523 {
void set_interrupt(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting interrupt on change for Port {} pins {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::INTPORT0 : Registers::INTPORT1;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -306,7 +290,7 @@ class Aw9523 {
logger_.debug("Setting interrupt on change p0:{}, p1:{}", p0, p1);
auto addr = Registers::INTPORT0;
const uint8_t data[] = {p0, p1};
- write_many_((uint8_t)addr, data, 2, ec);
+ write_many_to_register((uint8_t)addr, data, 2, ec);
}
/**
@@ -318,7 +302,7 @@ class Aw9523 {
void set_direction(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting direction for Port {} to {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::DIRPORT0 : Registers::DIRPORT1;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -331,7 +315,7 @@ class Aw9523 {
logger_.debug("Setting direction p0:{}, p1:{}", p0, p1);
auto addr = Registers::DIRPORT0;
const uint8_t data[] = {p0, p1};
- write_many_((uint8_t)addr, data, 2, ec);
+ write_many_to_register((uint8_t)addr, data, 2, ec);
}
/**
@@ -343,7 +327,7 @@ class Aw9523 {
void configure_led(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Configuring LED function for Port {} to {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::LEDMODE0 : Registers::LEDMODE1;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -356,7 +340,7 @@ class Aw9523 {
logger_.debug("Configuring LED function p0:{}, p1:{}", p0, p1);
auto addr = Registers::LEDMODE0;
const uint8_t data[] = {p0, p1};
- write_many_((uint8_t)addr, data, 2, ec);
+ write_many_to_register((uint8_t)addr, data, 2, ec);
}
/**
@@ -371,7 +355,7 @@ class Aw9523 {
logger_.debug("Configuring LED function p0:{}, p1:{}", p0, p1);
auto addr = Registers::LEDMODE0;
const uint8_t data[] = {p0, p1};
- write_many_((uint8_t)addr, data, 2, ec);
+ write_many_to_register((uint8_t)addr, data, 2, ec);
}
/**
@@ -436,7 +420,7 @@ class Aw9523 {
return; // bad mask, don't do anything!
break;
}
- write_one_(addr, brightness, ec);
+ write_u8_to_register(addr, brightness, ec);
}
/**
@@ -455,7 +439,7 @@ class Aw9523 {
uint8_t data = 0;
data |= ((uint8_t)output_drive_mode_p0) << (int)ControlBit::GPOMD;
data |= ((uint8_t)max_led_current) << (int)ControlBit::ISEL;
- write_one_((uint8_t)addr, data, ec);
+ write_u8_to_register((uint8_t)addr, data, ec);
}
protected:
@@ -516,46 +500,6 @@ class Aw9523 {
set_interrupt(Port::PORT1, config.port_1_interrupt_mask, ec);
}
- uint8_t read_one_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data;
- bool success = read_(address_, reg_addr, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
- uint16_t read_two_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data[2] = {0};
- bool success = read_(address_, reg_addr, data, 2);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return (data[1] << 8) | data[0];
- }
-
- void write_one_(uint8_t reg_addr, uint8_t data, std::error_code &ec) {
- write_many_(reg_addr, &data, 1, ec);
- }
-
- void write_many_(uint8_t reg_addr, const uint8_t *write_data, size_t write_data_len,
- std::error_code &ec) {
- uint8_t total_len = 1 + write_data_len;
- uint8_t data[total_len];
- data[0] = reg_addr;
- memcpy(&data[1], write_data, write_data_len);
- bool success = write_(address_, data, total_len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
Config config_;
- uint8_t address_;
- write_fn write_;
- read_fn read_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/base_peripheral/CMakeLists.txt b/components/base_peripheral/CMakeLists.txt
new file mode 100644
index 000000000..704e9cb79
--- /dev/null
+++ b/components/base_peripheral/CMakeLists.txt
@@ -0,0 +1,3 @@
+idf_component_register(
+ INCLUDE_DIRS "include"
+ REQUIRES base_component)
diff --git a/components/base_peripheral/include/base_peripheral.hpp b/components/base_peripheral/include/base_peripheral.hpp
new file mode 100644
index 000000000..242770cff
--- /dev/null
+++ b/components/base_peripheral/include/base_peripheral.hpp
@@ -0,0 +1,382 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "base_component.hpp"
+
+namespace espp {
+/// Base class for all peripherals
+/// This class provides a common interface for all peripherals
+///
+/// It provides a way to probe the peripheral, write data to the peripheral,
+/// read data from the peripheral, and write then read data from the
+/// peripheral.
+///
+/// The peripheral is protected by a mutex to ensure that only one
+/// operation can be performed at a time.
+class BasePeripheral : public BaseComponent {
+public:
+ /// Function to probe the peripheral
+ /// \param address The address to probe
+ /// \return True if the peripheral is found at the given address
+ typedef std::function probe_fn;
+
+ /// Function to write data to the peripheral
+ /// \param address The address of the peripheral to write to
+ /// \param data The data to write
+ /// \param length The length of the data to write
+ /// \return True if the write was successful
+ typedef std::function write_fn;
+
+ /// Function to read data from the peripheral
+ /// \param address The address of the peripheral to read from
+ /// \param data The buffer to read into
+ /// \param length The length of the buffer
+ /// \return True if the read was successful
+ typedef std::function read_fn;
+
+ /// Function to read data at a specific address from the peripheral
+ /// \param address The address of the peripheral to read from
+ /// \param reg_addr The address of the register to read from
+ /// \param data The buffer to read into
+ /// \param length The length of the buffer
+ /// \return True if the read was successful
+ typedef std::function read_register_fn;
+
+ /// Function to write then read data from the peripheral
+ /// \param address The address of the peripheral to write to
+ /// \param write_data The data to write
+ /// \param write_length The length of the data to write
+ /// \param read_data The buffer to read into
+ /// \param read_length The length of the buffer
+ /// \return True if the write then read was successful
+ typedef std::function
+ write_then_read_fn;
+
+ /// Configuration for the peripheral
+ struct Config {
+ uint8_t address{0}; ///< The address of the peripheral
+ probe_fn probe{nullptr}; ///< Function to probe the peripheral
+ write_fn write{nullptr}; ///< Function to write data to the peripheral
+ read_fn read{nullptr}; ///< Function to read data from the peripheral
+ read_register_fn read_register{
+ nullptr}; ///< Function to read data at a specific address from the peripheral
+ write_then_read_fn write_then_read{
+ nullptr}; ///< Function to write then read data from the peripheral
+ };
+
+protected:
+ /// Constructor
+ /// \param config The configuration for the peripheral
+ /// \param name The name of the peripheral
+ /// \param verbosity The verbosity level for the peripheral
+ BasePeripheral(const Config &config, std::string_view name,
+ espp::Logger::Verbosity verbosity = espp::Logger::Verbosity::WARN)
+ : BaseComponent(name, verbosity)
+ , base_config_(config) {}
+
+ /// Get the configuration for the peripheral
+ /// \return The configuration for the peripheral
+ const Config &config() const { return base_config_; }
+
+ /// Write data to the peripheral
+ /// \param data The data to write
+ /// \param length The length of the data to write
+ /// \param ec The error code to set if there is an error
+ void write_many(const uint8_t *data, size_t length, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ if (!base_config_.write(base_config_.address, data, length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Write a uint8_t to the peripheral
+ /// \param data The data to write
+ /// \param ec The error code to set if there is an error
+ void write_u8(uint8_t data, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ if (!base_config_.write(base_config_.address, &data, 1)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Write a uint16_t to the peripheral
+ /// \param data The data to write
+ /// \param ec The error code to set if there is an error
+ void write_u16(uint16_t data, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ uint8_t buffer[2];
+ buffer[0] = (data >> 8) & 0xff;
+ buffer[1] = data & 0xff;
+ if (!base_config_.write(base_config_.address, buffer, 2)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Read data from the peripheral
+ /// \param data The buffer to read into
+ /// \param length The length of the buffer
+ /// \param ec The error code to set if there is an error
+ void read_many(uint8_t *data, size_t length, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.read) {
+ if (!base_config_.read(base_config_.address, data, length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Read a uint8_t from the peripheral
+ /// \param ec The error code to set if there is an error
+ /// \return The data read from the peripheral
+ uint8_t read_u8(std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ uint8_t data = 0;
+ if (base_config_.read) {
+ if (!base_config_.read(base_config_.address, &data, 1)) {
+ ec = std::make_error_code(std::errc::io_error);
+ return 0;
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ return data;
+ }
+
+ /// Read a uint16_t from the peripheral
+ /// \param ec The error code to set if there is an error
+ /// \return The data read from the peripheral
+ uint16_t read_u16(std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = 0;
+ if (base_config_.read) {
+ uint8_t buffer[2];
+ if (!base_config_.read(base_config_.address, buffer, 2)) {
+ ec = std::make_error_code(std::errc::io_error);
+ return 0;
+ } else {
+ data = (buffer[0] << 8) | buffer[1];
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ return data;
+ }
+
+ /// Write then read data from the peripheral
+ /// \param write_data The data to write
+ /// \param write_length The length of the data to write
+ /// \param read_data The buffer to read into
+ /// \param read_length The length of the buffer
+ /// \param ec The error code to set if there is an error
+ void write_then_read(const uint8_t *write_data, size_t write_length, uint8_t *read_data,
+ size_t read_length, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write_then_read) {
+ if (!base_config_.write_then_read(base_config_.address, write_data, write_length, read_data,
+ read_length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else if (base_config_.write && base_config_.read) {
+ // write the data
+ if (!base_config_.write(base_config_.address, write_data, write_length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ // read the data
+ if (!base_config_.read(base_config_.address, read_data, read_length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Write a uint8_t to the peripheral
+ /// \param reg_addr The address of the register to write to
+ /// \param data The data to write
+ /// \param ec The error code to set if there is an error
+ void write_u8_to_register(uint8_t reg_addr, uint8_t data, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ uint8_t buffer[2] = {reg_addr, data};
+ if (!base_config_.write(base_config_.address, buffer, 2)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Write a uint16_t to the peripheral
+ /// \param reg_addr The address of the register to write to
+ /// \param data The data to write
+ /// \param ec The error code to set if there is an error
+ void write_u16_to_register(uint8_t reg_addr, uint16_t data, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ uint8_t buffer[3] = {reg_addr, uint8_t((data >> 8) & 0xff), uint8_t(data & 0xff)};
+ if (!base_config_.write(base_config_.address, buffer, 3)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Write many bytes to a register on the peripheral
+ /// \param reg_addr The address of the register to write to
+ /// \param data The data to write
+ /// \param length The length of the data to write
+ /// \param ec The error code to set if there is an error
+ void write_many_to_register(uint8_t reg_addr, const uint8_t *data, size_t length,
+ std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.write) {
+ uint8_t buffer[length + 1];
+ buffer[0] = reg_addr;
+ std::copy(data, data + length, buffer + 1);
+ if (!base_config_.write(base_config_.address, buffer, length + 1)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ }
+ }
+
+ /// Read a uint8_t from a register on the peripheral
+ /// \param register_address The address of the register to read from
+ /// \param ec The error code to set if there is an error
+ /// \return The data read from the peripheral
+ uint8_t read_u8_from_register(uint8_t register_address, std::error_code &ec) {
+ uint8_t data = 0;
+ if (base_config_.read_register) {
+ if (!base_config_.read_register(base_config_.address, register_address, &data, 1)) {
+ ec = std::make_error_code(std::errc::io_error);
+ return 0;
+ } else {
+ ec.clear();
+ }
+ } else {
+ write_then_read(®ister_address, 1, &data, 1, ec);
+ if (ec) {
+ return 0;
+ }
+ }
+ return data;
+ }
+
+ /// Read a uint16_t from a register on the peripheral
+ /// \param register_address The address of the register to read from
+ /// \param ec The error code to set if there is an error
+ /// \return The data read from the peripheral
+ uint16_t read_u16_from_register(uint8_t register_address, std::error_code &ec) {
+ uint8_t data[2];
+ if (base_config_.read_register) {
+ if (!base_config_.read_register(base_config_.address, register_address, data, 2)) {
+ ec = std::make_error_code(std::errc::io_error);
+ return 0;
+ } else {
+ ec.clear();
+ }
+ } else {
+ write_then_read(®ister_address, 1, (uint8_t *)&data, 2, ec);
+ if (ec) {
+ return 0;
+ }
+ }
+ return (data[0] << 8) | data[1];
+ }
+
+ /// Read many bytes from a register on the peripheral
+ /// \param register_address The address of the register to read from
+ /// \param data The buffer to read into
+ /// \param length The length of the buffer
+ /// \param ec The error code to set if there is an error
+ void read_many_from_register(uint8_t register_address, uint8_t *data, size_t length,
+ std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ if (base_config_.read_register) {
+ if (!base_config_.read_register(base_config_.address, register_address, data, length)) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ } else {
+ write_then_read(®ister_address, 1, data, length, ec);
+ }
+ }
+
+ /// Set bits in a register on the peripheral
+ /// \param register_address The address of the register to modify
+ /// \param mask The mask to set
+ /// \param ec The error code to set if there is an error
+ /// \note This function reads the register, sets the bits, and then writes the register
+ /// back to the peripheral
+ void set_bits_in_register(uint8_t register_address, uint8_t mask, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ uint8_t data = read_u8_from_register(register_address, ec);
+ if (ec) {
+ return;
+ }
+ data |= mask;
+ write_u8_to_register(register_address, data, ec);
+ }
+
+ /// Clear bits in a register on the peripheral
+ /// \param register_address The address of the register to modify
+ /// \param mask The mask to clear
+ /// \param ec The error code to set if there is an error
+ /// \note This function reads the register, clears the bits, and then writes the register
+ /// back to the peripheral
+ void clear_bits_in_register(uint8_t register_address, uint8_t mask, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
+ uint8_t data = read_u8_from_register(register_address, ec);
+ if (ec) {
+ return;
+ }
+ data &= ~mask;
+ write_u8_to_register(register_address, data, ec);
+ }
+
+ Config base_config_; ///< The configuration for the peripheral
+ std::recursive_mutex base_mutex_; ///< The mutex to protect access to the peripheral
+};
+} // namespace espp
diff --git a/components/bldc_driver/include/bldc_driver.hpp b/components/bldc_driver/include/bldc_driver.hpp
index d5bb8f297..3de25b7c8 100644
--- a/components/bldc_driver/include/bldc_driver.hpp
+++ b/components/bldc_driver/include/bldc_driver.hpp
@@ -274,6 +274,7 @@ class BldcDriver : public BaseComponent {
void configure_operators() {
logger_.info("Create MCPWM operator");
mcpwm_operator_config_t operator_config;
+ memset(&operator_config, 0, sizeof(operator_config));
operator_config.group_id = 0;
for (int i = 0; i < 3; i++) {
ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &operators_[i]));
@@ -322,6 +323,7 @@ class BldcDriver : public BaseComponent {
void configure_comparators() {
logger_.info("Create comparators");
mcpwm_comparator_config_t compare_config;
+ memset(&compare_config, 0, sizeof(compare_config));
compare_config.flags.update_cmp_on_tez = true;
for (int i = 0; i < 3; i++) {
ESP_ERROR_CHECK(mcpwm_new_comparator(operators_[i], &compare_config, &comparators_[i]));
diff --git a/components/bldc_haptics/example/main/bldc_haptics_example.cpp b/components/bldc_haptics/example/main/bldc_haptics_example.cpp
index 0d6e2071e..6d4a2522f 100644
--- a/components/bldc_haptics/example/main/bldc_haptics_example.cpp
+++ b/components/bldc_haptics/example/main/bldc_haptics_example.cpp
@@ -53,8 +53,9 @@ extern "C" void app_main(void) {
std::shared_ptr mt6701 = std::make_shared(espp::Mt6701::Config{
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .read_register =
+ std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
.velocity_filter = filter_fn,
.update_period = std::chrono::duration(core_update_period),
.log_level = espp::Logger::Verbosity::WARN});
diff --git a/components/bldc_motor/example/main/bldc_motor_example.cpp b/components/bldc_motor/example/main/bldc_motor_example.cpp
index c3a8ab2fa..43d9ca0d6 100644
--- a/components/bldc_motor/example/main/bldc_motor_example.cpp
+++ b/components/bldc_motor/example/main/bldc_motor_example.cpp
@@ -54,8 +54,9 @@ extern "C" void app_main(void) {
std::shared_ptr mt6701 = std::make_shared(espp::Mt6701::Config{
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .read_register =
+ std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
.velocity_filter = filter_fn,
.update_period = std::chrono::duration(core_update_period),
.log_level = espp::Logger::Verbosity::WARN});
diff --git a/components/bm8563/CMakeLists.txt b/components/bm8563/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/bm8563/CMakeLists.txt
+++ b/components/bm8563/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/bm8563/example/main/bm8563_example.cpp b/components/bm8563/example/main/bm8563_example.cpp
index 32b89af54..e8b1428ad 100644
--- a/components/bm8563/example/main/bm8563_example.cpp
+++ b/components/bm8563/example/main/bm8563_example.cpp
@@ -25,8 +25,9 @@ extern "C" void app_main(void) {
auto bm8563 = espp::Bm8563({
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .write_then_read =
+ std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
});
std::error_code ec;
diff --git a/components/bm8563/include/bm8563.hpp b/components/bm8563/include/bm8563.hpp
index aab237ccf..e8b59ade3 100644
--- a/components/bm8563/include/bm8563.hpp
+++ b/components/bm8563/include/bm8563.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/// @brief The BM8563 RTC driver.
@@ -10,26 +10,11 @@ namespace espp {
///
/// \section Example
/// \snippet bm8563_example.cpp bm8563 example
-class Bm8563 {
+class Bm8563 : public BasePeripheral {
public:
/// @brief The default I2C address for the BM8563.
static constexpr uint8_t DEFAULT_ADDRESS = (0x51);
- /// @brief Function prototype for the I2C write function.
- /// @param address The I2C address to write to.
- /// @param data The data to write.
- /// @param size The number of bytes to write.
- /// @return True if the write was successful, false otherwise.
- typedef std::function write_fn;
-
- /// @brief Function prototype for the I2C read function.
- /// @param address The I2C address to read from.
- /// @param register_address The register address to read from.
- /// @param data The data to read into.
- /// @param size The number of bytes to read.
- /// @return True if the read was successful, false otherwise.
- typedef std::function read_fn;
-
/// @brief The date structure.
struct Date {
uint16_t year; ///< The year.
@@ -53,8 +38,8 @@ class Bm8563 {
/// @brief The configuration structure.
struct Config {
- write_fn write; ///< The I2C write function.
- read_fn read; ///< The I2C read function.
+ BasePeripheral::write_fn write; ///< The I2C write function.
+ BasePeripheral::write_then_read_fn write_then_read; ///< The I2C write then read function.
espp::Logger::Verbosity log_level{
espp::Logger::Verbosity::WARN}; ///< Log verbosity for the input driver.
};
@@ -62,8 +47,10 @@ class Bm8563 {
/// @brief Constructor.
/// @param config The configuration.
explicit Bm8563(const Config &config)
- : write_(config.write), read_(config.read),
- logger_({.tag = "Bm8563", .level = config.log_level}) {
+ : BasePeripheral({.address = DEFAULT_ADDRESS,
+ .write = config.write,
+ .write_then_read = config.write_then_read},
+ "Bm8563", config.log_level) {
std::error_code ec;
init(ec);
if (ec) {
@@ -108,7 +95,7 @@ class Bm8563 {
Date get_date(std::error_code &ec) {
logger_.info("getting date");
uint8_t data[4];
- read_register(Registers::DATE, data, 4, ec);
+ read_many_from_register((uint8_t)Registers::DATE, data, 4, ec);
if (ec) {
return {};
}
@@ -128,7 +115,7 @@ class Bm8563 {
const uint8_t data[] = {byte2bcd(d.day), byte2bcd(d.weekday),
(uint8_t)(byte2bcd(d.month) | ((d.year < 2000) ? 0x80 : 0x00)),
byte2bcd(d.year % 100)};
- write_register(Registers::DATE, data, 4, ec);
+ write_many_to_register((uint8_t)Registers::DATE, data, 4, ec);
}
/// @brief Get the time.
@@ -136,7 +123,7 @@ class Bm8563 {
Time get_time(std::error_code &ec) {
logger_.info("getting time");
uint8_t data[3];
- read_register(Registers::TIME, data, 3, ec);
+ read_many_from_register((uint8_t)Registers::TIME, data, 3, ec);
if (ec) {
return {};
}
@@ -152,14 +139,14 @@ class Bm8563 {
void set_time(const Time &t, std::error_code &ec) {
logger_.info("Setting time");
const uint8_t data[] = {byte2bcd(t.second), byte2bcd(t.minute), byte2bcd(t.hour)};
- write_register(Registers::TIME, data, 3, ec);
+ write_many_to_register((uint8_t)Registers::TIME, data, 3, ec);
}
protected:
void init(std::error_code &ec) {
logger_.info("initializing");
const uint8_t data[] = {0, 0};
- write_register(Registers::CONTROL_STATUS1, data, 2, ec);
+ write_many_to_register((uint8_t)Registers::CONTROL_STATUS1, data, 2, ec);
}
static constexpr int CENTURY_BIT = 0b10000000;
@@ -184,27 +171,6 @@ class Bm8563 {
TIMER_CONTROL = 0x0e,
TIMER = 0x0f,
};
-
- void read_register(Registers reg, uint8_t *data, size_t size, std::error_code &ec) {
- bool success = read_(DEFAULT_ADDRESS, (uint8_t)reg, data, size);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- void write_register(Registers reg, const uint8_t *data, size_t size, std::error_code &ec) {
- uint8_t buf[size + 1];
- buf[0] = (uint8_t)reg;
- memcpy(buf + 1, data, size);
- bool success = write_(DEFAULT_ADDRESS, buf, size + 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- write_fn write_;
- read_fn read_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/drv2605/CMakeLists.txt b/components/drv2605/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/drv2605/CMakeLists.txt
+++ b/components/drv2605/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/drv2605/example/main/drv2605_example.cpp b/components/drv2605/example/main/drv2605_example.cpp
index 6a7bd44e2..c171dab30 100644
--- a/components/drv2605/example/main/drv2605_example.cpp
+++ b/components/drv2605/example/main/drv2605_example.cpp
@@ -26,8 +26,9 @@ extern "C" void app_main(void) {
.device_address = espp::Drv2605::DEFAULT_ADDRESS,
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .read_register =
+ std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
.motor_type = espp::Drv2605::MotorType::LRA});
std::error_code ec;
// we're using an ERM motor, so select an ERM library (1-5).
@@ -44,6 +45,11 @@ extern "C" void app_main(void) {
auto elapsed = std::chrono::duration(now - start).count();
static uint8_t waveform = 0;
std::error_code ec;
+ drv2605.stop(ec);
+ if (ec) {
+ logger.error("stop failed: {}", ec.message());
+ return false;
+ }
drv2605.set_waveform(0, (espp::Drv2605::Waveform)waveform, ec);
if (ec) {
logger.error("set waveform failed: {}", ec.message());
diff --git a/components/drv2605/include/drv2605.hpp b/components/drv2605/include/drv2605.hpp
index 192988f21..df6ee2b6d 100644
--- a/components/drv2605/include/drv2605.hpp
+++ b/components/drv2605/include/drv2605.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -15,30 +15,10 @@ namespace espp {
* \section drv2605_ex1 DRV2605 Example
* \snippet drv2605_example.cpp drv2605 example
*/
-class Drv2605 {
+class Drv2605 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = (0x5A);
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if the write was successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param reg_addr Register address to read from.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* @brief The mode of the vibration.
*/
@@ -113,8 +93,10 @@ class Drv2605 {
*/
struct Config {
uint8_t device_address = DEFAULT_ADDRESS; /**< I2C address of the device. */
- write_fn write; /**< Function for writing a byte to a register on the Drv2605. */
- read_fn read; /**< Function for reading a byte from a register on the Drv2605. */
+ BasePeripheral::write_fn
+ write; /**< Function for writing a byte to a register on the Drv2605. */
+ BasePeripheral::read_register_fn
+ read_register; /**< Function for reading a register from the Drv2605. */
MotorType motor_type{MotorType::ERM}; /**< MotorType that this driver is driving. */
bool auto_init{true}; /**< If true, the driver will initialize the DRV2605 on construction. */
espp::Logger::Verbosity log_level{
@@ -125,8 +107,11 @@ class Drv2605 {
* @brief Construct and initialize the DRV2605.
*/
explicit Drv2605(const Config &config)
- : motor_type_(config.motor_type), address_(config.device_address), write_(config.write),
- read_(config.read), logger_({.tag = "Drv2605", .level = config.log_level}) {
+ : BasePeripheral({.address = config.device_address,
+ .write = config.write,
+ .read_register = config.read_register},
+ "Drv2605", config.log_level)
+ , motor_type_(config.motor_type) {
if (config.auto_init) {
std::error_code ec;
initialize(ec);
@@ -148,7 +133,7 @@ class Drv2605 {
*/
void start(std::error_code &ec) {
logger_.info("Starting");
- write_one_((uint8_t)Register::START, 1, ec);
+ write_u8_to_register((uint8_t)Register::START, 1, ec);
}
/**
@@ -157,7 +142,7 @@ class Drv2605 {
*/
void stop(std::error_code &ec) {
logger_.info("Stopping");
- write_one_((uint8_t)Register::START, 0, ec);
+ write_u8_to_register((uint8_t)Register::START, 0, ec);
}
/**
@@ -167,7 +152,7 @@ class Drv2605 {
*/
void set_mode(Mode mode, std::error_code &ec) {
logger_.info("Setting mode {}", (uint8_t)mode);
- write_one_((uint8_t)Register::MODE, (uint8_t)mode, ec);
+ write_u8_to_register((uint8_t)Register::MODE, (uint8_t)mode, ec);
}
/**
@@ -182,7 +167,7 @@ class Drv2605 {
*/
void set_waveform(uint8_t slot, Waveform w, std::error_code &ec) {
logger_.info("Setting waveform {}", (uint8_t)w);
- write_one_((uint8_t)Register::WAVESEQ1 + slot, (uint8_t)w, ec);
+ write_u8_to_register((uint8_t)Register::WAVESEQ1 + slot, (uint8_t)w, ec);
}
/**
@@ -195,16 +180,16 @@ class Drv2605 {
if (motor_type_ == MotorType::LRA && lib != Library::LRA) {
logger_.warn("LRA motor selected, but library {} is not an LRA library", lib);
}
- write_one_((uint8_t)Register::LIBRARY, (uint8_t)lib, ec);
+ write_u8_to_register((uint8_t)Register::LIBRARY, (uint8_t)lib, ec);
}
protected:
void init(std::error_code &ec) {
logger_.info("Initializing motor");
- write_one_((uint8_t)Register::MODE, 0, ec); // out of standby
+ write_u8_to_register((uint8_t)Register::MODE, 0, ec); // out of standby
if (ec)
return;
- write_one_((uint8_t)Register::RTPIN, 0, ec); // no real-time playback
+ write_u8_to_register((uint8_t)Register::RTPIN, 0, ec); // no real-time playback
if (ec)
return;
set_waveform(0, Waveform::STRONG_CLICK, ec); // Strong Click
@@ -213,19 +198,19 @@ class Drv2605 {
set_waveform(1, Waveform::END, ec); // end sequence
if (ec)
return;
- write_one_((uint8_t)Register::OVERDRIVE, 0, ec); // no overdrive
+ write_u8_to_register((uint8_t)Register::OVERDRIVE, 0, ec); // no overdrive
if (ec)
return;
- write_one_((uint8_t)Register::SUSTAINPOS, 0, ec);
+ write_u8_to_register((uint8_t)Register::SUSTAINPOS, 0, ec);
if (ec)
return;
- write_one_((uint8_t)Register::SUSTAINNEG, 0, ec);
+ write_u8_to_register((uint8_t)Register::SUSTAINNEG, 0, ec);
if (ec)
return;
- write_one_((uint8_t)Register::BREAK, 0, ec);
+ write_u8_to_register((uint8_t)Register::BREAK, 0, ec);
if (ec)
return;
- write_one_((uint8_t)Register::AUDIOMAX, 0x64, ec);
+ write_u8_to_register((uint8_t)Register::AUDIOMAX, 0x64, ec);
if (ec)
return;
// set the motor type based on the config
@@ -233,20 +218,20 @@ class Drv2605 {
if (ec)
return;
// turn on ERM OPEN LOOP
- auto current_control3 = read_one_((uint8_t)Register::CONTROL3, ec);
+ auto current_control3 = read_u8_from_register((uint8_t)Register::CONTROL3, ec);
if (ec)
return;
- write_one_((uint8_t)Register::CONTROL3, current_control3 | 0x20, ec);
+ write_u8_to_register((uint8_t)Register::CONTROL3, current_control3 | 0x20, ec);
}
void set_motor_type(MotorType motor_type, std::error_code &ec) {
logger_.info("Setting motor type {}", motor_type == MotorType::ERM ? "ERM" : "LRA");
motor_type_ = motor_type;
- auto current_feedback = read_one_((uint8_t)Register::FEEDBACK, ec);
+ auto current_feedback = read_u8_from_register((uint8_t)Register::FEEDBACK, ec);
if (ec)
return;
uint8_t motor_config = (motor_type_ == MotorType::ERM) ? 0x7F : 0x80;
- write_one_((uint8_t)Register::FEEDBACK, current_feedback | motor_config, ec);
+ write_u8_to_register((uint8_t)Register::FEEDBACK, current_feedback | motor_config, ec);
}
enum class Register : uint8_t {
@@ -285,37 +270,7 @@ class Drv2605 {
LRARSON = 0x22, ///< LRA resonance-period
};
- uint8_t read_one_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data;
- bool success = read_(address_, reg_addr, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
- void write_one_(uint8_t reg_addr, uint8_t data, std::error_code &ec) {
- write_many_(reg_addr, &data, 1, ec);
- }
-
- void write_many_(uint8_t reg_addr, const uint8_t *write_data, size_t write_data_len,
- std::error_code &ec) {
- uint8_t total_len = 1 + write_data_len;
- uint8_t data[total_len];
- data[0] = reg_addr;
- memcpy(&data[1], write_data, write_data_len);
- bool success = write_(address_, data, total_len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
MotorType motor_type_;
- uint8_t address_;
- write_fn write_;
- read_fn read_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/ft5x06/CMakeLists.txt b/components/ft5x06/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/ft5x06/CMakeLists.txt
+++ b/components/ft5x06/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/ft5x06/example/main/ft5x06_example.cpp b/components/ft5x06/example/main/ft5x06_example.cpp
index b0a9b935e..b659802f4 100644
--- a/components/ft5x06/example/main/ft5x06_example.cpp
+++ b/components/ft5x06/example/main/ft5x06_example.cpp
@@ -24,9 +24,9 @@ extern "C" void app_main(void) {
// now make the ft5x06 which decodes the data
espp::Ft5x06 ft5x06({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
- .read_at_register = std::bind(
- &espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .read_register = std::bind(&espp::I2c::read_at_register, &i2c,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4),
.log_level = espp::Logger::Verbosity::WARN});
// and finally, make the task to periodically poll the ft5x06 and print
// the state
diff --git a/components/ft5x06/include/ft5x06.hpp b/components/ft5x06/include/ft5x06.hpp
index 08c572f3e..a23965d4c 100644
--- a/components/ft5x06/include/ft5x06.hpp
+++ b/components/ft5x06/include/ft5x06.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/// @brief The FT5x06 touch controller.
@@ -10,26 +10,11 @@ namespace espp {
///
/// \section Example
/// \snippet ft5x06_example.cpp ft5x06 example
-class Ft5x06 {
+class Ft5x06 : public BasePeripheral {
public:
/// @brief The default I2C address for the FT5x06.
static constexpr uint8_t DEFAULT_ADDRESS = (0x38);
- /// @brief The function to write data to the I2C bus.
- /// @param address The I2C address of the device.
- /// @param data The data to write to the I2C bus.
- /// @param data_len The length of the data to write to the I2C bus.
- /// @return true if the function succeeds.
- typedef std::function write_fn;
-
- /// @brief The function to read data starting at a register from the I2C bus.
- /// @param address The I2C address of the device.
- /// @param register The register to write to the I2C bus.
- /// @param data The data to read from the I2C bus.
- /// @param data_len The length of the data to read from the I2C bus.
- /// @return true if the function succeeds.
- typedef std::function read_at_register_fn;
-
/// @brief The gesture that was detected.
enum class Gesture : uint8_t {
NONE = 0x00,
@@ -43,17 +28,19 @@ class Ft5x06 {
/// @brief The configuration for the FT5x06.
struct Config {
- write_fn write; ///< The function to write data to the I2C bus.
- read_at_register_fn
- read_at_register; ///< The function to write then read data from the I2C bus.
+ BasePeripheral::write_fn write; ///< The function to write data to the I2C bus.
+ BasePeripheral::read_register_fn
+ read_register; ///< The function to write then read data from the I2C bus.
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< The log level.
};
/// @brief Construct a new FT5x06.
/// @param config The configuration for the FT5x06.
explicit Ft5x06(const Config &config)
- : write_(config.write), read_at_register_(config.read_at_register),
- logger_({.tag = "Ft5x06", .level = config.log_level}) {
+ : BasePeripheral({.address = DEFAULT_ADDRESS,
+ .write = config.write,
+ .read_register = config.read_register},
+ "Ft5x06", config.log_level) {
std::error_code ec;
init(ec);
if (ec) {
@@ -65,7 +52,7 @@ class Ft5x06 {
/// @param ec The error code if the function fails.
/// @return The number of touch points.
uint8_t get_num_touch_points(std::error_code &ec) {
- return read_register(Registers::TOUCH_POINTS, ec);
+ return read_u8_from_register((uint8_t)Registers::TOUCH_POINTS, ec);
}
/// @brief Get the touch point.
@@ -81,7 +68,7 @@ class Ft5x06 {
*num_touch_points = tp;
if (*num_touch_points != 0) {
uint8_t data[4];
- read(Registers::TOUCH1_XH, data, 4, ec);
+ read_many_from_register((uint8_t)Registers::TOUCH1_XH, data, 4, ec);
if (ec) {
return;
}
@@ -95,45 +82,45 @@ class Ft5x06 {
/// @param ec The error code if the function fails.
/// @return The gesture that was detected.
Gesture read_gesture(std::error_code &ec) {
- return (Gesture)read_register(Registers::GESTURE_ID, ec);
+ return (Gesture)read_u8_from_register((uint8_t)Registers::GESTURE_ID, ec);
}
protected:
void init(std::error_code &ec) {
// Valid touching detect threshold
- write_register(Registers::ID_G_THGROUP, 70, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THGROUP, 70, ec);
if (ec)
return;
// valid touching peak detect threshold
- write_register(Registers::ID_G_THPEAK, 60, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THPEAK, 60, ec);
if (ec)
return;
// Touch focus threshold
- write_register(Registers::ID_G_THCAL, 16, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THCAL, 16, ec);
if (ec)
return;
// threshold when there is surface water
- write_register(Registers::ID_G_THWATER, 60, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THWATER, 60, ec);
if (ec)
return;
// threshold of temperature compensation
- write_register(Registers::ID_G_THTEMP, 10, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THTEMP, 10, ec);
if (ec)
return;
// Touch difference threshold
- write_register(Registers::ID_G_THDIFF, 20, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_THDIFF, 20, ec);
if (ec)
return;
// Delay to enter 'Monitor' status (s)
- write_register(Registers::ID_G_TIME_ENTER_MONITOR, 2, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_TIME_ENTER_MONITOR, 2, ec);
if (ec)
return;
// Period of 'Active' status (ms)
- write_register(Registers::ID_G_PERIODACTIVE, 12, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_PERIODACTIVE, 12, ec);
if (ec)
return;
// Timer to enter 'idle' when in 'Monitor' (ms)
- write_register(Registers::ID_G_PERIODMONITOR, 40, ec);
+ write_u8_to_register((uint8_t)Registers::ID_G_PERIODMONITOR, 40, ec);
}
enum class Registers : uint8_t {
@@ -192,37 +179,5 @@ class Ft5x06 {
ID_G_FT5201ID = 0xA8,
ID_G_ERR = 0xA9,
};
-
- uint8_t read_register(Registers reg, std::error_code &ec) {
- uint8_t data = 0;
- bool success = read_at_register_(DEFAULT_ADDRESS, (uint8_t)reg, &data, 1);
- if (!success) {
- logger_.error("Failed to read register {}", (uint8_t)reg);
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
- void read(Registers reg, uint8_t *data, size_t data_len, std::error_code &ec) {
- bool success = read_at_register_(DEFAULT_ADDRESS, (uint8_t)reg, data, data_len);
- if (!success) {
- logger_.error("Failed to read register {}", (uint8_t)reg);
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- void write_register(Registers reg, uint8_t data, std::error_code &ec) {
- uint8_t buf[2] = {(uint8_t)reg, data};
- bool success = write_(DEFAULT_ADDRESS, buf, 2);
- if (!success) {
- logger_.error("Failed to write register {}", (uint8_t)reg);
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- write_fn write_;
- read_at_register_fn read_at_register_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/gt911/CMakeLists.txt b/components/gt911/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/gt911/CMakeLists.txt
+++ b/components/gt911/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/gt911/example/main/gt911_example.cpp b/components/gt911/example/main/gt911_example.cpp
index 929dc1555..cae360784 100644
--- a/components/gt911/example/main/gt911_example.cpp
+++ b/components/gt911/example/main/gt911_example.cpp
@@ -19,12 +19,14 @@ extern "C" void app_main(void) {
.sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
.scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
});
+
// now make the gt911 which decodes the data
espp::Gt911 gt911({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
- .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3),
- .log_level = espp::Logger::Verbosity::WARN});
+ .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ .log_level = espp::Logger::Verbosity::WARN});
+
// and finally, make the task to periodically poll the gt911 and print
// the state
auto task_fn = [>911](std::mutex &m, std::condition_variable &cv) {
@@ -51,7 +53,7 @@ extern "C" void app_main(void) {
// task is being stopped / destroyed
{
std::unique_lock lk(m);
- cv.wait_for(lk, 500ms);
+ cv.wait_for(lk, 100ms);
}
return false; // don't stop the task
};
diff --git a/components/gt911/include/gt911.hpp b/components/gt911/include/gt911.hpp
index 12b37ec48..ee934cda0 100644
--- a/components/gt911/include/gt911.hpp
+++ b/components/gt911/include/gt911.hpp
@@ -1,37 +1,26 @@
#pragma once
+#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/// @brief Driver for the GT911 touch controller
///
/// \section Example
/// \snippet gt911_example.cpp gt911 example
-class Gt911 {
+class Gt911 : public BasePeripheral {
public:
/// Default address for the GT911 chip
static constexpr uint8_t DEFAULT_ADDRESS_1 = 0x5D;
/// Alternate address for the GT911 chip
static constexpr uint8_t DEFAULT_ADDRESS_2 = 0x14;
- /// @brief Function for writing to the i2c device
- /// @param address The address of the i2c device
- /// @param data The data to write to the chip
- /// @param len The length of the data to write
- typedef std::function write_fn;
-
- /// @brief Function signature for reading from the i2c device
- /// @param dev_addr The device address
- /// @param data The data to read
- /// @param data_len The length of the data to read
- typedef std::function read_fn;
-
/// @brief Configuration for the GT911 driver
struct Config {
- write_fn write; ///< Function for writing to the GT911 chip
- read_fn read; ///< Function for reading from the GT911 chip
+ BasePeripheral::write_fn write; ///< Function for writing to the GT911 chip
+ BasePeripheral::read_fn read; ///< Function for reading from the GT911 chip
uint8_t address = DEFAULT_ADDRESS_1; ///< Which address to use for this chip?
espp::Logger::Verbosity log_level{
espp::Logger::Verbosity::WARN}; ///< Log verbosity for the input driver.
@@ -40,8 +29,8 @@ class Gt911 {
/// @brief Constructor for the GT911 driver
/// @param config The configuration for the driver
explicit Gt911(const Config &config)
- : write_(config.write), read_(config.read), address_(config.address),
- logger_({.tag = "Gt911", .level = config.log_level}) {}
+ : BasePeripheral({.address = config.address, .write = config.write, .read = config.read},
+ "Gt911", config.log_level) {}
/// @brief Update the state of the GT911 driver
/// @param ec Error code to set if an error occurs
@@ -49,14 +38,14 @@ class Gt911 {
bool update(std::error_code &ec) {
static constexpr size_t DATA_LEN = CONTACT_SIZE * MAX_CONTACTS;
static uint8_t data[DATA_LEN];
- read(Registers::POINT_INFO, data, 1, ec);
+ read_register(Registers::POINT_INFO, data, 1, ec);
if (ec) {
return false;
}
num_touch_points_ = data[0] & 0x0f;
+ logger_.debug("Got {} touch points", num_touch_points_);
if (num_touch_points_ > 0) {
- logger_.debug("Got {} touch points", num_touch_points_);
- read(Registers::POINTS, data, CONTACT_SIZE * num_touch_points_, ec);
+ read_register(Registers::POINTS, data, CONTACT_SIZE * num_touch_points_, ec);
if (ec) {
return false;
}
@@ -66,7 +55,7 @@ class Gt911 {
y_ = point->y;
logger_.debug("Touch at ({}, {})", x_, y_);
}
- write(Registers::POINT_INFO, 0x00, ec); // sync signal
+ write_register(Registers::POINT_INFO, 0x00, ec); // sync signal
if (ec) {
return false;
}
@@ -238,47 +227,26 @@ class Gt911 {
GTKeyConfig keys;
} __attribute__((packed));
- void write(Registers reg, uint8_t val, std::error_code &ec) { write(reg, &val, 1, ec); }
-
- void write(Registers reg, const uint8_t *data, size_t len, std::error_code &ec) {
- uint16_t reg_addr = (uint16_t)reg;
- size_t d_len = 2 + len;
- uint8_t d[d_len];
- d[0] = reg_addr >> 8;
- d[1] = reg_addr & 0xFF;
- if (len > 0 && data != nullptr)
- memcpy(&d[2], data, len);
- bool success = write_(address_, d, d_len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
+ // we use write_then_read since we have to write the u16 register address and
+ // then read the data
+ void read_register(Registers reg, uint8_t *data, size_t len, std::error_code &ec) {
+ uint16_t reg16 = static_cast(reg);
+ uint8_t reg_buf[2] = {static_cast(reg16 >> 8), static_cast(reg16 & 0xff)};
+ write_then_read(reg_buf, 2, data, len, ec);
}
- uint8_t read(Registers reg, std::error_code &ec) {
- uint8_t val = 0;
- read(reg, &val, 1, ec);
- if (ec) {
- return 0;
- }
- return val;
- }
-
- void read(Registers reg, uint8_t *data, size_t len, std::error_code &ec) {
- write(reg, nullptr, 0, ec);
- if (ec) return;
- bool success = read_(address_, data, len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
+ void write_register(Registers reg, const uint8_t value, std::error_code &ec) {
+ uint16_t reg16 = static_cast(reg);
+ uint8_t write_buf[3];
+ write_buf[0] = static_cast(reg16 >> 8);
+ write_buf[1] = static_cast(reg16 & 0xff);
+ write_buf[2] = value;
+ write_many(write_buf, 3, ec);
}
- write_fn write_;
- read_fn read_;
- uint8_t address_;
std::atomic home_button_pressed_{false};
std::atomic num_touch_points_;
std::atomic x_;
std::atomic y_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/max1704x/CMakeLists.txt b/components/max1704x/CMakeLists.txt
index 5ae0fe990..3d35d0937 100644
--- a/components/max1704x/CMakeLists.txt
+++ b/components/max1704x/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger" "math"
+ REQUIRES "base_peripheral" "math"
)
diff --git a/components/max1704x/include/max1704x.hpp b/components/max1704x/include/max1704x.hpp
index 3fc047d74..07f1036b0 100644
--- a/components/max1704x/include/max1704x.hpp
+++ b/components/max1704x/include/max1704x.hpp
@@ -3,7 +3,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -17,28 +17,10 @@ namespace espp {
* @section max1704x_ex1 MAX1704X Example
* @snippet max1704x_example.cpp max1704x example
*/
-class Max1704x {
+class Max1704x : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = 0x36; ///< Default address of the MAX1704x.
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if successful, false otherwise.
- */
- typedef std::function read_fn;
-
enum class AlertStatus {
SOC_CHANGE = 0x20, ///< Alert for state of charge change
SOC_LOW = 0x10, ///< Alert for state of charge low
@@ -52,8 +34,8 @@ class Max1704x {
*/
struct Config {
uint8_t device_address{DEFAULT_ADDRESS}; ///< Address of the MAX1704x.
- write_fn write; //< Function to write bytes to the device.
- read_fn read; //< Function to read bytes from the device.
+ BasePeripheral::write_fn write; //< Function to write bytes to the device.
+ BasePeripheral::read_fn read; //< Function to read bytes from the device.
bool auto_init{true}; ///< Whether to automatically initialize the MAX1704x.
Logger::Verbosity log_level{Logger::Verbosity::WARN}; ///< Log level for the MAX1704x.
};
@@ -63,8 +45,9 @@ class Max1704x {
* @param config Configuration for the MAX1704x.
*/
explicit Max1704x(const Config &config)
- : address_(config.device_address), write_(config.write), read_(config.read),
- logger_({.tag = "Max1704x", .level = config.log_level}) {
+ : BasePeripheral(
+ {.address = config.device_address, .write = config.write, .read = config.read},
+ "Max1704x", config.log_level) {
if (config.auto_init) {
std::error_code ec;
initalize(ec);
@@ -78,7 +61,7 @@ class Max1704x {
* @brief Initialize the MAX1704x.
*/
void initalize(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
+ std::lock_guard lock(base_mutex_);
// Get the IC version
version_ = get_version(ec);
if (ec) {
@@ -99,8 +82,8 @@ class Max1704x {
* @return The IC version.
*/
uint16_t get_version(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint16_t data = read_register(Register::VERSION, ec);
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = read_u16_from_register((uint8_t)Register::VERSION, ec);
if (ec) {
return 0;
}
@@ -114,8 +97,8 @@ class Max1704x {
* @return The chip ID.
*/
uint8_t get_chip_id(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint16_t data = read_register(Register::CHIPID, ec);
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = read_u16_from_register((uint8_t)Register::CHIPID, ec);
if (ec) {
return 0;
}
@@ -129,8 +112,8 @@ class Max1704x {
* @return The battery voltage in V.
*/
float get_battery_voltage(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint16_t data = read_register(Register::VCELL, ec);
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = read_u16_from_register((uint8_t)Register::VCELL, ec);
if (ec) {
return 0;
}
@@ -145,8 +128,8 @@ class Max1704x {
* @return The battery state of charge in %.
*/
float get_battery_percentage(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint16_t data = read_register(Register::SOC, ec);
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = read_u16_from_register((uint8_t)Register::SOC, ec);
if (ec) {
return 0;
}
@@ -163,8 +146,8 @@ class Max1704x {
* @return The battery charge or discharge rate in %/hr.
*/
float get_battery_charge_rate(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- int16_t data = read_register(Register::CRATE, ec);
+ std::lock_guard lock(base_mutex_);
+ int16_t data = read_u16_from_register((uint8_t)Register::CRATE, ec);
if (ec) {
return 0;
}
@@ -179,8 +162,8 @@ class Max1704x {
* @return The battery alert status as an AlertStatus.
*/
AlertStatus get_alert_status(std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint16_t data = read_register(Register::STATUS, ec);
+ std::lock_guard lock(base_mutex_);
+ uint16_t data = read_u16_from_register((uint8_t)Register::STATUS, ec);
if (ec) {
return AlertStatus::SOC_CHANGE;
}
@@ -195,13 +178,7 @@ class Max1704x {
* @param ec Error code set if an error occurs.
*/
void clear_alert_status(uint8_t flags_to_clear, std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint8_t data = read_register(Register::STATUS, ec);
- if (ec) {
- return;
- }
- data &= ~flags_to_clear;
- write_register(Register::STATUS, data, ec);
+ clear_bits_in_register((uint8_t)Register::STATUS, flags_to_clear, ec);
}
protected:
@@ -235,45 +212,7 @@ class Max1704x {
VOLTAGE_HIGH = 0x02, ///< Alert for voltage high
};
- void write_register(const Register reg, const uint8_t data, std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- uint8_t buf[2];
- buf[0] = (uint8_t)reg;
- buf[1] = (uint8_t)data;
- if (!write_(address_, buf, sizeof(buf))) {
- logger_.error("Failed to write register 0x{:02X}", (uint8_t)reg);
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
- ec.clear();
- }
-
- uint16_t read_register(const Register reg, std::error_code &ec) {
- std::scoped_lock lock(mutex_);
- // write the address
- if (!write_(address_, (uint8_t *)®, 1)) {
- ec = std::make_error_code(std::errc::io_error);
- logger_.error("Failed to write register 0x{:02X}", (uint8_t)reg);
- return 0;
- }
- // and read the data
- uint8_t data[2];
- if (!read_(address_, data, 2)) {
- ec = std::make_error_code(std::errc::io_error);
- logger_.error("Failed to read register 0x{:02X}", (uint8_t)reg);
- return 0;
- }
- ec.clear();
- return (data[0] << 8) | data[1];
- }
-
uint16_t version_{0}; ///< IC version
uint8_t chip_id_{0}; ///< Chip ID
-
- uint8_t address_;
- write_fn write_;
- read_fn read_;
- std::recursive_mutex mutex_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/mcp23x17/CMakeLists.txt b/components/mcp23x17/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/mcp23x17/CMakeLists.txt
+++ b/components/mcp23x17/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/mcp23x17/example/main/mcp23x17_example.cpp b/components/mcp23x17/example/main/mcp23x17_example.cpp
index 2001245fb..5afccbdd3 100644
--- a/components/mcp23x17/example/main/mcp23x17_example.cpp
+++ b/components/mcp23x17/example/main/mcp23x17_example.cpp
@@ -27,8 +27,9 @@ extern "C" void app_main(void) {
.port_1_interrupt_mask = (1 << 7), // interrupt on B7
.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .read_register =
+ std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
.log_level = espp::Logger::Verbosity::WARN});
// set pull up on the input pins
std::error_code ec;
diff --git a/components/mcp23x17/include/mcp23x17.hpp b/components/mcp23x17/include/mcp23x17.hpp
index e09e3af7f..96754886e 100644
--- a/components/mcp23x17/include/mcp23x17.hpp
+++ b/components/mcp23x17/include/mcp23x17.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -12,30 +12,11 @@ namespace espp {
* \section mcp23x17_ex1 MCP23x17 Example
* \snippet mcp23x17_example.cpp mcp23x17 example
*/
-class Mcp23x17 {
+class Mcp23x17 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS =
0b0100000; ///< Lower 3 bits are A2, A2, A0 pins on the chip.
- /**
- * @brief Function to write bytes to the device
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param reg_addr Register address to read from.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* The two GPIO ports the MCP23x17 has.
*/
@@ -53,10 +34,11 @@ class Mcp23x17 {
uint8_t port_0_interrupt_mask = 0x00; ///< Interrupt mask (1 = interrupt) for port 0 / A
uint8_t port_1_direction_mask = 0x00; ///< Direction mask (1 = input) for port 1 / B
uint8_t port_1_interrupt_mask = 0x00; ///< Interrupt mask (1 = interrupt) for port 1 / B
- write_fn write; ///< Function to write to the device.
- read_fn read; ///< Function to read from the device.
- bool auto_init = true; ///< True if the device should be initialized on
- ///< construction.
+ BasePeripheral::write_fn write; ///< Function to write to the device.
+ BasePeripheral::read_register_fn
+ read_register; ///< Function to read bytes at a register address from the device.
+ bool auto_init = true; ///< True if the device should be initialized on
+ ///< construction.
Logger::Verbosity log_level{Logger::Verbosity::WARN}; ///< Log verbosity for the component.
};
@@ -65,11 +47,14 @@ class Mcp23x17 {
* @param config Config structure for configuring the MCP23X17
*/
explicit Mcp23x17(const Config &config)
- : address_(config.device_address), port_0_direction_mask_(config.port_0_direction_mask),
- port_0_interrupt_mask_(config.port_0_interrupt_mask),
- port_1_direction_mask_(config.port_1_direction_mask),
- port_1_interrupt_mask_(config.port_1_interrupt_mask), write_(config.write),
- read_(config.read), logger_({.tag = "Mcp23x17", .level = config.log_level}) {
+ : BasePeripheral({.address = config.device_address,
+ .write = config.write,
+ .read_register = config.read_register},
+ "Mcp23x17", config.log_level)
+ , port_0_direction_mask_(config.port_0_direction_mask)
+ , port_0_interrupt_mask_(config.port_0_interrupt_mask)
+ , port_1_direction_mask_(config.port_1_direction_mask)
+ , port_1_interrupt_mask_(config.port_1_interrupt_mask) {
if (config.auto_init) {
std::error_code ec;
init(ec);
@@ -95,7 +80,7 @@ class Mcp23x17 {
*/
uint8_t get_pins(Port port, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::GPIOA : Registers::GPIOB;
- auto val = read_one_((uint8_t)addr, ec);
+ auto val = read_u8_from_register((uint8_t)addr, ec);
if (ec) {
logger_.error("Failed to read pins: {}", ec.message());
return 0;
@@ -109,10 +94,10 @@ class Mcp23x17 {
* @return The pin values as a 16 bit mask (PA_0 lsb, PB_7 msb).
*/
uint16_t get_pins(std::error_code &ec) {
- uint16_t p0 = read_one_((uint8_t)Registers::GPIOA, ec);
+ uint16_t p0 = read_u8_from_register((uint8_t)Registers::GPIOA, ec);
if (ec)
return 0;
- uint16_t p1 = read_one_((uint8_t)Registers::GPIOB, ec);
+ uint16_t p1 = read_u8_from_register((uint8_t)Registers::GPIOB, ec);
if (ec)
return 0;
return (p1 << 8) | p0;
@@ -126,7 +111,7 @@ class Mcp23x17 {
*/
void set_pins(Port port, uint8_t output, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::GPIOA : Registers::GPIOB;
- write_one_((uint8_t)addr, output, ec);
+ write_u8_to_register((uint8_t)addr, output, ec);
}
/**
@@ -137,7 +122,7 @@ class Mcp23x17 {
*/
uint8_t get_interrupt_capture(Port port, std::error_code &ec) {
auto addr = port == Port::PORT0 ? Registers::INTCAPA : Registers::INTCAPB;
- auto val = read_one_((uint8_t)addr, ec);
+ auto val = read_u8_from_register((uint8_t)addr, ec);
if (ec) {
logger_.error("Failed to read interrupt capture: {}", ec.message());
return 0;
@@ -154,7 +139,7 @@ class Mcp23x17 {
void set_interrupt_on_change(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting interrupt on change for {} pins {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::GPINTENA : Registers::GPINTENB;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -169,7 +154,7 @@ class Mcp23x17 {
val_mask);
// set the pin to enable interrupt
auto addr = port == Port::PORT0 ? Registers::GPINTENA : Registers::GPINTENB;
- write_one_((uint8_t)addr, pin_mask, ec);
+ write_u8_to_register((uint8_t)addr, pin_mask, ec);
if (ec) {
logger_.error("Failed to enable interrupt: {}", ec.message());
return;
@@ -177,7 +162,7 @@ class Mcp23x17 {
// set the pin to interrupt on comparison to defval register
addr = port == Port::PORT0 ? Registers::INTCONA : Registers::INTCONB;
- write_one_((uint8_t)addr, pin_mask, ec);
+ write_u8_to_register((uint8_t)addr, pin_mask, ec);
if (ec) {
logger_.error("Failed to set pin interrupt on comparison: {}", ec.message());
return;
@@ -185,7 +170,7 @@ class Mcp23x17 {
// set the defval register to be the value to compare against
addr = port == Port::PORT0 ? Registers::DEFVALA : Registers::DEFVALB;
- write_one_((uint8_t)addr, val_mask, ec);
+ write_u8_to_register((uint8_t)addr, val_mask, ec);
if (ec) {
logger_.error("Failed to set defval: {}", ec.message());
return;
@@ -201,7 +186,7 @@ class Mcp23x17 {
void set_direction(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting direction for {} to {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::IODIRA : Registers::IODIRB;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -213,7 +198,7 @@ class Mcp23x17 {
void set_input_polarity(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting input polarity for {} to {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::IOPOLA : Registers::IOPOLB;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -225,7 +210,7 @@ class Mcp23x17 {
void set_pull_up(Port port, uint8_t mask, std::error_code &ec) {
logger_.debug("Setting pull-up for {} to {}", (uint8_t)port, mask);
auto addr = port == Port::PORT0 ? Registers::GPPUA : Registers::GPPUB;
- write_one_((uint8_t)addr, mask, ec);
+ write_u8_to_register((uint8_t)addr, mask, ec);
}
/**
@@ -237,7 +222,7 @@ class Mcp23x17 {
void set_interrupt_mirror(bool mirror, std::error_code &ec) {
logger_.debug("Setting interrupt mirror: {}", mirror);
auto addr = (uint8_t)Registers::IOCON;
- auto config = read_one_(addr, ec);
+ auto config = read_u8_from_register(addr, ec);
if (ec) {
logger_.error("Failed to read config: {}", ec.message());
return;
@@ -250,7 +235,7 @@ class Mcp23x17 {
}
// now write it back
logger_.debug("Writing new config: {}", config);
- write_one_(addr, config, ec);
+ write_u8_to_register(addr, config, ec);
}
/**
@@ -262,7 +247,7 @@ class Mcp23x17 {
void set_interrupt_polarity(bool active_high, std::error_code &ec) {
logger_.debug("Setting interrupt polarity: {}", active_high);
auto addr = (uint8_t)Registers::IOCON;
- auto config = read_one_(addr, ec);
+ auto config = read_u8_from_register(addr, ec);
if (ec) {
logger_.error("Failed to read config: {}", ec.message());
return;
@@ -275,7 +260,7 @@ class Mcp23x17 {
}
// now write it back
logger_.debug("Writing new config: {}", config);
- write_one_(addr, config, ec);
+ write_u8_to_register(addr, config, ec);
}
protected:
@@ -343,31 +328,9 @@ class Mcp23x17 {
set_interrupt_on_change(Port::PORT1, port_1_interrupt_mask_, ec);
}
- void write_one_(uint8_t reg_addr, uint8_t write_data, std::error_code &ec) {
- uint8_t data[2] = {reg_addr, write_data};
- bool success = write_(address_, data, 2);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- uint8_t read_one_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data;
- bool success = read_(address_, reg_addr, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
- uint8_t address_;
uint8_t port_0_direction_mask_;
uint8_t port_0_interrupt_mask_;
uint8_t port_1_direction_mask_;
uint8_t port_1_interrupt_mask_;
- write_fn write_;
- read_fn read_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/mt6701/CMakeLists.txt b/components/mt6701/CMakeLists.txt
index a244e0474..f7698dd56 100644
--- a/components/mt6701/CMakeLists.txt
+++ b/components/mt6701/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger" "task"
+ REQUIRES "base_peripheral" "task"
)
diff --git a/components/mt6701/example/main/mt6701_example.cpp b/components/mt6701/example/main/mt6701_example.cpp
index 47661ee02..062d4a142 100644
--- a/components/mt6701/example/main/mt6701_example.cpp
+++ b/components/mt6701/example/main/mt6701_example.cpp
@@ -27,14 +27,14 @@ extern "C" void app_main(void) {
{.normalized_cutoff_frequency = 2.0f * filter_cutoff_hz * encoder_update_period});
auto filter_fn = [&filter](float raw) -> float { return filter.update(raw); };
// now make the mt6701 which decodes the data
- espp::Mt6701 mt6701(
- {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
- .velocity_filter = filter_fn,
- .update_period = std::chrono::duration(encoder_update_period),
- .log_level = espp::Logger::Verbosity::WARN});
+ espp::Mt6701 mt6701({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ .read_register = std::bind(&espp::I2c::read_at_register, &i2c,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4),
+ .velocity_filter = filter_fn,
+ .update_period = std::chrono::duration(encoder_update_period),
+ .log_level = espp::Logger::Verbosity::WARN});
// and finally, make the task to periodically poll the mt6701 and print the
// state. NOTE: the Mt6701 runs its own task to maintain state, so we're
// just polling the current state.
diff --git a/components/mt6701/include/mt6701.hpp b/components/mt6701/include/mt6701.hpp
index 8762757de..2156305f2 100644
--- a/components/mt6701/include/mt6701.hpp
+++ b/components/mt6701/include/mt6701.hpp
@@ -4,7 +4,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
#include "task.hpp"
namespace espp {
@@ -26,30 +26,10 @@ namespace espp {
* \section mt6701_ex1 Mt6701 Example
* \snippet mt6701_example.cpp mt6701 example
*/
-class Mt6701 {
+class Mt6701 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS = (0b0000110); ///< I2C address of the MT6701
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if the write was successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param reg_addr Register address to read from.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* @brief Filter the input raw velocity and return it.
* @param raw Most recent raw velocity measured.
@@ -74,9 +54,10 @@ class Mt6701 {
* @brief Configuration information for the Mt6701.
*/
struct Config {
- uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address of the device.
- write_fn write; ///< Function to write to the device.
- read_fn read; ///< Function to read from the device.
+ uint8_t device_address = DEFAULT_ADDRESS; ///< I2C address of the device.
+ BasePeripheral::write_fn write; ///< Function to write to the device.
+ BasePeripheral::read_register_fn
+ read_register; ///< Function to read data from a register on the device.
velocity_filter_fn velocity_filter{nullptr}; ///< Function to filter the veolcity. @note Will be
///< called once every update_period seconds.
std::chrono::duration update_period{
@@ -92,9 +73,12 @@ class Mt6701 {
* @brief Construct the Mt6701 and start the update task.
*/
explicit Mt6701(const Config &config)
- : address_(config.device_address), write_(config.write), read_(config.read),
- velocity_filter_(config.velocity_filter), update_period_(config.update_period),
- logger_({.tag = "Mt6701", .level = config.log_level}) {
+ : BasePeripheral({.address = config.device_address,
+ .write = config.write,
+ .read_register = config.read_register},
+ "Mt6701", config.log_level)
+ , velocity_filter_(config.velocity_filter)
+ , update_period_(config.update_period) {
if (config.auto_init) {
std::error_code ec;
initialize(ec);
@@ -184,11 +168,11 @@ class Mt6701 {
int read_count(std::error_code &ec) {
logger_.info("read_count");
// read the angle count registers
- uint8_t angle_h = read_one_((uint8_t)Registers::ANGLE_H, ec);
+ uint8_t angle_h = read_u8_from_register((uint8_t)Registers::ANGLE_H, ec);
if (ec) {
return 0;
}
- uint8_t angle_l = read_one_((uint8_t)Registers::ANGLE_L, ec) >> 2;
+ uint8_t angle_l = read_u8_from_register((uint8_t)Registers::ANGLE_L, ec) >> 2;
if (ec) {
return 0;
}
@@ -265,16 +249,6 @@ class Mt6701 {
task_->start();
}
- uint8_t read_one_(uint8_t reg_addr, std::error_code &ec) {
- uint8_t data;
- bool success = read_(address_, reg_addr, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
- }
-
/**
* @brief Register map for the MT6701.
*
@@ -304,15 +278,11 @@ class Mt6701 {
A_STOP_LOW = 0x40, ///< A_STOP[7:0]
};
- uint8_t address_;
- write_fn write_;
- read_fn read_;
velocity_filter_fn velocity_filter_{nullptr};
std::chrono::duration update_period_;
std::atomic count_{0};
std::atomic accumulator_{0};
std::atomic velocity_rpm_{0};
std::unique_ptr task_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/ndef/include/ndef.hpp b/components/ndef/include/ndef.hpp
index 94488911b..a288c91b0 100644
--- a/components/ndef/include/ndef.hpp
+++ b/components/ndef/include/ndef.hpp
@@ -245,7 +245,9 @@ class Ndef {
* @param payload The payload data for the packet
*/
explicit Ndef(TNF tnf, std::string_view type, std::string_view payload)
- : tnf_(tnf), type_(type), payload_(payload) {}
+ : tnf_(tnf)
+ , type_(type)
+ , payload_(payload) {}
/**
* @brief Static function to make an NDEF record for transmitting english
@@ -656,7 +658,7 @@ class Ndef {
uint8_t ME : 1;
uint8_t MB : 1;
};
- uint8_t raw;
+ uint8_t raw = 0;
};
};
@@ -760,7 +762,7 @@ class Ndef {
}
TNF tnf_;
- Flags flags_{0};
+ Flags flags_{};
int id_{-1};
std::string type_{""};
std::string payload_{""};
diff --git a/components/qwiicnes/CMakeLists.txt b/components/qwiicnes/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/qwiicnes/CMakeLists.txt
+++ b/components/qwiicnes/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/qwiicnes/example/main/qwiicnes_example.cpp b/components/qwiicnes/example/main/qwiicnes_example.cpp
index 2d6cfbd0b..77ac31ca1 100644
--- a/components/qwiicnes/example/main/qwiicnes_example.cpp
+++ b/components/qwiicnes/example/main/qwiicnes_example.cpp
@@ -20,12 +20,13 @@ extern "C" void app_main(void) {
.scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
});
// now make the qwiicnes which decodes the data
- espp::QwiicNes qwiicnes({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3),
- .write_read = std::bind(&espp::I2c::read_at_register, &i2c,
- std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3, std::placeholders::_4),
- .log_level = espp::Logger::Verbosity::WARN});
+ espp::QwiicNes qwiicnes(
+ {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3),
+ .read_register =
+ std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
+ .log_level = espp::Logger::Verbosity::WARN});
// and finally, make the task to periodically poll the qwiicnes and print
// the state
auto task_fn = [&quit_test, &qwiicnes](std::mutex &m, std::condition_variable &cv) {
diff --git a/components/qwiicnes/include/qwiicnes.hpp b/components/qwiicnes/include/qwiicnes.hpp
index afef45267..d3712baeb 100644
--- a/components/qwiicnes/include/qwiicnes.hpp
+++ b/components/qwiicnes/include/qwiicnes.hpp
@@ -2,7 +2,7 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/// @brief A class to interface with the Qwiic NES controller.
@@ -13,26 +13,11 @@ namespace espp {
///
/// \section Example
/// \snippet qwiicnes_example.cpp qwiicnes example
-class QwiicNes {
+class QwiicNes : public BasePeripheral {
public:
/// @brief The default I2C address of the device.
static constexpr uint8_t DEFAULT_ADDRESS = (0x54);
- /// @brief The function to write data to the I2C bus.
- /// @param address The I2C address of the device.
- /// @param data The data to write to the I2C bus.
- /// @param data_len The length of the data to write to the I2C bus.
- /// @return true if the function succeeds.
- typedef std::function write_fn;
-
- /// @brief The function to write then read data from the I2C bus.
- /// @param address The I2C address of the device.
- /// @param register The register to write to the I2C bus.
- /// @param data The data to read from the I2C bus.
- /// @param data_len The length of the data to read from the I2C bus.
- /// @return true if the function succeeds.
- typedef std::function write_read_fn;
-
/// @brief The buttons on the NES controller.
/// @deftails The values in this enum match the button's corresponding bit
/// field in the byte returned by read_current_state() and
@@ -53,14 +38,15 @@ class QwiicNes {
uint8_t left : 1;
uint8_t right : 1;
};
- uint8_t raw;
+ uint8_t raw = 0;
};
};
/// @brief The configuration for the QwiicNes class.
struct Config {
- write_fn write; ///< The function to write data to the I2C bus.
- write_read_fn write_read; ///< The function to write then read data from the I2C bus.
+ BasePeripheral::write_fn write; ///< The function to write data to the I2C bus.
+ BasePeripheral::read_register_fn
+ read_register; ///< The function to write then read data from the I2C bus.
espp::Logger::Verbosity log_level{
espp::Logger::Verbosity::WARN}; ///< The log level for the class.
};
@@ -68,8 +54,10 @@ class QwiicNes {
/// @brief Construct a new QwiicNes object.
/// @param config The configuration for the QwiicNes class.
explicit QwiicNes(const Config &config)
- : write_(config.write), write_read_(config.write_read),
- logger_({.tag = "QwiicNes", .level = config.log_level}) {}
+ : BasePeripheral({.address = DEFAULT_ADDRESS,
+ .write = config.write,
+ .read_register = config.read_register},
+ "QwiicNes", config.log_level) {}
/// @brief Return true if the given button is pressed.
/// @param state The byte returned by read_current_state().
@@ -126,8 +114,8 @@ class QwiicNes {
/// function.
/// The current state represents the buttons which are currently
/// pressed.
- uint8_t read_current_state(std::error_code &ec) const {
- return read_register(Registers::CURRENT_STATE, ec);
+ uint8_t read_current_state(std::error_code &ec) {
+ return read_u8_from_register((uint8_t)Registers::CURRENT_STATE, ec);
}
/// @brief Read the current I2C address of the device.
@@ -140,7 +128,9 @@ class QwiicNes {
/// significant bit is set to 0.
/// For example, if the I2C address is 0x54, then the value returned
/// by this function will be 0xA8.
- uint8_t read_address(std::error_code &ec) const { return read_register(Registers::ADDRESS, ec); }
+ uint8_t read_address(std::error_code &ec) {
+ return read_u8_from_register((uint8_t)Registers::ADDRESS, ec);
+ }
/// @brief Update the I2C address of the device.
/// @param new_address The new I2C address of the device.
@@ -151,14 +141,13 @@ class QwiicNes {
/// The 7-bit I2C address is shifted left by 1 bit and the least
/// significant bit is set to 0.
void update_address(uint8_t new_address, std::error_code &ec) {
- uint8_t data[2] = {(uint8_t)Registers::CHANGE_ADDRESS, new_address};
- bool success = write_(address_, data, 2);
- if (!success) {
- logger_.error("failed to update address");
- ec = std::make_error_code(std::errc::io_error);
+ write_u8_to_register((uint8_t)Registers::CHANGE_ADDRESS, new_address, ec);
+ if (ec) {
+ logger_.error("failed to update address: {}", ec.message());
return;
}
- address_ = new_address;
+ // update the address in the class
+ base_config_.address = new_address;
}
protected:
@@ -177,26 +166,12 @@ class QwiicNes {
/// The button accumulator represents all buttons which have been
/// pressed since the last time the accumulator was read - which is
/// the last time the update() function or this function was called.
- uint8_t read_button_accumulator(std::error_code &ec) const {
- return read_register(Registers::ACCUMULATOR, ec);
- }
-
- uint8_t read_register(Registers reg, std::error_code &ec) const {
- uint8_t data;
- bool success = write_read_(address_, (uint8_t)reg, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return data;
+ uint8_t read_button_accumulator(std::error_code &ec) {
+ return read_u8_from_register((uint8_t)Registers::ACCUMULATOR, ec);
}
- write_fn write_;
- write_read_fn write_read_;
uint8_t accumulated_states_{0};
- ButtonState button_state_{0};
- uint8_t address_{DEFAULT_ADDRESS};
- espp::Logger logger_;
+ ButtonState button_state_{};
};
} // namespace espp
diff --git a/components/st25dv/CMakeLists.txt b/components/st25dv/CMakeLists.txt
index 04ffe6760..814d4f0e5 100644
--- a/components/st25dv/CMakeLists.txt
+++ b/components/st25dv/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger" "ndef"
+ REQUIRES "base_peripheral" "ndef"
)
diff --git a/components/st25dv/example/main/st25dv_example.cpp b/components/st25dv/example/main/st25dv_example.cpp
index 70609035b..8e9af1003 100644
--- a/components/st25dv/example/main/st25dv_example.cpp
+++ b/components/st25dv/example/main/st25dv_example.cpp
@@ -69,13 +69,13 @@ extern "C" void app_main(void) {
.sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
.scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
});
+
// now make the st25dv which decodes the data
- espp::St25dv st25dv(
- {.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
- .read = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
- .log_level = espp::Logger::Verbosity::DEBUG});
+ espp::St25dv st25dv({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ .log_level = espp::Logger::Verbosity::DEBUG});
std::array programmed_data;
std::error_code ec;
@@ -130,10 +130,17 @@ extern "C" void app_main(void) {
// and finally, make the task to periodically poll the st25dv and print the
// state. The task will trigger sample quit when the phone reads the tag.
auto task_fn = [&quit_test, &st25dv](std::mutex &m, std::condition_variable &cv) {
+ {
+ std::unique_lock lock(m);
+ cv.wait_for(lock, 30ms);
+ }
std::error_code ec;
auto it_sts = st25dv.get_interrupt_status(ec);
if (ec) {
fmt::print("Failed to get interrupt status: {}\n", ec.message());
+ // wait a bit before trying again
+ std::unique_lock lock(m);
+ cv.wait_for(lock, 300ms);
return false;
}
static auto last_it_sts = it_sts;
@@ -141,8 +148,6 @@ extern "C" void app_main(void) {
fmt::print("[{:.3f}] IT STS: {:02x}\n", elapsed(), it_sts);
}
last_it_sts = it_sts;
- std::unique_lock lock(m);
- cv.wait_for(lock, 10ms);
// we don't want to stop the task, so return false
return false;
};
diff --git a/components/st25dv/example/sdkconfig.defaults b/components/st25dv/example/sdkconfig.defaults
index ef8d3a465..5ed4913e9 100644
--- a/components/st25dv/example/sdkconfig.defaults
+++ b/components/st25dv/example/sdkconfig.defaults
@@ -16,7 +16,7 @@ CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
# SPI Flash Config:
-CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM=y
diff --git a/components/st25dv/include/st25dv.hpp b/components/st25dv/include/st25dv.hpp
index 918bcadf2..acffe4782 100644
--- a/components/st25dv/include/st25dv.hpp
+++ b/components/st25dv/include/st25dv.hpp
@@ -6,9 +6,8 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
#include "ndef.hpp"
-#include "task.hpp"
namespace espp {
/**
@@ -24,7 +23,7 @@ namespace espp {
* \section st25dv_ex1 St25dv Example
* \snippet st25dv_example.cpp st25dv example
*/
-class St25dv {
+class St25dv : public BasePeripheral {
public:
// NOTE: when the datasheet mentions E2 device select, they are talking
// about Bit 4 of the address which selects between the data (user memory,
@@ -54,43 +53,22 @@ class St25dv {
static constexpr int RF_WRITE = 0b10000000; ///< Write in eeprom
};
- /**
- * @brief Function to write bytes to St25dv.
- * @param addr I2C address to write to
- * @param data Data to be written.
- * @param length Number of bytes to write.
- * @return True if the write was successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read a sequence of bytes from St25dv.
- * @param addr I2C address to read from
- * @param reg_addr Start register address to read from.
- * @param data Pointer to memory which will be filled with data read
- * from St25dv.
- * @param length Number of bytes to read
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function
- read_fn;
-
/**
* @brief Configuration information for the St25dv.
*/
struct Config {
- write_fn write; ///< Function to write to the device.
- read_fn read; ///< Function to read from the device.
+ BasePeripheral::write_fn write; ///< Function to write to the device.
+ BasePeripheral::read_fn read; ///< Function to read from the device.
bool auto_init{true}; ///< Automatically initialize the device.
Logger::Verbosity log_level{Logger::Verbosity::WARN}; /**< Log verbosity for the component. */
};
/**
- * @brief Construct the St25dv and start the update task.
+ * @brief Construct the St25dv with the provided configuration.
*/
explicit St25dv(const Config &config)
- : write_(config.write), read_(config.read),
- logger_({.tag = "St25dv", .level = config.log_level}) {
+ : BasePeripheral({.address = DATA_ADDRESS, .write = config.write, .read = config.read},
+ "St25dv", config.log_level) {
if (config.auto_init) {
std::error_code ec;
initialize(ec);
@@ -115,9 +93,11 @@ class St25dv {
*/
uint8_t get_interrupt_status(std::error_code &ec) {
uint8_t it_sts = 0;
- bool success = read_(DATA_ADDRESS, (uint16_t)Registers::IT_STS, &it_sts, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ // NOTE: we have to use the underlying peripheral's functions since we
+ // have to use different device addresses for the different types of
+ // registers
+ read_syst_register(Registers::IT_STS, &it_sts, 1, ec);
+ if (ec) {
return 0;
}
return it_sts;
@@ -227,9 +207,11 @@ class St25dv {
data[0] = (uint8_t)(AREA_1_START_ADDR >> 8);
data[1] = (uint8_t)(AREA_1_START_ADDR & 0xFF);
memcpy(&data[2], payload.data(), payload_size);
- bool success = write_(DATA_ADDRESS, data, sizeof(data));
+ bool success = base_config_.write(DATA_ADDRESS, data, sizeof(data));
if (!success) {
ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
}
}
@@ -254,10 +236,8 @@ class St25dv {
* reading.
*/
void read(uint8_t *data, uint8_t length, uint16_t offset, std::error_code &ec) {
- bool success = read_(DATA_ADDRESS, AREA_1_START_ADDR + offset, data, length);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
+ uint16_t reg = AREA_1_START_ADDR + offset;
+ read_data_register((Registers)reg, data, length, ec);
}
/**
@@ -278,9 +258,11 @@ class St25dv {
// data
MB_CTRL::EN,
};
- bool success = write_(DATA_ADDRESS, data, sizeof(data));
+ bool success = base_config_.write(DATA_ADDRESS, data, sizeof(data));
if (!success) {
ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
}
}
@@ -300,9 +282,11 @@ class St25dv {
// data
0,
};
- bool success = write_(DATA_ADDRESS, data, sizeof(data));
+ bool success = base_config_.write(DATA_ADDRESS, data, sizeof(data));
if (!success) {
ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
}
}
@@ -315,9 +299,8 @@ class St25dv {
*/
uint8_t get_ftm_length(std::error_code &ec) {
uint8_t len = 0;
- bool success = read_(DATA_ADDRESS, (uint16_t)Registers::MB_LEN, &len, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_data_register(Registers::MB_LEN, &len, 1, ec);
+ if (ec) {
return 0;
}
return len;
@@ -378,7 +361,7 @@ class St25dv {
all_data[0] = (uint8_t)(FTM_START_ADDR >> 8);
all_data[1] = (uint8_t)(FTM_START_ADDR & 0xFF);
memcpy(&all_data[2], data, length);
- bool success = write_(DATA_ADDRESS, all_data, length + 2);
+ bool success = base_config_.write(DATA_ADDRESS, all_data, length + 2);
if (!success) {
ec = std::make_error_code(std::errc::io_error);
}
@@ -390,17 +373,14 @@ class St25dv {
void read_ftm(uint8_t *data, uint8_t length, uint8_t offset, std::error_code &ec) {
// read can start from any byte offset within the FTM mailbox.
- bool success = read_(DATA_ADDRESS, FTM_START_ADDR + offset, data, length);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- }
+ uint16_t reg = FTM_START_ADDR + offset;
+ read_data_register((Registers)reg, data, length, ec);
}
uint64_t read_uuid(std::error_code &ec) {
uint8_t uuid[8];
- bool success = read_(SYST_ADDRESS, (uint16_t)Registers::UID, uuid, sizeof(uuid));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_syst_register(Registers::UID, uuid, sizeof(uuid), ec);
+ if (ec) {
return 0;
}
memcpy(&uuid_, uuid, sizeof(uuid));
@@ -410,9 +390,8 @@ class St25dv {
uint8_t read_block_size_bytes(std::error_code &ec) {
uint8_t block_size_bytes = 0;
- bool success = read_(SYST_ADDRESS, (uint16_t)Registers::MEM_SIZE, &block_size_bytes, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_syst_register(Registers::MEM_SIZE, &block_size_bytes, 1, ec);
+ if (ec) {
return 0;
}
logger_.debug("Block size (B): {}", block_size_bytes);
@@ -420,22 +399,21 @@ class St25dv {
}
uint16_t read_memory_size_blocks(std::error_code &ec) {
- uint16_t memory_size_blocks = 0;
- bool success =
- read_(SYST_ADDRESS, (uint16_t)Registers::BLK_SIZE, (uint8_t *)&memory_size_blocks, 2);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ uint8_t buffer[2];
+ read_syst_register(Registers::BLK_SIZE, buffer, 2, ec);
+ if (ec) {
return 0;
}
+ uint16_t memory_size_blocks = 0;
+ memory_size_blocks = (buffer[0] << 8) | buffer[1];
logger_.debug("Memory size (blocks): {}", memory_size_blocks);
return memory_size_blocks;
}
uint64_t read_password(std::error_code &ec) {
uint8_t pswds[8];
- bool success = read_(SYST_ADDRESS, (uint16_t)Registers::I2C_PWD, pswds, sizeof(pswds));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_syst_register(Registers::I2C_PWD, pswds, sizeof(pswds), ec);
+ if (ec) {
return 0;
}
memcpy(&password_, pswds, sizeof(pswds));
@@ -458,7 +436,7 @@ class St25dv {
data[2 + i + 13] = data[2 + i + 4];
}
logger_.debug("Presenting password: {}\n", data);
- bool success = write_(SYST_ADDRESS, data, sizeof(data));
+ bool success = base_config_.write(SYST_ADDRESS, data, sizeof(data));
if (!success) {
ec = std::make_error_code(std::errc::io_error);
}
@@ -595,11 +573,42 @@ class St25dv {
0x2008; /**< Start address of the Fast Transfer Mode Mailbox. */
static constexpr int FTM_SIZE = 0xFF; /**< Number of bytes in the Fast Transfer Mode Mailbox. */
- write_fn write_;
- read_fn read_;
+ void read_syst_register(Registers reg, uint8_t *data, uint8_t length, std::error_code &ec) {
+ uint8_t reg_addr[2];
+ reg_addr[0] = (uint16_t)reg >> 8;
+ reg_addr[1] = (uint16_t)reg & 0xFF;
+ bool success = base_config_.write(SYST_ADDRESS, reg_addr, 2);
+ if (!success) {
+ ec = std::make_error_code(std::errc::io_error);
+ return;
+ }
+ success = base_config_.read(SYST_ADDRESS, data, length);
+ if (!success) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ }
+
+ void read_data_register(Registers reg, uint8_t *data, uint8_t length, std::error_code &ec) {
+ uint8_t reg_addr[2];
+ reg_addr[0] = (uint16_t)reg >> 8;
+ reg_addr[1] = (uint16_t)reg & 0xFF;
+ bool success = base_config_.write(DATA_ADDRESS, reg_addr, 2);
+ if (!success) {
+ ec = std::make_error_code(std::errc::io_error);
+ return;
+ }
+ success = base_config_.read(DATA_ADDRESS, data, length);
+ if (!success) {
+ ec = std::make_error_code(std::errc::io_error);
+ } else {
+ ec.clear();
+ }
+ }
+
uint32_t memory_size_bytes_;
uint64_t uuid_;
uint64_t password_;
- Logger logger_;
};
} // namespace espp
diff --git a/components/t_keyboard/CMakeLists.txt b/components/t_keyboard/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/t_keyboard/CMakeLists.txt
+++ b/components/t_keyboard/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/t_keyboard/include/t_keyboard.hpp b/components/t_keyboard/include/t_keyboard.hpp
index 126154be0..1c3a5d829 100644
--- a/components/t_keyboard/include/t_keyboard.hpp
+++ b/components/t_keyboard/include/t_keyboard.hpp
@@ -4,7 +4,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
#include "task.hpp"
namespace espp {
@@ -16,27 +16,11 @@ namespace espp {
///
/// \section Example
/// \snippet t_keyboard_example.cpp tkeyboard example
-class TKeyboard {
+class TKeyboard : public BasePeripheral {
public:
/// The default address of the keyboard.
static constexpr uint8_t DEFAULT_ADDRESS = 0x55;
- /// \brief The function signature for the write function.
- /// \details This function is used to write data to the keyboard.
- /// \param address The address to write to.
- /// \param data The data to write.
- /// \param size The size of the data to write.
- /// \return True if the write was successful, false otherwise.
- typedef std::function write_fn;
-
- /// \brief The function signature for the read function.
- /// \details This function is used to read data from the keyboard.
- /// \param address The address to read from.
- /// \param data The data to read into.
- /// \param size The size of the data to read.
- /// \return True if the read was successful, false otherwise.
- typedef std::function read_fn;
-
/// \brief The function signature for the key callback function.
/// \details This function is called when a key is pressed.
/// \param key The key that was pressed.
@@ -45,10 +29,10 @@ class TKeyboard {
/// The configuration structure for the keyboard.
struct Config {
/// The write function to use.
- write_fn write;
+ BasePeripheral::write_fn write;
/// The read function to use.
- read_fn read;
+ BasePeripheral::read_fn read;
/// The key callback function to use. This function will be called when a
/// key is pressed if it is not null and the keyboard task is running.
@@ -70,9 +54,10 @@ class TKeyboard {
/// \brief Constructor for the TKeyboard class.
/// \param config The configuration to use.
explicit TKeyboard(const Config &config)
- : write_(config.write), read_(config.read), key_cb_(config.key_cb), address_(config.address),
- polling_interval_(config.polling_interval),
- logger_({.tag = "TKeyboard", .level = config.log_level}) {
+ : BasePeripheral({.address = config.address, .write = config.write, .read = config.read},
+ "TKeyboard", config.log_level)
+ , key_cb_(config.key_cb)
+ , polling_interval_(config.polling_interval) {
logger_.info("TKeyboard created");
task_ = std::make_shared(espp::Task::Config{
.name = "tkeyboard_task",
@@ -105,7 +90,7 @@ class TKeyboard {
ec = std::make_error_code(std::errc::operation_in_progress);
return 0;
}
- return read_char(ec);
+ return read_u8(ec);
}
/// \brief Start the keyboard task.
@@ -126,7 +111,7 @@ class TKeyboard {
bool key_task(std::mutex &m, std::condition_variable &cv) {
std::error_code ec;
auto start_time = std::chrono::steady_clock::now();
- auto key = read_char(ec);
+ auto key = read_u8(ec);
if (!ec) {
pressed_key_ = key;
if (key != 0 && key_cb_) {
@@ -143,35 +128,9 @@ class TKeyboard {
return false;
}
- uint8_t read_char(std::error_code &ec) {
- uint8_t data = 0;
- read(&data, 1, ec);
- if (ec) {
- logger_.error("Failed to read char: {}", ec.message());
- return 0;
- }
- return data;
- }
-
- void write(uint8_t *data, size_t size, std::error_code &ec) {
- if (!write_(address_, data, size)) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- void read(uint8_t *data, size_t size, std::error_code &ec) {
- if (!read_(address_, data, size)) {
- ec = std::make_error_code(std::errc::io_error);
- }
- }
-
- write_fn write_;
- read_fn read_;
key_cb_fn key_cb_;
- uint8_t address_;
std::atomic pressed_key_{0};
std::chrono::milliseconds polling_interval_;
std::shared_ptr task_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/tla2528/CMakeLists.txt b/components/tla2528/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/tla2528/CMakeLists.txt
+++ b/components/tla2528/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/tla2528/example/main/tla2528_example.cpp b/components/tla2528/example/main/tla2528_example.cpp
index dcb09a425..944767c9c 100644
--- a/components/tla2528/example/main/tla2528_example.cpp
+++ b/components/tla2528/example/main/tla2528_example.cpp
@@ -23,9 +23,10 @@ extern "C" void app_main(void) {
.scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
});
- static auto NTC_CHANNEL = espp::Tla2528::Channel::CH1;
- static auto X_CHANNEL = espp::Tla2528::Channel::CH6;
- static auto Y_CHANNEL = espp::Tla2528::Channel::CH7;
+ static std::vector channels = {
+ espp::Tla2528::Channel::CH0, espp::Tla2528::Channel::CH1, espp::Tla2528::Channel::CH2,
+ espp::Tla2528::Channel::CH3, espp::Tla2528::Channel::CH4, espp::Tla2528::Channel::CH5,
+ espp::Tla2528::Channel::CH6, espp::Tla2528::Channel::CH7};
// make the actual tla class
espp::Tla2528 tla(espp::Tla2528::Config{
@@ -33,7 +34,7 @@ extern "C" void app_main(void) {
// of 0x10 becomes 0x16
.device_address = espp::Tla2528::DEFAULT_ADDRESS | 0x06,
.mode = espp::Tla2528::Mode::AUTO_SEQ,
- .analog_inputs = {NTC_CHANNEL, X_CHANNEL, Y_CHANNEL},
+ .analog_inputs = channels,
.digital_inputs = {},
.digital_outputs = {},
// enable oversampling / averaging
@@ -54,16 +55,16 @@ extern "C" void app_main(void) {
// get the analog input data individually; NOTE: this only works if you have configured the
// TLA2528 to use MANUAL mode
- // auto ntc_mv = tla.get_mv(NTC_CHANNEL);
- // auto x_mv = tla.get_mv(X_CHANNEL);
- // auto y_mv = tla.get_mv(Y_CHANNEL);
+ // auto ch0_mv = tla.get_mv(channels[0]);
+ // auto ch1_mv = tla.get_mv(channels[1]);
+ // auto ch2_mv = tla.get_mv(channels[2]);
// Could also read them all at once; NOTE: this only works if you have configured the
// TLA2528 to use AUTO_SEQ mode (which is more efficient)
// auto all_mv = tla.get_all_mv();
- // auto ntc_mv = all_mv[0];
- // auto x_mv = all_mv[1];
- // auto y_mv = all_mv[2];
+ // auto ch0_mv = all_mv[0];
+ // auto ch1_mv = all_mv[1];
+ // auto ch2_mv = all_mv[2];
// Could also use the mapped version; NOTE: this only works if you have configured the
// TLA2528 to use AUTO_SEQ mode (which is more efficient)
@@ -73,13 +74,15 @@ extern "C" void app_main(void) {
logger.error("error reading TLA2528: {}", ec.message());
return false;
}
- auto ntc_mv = all_mv_map[NTC_CHANNEL];
- auto x_mv = all_mv_map[X_CHANNEL];
- auto y_mv = all_mv_map[Y_CHANNEL];
// use fmt to print so it doesn't have the prefix and can be used more
// easily as CSV (for plotting using uart_serial_plotter)
- fmt::print("{:.3f}, {:.3f}, {:.3f}, {:.3f}\n", elapsed, ntc_mv, x_mv, y_mv);
+ fmt::print("{:.3f}", elapsed);
+ for (auto &[ch, mv] : all_mv_map) {
+ fmt::print(", {:.1f}", mv);
+ }
+ fmt::print("\n");
+
// NOTE: sleeping in this way allows the sleep to exit early when the
// task is being stopped / destroyed
{
diff --git a/components/tla2528/include/tla2528.hpp b/components/tla2528/include/tla2528.hpp
index c661803a0..0cc8700e6 100644
--- a/components/tla2528/include/tla2528.hpp
+++ b/components/tla2528/include/tla2528.hpp
@@ -8,7 +8,7 @@
#include
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/**
@@ -25,30 +25,12 @@ namespace espp {
* \section tla2528_ex1 TLA2528 Example
* \snippet tla2528_example.cpp tla2528 example
*/
-class Tla2528 {
+class Tla2528 : public BasePeripheral {
public:
static constexpr uint8_t DEFAULT_ADDRESS =
(0x10); ///< Default I2C address of the device (when both R1 and R2 are DNP) (see data sheet
///< Table 2, p. 16)
- /**
- * @brief Function to write bytes to the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to write.
- * @param data_len Number of data bytes to write.
- * @return True if the write was successful, false otherwise.
- */
- typedef std::function write_fn;
-
- /**
- * @brief Function to read bytes from the device.
- * @param dev_addr Address of the device to write to.
- * @param data Pointer to array of bytes to read into.
- * @param data_len Number of data bytes to read.
- * @return True if the read was successful, false otherwise.
- */
- typedef std::function read_fn;
-
/// @brief Possible oversampling ratios, see data sheet Table 15 (p. 34)
enum class OversamplingRatio : uint8_t {
NONE = 0, ///< No oversampling
@@ -144,11 +126,11 @@ class Tla2528 {
///< the default value is false in open-drain
///< mode.
OversamplingRatio oversampling_ratio = OversamplingRatio::NONE; ///< Oversampling ratio to use.
- Append append = Append::NONE; ///< What data to append to samples when reading analog inputs.
- write_fn write; ///< Function to write to the ADC
- read_fn read; ///< Function to read from the ADC
- bool auto_init = true; ///< Automatically initialize the ADC on construction. If false,
- ///< initialize() must be called before any other functions.
+ Append append = Append::NONE; ///< What data to append to samples when reading analog inputs.
+ BasePeripheral::write_fn write; ///< Function to write to the ADC
+ BasePeripheral::read_fn read; ///< Function to read from the ADC
+ bool auto_init = true; ///< Automatically initialize the ADC on construction. If false,
+ ///< initialize() must be called before any other functions.
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< Verbosity for the logger.
};
@@ -157,15 +139,19 @@ class Tla2528 {
* @param config Configuration structure.
*/
explicit Tla2528(const Config &config)
- : config_(config), mode_(config.mode), avdd_mv_(config.avdd_volts * 1000.0f) // Convert to mV
- ,
- data_format_(config.oversampling_ratio == OversamplingRatio::NONE ? DataFormat::RAW
- : DataFormat::AVERAGED),
- append_(config.append), analog_inputs_(config.analog_inputs),
- digital_inputs_(config.digital_inputs), digital_outputs_(config.digital_outputs),
- oversampling_ratio_(config.oversampling_ratio), address_(config.device_address),
- write_(config.write), read_(config.read),
- logger_({.tag = "Tla2528", .level = config.log_level}) {
+ : BasePeripheral(
+ {.address = config.device_address, .write = config.write, .read = config.read},
+ "Tla2528", config.log_level)
+ , config_(config)
+ , mode_(config.mode)
+ , avdd_mv_(config.avdd_volts * 1000.0f)
+ , data_format_(config.oversampling_ratio == OversamplingRatio::NONE ? DataFormat::RAW
+ : DataFormat::AVERAGED)
+ , append_(config.append)
+ , analog_inputs_(config.analog_inputs)
+ , digital_inputs_(config.digital_inputs)
+ , digital_outputs_(config.digital_outputs)
+ , oversampling_ratio_(config.oversampling_ratio) {
num_bytes_per_sample_ = 2;
if (data_format_ == DataFormat::AVERAGED && append_ == Append::CHANNEL_ID) {
num_bytes_per_sample_ = 3;
@@ -205,16 +191,15 @@ class Tla2528 {
* configured as an analog input.
*/
float get_mv(Channel channel, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
// we need to trigger a conversion and then read the result
trigger_conversion(channel, ec);
if (ec) {
return 0.0f;
}
uint8_t data[num_bytes_per_sample_];
- bool success = read_(address_, data, num_bytes_per_sample_);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_many(data, num_bytes_per_sample_, ec);
+ if (ec) {
return 0.0f;
}
uint16_t raw = parse_frame(data);
@@ -237,7 +222,7 @@ class Tla2528 {
* ADC's buffer (blocking until conversion is complete).
*/
std::vector get_all_mv(std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
// TODO: handle the non-autonomous case
auto raw_values = read_all(ec);
if (ec) {
@@ -263,7 +248,7 @@ class Tla2528 {
* ADC's buffer (blocking until conversion is complete).
*/
std::unordered_map get_all_mv_map(std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
std::unordered_map values;
// TODO: handle the non-autonomous case
auto raw_values = read_all_map(ec);
@@ -283,7 +268,7 @@ class Tla2528 {
/// @param ec Error code to set if an error occurs.
/// @note The channel must have been configured as a digital output.
void set_digital_output_mode(Channel channel, OutputMode output_mode, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
if (!is_digital_output(channel)) {
logger_.error("Channel {} is not configured as a digital output", channel);
ec = std::make_error_code(std::errc::invalid_argument);
@@ -306,7 +291,7 @@ class Tla2528 {
* @note The channel must have been configured as a digital output.
*/
void set_digital_output_value(Channel channel, bool value, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
if (!is_digital_output(channel)) {
logger_.error("Channel {} is not configured as a digital output", channel);
ec = std::make_error_code(std::errc::invalid_argument);
@@ -327,7 +312,7 @@ class Tla2528 {
* @note The channel must have been configured as a digital input.
*/
bool get_digital_input_value(Channel channel, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
if (!is_digital_input(channel)) {
logger_.error("Channel {} is not configured as a digital input", channel);
ec = std::make_error_code(std::errc::invalid_argument);
@@ -357,7 +342,7 @@ class Tla2528 {
/// @note This will reset all registers to their default values (converting
/// all channels to analog inputs and disabling all events).
void reset(std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
// reset the device
write_one_(Register::GENERAL_CFG, SW_RST, ec);
if (ec) {
@@ -685,9 +670,8 @@ class Tla2528 {
if (ec) {
return {};
}
- bool success = read_(address_, raw_values, num_bytes);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ read_many(raw_values, num_bytes, ec);
+ if (ec) {
return {};
}
// stop the auto conversion sequence
@@ -841,29 +825,15 @@ class Tla2528 {
return std::find(analog_inputs_.begin(), analog_inputs_.end(), channel) != analog_inputs_.end();
}
- uint8_t read_only_(std::error_code &ec) {
- std::lock_guard lock(mutex_);
- uint8_t val;
- bool success = read_(address_, &val, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- return val;
- }
+ // NOTE: this chip has specific read and write operation commands that are
+ // used, so we don't use the subclass's read_* and write_* methods directly
uint8_t read_one_(Register reg, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
+ uint8_t data = 0;
uint8_t read_one_command[] = {OP_READ_ONE, (uint8_t)reg};
- bool success = write_(address_, read_one_command, sizeof(read_one_command));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return 0;
- }
- uint8_t data;
- success = read_(address_, &data, 1);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
+ write_then_read(read_one_command, sizeof(read_one_command), &data, 1, ec);
+ if (ec) {
return 0;
}
return data;
@@ -871,7 +841,7 @@ class Tla2528 {
uint16_t read_two_(Register reg, std::error_code &ec) {
uint8_t data[2];
- read_many_(reg, data, 2, ec);
+ read_block_(reg, data, 2, ec);
if (ec) {
return 0;
}
@@ -881,67 +851,42 @@ class Tla2528 {
return (data[1] << 8) | data[0];
}
- void read_many_(Register reg, uint8_t *data, uint8_t len, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ void read_block_(Register reg, uint8_t *data, uint8_t len, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
uint8_t read_block_command[] = {OP_READ_BLOCK, (uint8_t)reg};
- bool success = write_(address_, read_block_command, sizeof(read_block_command));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
- success = read_(address_, data, len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_then_read(read_block_command, sizeof(read_block_command), data, len, ec);
}
void set_bits_(Register reg, uint8_t bit, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_SET_BITS, (uint8_t)reg, bit};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void clear_bits_(Register reg, uint8_t bit, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_CLR_BITS, (uint8_t)reg, bit};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void write_one_(Register reg, uint8_t value, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ std::lock_guard lock(base_mutex_);
uint8_t data[] = {OP_WRITE_ONE, (uint8_t)reg, value};
- bool success = write_(address_, data, sizeof(data));
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data, sizeof(data), ec);
}
void write_two_(Register reg, uint16_t value, std::error_code &ec) {
- write_many_(reg, (uint8_t *)&value, 2, ec);
+ write_block_(reg, (uint8_t *)&value, 2, ec);
}
- void write_many_(Register reg, const uint8_t *data, uint8_t len, std::error_code &ec) {
- std::lock_guard lock(mutex_);
+ void write_block_(Register reg, const uint8_t *data, uint8_t len, std::error_code &ec) {
+ std::lock_guard lock(base_mutex_);
uint8_t total_len = len + 2;
uint8_t data_with_header[total_len];
data_with_header[0] = OP_WRITE_BLOCK;
data_with_header[1] = (uint8_t)reg;
memcpy(data_with_header + 2, data, len);
- bool success = write_(address_, data_with_header, total_len);
- if (!success) {
- ec = std::make_error_code(std::errc::io_error);
- return;
- }
+ write_many(data_with_header, total_len, ec);
}
Config config_;
@@ -955,11 +900,6 @@ class Tla2528 {
std::vector digital_inputs_;
std::vector digital_outputs_;
OversamplingRatio oversampling_ratio_;
- uint8_t address_;
- write_fn write_;
- read_fn read_;
- std::recursive_mutex mutex_; ///< mutex for thread safety
- espp::Logger logger_;
};
} // namespace espp
diff --git a/components/tt21100/CMakeLists.txt b/components/tt21100/CMakeLists.txt
index 17999ceee..d43ade275 100644
--- a/components/tt21100/CMakeLists.txt
+++ b/components/tt21100/CMakeLists.txt
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
- REQUIRES "logger"
+ REQUIRES "base_peripheral"
)
diff --git a/components/tt21100/include/tt21100.hpp b/components/tt21100/include/tt21100.hpp
index 143551546..1fe00e270 100644
--- a/components/tt21100/include/tt21100.hpp
+++ b/components/tt21100/include/tt21100.hpp
@@ -2,41 +2,30 @@
#include
-#include "logger.hpp"
+#include "base_peripheral.hpp"
namespace espp {
/// @brief Driver for the Tt21100 touch controller
///
/// \section Example
/// \snippet tt21100_example.cpp tt21100 example
-class Tt21100 {
+class Tt21100 : public BasePeripheral {
public:
/// @brief The default i2c address
static constexpr uint8_t DEFAULT_ADDRESS = (0x24);
- /// @brief Function for writing to the i2c device
- /// @param address The address of the i2c device
- /// @param data The data to write to the chip
- /// @param len The length of the data to write
- typedef std::function write_fn;
-
- /// @brief Function signature for reading from the i2c device
- /// @param dev_addr The device address
- /// @param data The data to read
- /// @param data_len The length of the data to read
- typedef std::function read_fn;
-
/// @brief Configuration for the Tt21100 driver
struct Config {
- write_fn write = nullptr; ///< Function for writing to the i2c device (unused)
- read_fn read; ///< Function for reading from the i2c device
+ BasePeripheral::write_fn write = nullptr; ///< Function for writing to the i2c device (unused)
+ BasePeripheral::read_fn read; ///< Function for reading from the i2c device
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN}; ///< Log level
};
/// @brief Constructor
/// @param config The configuration for the driver
explicit Tt21100(const Config &config)
- : read_(config.read), logger_({.tag = "Tt21100", .level = config.log_level}) {
+ : BasePeripheral({.address = DEFAULT_ADDRESS, .read = config.read}, "Tt21100",
+ config.log_level) {
std::error_code ec;
init(ec);
if (ec) {
@@ -51,25 +40,28 @@ class Tt21100 {
static uint16_t data_len;
static uint8_t data[256];
- bool success = read_(DEFAULT_ADDRESS, (uint8_t *)&data_len, sizeof(data_len));
- if (!success) {
- logger_.error("Failed to read data length");
- ec = std::make_error_code(std::errc::io_error);
+ // NOTE: this chip is weird, and even though we're reading a u16, we can't
+ // use the read_u16 since that function assumes the data is in little
+ // endian format, but this chip sends the data in big endian format meaning
+ // the bytes are swapped
+
+ read_many((uint8_t *)&data_len, 2, ec);
+ if (ec) {
+ logger_.error("Failed to read data length: {}", ec.message());
return false;
}
logger_.debug("Data length: {}", data_len);
- if (data_len == 0xff) {
+ if (data_len >= 0xff) {
logger_.error("Invalid data length");
ec = std::make_error_code(std::errc::io_error);
return false;
}
- success = read_(DEFAULT_ADDRESS, data, data_len);
- if (!success) {
+ read_many(data, data_len, ec);
+ if (ec) {
logger_.error("Failed to read data");
- ec = std::make_error_code(std::errc::io_error);
return false;
}
@@ -137,17 +129,21 @@ class Tt21100 {
void init(std::error_code &ec) {
logger_.debug("Initializing...");
uint16_t reg_val = 0;
+ static constexpr int max_tries = 10;
+ int num_tries = 0;
do {
using namespace std::chrono_literals;
- bool success = read_(DEFAULT_ADDRESS, (uint8_t *)®_val, 2);
- if (!success) {
+ read_many((uint8_t *)®_val, 2, ec);
+ if (ec) {
logger_.error("Failed to read...");
- ec = std::make_error_code(std::errc::io_error);
return;
}
logger_.debug("reg_val: {:#04x}", reg_val);
std::this_thread::sleep_for(20ms);
- } while (0x0002 != reg_val);
+ } while (0x0002 != reg_val && ++num_tries < max_tries);
+ if (num_tries >= max_tries) {
+ logger_.warn("Reached max tries trying to read...");
+ }
}
enum class Registers : uint8_t {
@@ -190,11 +186,9 @@ class Tt21100 {
uint16_t btn_signal[4];
} __attribute__((packed));
- read_fn read_;
std::atomic home_button_pressed_{false};
std::atomic num_touch_points_;
std::atomic x_;
std::atomic y_;
- espp::Logger logger_;
};
} // namespace espp
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 32a7edceb..54a44abcf 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -85,6 +85,7 @@ INPUT += $(PROJECT_PATH)/components/ads7138/include/ads7138.hpp
INPUT += $(PROJECT_PATH)/components/as5600/include/as5600.hpp
INPUT += $(PROJECT_PATH)/components/aw9523/include/aw9523.hpp
INPUT += $(PROJECT_PATH)/components/base_component/include/base_component.hpp
+INPUT += $(PROJECT_PATH)/components/base_peripheral/include/base_peripheral.hpp
INPUT += $(PROJECT_PATH)/components/bldc_driver/include/bldc_driver.hpp
INPUT += $(PROJECT_PATH)/components/bldc_haptics/include/bldc_haptics.hpp
INPUT += $(PROJECT_PATH)/components/bldc_haptics/include/detent_config.hpp
diff --git a/doc/en/base_peripheral.rst b/doc/en/base_peripheral.rst
new file mode 100644
index 000000000..cf48e7675
--- /dev/null
+++ b/doc/en/base_peripheral.rst
@@ -0,0 +1,20 @@
+Base Peripheral
+***************
+
+The `espp::BasePeripheral` class is a base class for all peripherals. It
+provides a common interface for all peripherals and is used to access the
+peripheral's registers. It is primarily designed to be used as a base class for
+peripheral classes that communicate using I2C (address-based) or SPI (CS-based)
+protocols.
+
+The base class provides an interface for specifying different communications
+functions that the peripheral may use, as well as providing some base
+implementations for common functionality such as reading / writing u8 and u16
+values from / to a register.
+
+.. ---------------------------- API Reference ----------------------------------
+
+API Reference
+-------------
+
+.. include-build-file:: inc/base_peripheral.inc
diff --git a/doc/en/index.rst b/doc/en/index.rst
index 85689db81..706501485 100644
--- a/doc/en/index.rst
+++ b/doc/en/index.rst
@@ -12,6 +12,7 @@ This is the documentation for esp-idf c++ components, ESPP (`espp
Base Compoenent
+Base Peripheral
Battery APIs
BLDC APIs
Button APIs
@@ -147,7 +148,7 @@
ADC APIs »
ADC Types
- Edit on GitHub
+ Edit on GitHub
diff --git a/docs/adc/ads1x15.html b/docs/adc/ads1x15.html
index e1970fa6a..a1bbb80a8 100644
--- a/docs/adc/ads1x15.html
+++ b/docs/adc/ads1x15.html
@@ -92,6 +92,7 @@
Base Compoenent
+Base Peripheral
Battery APIs
BLDC APIs
Button APIs
@@ -148,7 +149,7 @@
ADC APIs »
ADS1x15 I2C ADC
- Edit on GitHub
+ Edit on GitHub
@@ -165,14 +166,14 @@ API Reference // make the actual ads class
espp :: Ads1x15 ads ( espp :: Ads1x15 :: Ads1015Config {
. device_address = espp :: Ads1x15 :: DEFAULT_ADDRESS ,
- . write = std :: bind ( & espp :: I2c :: write , & i2c , std :: placeholders :: _1 , std :: placeholders :: _2 ,
- std :: placeholders :: _3 ),
- . read = std :: bind ( & espp :: I2c :: read , & i2c , std :: placeholders :: _1 , std :: placeholders :: _2 ,
- std :: placeholders :: _3 )});
+ . write = [ & i2c ]( uint8_t addr , const uint8_t * data ,
+ size_t len ) { return i2c . write ( addr , data , len ); },
+ . read = [ & i2c ]( uint8_t addr , uint8_t * data ,
+ size_t len ) { return i2c . read ( addr , data , len ); },
+ });
// make the task which will get the raw data from the I2C ADC
auto ads_read_task_fn = [ & ads ]( std :: mutex & m , std :: condition_variable & cv ) {
static auto start = std :: chrono :: high_resolution_clock :: now ();
@@ -374,42 +376,105 @@ ADS1X15 Example
+
+Parameters
+level – The verbosity level to use for the logger
+
+
+
+
+
+
+inline void set_log_verbosity ( Logger :: Verbosity level )
+Set the log verbosity for the logger
+
+
+
+
+
Note
+
This is a convenience method that calls set_log_level
+
+
+Parameters
+level – The verbosity level to use for the logger
+
+
+
+
+
+
+inline void set_log_rate_limit ( std :: chrono :: duration < float > rate_limit )
+Set the rate limit for the logger
+
+
+
Note
+
Only calls to the logger that have _rate_limit suffix will be rate limited
+
+
+Parameters
+rate_limit – The rate limit to use for the logger
+
+
+
+
Public Static Attributes
@@ -480,13 +621,13 @@
ADS1X15 ExampleBasePeripheral :: write_fn write
Function to write to the ADC.
-read_fn read
+BasePeripheral :: read_fn read
Function to read from the ADC.
@@ -525,13 +666,13 @@ ADS1X15 ExampleBasePeripheral :: write_fn write
Function to write to the ADC.
-read_fn read
+BasePeripheral :: read_fn read
Function to read from the ADC.
diff --git a/docs/adc/ads7138.html b/docs/adc/ads7138.html
index fee30e20e..ce8efefa7 100644
--- a/docs/adc/ads7138.html
+++ b/docs/adc/ads7138.html
@@ -92,6 +92,7 @@
Base Compoenent
+
Base Peripheral
Battery APIs
BLDC APIs
Button APIs
@@ -148,7 +149,7 @@
ADC APIs »
ADS7138 I2C ADC
- Edit on GitHub
+ Edit on GitHub
@@ -170,14 +171,14 @@
API Reference
-
+
diff --git a/docs/battery/bldc_driver.html b/docs/battery/bldc_driver.html
index ad9ad43b1..bff2788a5 100644
--- a/docs/battery/bldc_driver.html
+++ b/docs/battery/bldc_driver.html
@@ -75,6 +75,7 @@
@@ -147,7 +148,7 @@ API Reference