Files
trail-mate/platform/linux/uconsole/src/uconsole_hardware_probe.cpp
T
vicliuandGitHub adf33068d7 v0.1.25-alpha (#30)
* Add uConsole GTK shell with SQLite map cache

* Improve uConsole GTK overview dashboard

* Detect uConsole hardware endpoints

* Add uConsole hardware binding and map fallback

* Improve uConsole settings and map UI

* feat: adapt uConsole Linux shell

* docs: document GPS settings and T-Deck UART noise

* style: apply clang-format

* site: update 0.1.25 release highlights

---------

Co-authored-by: vicliu624 <vicliu@outlook.com>
2026-05-12 01:24:04 +08:00

187 lines
4.0 KiB
C++

#include "uconsole/uconsole_hardware_probe.h"
#include <algorithm>
#include <cstdlib>
#include <filesystem>
#include <sstream>
#include <string>
#include <vector>
namespace trailmate::uconsole
{
namespace
{
namespace fs = std::filesystem;
[[nodiscard]] bool containsToken(const std::string& text,
const char* token) noexcept
{
return text.find(token) != std::string::npos;
}
[[nodiscard]] std::string pathString(const fs::path& path)
{
return path.string();
}
[[nodiscard]] bool existingPath(const fs::path& path)
{
std::error_code ec;
return fs::exists(path, ec) && !ec;
}
[[nodiscard]] std::vector<fs::path> directoryEntries(const fs::path& dir)
{
std::vector<fs::path> out{};
std::error_code ec;
if (!fs::exists(dir, ec) || ec)
{
return out;
}
for (const auto& entry : fs::directory_iterator(dir, ec))
{
if (ec)
{
break;
}
out.push_back(entry.path());
}
std::sort(out.begin(), out.end());
return out;
}
[[nodiscard]] fs::path resolvedDevicePath(const fs::path& path)
{
std::error_code ec;
fs::path resolved = fs::canonical(path, ec);
if (ec)
{
return path;
}
return resolved;
}
[[nodiscard]] bool findClockworkPiSerial(fs::path& out_path)
{
for (const auto& path : directoryEntries("/dev/serial/by-id"))
{
const std::string name = path.filename().string();
if (containsToken(name, "ClockworkPI") &&
containsToken(name, "uConsole"))
{
out_path = path;
return true;
}
}
return false;
}
[[nodiscard]] bool findSpiDevice(fs::path& out_path)
{
if (const char* configured = std::getenv("TRAIL_MATE_LORA_SPI");
configured != nullptr && configured[0] != '\0' &&
existingPath(configured))
{
out_path = configured;
return true;
}
if (existingPath("/dev/spidev1.0"))
{
out_path = "/dev/spidev1.0";
return true;
}
return false;
}
[[nodiscard]] std::string summarizeI2c()
{
std::vector<std::string> names{};
for (const auto& path : directoryEntries("/dev"))
{
const std::string name = path.filename().string();
if (name.rfind("i2c-", 0) == 0)
{
names.push_back("/dev/" + name);
}
}
if (names.empty())
{
return {};
}
std::ostringstream out;
for (std::size_t index = 0; index < names.size(); ++index)
{
if (index != 0)
{
out << ", ";
}
out << names[index];
}
return out.str();
}
} // namespace
bool uconsoleAutoGpsSerialPath(std::string& out_path)
{
fs::path path{};
if (!findClockworkPiSerial(path))
{
out_path.clear();
return false;
}
out_path = pathString(path);
return true;
}
UConsoleHardwareProbe probeUConsoleHardware()
{
UConsoleHardwareProbe out{};
fs::path serial_path{};
if (findClockworkPiSerial(serial_path))
{
out.aio2_detected = true;
out.gps_serial_detected = true;
out.aio2_serial_path = pathString(resolvedDevicePath(serial_path));
out.gps_serial_path = pathString(serial_path);
}
fs::path spi_path{};
if (findSpiDevice(spi_path))
{
out.aio2_detected = true;
out.lora_spi_detected = true;
out.lora_spi_path = pathString(spi_path);
}
out.i2c_summary = summarizeI2c();
out.i2c_detected = !out.i2c_summary.empty();
std::ostringstream summary;
summary << (out.aio2_detected ? "AIO2 endpoints present"
: "No AIO2 endpoint detected");
if (!out.aio2_serial_path.empty())
{
summary << " / serial " << out.aio2_serial_path;
}
if (!out.lora_spi_path.empty())
{
summary << " / SPI " << out.lora_spi_path;
}
if (out.i2c_detected)
{
summary << " / I2C " << out.i2c_summary;
}
out.summary = summary.str();
return out;
}
} // namespace trailmate::uconsole