1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00

Merge branch 'progmem_string_table' into integration

This commit is contained in:
J. Nick Koston
2026-01-30 22:45:36 -06:00
9 changed files with 25 additions and 46 deletions

View File

@@ -26,10 +26,7 @@ const LogString *cover_command_to_str(float pos) {
PROGMEM_STRING_TABLE(CoverOperationStrings, "IDLE", "OPENING", "CLOSING", "UNKNOWN");
const LogString *cover_operation_to_str(CoverOperation op) {
uint8_t index = static_cast<uint8_t>(op);
if (index > COVER_OPERATION_LAST)
index = COVER_OPERATION_UNKNOWN_INDEX;
return CoverOperationStrings::get_log_str(index);
return CoverOperationStrings::get_log_str(static_cast<uint8_t>(op), CoverOperationStrings::LAST_INDEX);
}
Cover::Cover() : position{COVER_OPEN} {}

View File

@@ -84,8 +84,6 @@ enum CoverOperation : uint8_t {
/// The cover is currently closing.
COVER_OPERATION_CLOSING,
};
constexpr uint8_t COVER_OPERATION_LAST = static_cast<uint8_t>(COVER_OPERATION_CLOSING);
constexpr uint8_t COVER_OPERATION_UNKNOWN_INDEX = COVER_OPERATION_LAST + 1;
const LogString *cover_operation_to_str(CoverOperation op);

View File

@@ -20,7 +20,8 @@ static ProgmemStr get_color_mode_json_str(ColorMode mode) {
unsigned bit = ColorModeBitPolicy::to_bit(mode);
if (bit == 0)
return nullptr;
return ColorModeStrings::get_progmem_str(bit - 1);
// bit is 1-9 for valid modes, so bit-1 is always valid (0-8). LAST_INDEX fallback never used.
return ColorModeStrings::get_progmem_str(bit - 1, ColorModeStrings::LAST_INDEX);
}
void LightJSONSchema::dump_json(LightState &state, JsonObject root) {

View File

@@ -294,12 +294,9 @@ float Logger::get_setup_priority() const { return setup_priority::BUS + 500.0f;
// Log level strings - packed into flash on ESP8266, indexed by log level (0-7)
PROGMEM_STRING_TABLE(LogLevelStrings, "NONE", "ERROR", "WARN", "INFO", "CONFIG", "DEBUG", "VERBOSE", "VERY_VERBOSE");
constexpr uint8_t LOG_LEVEL_LAST = ESPHOME_LOG_LEVEL_VERY_VERBOSE;
static const LogString *get_log_level_str(uint8_t level) {
if (level > LOG_LEVEL_LAST)
level = LOG_LEVEL_LAST;
return LogLevelStrings::get_log_str(level);
return LogLevelStrings::get_log_str(level, LogLevelStrings::LAST_INDEX);
}
void Logger::dump_config() {

View File

@@ -35,10 +35,8 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o
PROGMEM_STRING_TABLE(StateClassStrings, "", "measurement", "total_increasing", "total", "measurement_angle");
const LogString *state_class_to_string(StateClass state_class) {
uint8_t index = static_cast<uint8_t>(state_class);
if (index > STATE_CLASS_LAST)
index = 0; // Default to empty string (STATE_CLASS_NONE)
return StateClassStrings::get_log_str(index);
// Fallback to index 0 (empty string for STATE_CLASS_NONE) if out of range
return StateClassStrings::get_log_str(static_cast<uint8_t>(state_class), 0);
}
Sensor::Sensor() : state(NAN), raw_state(NAN) {}

View File

@@ -27,10 +27,7 @@ const LogString *valve_command_to_str(float pos) {
PROGMEM_STRING_TABLE(ValveOperationStrings, "IDLE", "OPENING", "CLOSING", "UNKNOWN");
const LogString *valve_operation_to_str(ValveOperation op) {
uint8_t index = static_cast<uint8_t>(op);
if (index > VALVE_OPERATION_LAST)
index = VALVE_OPERATION_UNKNOWN_INDEX;
return ValveOperationStrings::get_log_str(index);
return ValveOperationStrings::get_log_str(static_cast<uint8_t>(op), ValveOperationStrings::LAST_INDEX);
}
Valve::Valve() : position{VALVE_OPEN} {}

View File

@@ -79,8 +79,6 @@ enum ValveOperation : uint8_t {
/// The valve is currently closing.
VALVE_OPERATION_CLOSING,
};
constexpr uint8_t VALVE_OPERATION_LAST = static_cast<uint8_t>(VALVE_OPERATION_CLOSING);
constexpr uint8_t VALVE_OPERATION_UNKNOWN_INDEX = VALVE_OPERATION_LAST + 1;
const LogString *valve_operation_to_str(ValveOperation op);

View File

@@ -399,32 +399,22 @@ class WiFiMockClass : public ESP8266WiFiGenericClass {
static void _event_callback(void *event) { ESP8266WiFiGenericClass::_eventCallback(event); } // NOLINT
};
// Auth mode strings indexed by AUTH_* constants (0-4), with UNKNOWN at index 5
// Auth mode strings indexed by AUTH_* constants (0-4), with UNKNOWN at last index
// Static asserts verify the SDK constants are contiguous as expected
static_assert(AUTH_OPEN == 0 && AUTH_WEP == 1 && AUTH_WPA_PSK == 2 && AUTH_WPA2_PSK == 3 && AUTH_WPA_WPA2_PSK == 4,
"AUTH_* constants are not contiguous");
constexpr uint8_t AUTH_MODE_LAST = AUTH_WPA_WPA2_PSK;
constexpr uint8_t AUTH_MODE_UNKNOWN_INDEX = AUTH_MODE_LAST + 1;
PROGMEM_STRING_TABLE(AuthModeStrings, "OPEN", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2 PSK", "UNKNOWN");
const LogString *get_auth_mode_str(uint8_t mode) {
if (mode > AUTH_MODE_LAST)
mode = AUTH_MODE_UNKNOWN_INDEX;
return AuthModeStrings::get_log_str(mode);
return AuthModeStrings::get_log_str(mode, AuthModeStrings::LAST_INDEX);
}
// WiFi op mode strings indexed by WIFI_* constants (0-3), with UNKNOWN at index 4
// WiFi op mode strings indexed by WIFI_* constants (0-3), with UNKNOWN at last index
static_assert(WIFI_OFF == 0 && WIFI_STA == 1 && WIFI_AP == 2 && WIFI_AP_STA == 3,
"WIFI_* op mode constants are not contiguous");
constexpr uint8_t OP_MODE_LAST = WIFI_AP_STA;
constexpr uint8_t OP_MODE_UNKNOWN_INDEX = OP_MODE_LAST + 1;
PROGMEM_STRING_TABLE(OpModeStrings, "OFF", "STA", "AP", "AP+STA", "UNKNOWN");
const LogString *get_op_mode_str(uint8_t mode) {
if (mode > OP_MODE_LAST)
mode = OP_MODE_UNKNOWN_INDEX;
return OpModeStrings::get_log_str(mode);
}
const LogString *get_op_mode_str(uint8_t mode) { return OpModeStrings::get_log_str(mode, OpModeStrings::LAST_INDEX); }
const LogString *get_disconnect_reason_str(uint8_t reason) {
/* If this were one big switch statement, GCC would generate a lookup table for it. However, the values of the

View File

@@ -56,12 +56,12 @@ template<size_t N> struct FixedString {
///
/// Example:
/// PROGMEM_STRING_TABLE(MyStrings, "foo", "bar", "baz");
/// ProgmemStr str = MyStrings::get_progmem_str(index); // For ArduinoJson
/// const LogString *log_str = MyStrings::get_log_str(index); // For logging
/// ProgmemStr str = MyStrings::get_progmem_str(index, MyStrings::LAST_INDEX); // For ArduinoJson
/// const LogString *log_str = MyStrings::get_log_str(index, MyStrings::LAST_INDEX); // For logging
///
template<FixedString... Strs> struct ProgmemStringTable {
static constexpr size_t COUNT = sizeof...(Strs);
static constexpr size_t BLOB_SIZE = (... + (Strs.size() + 1));
static constexpr size_t BLOB_SIZE = (0 + ... + (Strs.size() + 1));
/// Generate packed string blob at compile time
static constexpr auto make_blob() {
@@ -91,23 +91,26 @@ template<FixedString... Strs> struct ProgmemStringTable {
struct LogString;
/// Instantiate a ProgmemStringTable with PROGMEM storage.
/// Creates: Name::get_progmem_str(index), Name::get_log_str(index)
/// Creates: Name::get_progmem_str(index, fallback), Name::get_log_str(index, fallback)
/// If index >= COUNT, returns string at fallback_index. Use LAST_INDEX for common patterns.
#define PROGMEM_STRING_TABLE(Name, ...) \
struct Name { \
using Table = ::esphome::ProgmemStringTable<__VA_ARGS__>; \
static constexpr size_t COUNT = Table::COUNT; \
static constexpr uint8_t LAST_INDEX = COUNT - 1; \
static constexpr size_t BLOB_SIZE = Table::BLOB_SIZE; \
static constexpr auto BLOB PROGMEM = Table::make_blob(); \
static constexpr auto OFFSETS PROGMEM = Table::make_offsets(); \
static ::ProgmemStr get_progmem_str(uint8_t index) { \
static const char *get_(uint8_t index, uint8_t fallback_index) { \
if (index >= COUNT) \
return nullptr; \
return reinterpret_cast<::ProgmemStr>(&BLOB[::esphome::progmem_read_byte(&OFFSETS[index])]); \
index = fallback_index; \
return &BLOB[::esphome::progmem_read_byte(&OFFSETS[index])]; \
} \
static const ::esphome::LogString *get_log_str(uint8_t index) { \
if (index >= COUNT) \
return nullptr; \
return reinterpret_cast<const ::esphome::LogString *>(&BLOB[::esphome::progmem_read_byte(&OFFSETS[index])]); \
static ::ProgmemStr get_progmem_str(uint8_t index, uint8_t fallback_index) { \
return reinterpret_cast<::ProgmemStr>(get_(index, fallback_index)); \
} \
static const ::esphome::LogString *get_log_str(uint8_t index, uint8_t fallback_index) { \
return reinterpret_cast<const ::esphome::LogString *>(get_(index, fallback_index)); \
} \
}