fwt_software/src/core/DiagParser.cpp

125 lines
4.3 KiB
C++

#include "fgc/DiagParser.h"
#include <map>
#include <sstream>
namespace fgc {
namespace {
long toLong(const std::string& s, long fallback = 0) {
if (s.empty()) return fallback;
try {
bool hex = s.size() > 1 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X');
return std::stol(s, nullptr, hex ? 16 : 10);
} catch (const std::exception&) {
return fallback;
}
}
} // namespace
bool DiagResult::allPass() const {
bool any = false;
for (const auto& ax : axes) {
if (!ax.has_result) continue;
any = true;
if (!ax.pass) return false;
}
return any;
}
DiagResult parseDiag(const std::string& block) {
DiagResult d;
std::istringstream iss(block);
std::string line;
DiagAxis* cur = nullptr;
auto axisFor = [&d](char a) -> DiagAxis& {
for (auto& ax : d.axes)
if (ax.axis == a) return ax;
d.axes.push_back(DiagAxis{});
d.axes.back().axis = a;
return d.axes.back();
};
while (std::getline(iss, line)) {
if (!line.empty() && line.back() == '\r') line.pop_back();
// Only "DG ..." lines are part of the diag (ST/other lines interleave).
auto pos = line.find("DG ");
if (pos == std::string::npos) continue;
std::istringstream ls(line.substr(pos));
std::vector<std::string> tok;
std::string t;
while (ls >> t) tok.push_back(t);
if (tok.size() < 2) continue; // "DG" + something
d.valid = true;
if (tok[1] == "DONE") { d.done = true; continue; }
if (tok[1] == "BEGIN" && tok.size() >= 3) { cur = &axisFor(tok[2][0]); continue; }
// Otherwise tok[1] is the axis letter.
char axis = tok[1][0];
if (axis != 'Y' && axis != 'P') continue;
DiagAxis& ax = axisFor(axis);
cur = &ax;
if (tok.size() >= 4 && tok[2] == "RESULT") {
ax.has_result = true;
ax.pass = (tok[3] == "PASS");
continue;
}
// Test line: "DG <axis> S<speed> <FWD|REV> KEY val KEY val ... <PASS|FAIL>"
if (tok.size() < 4 || tok[2].empty() || (tok[2][0] != 'S' && tok[2][0] != 's'))
continue;
DiagTest test;
test.speed = static_cast<int>(toLong(tok[2].substr(1)));
test.fwd = (tok[3] != "REV");
test.pass = (tok.back() == "PASS");
// Remaining KEY value pairs (between dir and the trailing PASS/FAIL).
std::map<std::string, std::string> kv;
for (size_t i = 4; i + 1 < tok.size(); i += 2) kv[tok[i]] = tok[i + 1];
auto g = [&](const char* k) { auto it = kv.find(k); return it == kv.end() ? std::string() : it->second; };
test.err_peak = toLong(g("ERR_PEAK"), 0);
test.err_rms = toLong(g("ERR_RMS"), 0);
test.err_still = toLong(g("ERR_STILL"), 0);
test.cs_min = static_cast<int>(toLong(g("CS_MIN")));
test.cs_max = static_cast<int>(toLong(g("CS_MAX")));
test.sg_min = static_cast<int>(toLong(g("SG_MIN")));
test.pwm_avg = static_cast<int>(toLong(g("PWM_AVG")));
test.flags = static_cast<unsigned>(toLong(g("FLAGS")));
ax.tests.push_back(test);
}
return d;
}
std::vector<std::string> formatDiag(const DiagResult& d) {
std::vector<std::string> out;
if (!d.valid) {
out.emplace_back("(no diagnostic data)");
return out;
}
for (const auto& ax : d.axes) {
std::ostringstream hdr;
hdr << "[" << ax.axis << "] " << ax.tests.size() << " tests RESULT="
<< (ax.has_result ? (ax.pass ? "PASS" : "FAIL") : "?");
out.push_back(hdr.str());
for (const auto& t : ax.tests) {
std::ostringstream os;
os << " S" << t.speed << " " << (t.fwd ? "FWD" : "REV")
<< " err_peak=" << t.err_peak << " err_rms=" << t.err_rms
<< " err_still=" << t.err_still << " cs=" << t.cs_min << ".." << t.cs_max
<< " sg_min=" << t.sg_min << " pwm=" << t.pwm_avg
<< " flags=0x" << std::hex << t.flags << std::dec
<< " " << (t.pass ? "PASS" : "FAIL");
out.push_back(os.str());
}
}
out.push_back(std::string("overall: ") + (d.allPass() ? "PASS" : "FAIL") +
(d.done ? "" : " (incomplete - no DG DONE)"));
return out;
}
} // namespace fgc