Files
sweep_driver/src/device_discovery.cpp
2026-02-20 16:44:26 +03:00

94 lines
2.5 KiB
C++

#include "adc_sweep/device_discovery.hpp"
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
namespace adc_sweep {
namespace fs = std::filesystem;
namespace {
std::string trim(std::string s) {
while (!s.empty() && (s.back() == '\n' || s.back() == '\r' || s.back() == ' ' || s.back() == '\t')) {
s.pop_back();
}
size_t i = 0;
while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) {
++i;
}
return s.substr(i);
}
std::string read_file_trim(const fs::path& p) {
std::ifstream f(p);
if (!f.is_open()) {
return {};
}
std::ostringstream ss;
ss << f.rdbuf();
return trim(ss.str());
}
std::string hex4(uint16_t v) {
constexpr char kHex[] = "0123456789abcdef";
std::string out(4, '0');
out[0] = kHex[(v >> 12U) & 0xFU];
out[1] = kHex[(v >> 8U) & 0xFU];
out[2] = kHex[(v >> 4U) & 0xFU];
out[3] = kHex[v & 0xFU];
return out;
}
bool tty_name_ok(const std::string& name) {
return (name.rfind("ttyACM", 0) == 0) || (name.rfind("ttyUSB", 0) == 0);
}
} // namespace
std::optional<std::string> find_tty_by_vid_pid(uint16_t vid, uint16_t pid) {
const fs::path usb_root("/sys/bus/usb/devices");
if (!fs::exists(usb_root)) {
return std::nullopt;
}
const std::string vid_s = hex4(vid);
const std::string pid_s = hex4(pid);
std::vector<std::string> candidates;
for (const auto& entry : fs::directory_iterator(usb_root)) {
if (!entry.is_directory()) {
continue;
}
const fs::path devdir = entry.path();
const std::string v = read_file_trim(devdir / "idVendor");
const std::string p = read_file_trim(devdir / "idProduct");
if (v != vid_s || p != pid_s) {
continue;
}
for (const auto& sub : fs::recursive_directory_iterator(devdir, fs::directory_options::skip_permission_denied)) {
const std::string name = sub.path().filename().string();
if (!tty_name_ok(name)) {
continue;
}
const std::string devnode = "/dev/" + name;
if (fs::exists(devnode)) {
candidates.push_back(devnode);
}
}
}
if (candidates.empty()) {
return std::nullopt;
}
std::sort(candidates.begin(), candidates.end());
candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
return candidates.front();
}
} // namespace adc_sweep