[light] Keep one copy of the color mode lookup table in flash (#20394)

This commit is contained in:
J. Nick Koston
2026-10-12 15:46:41 -10:00
committed by GitHub
parent fb14db267c
commit 5a39097b3a
+13 -7
View File
@@ -2,6 +2,7 @@
#include <cstdint>
#include "esphome/core/finite_set_mask.h"
#include "esphome/core/hal.h"
namespace esphome::light {
@@ -108,8 +109,9 @@ constexpr ColorModeHelper operator|(ColorModeHelper lhs, ColorMode rhs) {
using color_mode_bitmask_t = uint16_t;
// Lookup table for ColorMode bit mapping
// This array defines the canonical order of color modes (bit 0-9)
constexpr ColorMode COLOR_MODE_LOOKUP[] = {
// This array defines the canonical order of color modes (bit 0-9). One shared copy in flash; read it at run time
// through color_mode_at().
inline constexpr ColorMode COLOR_MODE_LOOKUP[] PROGMEM = {
ColorMode::UNKNOWN, // bit 0
ColorMode::ON_OFF, // bit 1
ColorMode::BRIGHTNESS, // bit 2
@@ -122,6 +124,12 @@ constexpr ColorMode COLOR_MODE_LOOKUP[] = {
ColorMode::RGB_COLD_WARM_WHITE, // bit 9
};
constexpr ColorMode color_mode_at(unsigned bit) {
if (__builtin_is_constant_evaluated())
return COLOR_MODE_LOOKUP[bit];
return static_cast<ColorMode>(progmem_read_byte(reinterpret_cast<const uint8_t *>(&COLOR_MODE_LOOKUP[bit])));
}
/// Bit mapping policy for ColorMode
/// Uses lookup table for non-contiguous enum values
struct ColorModeBitPolicy {
@@ -129,17 +137,15 @@ struct ColorModeBitPolicy {
static constexpr int MAX_BITS = sizeof(COLOR_MODE_LOOKUP) / sizeof(COLOR_MODE_LOOKUP[0]);
static constexpr unsigned to_bit(ColorMode mode) {
// Linear search through lookup table
// Compiler optimizes this to efficient code since array is constexpr
for (int i = 0; i < MAX_BITS; ++i) {
if (COLOR_MODE_LOOKUP[i] == mode)
if (color_mode_at(i) == mode)
return i;
}
return 0;
}
static constexpr ColorMode from_bit(unsigned bit) {
return (bit < MAX_BITS) ? COLOR_MODE_LOOKUP[bit] : ColorMode::UNKNOWN;
return (bit < MAX_BITS) ? color_mode_at(bit) : ColorMode::UNKNOWN;
}
};
@@ -157,7 +163,7 @@ constexpr uint16_t compute_capability_bitmask(ColorCapability capability) {
// Check each ColorMode to see if it has this capability
constexpr int color_mode_count = sizeof(COLOR_MODE_LOOKUP) / sizeof(COLOR_MODE_LOOKUP[0]);
for (int bit = 0; bit < color_mode_count; ++bit) {
uint8_t mode_val = static_cast<uint8_t>(COLOR_MODE_LOOKUP[bit]);
uint8_t mode_val = static_cast<uint8_t>(color_mode_at(bit));
if ((mode_val & cap_bit) != 0) {
mask |= (1 << bit);
}