19#include <radio_tool/radio/usb_radio_factory.hpp>
20#include <radio_tool/radio/tyt_radio.hpp>
21#include <radio_tool/radio/tyt_sgl_radio.hpp>
22#include <radio_tool/radio/yaesu_radio.hpp>
24#include <libusb-1.0/libusb.h>
37 std::function<bool(
const libusb_device_descriptor&)> SupportsDevice;
38 std::function<
RadioOperations* (libusb_device_handle*)> CreateOperations;
44const std::vector<DeviceMapper> RadioSupports = {
45 {TYTRadio::SupportsDevice, TYTRadio::Create},
46 {TYTSGLRadio::SupportsDevice, TYTSGLRadio::Create},
47 {YaesuRadio::SupportsDevice, YaesuRadio::Create}
50USBRadioFactory::USBRadioFactory() : usb_ctx(nullptr)
52 usb_ctx = CreateContext();
53 events = std::thread(&USBRadioFactory::HandleEvents,
this);
56USBRadioFactory::~USBRadioFactory()
65auto USBRadioFactory::ListDevices(
const uint16_t& idx_offset)
const ->
const std::vector<RadioInfo*>
67 std::vector<RadioInfo*> ret;
70 auto ndev = libusb_get_device_list(usb_ctx, &devs);
71 int err = LIBUSB_SUCCESS;
76 for (
auto x = 0; x < ndev; x++)
78 libusb_device_descriptor desc;
79 if (LIBUSB_SUCCESS == (err = libusb_get_device_descriptor(devs[x], &desc)))
81 for (
const auto& fnSupport : RadioSupports)
83 if (fnSupport.SupportsDevice(desc))
85 int err = LIBUSB_SUCCESS;
86 libusb_device_handle* h;
87 auto cdev =
const_cast<libusb_device*
>(devs[x]);
88 if (LIBUSB_SUCCESS == (err = libusb_open(cdev, &h)))
90 std::wstring mfg, prd;
92 if (desc.idVendor == YaesuRadio::VID && desc.idProduct == YaesuRadio::PID)
99 mfg = GetDeviceString(desc.iManufacturer, h);
100 prd = GetDeviceString(desc.iProduct, h);
103 auto bus = libusb_get_bus_number(cdev);
104 auto port = libusb_get_port_number(cdev);
106 auto fnOpen = [bus, port, &fnSupport]()
108 auto openDev = OpenDevice(bus, port);
109 return fnSupport.CreateOperations(openDev);
112 auto nInf =
new USBRadioInfo(fnOpen, mfg, prd, desc.idVendor, desc.idProduct, idx_offset + n_idx);
119 std::cerr <<
"Failed to open device VID=0x"
120 << std::hex << std::setw(4) << std::setfill(
'0') << desc.idVendor
122 << std::hex << std::setw(4) << std::setfill(
'0') << desc.idProduct
123 <<
" (" << libusb_error_name(err) <<
")"
131 libusb_free_device_list(devs, 1);
135 throw std::runtime_error(libusb_error_name(ndev));
140auto USBRadioFactory::GetDeviceString(
const uint8_t& desc, libusb_device_handle* h)
const -> std::wstring
144 unsigned char lang[42], prd[255];
147 err = libusb_get_string_descriptor(h, 0, 0, lang, 42);
148 if (LIBUSB_SUCCESS > err)
150 throw std::runtime_error(libusb_error_name(err));
152 if (LIBUSB_SUCCESS > (prd_len = libusb_get_string_descriptor(h, desc, lang[2] << 8 | lang[3], prd, 255)))
154 throw std::runtime_error(libusb_error_name(prd_len));
158 typedef std::codecvt_utf16<char16_t, 1114111UL, std::little_endian> cvt;
159 auto u16 = std::wstring_convert<cvt, char16_t>().from_bytes((
const char*)prd + 2, (
const char*)prd + prd_len);
160 return std::wstring(u16.begin(), u16.end());
163auto USBRadioFactory::OpenDevice(
const uint8_t& bus,
const uint8_t& port) -> libusb_device_handle*
165 auto usb_ctx = CreateContext();
167 libusb_device** devs;
168 auto ndev = libusb_get_device_list(usb_ctx, &devs);
169 int err = LIBUSB_SUCCESS;
174 for (
auto x = 0; x < ndev; x++)
176 auto b = libusb_get_bus_number(devs[x]);
177 auto p = libusb_get_port_number(devs[x]);
178 if (b == bus && p == port)
180 libusb_device_handle* handle;
182 if (libusb_open(devs[x], &handle) == LIBUSB_SUCCESS)
190 libusb_free_device_list(devs, 1);
194 throw std::runtime_error(libusb_error_name(ndev));
200auto USBRadioFactory::CreateContext() -> libusb_context*
202 libusb_context* usb_ctx;
204 auto err = libusb_init(&usb_ctx);
205 if (err != LIBUSB_SUCCESS)
207 throw std::runtime_error(libusb_error_name(err));
209#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
211 usb_ctx, [](libusb_context*,
enum libusb_log_level,
const char* str)
212 { std::wcout << str << std::endl; },
213 LIBUSB_LOG_CB_CONTEXT);
219auto USBRadioFactory::HandleEvents() ->
void
221 std::cerr <<
"USB events tread started: #" << std::this_thread::get_id() << std::endl;
222 while (usb_ctx !=
nullptr)
224 timeval timeout = { 0, 100 };
225 auto err = libusb_handle_events_timeout(usb_ctx, &timeout);
226 if (err != LIBUSB_SUCCESS)
228 if (err != LIBUSB_ERROR_BUSY &&
229 err != LIBUSB_ERROR_TIMEOUT &&
230 err != LIBUSB_ERROR_OVERFLOW &&
231 err != LIBUSB_ERROR_INTERRUPTED)
237 std::cerr <<
"USB events tread exited: #" << std::this_thread::get_id() << std::endl;