Optimize DLMS parser buffers and RX timing
Replace heavy std::string/iostream usage in the DLMS parser with stack-allocated char buffers and snprintf to avoid heap allocations and reduce runtime overhead. Introduce buffer-based helpers (data_to_string_, obis_to_string_) and switch hex formatting to format_hex_pretty_to; remove <sstream>/<iomanip> and include <cstdio>. Update header signatures accordingly. Also change DlmsPushComponent to use App.get_loop_component_start_time() instead of millis() when tracking last_rx_char_time_ for RX timeout handling. Files changed: components/dlms_push/dlms_parser.cpp/.h (buffer-based string helpers, logging, include changes), components/dlms_push/dlms_push.cpp (use App loop time for timeout). Note: The string helper APIs were converted to buffer-oriented versions — update any callers to provide an output buffer.main
parent
81bbd19c09
commit
8fc10fb496
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <cstdio>
|
||||||
#include <iomanip>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
@ -400,10 +399,18 @@ bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &p
|
||||||
void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c) {
|
void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c) {
|
||||||
if (!c.obis || !this->callback_) return;
|
if (!c.obis || !this->callback_) return;
|
||||||
|
|
||||||
std::string obis_str = this->obis_to_string_(c.obis);
|
// Use stack-allocated buffer for OBIS to avoid string allocation
|
||||||
|
char obis_str_buf[32];
|
||||||
|
this->obis_to_string_(c.obis, obis_str_buf, sizeof(obis_str_buf));
|
||||||
|
std::string obis_str(obis_str_buf);
|
||||||
|
|
||||||
float raw_val_f = this->data_as_float_(c.value_type, c.value_ptr, c.value_len);
|
float raw_val_f = this->data_as_float_(c.value_type, c.value_ptr, c.value_len);
|
||||||
float val_f = raw_val_f;
|
float val_f = raw_val_f;
|
||||||
std::string val_s = this->data_as_string_(c.value_type, c.value_ptr, c.value_len);
|
|
||||||
|
// Use stack-allocated buffer for formatting data
|
||||||
|
char val_s_buf[128];
|
||||||
|
this->data_to_string_(c.value_type, c.value_ptr, c.value_len, val_s_buf, sizeof(val_s_buf));
|
||||||
|
std::string val_s(val_s_buf);
|
||||||
|
|
||||||
bool is_numeric = (c.value_type != DLMS_DATA_TYPE_OCTET_STRING &&
|
bool is_numeric = (c.value_type != DLMS_DATA_TYPE_OCTET_STRING &&
|
||||||
c.value_type != DLMS_DATA_TYPE_STRING &&
|
c.value_type != DLMS_DATA_TYPE_STRING &&
|
||||||
|
|
@ -427,7 +434,9 @@ void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptur
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.value_ptr && c.value_len > 0) {
|
if (c.value_ptr && c.value_len > 0) {
|
||||||
ESP_LOGI(TAG, " as hex dump : %s", esphome::format_hex_pretty(c.value_ptr, c.value_len).c_str());
|
char hex_buf[512];
|
||||||
|
esphome::format_hex_pretty_to(hex_buf, sizeof(hex_buf), c.value_ptr, c.value_len);
|
||||||
|
ESP_LOGI(TAG, " as hex dump : %s", hex_buf);
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, " as string :'%s'", val_s.c_str());
|
ESP_LOGI(TAG, " as string :'%s'", val_s.c_str());
|
||||||
ESP_LOGI(TAG, " as number : %f", raw_val_f);
|
ESP_LOGI(TAG, " as number : %f", raw_val_f);
|
||||||
|
|
@ -481,16 +490,17 @@ float DlmsParser::data_as_float_(DlmsDataType value_type, const uint8_t *ptr, ui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DlmsParser::data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len) {
|
void DlmsParser::data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len, char *buffer, size_t max_len) {
|
||||||
if (!ptr || len == 0) return "";
|
if (max_len > 0) buffer[0] = '\0';
|
||||||
|
if (!ptr || len == 0 || max_len == 0) return;
|
||||||
|
|
||||||
auto hex_of = [](const uint8_t *p, uint8_t l) {
|
auto hex_of = [](const uint8_t *p, uint8_t l, char *out, size_t max_out) {
|
||||||
std::ostringstream ss;
|
if (max_out == 0) return;
|
||||||
ss << std::hex << std::setfill('0');
|
out[0] = '\0';
|
||||||
for (uint8_t i = 0; i < l; i++) {
|
size_t pos = 0;
|
||||||
ss << std::setw(2) << static_cast<int>(p[i]);
|
for (uint8_t i = 0; i < l && pos + 2 < max_out; i++) {
|
||||||
|
pos += snprintf(out + pos, max_out - pos, "%02x", p[i]);
|
||||||
}
|
}
|
||||||
return ss.str();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); };
|
auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); };
|
||||||
|
|
@ -504,58 +514,70 @@ std::string DlmsParser::data_as_string_(DlmsDataType value_type, const uint8_t *
|
||||||
switch (value_type) {
|
switch (value_type) {
|
||||||
case DLMS_DATA_TYPE_OCTET_STRING:
|
case DLMS_DATA_TYPE_OCTET_STRING:
|
||||||
case DLMS_DATA_TYPE_STRING:
|
case DLMS_DATA_TYPE_STRING:
|
||||||
case DLMS_DATA_TYPE_STRING_UTF8:
|
case DLMS_DATA_TYPE_STRING_UTF8: {
|
||||||
return std::string(reinterpret_cast<const char *>(ptr), len);
|
size_t copy_len = std::min((size_t)len, max_len - 1);
|
||||||
|
std::memcpy(buffer, ptr, copy_len);
|
||||||
|
buffer[copy_len] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_BIT_STRING:
|
case DLMS_DATA_TYPE_BIT_STRING:
|
||||||
case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL:
|
case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL:
|
||||||
case DLMS_DATA_TYPE_DATETIME:
|
case DLMS_DATA_TYPE_DATETIME:
|
||||||
case DLMS_DATA_TYPE_DATE:
|
case DLMS_DATA_TYPE_DATE:
|
||||||
case DLMS_DATA_TYPE_TIME:
|
case DLMS_DATA_TYPE_TIME:
|
||||||
return hex_of(ptr, len);
|
hex_of(ptr, len, buffer, max_len);
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_BOOLEAN:
|
case DLMS_DATA_TYPE_BOOLEAN:
|
||||||
case DLMS_DATA_TYPE_ENUM:
|
case DLMS_DATA_TYPE_ENUM:
|
||||||
case DLMS_DATA_TYPE_UINT8:
|
case DLMS_DATA_TYPE_UINT8:
|
||||||
return std::to_string(static_cast<unsigned>(ptr[0]));
|
snprintf(buffer, max_len, "%u", static_cast<unsigned>(ptr[0]));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT8:
|
case DLMS_DATA_TYPE_INT8:
|
||||||
return std::to_string(static_cast<int>(static_cast<int8_t>(ptr[0])));
|
snprintf(buffer, max_len, "%d", static_cast<int>(static_cast<int8_t>(ptr[0])));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT16:
|
case DLMS_DATA_TYPE_UINT16:
|
||||||
return len >= 2 ? std::to_string(be16(ptr)) : "";
|
if (len >= 2) snprintf(buffer, max_len, "%u", be16(ptr));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT16:
|
case DLMS_DATA_TYPE_INT16:
|
||||||
return len >= 2 ? std::to_string(static_cast<int16_t>(be16(ptr))) : "";
|
if (len >= 2) snprintf(buffer, max_len, "%d", static_cast<int16_t>(be16(ptr)));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT32:
|
case DLMS_DATA_TYPE_UINT32:
|
||||||
return len >= 4 ? std::to_string(be32(ptr)) : "";
|
if (len >= 4) snprintf(buffer, max_len, "%lu", (unsigned long)be32(ptr));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT32:
|
case DLMS_DATA_TYPE_INT32:
|
||||||
return len >= 4 ? std::to_string(static_cast<int32_t>(be32(ptr))) : "";
|
if (len >= 4) snprintf(buffer, max_len, "%ld", (long)static_cast<int32_t>(be32(ptr)));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT64:
|
case DLMS_DATA_TYPE_UINT64:
|
||||||
return len >= 8 ? std::to_string(be64(ptr)) : "";
|
if (len >= 8) snprintf(buffer, max_len, "%llu", (unsigned long long)be64(ptr));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT64:
|
case DLMS_DATA_TYPE_INT64:
|
||||||
return len >= 8 ? std::to_string(static_cast<int64_t>(be64(ptr))) : "";
|
if (len >= 8) snprintf(buffer, max_len, "%lld", (long long)static_cast<int64_t>(be64(ptr)));
|
||||||
|
break;
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_FLOAT32:
|
case DLMS_DATA_TYPE_FLOAT32:
|
||||||
case DLMS_DATA_TYPE_FLOAT64: {
|
case DLMS_DATA_TYPE_FLOAT64: {
|
||||||
std::ostringstream ss;
|
snprintf(buffer, max_len, "%f", this->data_as_float_(value_type, ptr, len));
|
||||||
ss << this->data_as_float_(value_type, ptr, len);
|
break;
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "";
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DlmsParser::obis_to_string_(const uint8_t *obis) {
|
void DlmsParser::obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len) {
|
||||||
char buf[32];
|
if (max_len > 0) buffer[0] = '\0';
|
||||||
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]);
|
if (!obis || max_len == 0) return;
|
||||||
return std::string(buf);
|
snprintf(buffer, max_len, "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) {
|
const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) {
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,8 @@ class DlmsParser {
|
||||||
void emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c);
|
void emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c);
|
||||||
|
|
||||||
float data_as_float_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len);
|
float data_as_float_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len);
|
||||||
std::string data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len);
|
std::string data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len, char *buffer, size_t max_len);
|
||||||
std::string obis_to_string_(const uint8_t *obis);
|
std::string obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len);
|
||||||
const char *dlms_data_type_to_string_(DlmsDataType vt);
|
const char *dlms_data_type_to_string_(DlmsDataType vt);
|
||||||
|
|
||||||
const uint8_t *buffer_{nullptr};
|
const uint8_t *buffer_{nullptr};
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ void DlmsPushComponent::dump_config() {
|
||||||
void DlmsPushComponent::loop() {
|
void DlmsPushComponent::loop() {
|
||||||
this->read_rx_buffer_();
|
this->read_rx_buffer_();
|
||||||
|
|
||||||
if (this->receiving_ && (millis() - this->last_rx_char_time_ > this->receive_timeout_ms_)) {
|
if (this->receiving_ && (App.get_loop_component_start_time() - this->last_rx_char_time_ > this->receive_timeout_ms_)) {
|
||||||
this->receiving_ = false;
|
this->receiving_ = false;
|
||||||
this->process_frame_();
|
this->process_frame_();
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +68,7 @@ void DlmsPushComponent::read_rx_buffer_() {
|
||||||
if (available == 0) return;
|
if (available == 0) return;
|
||||||
|
|
||||||
this->receiving_ = true;
|
this->receiving_ = true;
|
||||||
this->last_rx_char_time_ = millis();
|
this->last_rx_char_time_ = App.get_loop_component_start_time();
|
||||||
|
|
||||||
while (this->available()) {
|
while (this->available()) {
|
||||||
if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) {
|
if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue