Modify the message decoder to avoid std::string

This commit is contained in:
Jos van Eijndhoven
2026-06-02 22:30:18 +02:00
parent 4f2bfd616a
commit 4ef7e94a9f
4 changed files with 52 additions and 27 deletions
+10 -7
View File
@@ -153,7 +153,7 @@ template<uint32_t OPERANDS> bool Decoder::do_operand_() {
}
}
#define APPEND_LINE(...) (length_ = buf_append_printf(line_.data(), line_.size(), length_, __VA_ARGS__))
#define APPEND_LINE(...) (length_ = buf_append_printf(line_, size_, length_, __VA_ARGS__))
/**
* List of specialised operand decode functions, one function per operand type.
@@ -441,16 +441,19 @@ const char *Decoder::find_opcode_name_(uint32_t opcode) const {
bool Decoder::append_operand_(const char *word, uint8_t offset_incr /* default 1 */) {
APPEND_LINE("[%s]", word);
offset_ += offset_incr;
return (length_ < line_.size()) && (offset_ < frame_.size());
return (length_ < size_) && (offset_ < frame_.size());
}
/**
* Entry function 'decode' to call for full decode of a CEC frame
*/
const char *Decoder::decode() {
// prepare text buffer as empty
length_ = 0; // currently accumulated length of text of operands
line_[length_] = 0; // initialise operand text to empty string
int Decoder::decode() {
// prepare text buffer state variables for an empty line
length_ = 0; // currently accumulated length of text of operands
line_[length_] = '\0'; // initialise output text to empty string
if (!line_ || !size_)
return 0;
// print src and dest fields into 'line_'
address_decode_();
@@ -473,7 +476,7 @@ const char *Decoder::decode() {
OperandDecode_f f = frametype->decode_f_;
(this->*f)(); // call one of the above 'do_operand_<xx>' methods
}
return line_.data();
return length_;
}
} // namespace hdmi_cec
+13 -5
View File
@@ -53,8 +53,15 @@ template<typename KeyT, typename ValueT, unsigned int SIZE> class LookupTable {
*/
class Decoder {
public:
Decoder(const Frame &frame) : frame_(frame), length_(0), offset_(2) {}
const char *decode();
Decoder(const Frame &frame, char *line, unsigned int size)
: frame_(frame), line_(line), size_(size), length_(0), offset_(2) {}
/**
* Create a one-line textual representation of the Frame content for logging and debugging
* Store the text in the earlier provided 'line' buffer
* @return the length of the written text, excluding the terminating null character
*/
int decode();
protected:
const char *find_opcode_name_(uint32_t opcode) const;
@@ -80,9 +87,10 @@ class Decoder {
using VendorIdTable = LookupTable<uint32_t, const char *, 28>;
const Frame &frame_;
std::array<char, 256> line_; // to hold the text of the decoded frame
unsigned int length_; // currently accumulated length of output text in 'line'
unsigned int offset_; // current offset in frame to process next operand byte(s) (frame[0] and [1] are skipped)
char *const line_; // buffer to hold the text of the decoded frame
const unsigned int size_; // size of the 'line_' buffer
unsigned int length_; // currently accumulated length of output text in 'line'
unsigned int offset_; // current offset in frame to process next operand byte(s) (frame[0] and [1] are skipped)
/**
* The HDMI CEC standard specifies a set of distinct operand (parameter) types,
+20 -14
View File
@@ -46,25 +46,22 @@ void Frame::set_header(uint8_t initiator_addr, uint8_t target_addr) {
size_ = 1;
}
std::string Frame::to_string() const {
static constexpr unsigned int HEX_LINE_SIZE = Frame::MAX_LENGTH * 3 + 1;
char hex_line[HEX_LINE_SIZE];
int Frame::to_text(char *line, unsigned int size) const {
unsigned int offset = 0;
for (int i = 0; i < size_; i++) {
offset = buf_append_printf(hex_line, HEX_LINE_SIZE, offset, "%02X:", data_[i]);
offset = buf_append_printf(line, size, offset, "%02X:", data_[i]);
}
// clear last printed ':'
if (offset > 0)
hex_line[offset - 1] = '\0';
std::string result{hex_line};
line[--offset] = '\0';
#ifdef HDMI_CEC_USE_DECODER
Decoder decoder(*this);
result += " => ";
result += decoder.decode();
offset = buf_append_printf(line, size, offset, " => ");
Decoder decoder(*this, line + offset, size - offset);
offset += decoder.decode();
#endif
return result;
return offset;
}
void HDMICEC::setup() {
@@ -110,8 +107,11 @@ void HDMICEC::handle_received_message_(const Frame *frame) {
return;
}
auto frame_str = frame->to_string();
ESP_LOGD(TAG, "Received: %s", frame_str.c_str());
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
std::array<char, 256> line;
frame->to_text(line.data(), (unsigned int) (line.size()));
ESP_LOGD(TAG, "Received: %s", line.data());
#endif
std::vector<uint8_t> data(frame->size() - 1);
for (int i = 1; i < frame->size(); i++)
@@ -362,9 +362,15 @@ void CECTransmit::transmit_message() {
// Launch the transmit of the frame that is on the front of the queue
transmit_state_ = TransmitState::BUSY;
transmit_attempts_++;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
if (transmit_attempts_ <= 1) {
ESP_LOGD(TAG, "Sending: %s", (frame->to_string()).c_str());
std::array<char, 256> line;
frame->to_text(line.data(), (unsigned int) (line.size()));
ESP_LOGD(TAG, "Sending: %s", line.data());
}
#endif
// Reset info from receiver on progress of this transmit
// (The receiver will see this transmit and keep track of acknowledge bits.)
n_bytes_received_ = 0;
@@ -573,7 +579,7 @@ void IRAM_ATTR CECTransmit::got_byte_eom_ack(bool eom, bool ack) {
if (eom) {
// some bus transfer ended. When the bus is free for a little while, we are allowed to transmit.
required_idle_period_ = SIGNAL_FREE_TIME_AFTER_RECEIVE;
ATOMIC_SET(receiver_is_busy_, false);
ATOMIC_SET(receiver_is_busy_, false); // unblock the transmitter
ATOMIC_SET(eom_received_, true); // atomic write to synchronize/commit above increments to the transmitter thread
}
}
+9 -1
View File
@@ -57,7 +57,15 @@ class Frame {
data_[size_++] = data;
}
}
std::string to_string() const; // NOLINT
/**
* Create a one-line textual representation of the Frame content for logging and debugging
* @param line: a buffer in which the text is to be written
* @param size: The size of this buffer not to exceed with text
* @return the length of the written text, excluding the terminating null character
*/
int to_text(char *line, unsigned int size) const;
constexpr static unsigned int MAX_LENGTH = 16;
constexpr static unsigned int MAX_PAYLOAD_LENGTH = MAX_LENGTH - 1; // subtract 1 byte for the src&dst field