#include "source/solar/cb_frame.h" // limit the amount of logging from this class as it can be called very frequently. Too much logging can lead to instability and no connectivity. namespace solar { cb_frame::cb_frame(int msg_id, uint32_t can_id) { this->msg_id = msg_id; this->rtr = false; this->can_id = can_id; this->frame.clear(); // ESP_LOGI(tag("frame CTOR1").c_str(), "%-20s %s", "Created frame", this->to_string().c_str()); } cb_frame::cb_frame(int msg_id, uint32_t can_id, const byte_vector& frame, bool rtr) { this->msg_id = msg_id; this->rtr = rtr; this->can_id = can_id; this->frame = frame; // ESP_LOGI(tag("frame CTOR2").c_str(), "%-20s %s", "Created frame", this->to_string().c_str()); } void cb_frame::clear() { this->msg_id = 0; this->rtr = false; this->can_id = 0; this->frame.clear(); } void cb_frame::swap(cb_frame &s) { std::swap(this->msg_id, s.msg_id); std::swap(this->rtr, s.rtr); std::swap(this->can_id, s.can_id); this->frame.swap(s.frame); } bool cb_frame::is_valid() const { return this->can_id != 0; } int cb_frame::compare(const cb_frame& b, const int *comparecolumns) const { int result = 0; bool stopcompare = false; bool isdefaultcompare = comparecolumns == nullptr || *comparecolumns == 0; int ncmpcols = 0; while (comparecolumns[ncmpcols] != 0) ncmpcols++; if (isdefaultcompare) { for (int i = sisortNULL + 1; i < sisortEND && !stopcompare && result == 0; i++) { bool validnextcol = i < sisortEND - 1; result = compare(b, i, &stopcompare, validnextcol); } } else { for (int i = 0; i < ncmpcols && !stopcompare && result == 0; i++) { result = compare(b, comparecolumns[i], &stopcompare, true); } } return result; } int cb_frame::compare(const cb_frame &b, int cmpflag, bool *stopcomparesignal, bool validnextcol) const { int result = 0; int reverseorderflag = cmpflag & sisortreverse; int casesensitiveflag = cmpflag & sisortcase; int nulliswildcardflag = cmpflag & sisortwild; int stopcompareflag = cmpflag & sistopcomparecol; cmpflag = cmpflag & ~FLAGBITS; if (cmpflag == 0) return result; bool casesensitive = casesensitiveflag != 0; bool sortwild = nulliswildcardflag != 0; bool stopcompare = stopcompareflag != 0; *stopcomparesignal = false; switch (cmpflag) { case sisortNULL: return 0; case sisortcanid: { bool bothvalid = this->is_valid() && b.is_valid(); if (bothvalid) { result = num_compare(this->can_id, b.can_id); *stopcomparesignal = stopcompare; // set flag only if both items are valid } else { if (sortwild) result = 0; else { bool bothinvalid = !(this->is_valid() || b.is_valid()); if (validnextcol && bothinvalid) result = 0; //if validnextcol then return 0 if both IDs are invalid result = this->can_id ? 1 : -1; } } break; } case sisortmsgid: result = num_compare(this->msg_id, b.msg_id); break; case sisortrtr: result = bool_compare(this->rtr, b.rtr); break; case sisortframe: { result = this->compare_frame(b.frame); break; } default: result = 0; ESP_LOGE("cb_frame::compare", "Unknown compare column %d", cmpflag); *stopcomparesignal = true; // stop compare as we don't know how to handle // should never reach here as all cases must be dealt with break; } if (reverseorderflag != 0) result = -result; return result; } int cb_frame::compare_frame(const byte_vector& _frame) const { int result = 0; auto j = _frame.begin(); for(auto i = this->frame.begin(); i != this->frame.end() && result == 0; ++i) { if(j == _frame.end()) { // ESP_LOGW("cb_frame::compare", "Frame size mismatch: this.frame.size()=%zu, _frame.size()=%zu", this->frame.size(), _frame.size()); result = 1; // this frame is longer than _frame break; } // ESP_LOGI("cb_frame::compare", "Comparing frame byte %zu: %02X vs %02X", i - this->frame.begin(), *i, *j); result = num_compare(*i, *j); // if (result != 0) { // ESP_LOGI("cb_frame::compare", "Frame byte %zu mismatch: %02X vs %02X", i - this->frame.begin(), *i, *j); // } j++; } return result; } std::string cb_frame::tag(const std::string& prefix) const { char tag[48]; if(prefix.length() == 0) snprintf(tag, sizeof(tag), "%04d 0x%03X ", msg_id, can_id); else snprintf(tag, sizeof(tag), "%-18s %04d 0x%03X ", prefix.c_str(), msg_id, can_id); return std::string(tag); } std::string cb_frame::to_string() const { // Be extra careful with the placement of printf format specifiers and their corresponding arguments to avoid buffer overflows and ensure correct formatting. // Incorrect placement / misaligned arguments can lead to undefined behavior and processor crashes. std::string text = ""; char hex[10]; snprintf(hex, sizeof(hex), " %s", rtr ? "RTR" : " "); std::string line(hex); if (this->frame.empty()) { line += " "; return line; } for (const auto& byte : frame) { snprintf(hex, sizeof(hex), "%02X ", byte); line += hex; if(byte > 31 && byte < 127) { text += (char) byte; } else { text += "."; } } return line + " " + text; } } // namespace solar