125 lines
4.3 KiB
C++
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
|