102 lines
3.4 KiB
C++
102 lines
3.4 KiB
C++
#include "fgc/ui/UiSnapshot.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
|
|
namespace fgc {
|
|
|
|
const char* axisStateLabel(AxisState s) {
|
|
switch (s) {
|
|
case AxisState::Boot: return "BOOT";
|
|
case AxisState::Reset: return "RESET";
|
|
case AxisState::Homing: return "HOMING";
|
|
case AxisState::Ready: return "READY";
|
|
case AxisState::Error: return "ERROR";
|
|
case AxisState::Unknown:
|
|
default: return "----";
|
|
}
|
|
}
|
|
|
|
UiColor axisStateColor(AxisState s) {
|
|
switch (s) {
|
|
case AxisState::Ready:
|
|
case AxisState::Homing: return UiColor::Cyan;
|
|
case AxisState::Error: return UiColor::Red;
|
|
case AxisState::Boot:
|
|
case AxisState::Reset: return UiColor::Dim;
|
|
case AxisState::Unknown:
|
|
default: return UiColor::Default;
|
|
}
|
|
}
|
|
|
|
std::string formatImuMount(const ImuMount& m) {
|
|
if (m.identity()) return "";
|
|
char b[64];
|
|
std::snprintf(b, sizeof(b), "x %.1f y %.1f z %.1f", m.x_deg, m.y_deg, m.z_deg);
|
|
return b;
|
|
}
|
|
|
|
std::string formatDegrees(double deg) {
|
|
char buf[32];
|
|
std::snprintf(buf, sizeof(buf), "%.1f\xC2\xB0", deg); // UTF-8 degree sign
|
|
return buf;
|
|
}
|
|
|
|
std::string formatTimeAgo(long long now_ms, long long then_ms) {
|
|
if (then_ms <= 0) return "\xE2\x80\x94"; // em dash: never
|
|
long long d = now_ms - then_ms;
|
|
if (d < 0) d = 0;
|
|
long long s = d / 1000;
|
|
char buf[32];
|
|
if (s < 60) std::snprintf(buf, sizeof(buf), "%llds ago", s);
|
|
else if (s < 3600) std::snprintf(buf, sizeof(buf), "%lldm ago", s / 60);
|
|
else std::snprintf(buf, sizeof(buf), "%lldh ago", s / 3600);
|
|
return buf;
|
|
}
|
|
|
|
bool backgroundAvailable(const char* tmux_env) {
|
|
// An empty TMUX is not "in tmux": the variable exists but names no server,
|
|
// so detach-client would have nothing to talk to.
|
|
return tmux_env != nullptr && *tmux_env != '\0';
|
|
}
|
|
|
|
std::string topicLeaf(const std::string& topic) {
|
|
const auto slash = topic.rfind('/');
|
|
if (slash == std::string::npos) return topic;
|
|
return topic.substr(slash + 1);
|
|
}
|
|
|
|
std::string formatClockMs(long long ms) {
|
|
if (ms <= 0) return "\xE2\x80\x94"; // em dash: never
|
|
const std::time_t secs = static_cast<std::time_t>(ms / 1000);
|
|
std::tm tm{};
|
|
localtime_r(&secs, &tm);
|
|
char buf[32];
|
|
std::snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03d", tm.tm_hour, tm.tm_min, tm.tm_sec,
|
|
static_cast<int>(ms % 1000));
|
|
return buf;
|
|
}
|
|
|
|
SensorsView pendingSensorsView() {
|
|
SensorsView v;
|
|
// Xsens MTi-28 AHRS: drift-free Euler orientation. The device's internal
|
|
// temperature is deliberately NOT here — it is diagnostic detail shown only
|
|
// in the expanded view, so the sole temperature on the main window is the
|
|
// SHT41's ambient one below.
|
|
v.imu.title = "MTi (orientation)";
|
|
v.imu.status = "pending";
|
|
v.imu.fields.push_back({"Roll", "--.-", "\xC2\xB0", false});
|
|
v.imu.fields.push_back({"Pitch", "--.-", "\xC2\xB0", false});
|
|
v.imu.fields.push_back({"Yaw", "--.-", "\xC2\xB0", false});
|
|
// SHT41 temperature & humidity (Adafruit, I2C on the LattePanda's own bus):
|
|
// ±0.2 °C, ±1.8 %RH (ambient).
|
|
v.env.title = "SHT41 (ambient)";
|
|
v.env.status = "pending";
|
|
v.env.fields.push_back({"Temp", "--.-", "\xC2\xB0""C", false});
|
|
v.env.fields.push_back({"Humid", "--", "%RH", false});
|
|
return v;
|
|
}
|
|
|
|
} // namespace fgc
|