mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 17:27:59 +01:00
[kp18058] take softI2C class outside of the component. Fix Arduino 2 clang formatting issues
This commit is contained in:
parent
4f9436208d
commit
6edfe8d8b4
8 changed files with 57 additions and 56 deletions
1
esphome/components/i2c_soft/__init__.py
Normal file
1
esphome/components/i2c_soft/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CODEOWNERS = ["@NewoPL"]
|
|
@ -1,7 +1,7 @@
|
||||||
#include "softi2c.h"
|
#include "softi2c.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace kp18058 {
|
namespace i2c_soft {
|
||||||
|
|
||||||
// Hold time is 250 ns
|
// Hold time is 250 ns
|
||||||
static const uint8_t SOFT_I2C_CLOCK_TIME = 50;
|
static const uint8_t SOFT_I2C_CLOCK_TIME = 50;
|
||||||
|
@ -12,15 +12,15 @@ void ns_sleep(int ns_delay) {
|
||||||
__asm__("nop");
|
__asm__("nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool softI2C::reset() {
|
bool SoftI2C::reset() {
|
||||||
// Ensure SDA is released (high) to avoid conflict during reset
|
// Ensure SDA is released (high) to avoid conflict during reset
|
||||||
set_high(data_pin_);
|
set_high_(data_pin_);
|
||||||
|
|
||||||
// Clock SCL up to 9 times to clear any stuck data
|
// Clock SCL up to 9 times to clear any stuck data
|
||||||
for (int i = 0; i < 9; ++i) {
|
for (int i = 0; i < 9; ++i) {
|
||||||
set_high(clock_pin_);
|
set_high_(clock_pin_);
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_low(clock_pin_);
|
set_low_(clock_pin_);
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
|
|
||||||
// Check if SDA is released (high) by the device during clocking
|
// Check if SDA is released (high) by the device during clocking
|
||||||
|
@ -44,18 +44,18 @@ bool softI2C::reset() {
|
||||||
return (data_pin_->digital_read()) && (clock_pin_->digital_read());
|
return (data_pin_->digital_read()) && (clock_pin_->digital_read());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool softI2C::write_byte(uint8_t value) {
|
bool SoftI2C::write_byte(uint8_t value) {
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
|
|
||||||
for (uint8_t curr = 0x80; curr != 0; curr >>= 1) {
|
for (uint8_t curr = 0x80; curr != 0; curr >>= 1) {
|
||||||
if (curr & value) {
|
if (curr & value) {
|
||||||
set_high(data_pin_);
|
set_high_(data_pin_);
|
||||||
} else {
|
} else {
|
||||||
set_low(data_pin_);
|
set_low_(data_pin_);
|
||||||
}
|
}
|
||||||
set_high(clock_pin_);
|
set_high_(clock_pin_);
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME);
|
ns_sleep(SOFT_I2C_CLOCK_TIME);
|
||||||
set_low(clock_pin_);
|
set_low_(clock_pin_);
|
||||||
// Data is written to the register on the falling edge of SCL
|
// Data is written to the register on the falling edge of SCL
|
||||||
// it needs to be valid through at least HOLD TIME
|
// it needs to be valid through at least HOLD TIME
|
||||||
// waiting half a cycle assuming it is longer than HOLD_TIME
|
// waiting half a cycle assuming it is longer than HOLD_TIME
|
||||||
|
@ -66,34 +66,34 @@ bool softI2C::write_byte(uint8_t value) {
|
||||||
// is completed, in the ninth SCL, KP18058 internally
|
// is completed, in the ninth SCL, KP18058 internally
|
||||||
// generates a response signal ACK
|
// generates a response signal ACK
|
||||||
bool ack_received;
|
bool ack_received;
|
||||||
set_high(data_pin_);
|
set_high_(data_pin_);
|
||||||
set_high(clock_pin_);
|
set_high_(clock_pin_);
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
ack_received = !data_pin_->digital_read();
|
ack_received = !data_pin_->digital_read();
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_low(clock_pin_);
|
set_low_(clock_pin_);
|
||||||
|
|
||||||
return ack_received;
|
return ack_received;
|
||||||
}
|
}
|
||||||
|
|
||||||
void softI2C::start() {
|
void SoftI2C::start() {
|
||||||
set_low(data_pin_);
|
set_low_(data_pin_);
|
||||||
// It needs to be valid through at least HOLD TIME
|
// It needs to be valid through at least HOLD TIME
|
||||||
// Waiting half a cycle. Assuming it is longer than HOLD_TIME
|
// Waiting half a cycle. Assuming it is longer than HOLD_TIME
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_low(clock_pin_);
|
set_low_(clock_pin_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void softI2C::stop() {
|
void SoftI2C::stop() {
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_low(data_pin_);
|
set_low_(data_pin_);
|
||||||
// It needs to be valid through at least HOLD TIME
|
// It needs to be valid through at least HOLD TIME
|
||||||
// Waiting half a cycle. Assuming it is longer than HOLD_TIME
|
// Waiting half a cycle. Assuming it is longer than HOLD_TIME
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_high(clock_pin_);
|
set_high_(clock_pin_);
|
||||||
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
|
||||||
set_high(data_pin_);
|
set_high_(data_pin_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace kp18058
|
} // namespace i2c_soft
|
||||||
} // namespace esphome
|
} // namespace esphome
|
|
@ -3,7 +3,7 @@
|
||||||
#include "esphome/core/gpio.h"
|
#include "esphome/core/gpio.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace kp18058 {
|
namespace i2c_soft {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class to implement a software I2C protocol.
|
* @brief Class to implement a software I2C protocol.
|
||||||
|
@ -11,9 +11,9 @@ namespace kp18058 {
|
||||||
* This class allows communication with I2C devices using GPIO pins
|
* This class allows communication with I2C devices using GPIO pins
|
||||||
* to simulate I2C communication through software control.
|
* to simulate I2C communication through software control.
|
||||||
*/
|
*/
|
||||||
class softI2C {
|
class SoftI2C {
|
||||||
public:
|
public:
|
||||||
softI2C() : data_pin_(nullptr), clock_pin_(nullptr) {}
|
SoftI2C() : data_pin_(nullptr), clock_pin_(nullptr) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets up the I2C pins.
|
* @brief Sets up the I2C pins.
|
||||||
|
@ -101,7 +101,7 @@ class softI2C {
|
||||||
*
|
*
|
||||||
* @param pin Pointer to the GPIOPin object representing the pin to set low.
|
* @param pin Pointer to the GPIOPin object representing the pin to set low.
|
||||||
*/
|
*/
|
||||||
void set_low(GPIOPin *pin) {
|
void set_low_(GPIOPin *pin) {
|
||||||
pin->pin_mode(gpio::FLAG_OUTPUT);
|
pin->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
pin->digital_write(false);
|
pin->digital_write(false);
|
||||||
}
|
}
|
||||||
|
@ -113,11 +113,11 @@ class softI2C {
|
||||||
*
|
*
|
||||||
* @param pin Pointer to the GPIOPin object representing the pin to set high.
|
* @param pin Pointer to the GPIOPin object representing the pin to set high.
|
||||||
*/
|
*/
|
||||||
void set_high(GPIOPin *pin) { pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); }
|
void set_high_(GPIOPin *pin) { pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); }
|
||||||
|
|
||||||
GPIOPin *data_pin_; ///< Pointer to the GPIOPin object for the data line (SDA).
|
GPIOPin *data_pin_; ///< Pointer to the GPIOPin object for the data line (SDA).
|
||||||
GPIOPin *clock_pin_; ///< Pointer to the GPIOPin object for the clock line (SCL).
|
GPIOPin *clock_pin_; ///< Pointer to the GPIOPin object for the clock line (SCL).
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kp18058
|
} // namespace i2c_soft
|
||||||
} // namespace esphome
|
} // namespace esphome
|
|
@ -3,6 +3,7 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID
|
from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID
|
||||||
|
|
||||||
|
AUTO_LOAD = ["i2c_soft"]
|
||||||
CODEOWNERS = ["@NewoPL"]
|
CODEOWNERS = ["@NewoPL"]
|
||||||
|
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
@ -11,7 +12,7 @@ CONF_CW_CURRENT = "cw_current"
|
||||||
CONF_RGB_CURRENT = "rgb_current"
|
CONF_RGB_CURRENT = "rgb_current"
|
||||||
|
|
||||||
KP18058_ns = cg.esphome_ns.namespace("kp18058")
|
KP18058_ns = cg.esphome_ns.namespace("kp18058")
|
||||||
KP18058 = KP18058_ns.class_("kp18058", cg.Component)
|
KP18058 = KP18058_ns.class_("KP18058", cg.Component)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "kp18058.h"
|
#include "kp18058.h"
|
||||||
#include "message.h"
|
#include "kp18058_cfg.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace kp18058 {
|
namespace kp18058 {
|
||||||
|
|
||||||
static const char *const TAG = "kp18058";
|
static const char *const TAG = "KP18058";
|
||||||
static const uint8_t I2C_MAX_RETRY = 3;
|
static const uint8_t I2C_MAX_RETRY = 3;
|
||||||
#define BIT_CHECK(PIN, N) !!(((PIN) & (1 << (N))))
|
#define BIT_CHECK(PIN, N) !!(((PIN) & (1 << (N))))
|
||||||
|
|
||||||
|
@ -18,18 +18,18 @@ uint8_t get_parity_bit(uint8_t b) {
|
||||||
return sum % 2; // 0 for even, 1 for odd
|
return sum % 2; // 0 for even, 1 for odd
|
||||||
}
|
}
|
||||||
|
|
||||||
kp18058::kp18058() : max_cw_current_(0), max_rgb_current_(0), i2c_ready_(false) {
|
KP18058::KP18058() : max_cw_current_(0), max_rgb_current_(0), i2c_ready_(false) {
|
||||||
for (auto &channel : channels_) {
|
for (auto &channel : channels_) {
|
||||||
channel = nullptr;
|
channel = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kp18058::setup() {
|
void KP18058::setup() {
|
||||||
i2c_.setup();
|
i2c_.setup();
|
||||||
i2c_ready_ = i2c_.reset();
|
i2c_ready_ = i2c_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kp18058::dump_config() {
|
void KP18058::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "KP18058 LED Driver:");
|
ESP_LOGCONFIG(TAG, "KP18058 LED Driver:");
|
||||||
LOG_PIN(" Data Pin: ", i2c_.get_data_pin());
|
LOG_PIN(" Data Pin: ", i2c_.get_data_pin());
|
||||||
LOG_PIN(" Clock Pin: ", i2c_.get_clock_pin());
|
LOG_PIN(" Clock Pin: ", i2c_.get_clock_pin());
|
||||||
|
@ -38,7 +38,7 @@ void kp18058::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, " RGB max current: %.1f", this->max_rgb_current_);
|
ESP_LOGCONFIG(TAG, " RGB max current: %.1f", this->max_rgb_current_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kp18058::program_led_driver() {
|
void KP18058::program_led_driver() {
|
||||||
if (!i2c_ready_) {
|
if (!i2c_ready_) {
|
||||||
ESP_LOGI(TAG, "Reestablishing communication with KP18058.");
|
ESP_LOGI(TAG, "Reestablishing communication with KP18058.");
|
||||||
i2c_ready_ = i2c_.reset();
|
i2c_ready_ = i2c_.reset();
|
||||||
|
@ -90,8 +90,8 @@ void kp18058::program_led_driver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate parity bits for each byte
|
// Calculate parity bits for each byte
|
||||||
for (int i = 0; i < sizeof(KP18058_Settings); ++i) {
|
for (auto &byte : settings.bytes) {
|
||||||
settings.bytes[i] |= get_parity_bit(settings.bytes[i]);
|
byte |= get_parity_bit(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the I2C message
|
// Send the I2C message
|
||||||
|
|
|
@ -3,17 +3,16 @@
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/gpio.h"
|
#include "esphome/core/gpio.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/i2c_soft/softi2c.h"
|
||||||
#include "esphome/components/output/float_output.h"
|
#include "esphome/components/output/float_output.h"
|
||||||
|
|
||||||
#include "softi2c.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace kp18058 {
|
namespace kp18058 {
|
||||||
|
|
||||||
// KP18058 main component for controlling LED drivers over soft I2C
|
// KP18058 main component for controlling LED drivers over soft I2C
|
||||||
class kp18058 : public Component {
|
class KP18058 : public Component {
|
||||||
public:
|
public:
|
||||||
kp18058();
|
KP18058();
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,12 +30,12 @@ class kp18058 : public Component {
|
||||||
void set_i2c_pins(GPIOPin *data_pin, GPIOPin *clock_pin) { i2c_.set_pins(data_pin, clock_pin); }
|
void set_i2c_pins(GPIOPin *data_pin, GPIOPin *clock_pin) { i2c_.set_pins(data_pin, clock_pin); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns an output channel to the kp18058 driver for LED control.
|
* Assigns an output channel to the KP18058 driver for LED control.
|
||||||
*
|
*
|
||||||
* @param channel The output channel to assign (1-5).
|
* @param channel The output channel to assign (1-5).
|
||||||
* @param output Pointer to the kp18058_output instance for this channel.
|
* @param output Pointer to the kp18058_output instance for this channel.
|
||||||
*/
|
*/
|
||||||
void set_output_channel(uint8_t channel, class kp18058_output *output) { channels_[channel - 1] = output; }
|
void set_output_channel(uint8_t channel, class KP18058_output *output) { channels_[channel - 1] = output; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum current for the CW (cold-white) channels.
|
* Sets the maximum current for the CW (cold-white) channels.
|
||||||
|
@ -63,26 +62,26 @@ class kp18058 : public Component {
|
||||||
float max_rgb_current_;
|
float max_rgb_current_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class kp18058_output *channels_[5];
|
class KP18058_output *channels_[5];
|
||||||
class softI2C i2c_;
|
class i2c_soft::SoftI2C i2c_;
|
||||||
bool i2c_ready_;
|
bool i2c_ready_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// class represents an output channel for the KP18058 LED driver
|
// class represents an output channel for the KP18058 LED driver
|
||||||
class kp18058_output : public output::FloatOutput {
|
class KP18058_output : public output::FloatOutput {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor for the kp18058_output class.
|
* Constructor for the KP18058_output class.
|
||||||
* Initializes the channel with default values.
|
* Initializes the channel with default values.
|
||||||
*/
|
*/
|
||||||
kp18058_output() : value_(0), parent_(nullptr) {}
|
KP18058_output() : value_(0), parent_(nullptr) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the parent kp18058 driver instance for this output channel.
|
* Sets the parent KP18058 driver instance for this output channel.
|
||||||
*
|
*
|
||||||
* @param parent Pointer to the parent kp18058 instance.
|
* @param parent Pointer to the parent KP18058 instance.
|
||||||
*/
|
*/
|
||||||
void set_parent(kp18058 *parent) { parent_ = parent; }
|
void set_parent(KP18058 *parent) { parent_ = parent; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current grayscale value for this output channel.
|
* Retrieves the current grayscale value for this output channel.
|
||||||
|
@ -100,11 +99,11 @@ class kp18058_output : public output::FloatOutput {
|
||||||
* the parent class to program the LED driver.
|
* the parent class to program the LED driver.
|
||||||
*/
|
*/
|
||||||
void write_state(float state) override {
|
void write_state(float state) override {
|
||||||
if (state >= 1)
|
if (state >= 1) {
|
||||||
state = 1;
|
state = 1;
|
||||||
else if (state <= 0)
|
} else if (state <= 0) {
|
||||||
state = 0;
|
state = 0;
|
||||||
|
}
|
||||||
// Convert brightness state (0.0 - 1.0) to 10-bit value (0 - 1023).
|
// Convert brightness state (0.0 - 1.0) to 10-bit value (0 - 1023).
|
||||||
value_ = static_cast<uint16_t>(roundf(state * 1023));
|
value_ = static_cast<uint16_t>(roundf(state * 1023));
|
||||||
|
|
||||||
|
@ -114,8 +113,8 @@ class kp18058_output : public output::FloatOutput {
|
||||||
|
|
||||||
// 10-bit grayscale value representing intensity (0-1023) of the output.
|
// 10-bit grayscale value representing intensity (0-1023) of the output.
|
||||||
uint16_t value_;
|
uint16_t value_;
|
||||||
// Pointer to the parent kp18058 driver class for this output channel.
|
// Pointer to the parent KP18058 driver class for this output channel.
|
||||||
kp18058 *parent_;
|
KP18058 *parent_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kp18058
|
} // namespace kp18058
|
||||||
|
|
|
@ -6,7 +6,7 @@ from esphome.const import CONF_CHANNEL, CONF_ID
|
||||||
from . import KP18058
|
from . import KP18058
|
||||||
|
|
||||||
KP18058_ns = cg.esphome_ns.namespace("kp18058")
|
KP18058_ns = cg.esphome_ns.namespace("kp18058")
|
||||||
DriverOutput = KP18058_ns.class_("kp18058_output", output.FloatOutput)
|
DriverOutput = KP18058_ns.class_("KP18058_output", output.FloatOutput)
|
||||||
|
|
||||||
CONF_KP18058_ID = "kp18058_id"
|
CONF_KP18058_ID = "kp18058_id"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue