mirror of
https://github.com/esphome/esphome.git
synced 2026-10-23 14:38:52 +00:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9180658d8d | ||
|
|
54de6dded4 | ||
|
|
02f3f8249a | ||
|
|
0cf6cbd1ec | ||
|
|
b8e109aa2e | ||
|
|
cbce5542f9 | ||
|
|
1233e5b7a1 | ||
|
|
e7a653cc5f | ||
|
|
79b8276c70 | ||
|
|
62310edd98 | ||
|
|
716b5ff166 | ||
|
|
d403b74954 | ||
|
|
6bae24e771 | ||
|
|
136500ee95 | ||
|
|
13c97ad7d4 | ||
|
|
3c32d960e9 | ||
|
|
7763b1ee3d | ||
|
|
333436e82c | ||
|
|
ec62b755db | ||
|
|
e878d76e3a |
No files matched your search
@@ -293,14 +293,9 @@ void BekenSPILEDStripLightOutput::set_led_params(uint8_t bit0, uint8_t bit1, uin
|
||||
}
|
||||
|
||||
void BekenSPILEDStripLightOutput::write_state(light::LightState *state) {
|
||||
// protect from refreshing too often
|
||||
uint32_t now = micros();
|
||||
if (this->max_refresh_rate_.has_value() && *this->max_refresh_rate_ != 0 &&
|
||||
(now - this->last_refresh_) < *this->max_refresh_rate_) {
|
||||
// try again next loop iteration, so that this change won't get lost
|
||||
this->schedule_show();
|
||||
if (this->throttle_show_(now, this->last_refresh_, this->max_refresh_rate_))
|
||||
return;
|
||||
}
|
||||
this->last_refresh_ = now;
|
||||
this->mark_shown_();
|
||||
|
||||
@@ -369,17 +364,6 @@ void BekenSPILEDStripLightOutput::write_state(light::LightState *state) {
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
light::ESPColorView BekenSPILEDStripLightOutput::get_view_internal(int32_t index) const {
|
||||
const light::ChannelColors &colors = this->channel_colors_;
|
||||
uint8_t *led = this->buf_ + (index * colors.bytes_per_led());
|
||||
return {led + colors.r,
|
||||
led + colors.g,
|
||||
led + colors.b,
|
||||
colors.has_white() ? led + colors.w : nullptr,
|
||||
&this->effect_data_[index],
|
||||
&this->correction_};
|
||||
}
|
||||
|
||||
void BekenSPILEDStripLightOutput::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Beken SPI LED Strip:\n"
|
||||
@@ -390,7 +374,7 @@ void BekenSPILEDStripLightOutput::dump_config() {
|
||||
" Channel colors: %s\n"
|
||||
" Max refresh rate: %" PRIu32 "\n"
|
||||
" Number of LEDs: %u",
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_.value_or(0), this->num_leds_);
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_, this->num_leds_);
|
||||
}
|
||||
|
||||
float BekenSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
@@ -18,15 +18,7 @@ class BekenSPILEDStripLightOutput final : public light::AddressableLight {
|
||||
float get_setup_priority() const override;
|
||||
|
||||
int32_t size() const override { return this->num_leds_; }
|
||||
light::LightTraits get_traits() override {
|
||||
auto traits = light::LightTraits();
|
||||
if (this->channel_colors_.has_white()) {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
|
||||
} else {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB});
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
light::LightTraits get_traits() override { return this->channel_colors_.traits(); }
|
||||
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
|
||||
@@ -38,14 +30,16 @@ class BekenSPILEDStripLightOutput final : public light::AddressableLight {
|
||||
void set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency);
|
||||
|
||||
void clear_effect_data() override {
|
||||
for (int i = 0; i < this->size(); i++)
|
||||
this->effect_data_[i] = 0;
|
||||
if (this->effect_data_ != nullptr)
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
}
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override;
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return this->channel_colors_.view(this->buf_, this->effect_data_, index, &this->correction_);
|
||||
}
|
||||
|
||||
size_t get_buffer_size_() const { return this->num_leds_ * this->channel_colors_.bytes_per_led(); }
|
||||
|
||||
@@ -62,7 +56,7 @@ class BekenSPILEDStripLightOutput final : public light::AddressableLight {
|
||||
light::ChannelColors channel_colors_{0, 1, 2, light::ChannelColors::NO_WHITE};
|
||||
|
||||
uint32_t last_refresh_{0};
|
||||
optional<uint32_t> max_refresh_rate_{};
|
||||
uint32_t max_refresh_rate_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome::beken_spi_led_strip
|
||||
|
||||
@@ -157,14 +157,9 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
|
||||
}
|
||||
|
||||
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||
// protect from refreshing too often
|
||||
uint32_t now = micros();
|
||||
auto rate = this->max_refresh_rate_.value_or(0);
|
||||
if (rate != 0 && (now - this->last_refresh_) < rate) {
|
||||
// try again next loop iteration, so that this change won't get lost
|
||||
this->schedule_show();
|
||||
if (this->throttle_show_(now, this->last_refresh_, this->max_refresh_rate_))
|
||||
return;
|
||||
}
|
||||
this->last_refresh_ = now;
|
||||
this->mark_shown_();
|
||||
|
||||
@@ -217,17 +212,6 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||
}
|
||||
}
|
||||
|
||||
light::ESPColorView ESP32RMTLEDStripLightOutput::get_view_internal(int32_t index) const {
|
||||
const light::ChannelColors &colors = this->channel_colors_;
|
||||
uint8_t *led = this->buf_ + (index * colors.bytes_per_led());
|
||||
return {led + colors.r,
|
||||
led + colors.g,
|
||||
led + colors.b,
|
||||
colors.has_white() ? led + colors.w : nullptr,
|
||||
&this->effect_data_[index],
|
||||
&this->correction_};
|
||||
}
|
||||
|
||||
void ESP32RMTLEDStripLightOutput::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ESP32 RMT LED Strip:\n"
|
||||
@@ -239,7 +223,7 @@ void ESP32RMTLEDStripLightOutput::dump_config() {
|
||||
" Channel colors: %s\n"
|
||||
" Max refresh rate: %" PRIu32 "\n"
|
||||
" Number of LEDs: %u",
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_.value_or(0), this->num_leds_);
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_, this->num_leds_);
|
||||
}
|
||||
|
||||
float ESP32RMTLEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
@@ -29,15 +29,7 @@ class ESP32RMTLEDStripLightOutput final : public light::AddressableLight {
|
||||
float get_setup_priority() const override;
|
||||
|
||||
int32_t size() const override { return this->num_leds_; }
|
||||
light::LightTraits get_traits() override {
|
||||
auto traits = light::LightTraits();
|
||||
if (this->channel_colors_.has_white()) {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
|
||||
} else {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB});
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
light::LightTraits get_traits() override { return this->channel_colors_.traits(); }
|
||||
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_inverted(bool inverted) { this->invert_out_ = inverted; }
|
||||
@@ -55,14 +47,16 @@ class ESP32RMTLEDStripLightOutput final : public light::AddressableLight {
|
||||
void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; }
|
||||
|
||||
void clear_effect_data() override {
|
||||
for (int i = 0; i < this->size(); i++)
|
||||
this->effect_data_[i] = 0;
|
||||
if (this->effect_data_ != nullptr)
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
}
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override;
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return this->channel_colors_.view(this->buf_, this->effect_data_, index, &this->correction_);
|
||||
}
|
||||
|
||||
size_t get_buffer_size_() const { return this->num_leds_ * this->channel_colors_.bytes_per_led(); }
|
||||
|
||||
@@ -86,7 +80,7 @@ class ESP32RMTLEDStripLightOutput final : public light::AddressableLight {
|
||||
light::ChannelColors channel_colors_{0, 1, 2, light::ChannelColors::NO_WHITE};
|
||||
|
||||
uint32_t last_refresh_{0};
|
||||
optional<uint32_t> max_refresh_rate_{};
|
||||
uint32_t max_refresh_rate_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome::esp32_rmt_led_strip
|
||||
|
||||
@@ -149,17 +149,12 @@ bool I2SClocklessLedStrip::allocate_buffers_() {
|
||||
RAMAllocator<uint8_t> allocator(RAMAllocator<uint8_t>::ALLOC_INTERNAL);
|
||||
this->i2s_data_ = allocator.allocate(i2s_data_bytes);
|
||||
if (this->i2s_data_ != nullptr) {
|
||||
this->color_data_ = allocator.allocate(this->color_data_bytes_);
|
||||
// The effect data follows the color data
|
||||
this->color_data_ = allocator.allocate(this->color_data_bytes_ + this->num_leds_);
|
||||
if (this->color_data_ != nullptr) {
|
||||
this->effect_data_ = allocator.allocate(this->num_leds_);
|
||||
if (this->effect_data_ != nullptr) {
|
||||
memset(this->i2s_data_, 0, i2s_data_bytes);
|
||||
memset(this->color_data_, 0, this->color_data_bytes_);
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
return true;
|
||||
}
|
||||
allocator.deallocate(this->color_data_, this->color_data_bytes_);
|
||||
this->color_data_ = nullptr;
|
||||
memset(this->i2s_data_, 0, i2s_data_bytes);
|
||||
memset(this->color_data_, 0, this->color_data_bytes_ + this->num_leds_);
|
||||
return true;
|
||||
}
|
||||
allocator.deallocate(this->i2s_data_, i2s_data_bytes);
|
||||
this->i2s_data_ = nullptr;
|
||||
@@ -167,16 +162,6 @@ bool I2SClocklessLedStrip::allocate_buffers_() {
|
||||
return false;
|
||||
}
|
||||
|
||||
light::LightTraits I2SClocklessLedStrip::get_traits() {
|
||||
auto traits = light::LightTraits();
|
||||
if (this->channel_colors_.has_white()) {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
|
||||
} else {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB});
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
||||
void I2SClocklessLedStrip::write_state(light::LightState *state) {
|
||||
if (this->is_failed())
|
||||
return;
|
||||
@@ -236,19 +221,6 @@ bool IRAM_ATTR HOT I2SClocklessLedStrip::i2s_on_sent_callback(i2s_chan_handle_t
|
||||
return false;
|
||||
}
|
||||
|
||||
void I2SClocklessLedStrip::clear_effect_data() { memset(this->effect_data_, 0, this->num_leds_); }
|
||||
|
||||
light::ESPColorView I2SClocklessLedStrip::get_view_internal(int32_t index) const {
|
||||
const light::ChannelColors &colors = this->channel_colors_;
|
||||
uint8_t *led = this->color_data_ + (index * colors.bytes_per_led());
|
||||
return {led + colors.r,
|
||||
led + colors.g,
|
||||
led + colors.b,
|
||||
colors.has_white() ? led + colors.w : nullptr,
|
||||
&this->effect_data_[index],
|
||||
&this->correction_};
|
||||
}
|
||||
|
||||
} // namespace esphome::i2s_clockless_led_strip
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -27,20 +28,27 @@ class I2SClocklessLedStrip final : public light::AddressableLight {
|
||||
float get_setup_priority() const override;
|
||||
void setup() override;
|
||||
|
||||
light::LightTraits get_traits() override;
|
||||
light::LightTraits get_traits() override { return this->channel_colors_.traits(); }
|
||||
|
||||
int32_t size() const override { return this->num_leds_; }
|
||||
void clear_effect_data() override;
|
||||
void clear_effect_data() override {
|
||||
if (uint8_t *effect = this->effect_data_())
|
||||
memset(effect, 0, this->num_leds_);
|
||||
}
|
||||
void write_state(light::LightState *state) override;
|
||||
|
||||
protected:
|
||||
static bool i2s_on_sent_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx);
|
||||
|
||||
bool allocate_buffers_();
|
||||
light::ESPColorView get_view_internal(int32_t index) const override;
|
||||
uint8_t *effect_data_() const {
|
||||
return this->color_data_ == nullptr ? nullptr : this->color_data_ + this->color_data_bytes_;
|
||||
}
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return this->channel_colors_.view(this->color_data_, this->effect_data_(), index, &this->correction_);
|
||||
}
|
||||
|
||||
const size_t color_data_bytes_;
|
||||
uint8_t *effect_data_{nullptr};
|
||||
uint8_t *color_data_{nullptr};
|
||||
uint8_t *i2s_data_{nullptr};
|
||||
size_t i2s_data_sent_{0};
|
||||
|
||||
@@ -134,6 +134,13 @@ class AddressableLight : public LightOutput, public Component {
|
||||
#endif
|
||||
}
|
||||
virtual ESPColorView get_view_internal(int32_t index) const = 0;
|
||||
// Queues the frame for the next loop and returns true until interval_us has passed since last_us
|
||||
bool throttle_show_(uint32_t now_us, uint32_t last_us, uint32_t interval_us) {
|
||||
if (now_us - last_us >= interval_us)
|
||||
return false;
|
||||
this->schedule_show();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT_POWER_ESTIMATION
|
||||
friend class AddressableLightState;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "esp_color_view.h"
|
||||
#include "light_traits.h"
|
||||
|
||||
namespace esphome::light {
|
||||
|
||||
/// Which byte of an addressable LED's data carries each colour.
|
||||
@@ -36,6 +39,30 @@ struct ChannelColors {
|
||||
buf[this->bytes_per_led()] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// Colour modes of a strip with this channel order.
|
||||
LightTraits traits() const {
|
||||
LightTraits traits;
|
||||
if (this->has_white()) {
|
||||
traits.set_supported_color_modes({ColorMode::RGB_WHITE, ColorMode::WHITE});
|
||||
} else {
|
||||
traits.set_supported_color_modes({ColorMode::RGB});
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
||||
/// View of LED `index` in `buf`; a scratch pixel while `buf` or `effect_data` is unallocated (failed setup()).
|
||||
ESPColorView view(uint8_t *buf, uint8_t *effect_data, int32_t index, const ESPColorCorrection *correction) const {
|
||||
static uint8_t scratch[4];
|
||||
if (buf == nullptr || effect_data == nullptr) {
|
||||
buf = scratch;
|
||||
effect_data = nullptr;
|
||||
index = 0;
|
||||
}
|
||||
uint8_t *led = buf + index * this->bytes_per_led();
|
||||
return {led + this->r, led + this->g, led + this->b, this->has_white() ? led + this->w : nullptr,
|
||||
effect_data + index, correction};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace esphome::light
|
||||
@@ -141,32 +141,13 @@ void LN882xSPILEDStripLightOutput::dump_config() {
|
||||
|
||||
float LN882xSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
light::LightTraits LN882xSPILEDStripLightOutput::get_traits() {
|
||||
auto traits = light::LightTraits();
|
||||
if (this->channel_colors_.has_white()) {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
|
||||
} else {
|
||||
traits.set_supported_color_modes({light::ColorMode::RGB});
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
||||
void LN882xSPILEDStripLightOutput::clear_effect_data() {
|
||||
if (this->effect_data_ != nullptr)
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
}
|
||||
|
||||
void LN882xSPILEDStripLightOutput::write_state(light::LightState *state) {
|
||||
if (this->is_failed())
|
||||
return;
|
||||
|
||||
// protect from refreshing too often
|
||||
const uint32_t now = micros();
|
||||
if (this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < this->max_refresh_rate_) {
|
||||
// try again next loop iteration, so that this change won't get lost
|
||||
this->schedule_show();
|
||||
if (this->throttle_show_(now, this->last_refresh_, this->max_refresh_rate_))
|
||||
return;
|
||||
}
|
||||
|
||||
if (spi_dma_busy()) {
|
||||
// Busy sending the last frame, try again later.
|
||||
@@ -191,20 +172,6 @@ void LN882xSPILEDStripLightOutput::write_state(light::LightState *state) {
|
||||
spi_dma_transmit(this->dma_data_, this->dma_data_bytes_);
|
||||
}
|
||||
|
||||
light::ESPColorView LN882xSPILEDStripLightOutput::get_view_internal(int32_t index) const {
|
||||
const light::ChannelColors &colors = this->channel_colors_;
|
||||
// After a failed setup() effects and partitions still write pixels, so they get a scratch pixel.
|
||||
static uint8_t scratch[5];
|
||||
const bool ready = this->color_data_ != nullptr;
|
||||
uint8_t *led = ready ? this->color_data_ + (index * colors.bytes_per_led()) : scratch;
|
||||
return {led + colors.r,
|
||||
led + colors.g,
|
||||
led + colors.b,
|
||||
colors.has_white() ? led + colors.w : nullptr,
|
||||
ready ? &this->effect_data_[index] : scratch + 4,
|
||||
&this->correction_};
|
||||
}
|
||||
|
||||
} // namespace esphome::ln882x_spi_led_strip
|
||||
|
||||
#endif // USE_LN882X
|
||||
@@ -23,16 +23,21 @@ class LN882xSPILEDStripLightOutput final : public light::AddressableLight {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
light::LightTraits get_traits() override;
|
||||
light::LightTraits get_traits() override { return this->channel_colors_.traits(); }
|
||||
int32_t size() const override { return this->num_leds_; }
|
||||
void clear_effect_data() override;
|
||||
void clear_effect_data() override {
|
||||
if (this->effect_data_ != nullptr)
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
}
|
||||
void write_state(light::LightState *state) override;
|
||||
|
||||
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
||||
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override;
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return this->channel_colors_.view(this->color_data_, this->effect_data_, index, &this->correction_);
|
||||
}
|
||||
|
||||
const size_t color_data_bytes_;
|
||||
const size_t dma_data_bytes_;
|
||||
|
||||
@@ -141,17 +141,6 @@ void RP2040PIOLEDStripLightOutput::write_state(light::LightState *state) {
|
||||
dma_channel_transfer_from_buffer_now(this->dma_chan_, this->buf_, this->get_buffer_size_());
|
||||
}
|
||||
|
||||
light::ESPColorView RP2040PIOLEDStripLightOutput::get_view_internal(int32_t index) const {
|
||||
const light::ChannelColors &colors = this->channel_colors_;
|
||||
uint8_t *led = this->buf_ + (index * colors.bytes_per_led());
|
||||
return {led + colors.r,
|
||||
led + colors.g,
|
||||
led + colors.b,
|
||||
colors.has_white() ? led + colors.w : nullptr,
|
||||
&this->effect_data_[index],
|
||||
&this->correction_};
|
||||
}
|
||||
|
||||
void RP2040PIOLEDStripLightOutput::dump_config() {
|
||||
char channel_colors[5];
|
||||
ESP_LOGCONFIG(TAG,
|
||||
|
||||
@@ -37,13 +37,7 @@ class RP2040PIOLEDStripLightOutput final : public light::AddressableLight {
|
||||
float get_setup_priority() const override;
|
||||
|
||||
int32_t size() const override { return this->num_leds_; }
|
||||
light::LightTraits get_traits() override {
|
||||
auto traits = light::LightTraits();
|
||||
this->channel_colors_.has_white()
|
||||
? traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE})
|
||||
: traits.set_supported_color_modes({light::ColorMode::RGB});
|
||||
return traits;
|
||||
}
|
||||
light::LightTraits get_traits() override { return this->channel_colors_.traits(); }
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_num_leds(uint32_t num_leds) { this->num_leds_ = num_leds; }
|
||||
void set_channel_colors(light::ChannelColors channel_colors) { this->channel_colors_ = channel_colors; }
|
||||
@@ -56,15 +50,16 @@ class RP2040PIOLEDStripLightOutput final : public light::AddressableLight {
|
||||
|
||||
void set_chipset(Chipset chipset) { this->chipset_ = chipset; };
|
||||
void clear_effect_data() override {
|
||||
for (int i = 0; i < this->size(); i++) {
|
||||
this->effect_data_[i] = 0;
|
||||
}
|
||||
if (this->effect_data_ != nullptr)
|
||||
memset(this->effect_data_, 0, this->num_leds_);
|
||||
}
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override;
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return this->channel_colors_.view(this->buf_, this->effect_data_, index, &this->correction_);
|
||||
}
|
||||
|
||||
size_t get_buffer_size_() const { return this->num_leds_ * this->channel_colors_.bytes_per_led(); }
|
||||
|
||||
@@ -84,7 +79,6 @@ class RP2040PIOLEDStripLightOutput final : public light::AddressableLight {
|
||||
light::ChannelColors channel_colors_{0, 1, 2, light::ChannelColors::NO_WHITE};
|
||||
Chipset chipset_{CHIPSET_CUSTOM};
|
||||
|
||||
uint32_t last_refresh_{0};
|
||||
float max_refresh_rate_;
|
||||
|
||||
const pio_program_t *program_;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include "esphome/components/light/addressable_light.h"
|
||||
#include "esphome/components/light/channel_colors.h"
|
||||
#include "esphome/components/light/light_state.h"
|
||||
|
||||
namespace esphome::light::testing {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr ChannelColors GRB{1, 0, 2, ChannelColors::NO_WHITE};
|
||||
constexpr ChannelColors GRBW{1, 0, 2, 3};
|
||||
|
||||
// Exposes the protected strip helpers
|
||||
class HelperStrip : public AddressableLight {
|
||||
public:
|
||||
int32_t size() const override { return 1; }
|
||||
void clear_effect_data() override {}
|
||||
LightTraits get_traits() override { return {}; }
|
||||
void write_state(LightState *state) override {}
|
||||
using AddressableLight::throttle_show_;
|
||||
|
||||
protected:
|
||||
ESPColorView get_view_internal(int32_t index) const override {
|
||||
return GRB.view(nullptr, nullptr, index, &this->correction_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LedStripHelpers, TraitsFollowTheWhiteChannel) {
|
||||
const auto rgb = GRB.traits().get_supported_color_modes();
|
||||
EXPECT_TRUE(rgb.count(ColorMode::RGB));
|
||||
EXPECT_EQ(rgb.size(), 1u);
|
||||
const auto rgbw = GRBW.traits().get_supported_color_modes();
|
||||
EXPECT_TRUE(rgbw.count(ColorMode::RGB_WHITE));
|
||||
EXPECT_TRUE(rgbw.count(ColorMode::WHITE));
|
||||
EXPECT_EQ(rgbw.size(), 2u);
|
||||
}
|
||||
|
||||
TEST(LedStripHelpers, ViewWritesTheChannelOrder) {
|
||||
ESPColorCorrection correction;
|
||||
std::array<uint8_t, 8> buf{};
|
||||
std::array<uint8_t, 2> effect{};
|
||||
GRBW.view(buf.data(), effect.data(), 1, &correction) = Color(10, 20, 30, 40);
|
||||
GRBW.view(buf.data(), effect.data(), 1, &correction).set_effect_data(7);
|
||||
EXPECT_EQ(buf, (std::array<uint8_t, 8>{0, 0, 0, 0, 20, 10, 30, 40}));
|
||||
EXPECT_EQ(effect[1], 7);
|
||||
|
||||
std::array<uint8_t, 6> rgb_buf{};
|
||||
auto view = GRB.view(rgb_buf.data(), effect.data(), 1, &correction);
|
||||
view = Color(10, 20, 30, 40);
|
||||
EXPECT_EQ(rgb_buf, (std::array<uint8_t, 6>{0, 0, 0, 20, 10, 30}));
|
||||
EXPECT_EQ(view.get_white_raw(), 0);
|
||||
}
|
||||
|
||||
TEST(LedStripHelpers, ViewFallsBackToScratchBeforeSetup) {
|
||||
ESPColorCorrection correction;
|
||||
std::array<uint8_t, 4> buf{};
|
||||
// Any index is safe without a buffer, as is a buffer without effect data
|
||||
GRBW.view(nullptr, nullptr, 1000, &correction) = Color(1, 2, 3, 4);
|
||||
auto scratch = GRBW.view(nullptr, nullptr, 1000, &correction);
|
||||
scratch.set_effect_data(5);
|
||||
EXPECT_EQ(scratch.get_effect_data(), 0);
|
||||
GRBW.view(buf.data(), nullptr, 0, &correction) = Color(1, 2, 3, 4);
|
||||
EXPECT_EQ(buf, (std::array<uint8_t, 4>{}));
|
||||
// Effect data without a buffer is left alone too
|
||||
std::array<uint8_t, 4> effect{};
|
||||
GRBW.view(nullptr, effect.data(), 3, &correction).set_effect_data(5);
|
||||
EXPECT_EQ(effect, (std::array<uint8_t, 4>{}));
|
||||
}
|
||||
|
||||
TEST(LedStripHelpers, ThrottleShowHoldsTheFrame) {
|
||||
HelperStrip strip;
|
||||
LightState state(&strip);
|
||||
strip.setup_state(&state);
|
||||
EXPECT_FALSE(strip.throttle_show_(1000, 0, 0));
|
||||
EXPECT_TRUE(strip.throttle_show_(1000, 500, 600));
|
||||
EXPECT_FALSE(strip.throttle_show_(1100, 500, 600));
|
||||
// micros() wraps
|
||||
EXPECT_TRUE(strip.throttle_show_(100, UINT32_MAX - 99, 300));
|
||||
EXPECT_FALSE(strip.throttle_show_(200, UINT32_MAX - 99, 300));
|
||||
}
|
||||
|
||||
} // namespace esphome::light::testing
|
||||
Reference in new issue
Block a user