#include "adc_sweep/device_discovery.hpp" #include #include #include #include #include #include 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 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 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