94 lines
2.5 KiB
C++
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
|