Tidying low-level debug tool driver code:

- Use automatic objects for libusb/hidapi resources, where possible (to reduce manual resource management)
- Removed unused/redundant code
- Tidied HidInterface class
- Tidied debug tool initialisation code
- Other bits of tidying
This commit is contained in:
Nav
2022-10-01 16:50:57 +01:00
parent ef4eb4f768
commit a5b0097036
36 changed files with 448 additions and 727 deletions

View File

@@ -9,65 +9,71 @@ namespace Bloom::Usb
{
using namespace Bloom::Exceptions;
HidInterface::HidInterface(std::uint8_t interfaceNumber, std::uint16_t vendorId, std::uint16_t productId)
: interfaceNumber(interfaceNumber)
, vendorId(vendorId)
, productId(productId)
{}
void HidInterface::init() {
if (this->libUsbDevice == nullptr) {
throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer.");
}
::hid_init();
::hid_device* hidDevice = nullptr;
hid_init();
hid_device* hidDevice = nullptr;
std::string hidInterfacePath = this->getDevicePathByInterfaceNumber(this->getNumber());
const auto hidInterfacePath = this->getHidDevicePath();
Logger::debug("HID device path: " + hidInterfacePath);
if ((hidDevice = hid_open_path(hidInterfacePath.c_str())) == nullptr) {
if ((hidDevice = ::hid_open_path(hidInterfacePath.c_str())) == nullptr) {
throw DeviceInitializationFailure("Failed to open HID device via hidapi.");
}
if (hidDevice->input_ep_max_packet_size < 1) {
this->hidDevice.reset(hidDevice);
if (this->hidDevice->input_ep_max_packet_size < 1) {
throw DeviceInitializationFailure(
"Invalid max packet size for USB endpoint, on interface "
+ std::to_string(this->getNumber())
+ std::to_string(this->interfaceNumber)
);
}
this->setHidDevice(hidDevice);
this->setInputReportSize(static_cast<std::size_t>(hidDevice->input_ep_max_packet_size));
this->libUsbDeviceHandle = hidDevice->device_handle;
this->initialised = true;
this->inputReportSize = static_cast<std::size_t>(this->hidDevice->input_ep_max_packet_size);
}
void HidInterface::close() {
auto* hidDevice = this->getHidDevice();
if (hidDevice != nullptr) {
this->libUsbDeviceHandle = nullptr;
hid_close(hidDevice);
// hid_close() releases the interface
this->claimed = false;
}
hid_exit();
Interface::close();
this->hidDevice.reset();
::hid_exit();
}
std::vector<unsigned char> HidInterface::read(unsigned int timeout) {
std::vector<unsigned char> output;
auto readSize = this->getInputReportSize();
std::vector<unsigned char> HidInterface::read(std::optional<std::chrono::milliseconds> timeout) {
auto output = std::vector<unsigned char>();
// Attempt to read the first HID report packet, and whatever is left after that.
output.resize(readSize);
auto transferredByteCount = this->read(output.data(), readSize, timeout);
auto totalByteCount = transferredByteCount;
const auto readSize = this->inputReportSize;
auto transferredByteCount = int(0);
auto totalByteCount = std::size_t(0);
while (transferredByteCount >= readSize) {
output.resize(totalByteCount + readSize);
do {
output.resize(totalByteCount + readSize, 0x00);
transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1);
totalByteCount += transferredByteCount;
}
transferredByteCount = ::hid_read_timeout(
this->hidDevice.get(),
output.data() + totalByteCount,
readSize,
timeout.has_value() ? static_cast<int>(timeout->count()) : -1
);
output.resize(totalByteCount);
if (transferredByteCount == -1) {
throw DeviceCommunicationFailure("Failed to read from HID device.");
}
if (totalByteCount == 0) {
// After the first read, set the timeout to 1 millisecond, as we don't want to wait for subsequent data
timeout = std::chrono::milliseconds(1);
}
totalByteCount += static_cast<std::size_t>(transferredByteCount);
} while (transferredByteCount >= readSize);
output.resize(totalByteCount, 0x00);
return output;
}
@@ -89,49 +95,35 @@ namespace Bloom::Usb
int transferred = 0;
const auto length = buffer.size();
if ((transferred = hid_write(this->getHidDevice(), buffer.data(), length)) != length) {
if ((transferred = ::hid_write(this->hidDevice.get(), buffer.data(), length)) != length) {
Logger::debug("Attempted to write " + std::to_string(length)
+ " bytes to HID interface. Bytes written: " + std::to_string(transferred));
throw DeviceCommunicationFailure("Failed to write data to HID interface.");
}
}
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) {
int transferred;
if ((transferred = hid_read_timeout(
this->hidDevice,
buffer,
maxLength,
timeout == 0 ? -1 : static_cast<int>(timeout))
) == -1
) {
throw DeviceCommunicationFailure("Failed to read from HID device.");
}
return static_cast<std::size_t>(transferred);
}
std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) {
hid_device_info* hidDeviceInfoList = hid_enumerate(
this->getVendorId(),
this->getProductId()
std::string HidInterface::getHidDevicePath() {
const auto hidDeviceInfoList = std::unique_ptr<::hid_device_info, decltype(&::hid_free_enumeration)>(
::hid_enumerate(this->vendorId, this->productId),
::hid_free_enumeration
);
while (hidDeviceInfoList != nullptr) {
if (hidDeviceInfoList->interface_number == interfaceNumber) {
auto matchedDevice = std::optional<::hid_device_info*>();
auto* hidDeviceInfo = hidDeviceInfoList.get();
while (hidDeviceInfo != nullptr) {
if (hidDeviceInfo->interface_number == this->interfaceNumber) {
matchedDevice = hidDeviceInfo;
break;
}
hidDeviceInfoList = hidDeviceInfoList->next;
hidDeviceInfo = hidDeviceInfoList->next;
}
if (hidDeviceInfoList == nullptr) {
if (!matchedDevice.has_value()) {
throw DeviceInitializationFailure("Failed to match interface number with HID interface.");
}
auto path = std::string(hidDeviceInfoList->path);
hid_free_enumeration(hidDeviceInfoList);
return path;
return std::string(matchedDevice.value()->path);
}
}

View File

@@ -1,11 +1,13 @@
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include <optional>
#include <chrono>
#include "hidapi.hpp"
#include "src/DebugToolDrivers/USB/Interface.hpp"
namespace Bloom::Usb
{
@@ -15,35 +17,46 @@ namespace Bloom::Usb
* Currently, this interface only supports single-report HID implementations. HID interfaces with
* multiple reports will be supported as-and-when we need it.
*/
class HidInterface: public Interface
class HidInterface
{
public:
std::uint8_t interfaceNumber = 0;
HidInterface(
std::uint8_t interfaceNumber,
std::uint16_t vendorId,
std::uint16_t productId
);
HidInterface(const HidInterface& other) = delete;
HidInterface& operator = (const HidInterface& other) = delete;
HidInterface(HidInterface&& other) = default;
HidInterface& operator = (HidInterface&& other) = default;
std::size_t getInputReportSize() const {
return this->inputReportSize;
}
/**
* Claims the USB HID interface and obtains a hid_device instance
* Obtains a hid_device instance and claims the HID interface on the device.
*/
void init() override;
void init();
/**
* Closes the hid_device and releases any claimed interfaces (via hid_close())
* Releases any claimed interfaces and closes the hid_device.
*/
void close() override;
void close();
/**
* Reads as much data as the device has to offer, into a vector.
*
* If `timeout` is set to 0, this method will block until at least one HID report
* packet is received.
*
* @param timeout
*
* @return
* A vector of the data received from the device.
*/
std::vector<unsigned char> read(unsigned int timeout = 0);
std::vector<unsigned char> read(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
/**
* Writes buffer to HID output endpoint.
@@ -52,59 +65,20 @@ namespace Bloom::Usb
*/
void write(std::vector<unsigned char>&& buffer);
/**
* Resolves a device path from a USB interface number.
*
* @param interfaceNumber
* @return
*/
std::string getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber);
protected:
hid_device* getHidDevice() const {
return this->hidDevice;
}
std::string getHidDevicePath();
private:
/**
* The HIDAPI library provides a hid_device data structure to represent a USB HID interface.
*
* @see hidapi.hpp or the HIDAPI documentation for more on this.
*/
hid_device* hidDevice = nullptr;
using HidDeviceType = std::unique_ptr<::hid_device, decltype(&::hid_close)>;
HidDeviceType hidDevice = HidDeviceType(nullptr, ::hid_close);
/**
* All HID reports have a fixed report length. This means that every packet
* we send or receive to/from an HID endpoint must be equal to the report length in size.
*
* The default input report size is 64 bytes, but this is overridden at interface initialisation.
* @see definition of init() for more on this.
* All HID reports have a fixed report length. This means that every packet we send or receive to/from an HID
* endpoint must be equal (in size) to the report length.
*/
std::size_t inputReportSize = 64;
void setHidDevice(hid_device* hidDevice) {
this->hidDevice = hidDevice;
}
void setInputReportSize(const std::size_t& inputReportSize) {
this->inputReportSize = inputReportSize;
}
/**
* Reads a maximum of `maxLength` bytes into `buffer`, from the HID input endpoint.
*
* Keeping this in the private scope to enforce use of vector<unsigned char>. See read()
* method in public scope.
*
* @TODO: Do we really need this? Why not just have the one that accepts the vector. Review
*
* @param buffer
* @param maxLength
* @param timeout
*
* @return
* Number of bytes read.
*/
std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout);
std::uint16_t vendorId = 0;
std::uint16_t productId = 0;
};
}

View File

@@ -1,123 +0,0 @@
#include "Interface.hpp"
#include <libusb-1.0/libusb.h>
#include "src/TargetController/Exceptions/DeviceFailure.hpp"
#include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp"
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
namespace Bloom::Usb
{
using namespace Bloom::Exceptions;
void Interface::init() {
if (this->libUsbDevice == nullptr) {
throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer.");
}
if (this->libUsbDeviceHandle == nullptr) {
throw DeviceInitializationFailure("Cannot initialise interface without libusb device handle.");
}
this->initialised = true;
}
void Interface::close() {
if (this->libUsbDeviceHandle != nullptr) {
this->release();
}
this->initialised = false;
}
void Interface::claim() {
int interfaceNumber = this->getNumber();
this->detachKernelDriver();
if (libusb_claim_interface(this->libUsbDeviceHandle, interfaceNumber) != 0) {
throw DeviceInitializationFailure(
"Failed to claim interface {" + std::to_string(interfaceNumber) + "} on USB device\n"
);
}
this->claimed = true;
}
void Interface::detachKernelDriver() {
int interfaceNumber = this->getNumber();
int libUsbStatusCode;
if ((libUsbStatusCode = libusb_kernel_driver_active(this->libUsbDeviceHandle, interfaceNumber)) != 0) {
if (libUsbStatusCode == 1) {
// A kernel driver is active on this interface. Attempt to detach it
if (libusb_detach_kernel_driver(this->libUsbDeviceHandle, interfaceNumber) != 0) {
throw DeviceInitializationFailure("Failed to detach kernel driver from interface " +
std::to_string(interfaceNumber) + "\n");
}
} else {
throw DeviceInitializationFailure("Failed to check for active kernel driver on USB interface.");
}
}
}
void Interface::release() {
if (this->isClaimed()) {
if (libusb_release_interface(this->libUsbDeviceHandle, this->getNumber()) != 0) {
throw DeviceFailure(
"Failed to release interface {" + std::to_string(this->getNumber())
+ "} on USB device\n"
);
}
this->claimed = false;
}
}
int Interface::read(unsigned char* buffer, unsigned char endPoint, size_t length, size_t timeout) {
int totalTransferred = 0;
int transferred = 0;
int libUsbStatusCode = 0;
while (length > totalTransferred) {
libUsbStatusCode = libusb_interrupt_transfer(
this->libUsbDeviceHandle,
endPoint,
buffer,
static_cast<int>(length),
&transferred,
static_cast<unsigned int>(timeout)
);
if (libUsbStatusCode != 0 && libUsbStatusCode != -7) {
throw DeviceCommunicationFailure(
"Failed to read from USB device. Error code returned: " + std::to_string(libUsbStatusCode)
);
}
totalTransferred += transferred;
}
return transferred;
}
void Interface::write(unsigned char* buffer, unsigned char endPoint, int length) {
int transferred = 0;
int libUsbStatusCode = 0;
libUsbStatusCode = libusb_interrupt_transfer(
this->libUsbDeviceHandle,
endPoint,
buffer,
length,
&transferred,
0
);
if (libUsbStatusCode != 0) {
throw DeviceCommunicationFailure(
"Failed to read from USB device. Error code returned: " + std::to_string(libUsbStatusCode)
);
}
}
}

View File

@@ -1,124 +0,0 @@
#pragma once
#include <cstdint>
#include <libusb-1.0/libusb.h>
#include <string>
#include "UsbDevice.hpp"
namespace Bloom::Usb
{
class Interface
{
public:
explicit Interface(const std::uint8_t& interfaceNumber = 0) {
this->setNumber(interfaceNumber);
}
virtual ~Interface() = default;
Interface(const Interface& other) = default;
Interface(Interface&& other) = default;
Interface& operator = (const Interface& other) = default;
Interface& operator = (Interface&& other) = default;
void setLibUsbDevice(libusb_device* libUsbDevice) {
this->libUsbDevice = libUsbDevice;
}
void setLibUsbDeviceHandle(libusb_device_handle* libUsbDeviceHandle) {
this->libUsbDeviceHandle = libUsbDeviceHandle;
}
std::uint8_t getNumber() const {
return this->number;
}
void setNumber(std::uint8_t number) {
this->number = number;
}
const std::string& getName() const {
return this->name;
}
void setName(const std::string& name) {
this->name = name;
}
bool isClaimed() const {
return this->claimed;
}
bool isInitialised() const {
return this->initialised;
}
std::uint16_t getVendorId() const {
return this->vendorId;
}
void setVendorId(std::uint16_t vendorId) {
this->vendorId = vendorId;
}
std::uint16_t getProductId() const {
return this->productId;
}
void setProductId(std::uint16_t productId) {
this->productId = productId;
}
/**
* Attempts to obtain a device descriptor and device handle via libusb.
*/
virtual void init();
/**
* Releases the interface and closes the device descriptor.
*/
virtual void close();
/**
* Attempts to claim the interface
*/
void claim();
/**
* If a kernel driver is attached to the interface, this method will detach it.
*/
void detachKernelDriver();
/**
* Releases the interface, if claimed.
*/
void release();
/**
* @TODO Remove or refactor these (read() and write()) - they're not currently used
*
* @param buffer
* @param endPoint
* @param length
* @param timeout
* @return
*/
virtual int read(unsigned char* buffer, unsigned char endPoint, std::size_t length, std::size_t timeout);
virtual void write(unsigned char* buffer, unsigned char endPoint, int length);
protected:
libusb_device* libUsbDevice = nullptr;
libusb_device_handle* libUsbDeviceHandle = nullptr;
std::uint16_t vendorId = 0;
std::uint16_t productId = 0;
std::uint8_t number = 0;
std::string name;
bool initialised = false;
bool claimed = false;
};
}

View File

@@ -1,5 +1,7 @@
#include "UsbDevice.hpp"
#include <libusb-1.0/libusb.h>
#include "src/Logger/Logger.hpp"
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
@@ -7,103 +9,134 @@ namespace Bloom::Usb
{
using namespace Bloom::Exceptions;
UsbDevice::UsbDevice(std::uint16_t vendorId, std::uint16_t productId)
: vendorId(vendorId)
, productId(productId)
{
if (!UsbDevice::libusbContext) {
::libusb_context* libusbContext = nullptr;
::libusb_init(&libusbContext);
UsbDevice::libusbContext.reset(libusbContext);
}
}
void UsbDevice::init() {
libusb_init(&this->libUsbContext);
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
auto devices = this->findMatchingDevices();
// ::libusb_set_option(this->libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
auto devices = this->findMatchingDevices(this->vendorId, this->productId);
if (devices.empty()) {
throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID.");
throw DeviceInitializationFailure(
"Failed to find USB device with matching vendor and product ID. Please examine the debug tool's USB "
"connection, as well as the selected environment's debug tool configuration in bloom.yaml"
);
}
if (devices.size() > 1) {
// TODO: implement support for multiple devices (maybe via serial number?)
// TODO: implement support for multiple devices via serial number matching?
throw DeviceInitializationFailure(
"Numerous devices of matching vendor & product ID found.\n"
"Numerous devices of matching vendor and product ID found.\n"
"Please ensure that only one debug tool is connected and then try again."
);
}
// For now, just use the first device found.
auto* device = devices.front();
this->setLibUsbDevice(device);
this->libusbDevice.swap(devices.front());
::libusb_device_handle* deviceHandle = nullptr;
const int libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle);
const int libusbStatusCode = ::libusb_open(this->libusbDevice.get(), &deviceHandle);
// Obtain a device handle from libusb
if (libUsbStatusCode < 0) {
if (libusbStatusCode < 0) {
// Failed to a device handle from libusb
throw DeviceInitializationFailure(
"Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned."
"Failed to open USB device - error code " + std::to_string(libusbStatusCode) + " returned."
);
}
this->libusbDeviceHandle.reset(deviceHandle);
}
void UsbDevice::setConfiguration(int configIndex) {
libusb_config_descriptor* configDescriptor = {};
int libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor);
::libusb_config_descriptor* configDescriptor = {};
int libusbStatusCode = ::libusb_get_config_descriptor(this->libusbDevice.get(), 0, &configDescriptor);
if (libUsbStatusCode < 0) {
if (libusbStatusCode < 0) {
throw DeviceInitializationFailure(
"Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode)
"Failed to obtain USB configuration descriptor - error code " + std::to_string(libusbStatusCode)
+ " returned."
);
}
libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue);
if (libUsbStatusCode < 0) {
libusbStatusCode = ::libusb_set_configuration(
this->libusbDeviceHandle.get(),
configDescriptor->bConfigurationValue
);
if (libusbStatusCode < 0) {
throw DeviceInitializationFailure(
"Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned."
"Failed to set USB configuration - error code " + std::to_string(libusbStatusCode) + " returned."
);
}
libusb_free_config_descriptor(configDescriptor);
::libusb_free_config_descriptor(configDescriptor);
}
std::vector<libusb_device*> UsbDevice::findMatchingDevices(
std::optional<std::uint16_t> vendorId, std::optional<std::uint16_t> productId
std::vector<LibusbDeviceType> UsbDevice::findMatchingDevices(
std::uint16_t vendorId, std::uint16_t productId
) {
auto* libUsbContext = this->libUsbContext;
libusb_device** devices = nullptr;
libusb_device* device;
std::vector<libusb_device*> matchedDevices;
::libusb_device** devices = nullptr;
::libusb_device* device;
std::vector<LibusbDeviceType> matchedDevices;
auto vendorIdToMatch = vendorId.value_or(this->vendorId);
auto productIdToMatch = productId.value_or(this->productId);
ssize_t libUsbStatusCode = libusb_get_device_list(libUsbContext, &devices);
if (libUsbStatusCode < 0) {
auto libusbStatusCode = ::libusb_get_device_list(UsbDevice::libusbContext.get(), &devices);
if (libusbStatusCode < 0) {
throw DeviceInitializationFailure(
"Failed to retrieve USB devices - return code: '" + std::to_string(libUsbStatusCode) + "'"
"Failed to retrieve USB devices - return code: '" + std::to_string(libusbStatusCode) + "'"
);
}
ssize_t i = 0;
while ((device = devices[i++]) != nullptr) {
struct libusb_device_descriptor desc = {};
auto libusbDevice = LibusbDeviceType(device, ::libusb_unref_device);
struct ::libusb_device_descriptor desc = {};
if ((libUsbStatusCode = libusb_get_device_descriptor(device, &desc)) < 0) {
if ((libusbStatusCode = ::libusb_get_device_descriptor(device, &desc)) < 0) {
Logger::warning("Failed to retrieve USB device descriptor - return code: '"
+ std::to_string(libUsbStatusCode) + "'");
+ std::to_string(libusbStatusCode) + "'");
continue;
}
if (desc.idVendor == vendorIdToMatch && desc.idProduct == productIdToMatch) {
matchedDevices.push_back(device);
if (desc.idVendor != vendorId || desc.idProduct != productId) {
continue;
}
matchedDevices.emplace_back(std::move(libusbDevice));
}
libusb_free_device_list(devices, 1);
::libusb_free_device_list(devices, 0);
return matchedDevices;
}
void UsbDevice::close() {
if (this->libUsbDeviceHandle != nullptr) {
libusb_close(this->libUsbDeviceHandle);
this->libUsbDeviceHandle = nullptr;
}
void UsbDevice::detachKernelDriverFromInterface(std::uint8_t interfaceNumber) {
const auto libusbStatusCode = ::libusb_kernel_driver_active(this->libusbDeviceHandle.get(), interfaceNumber);
if (this->libUsbContext != nullptr) {
libusb_exit(this->libUsbContext);
if (libusbStatusCode == 1) {
// A kernel driver is active on this interface. Attempt to detach it
if (::libusb_detach_kernel_driver(this->libusbDeviceHandle.get(), interfaceNumber) != 0) {
throw DeviceInitializationFailure("Failed to detach kernel driver from interface " +
std::to_string(interfaceNumber) + "\n");
}
} else if (libusbStatusCode != 0) {
throw DeviceInitializationFailure("Failed to check for active kernel driver on USB interface.");
}
}
void UsbDevice::close() {
this->libusbDeviceHandle.reset();
this->libusbDevice.reset();
}
UsbDevice::~UsbDevice() {
this->close();
}
}

View File

@@ -10,37 +10,26 @@
namespace Bloom::Usb
{
using LibusbContextType = std::unique_ptr<::libusb_context, decltype(&::libusb_exit)>;
using LibusbDeviceType = std::unique_ptr<::libusb_device, decltype(&::libusb_unref_device)>;
using LibusbDeviceHandleType = std::unique_ptr<::libusb_device_handle, decltype(&::libusb_close)>;
class UsbDevice
{
public:
UsbDevice(std::uint16_t vendorId, std::uint16_t productId): vendorId(vendorId), productId(productId) {};
std::uint16_t vendorId;
std::uint16_t productId;
virtual ~UsbDevice() = default;
UsbDevice(std::uint16_t vendorId, std::uint16_t productId);
UsbDevice(const UsbDevice& other) = delete;
UsbDevice& operator = (const UsbDevice& other) = delete;
UsbDevice(const UsbDevice& other) = default;
UsbDevice(UsbDevice&& other) = default;
UsbDevice& operator = (const UsbDevice& other) = default;
UsbDevice& operator = (UsbDevice&& other) = default;
void init();
[[nodiscard]] libusb_device* getLibUsbDevice() const {
return this->libUsbDevice;
}
void setLibUsbDevice(libusb_device* libUsbDevice) {
this->libUsbDevice = libUsbDevice;
}
[[nodiscard]] std::uint16_t getVendorId() const {
return this->vendorId;
}
[[nodiscard]] std::uint16_t getProductId() const {
return this->productId;
}
/**
* Selects a specific configuration on the device, using the configuration index.
*
@@ -48,16 +37,17 @@ namespace Bloom::Usb
*/
virtual void setConfiguration(int configIndex);
protected:
libusb_context* libUsbContext = nullptr;
libusb_device* libUsbDevice = nullptr;
libusb_device_handle* libUsbDeviceHandle = nullptr;
std::uint16_t vendorId;
std::uint16_t productId;
virtual ~UsbDevice();
std::vector<libusb_device*> findMatchingDevices(
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt
);
protected:
static inline LibusbContextType libusbContext = LibusbContextType(nullptr, ::libusb_exit);
LibusbDeviceType libusbDevice = LibusbDeviceType(nullptr, ::libusb_unref_device);
LibusbDeviceHandleType libusbDeviceHandle = LibusbDeviceHandleType(nullptr, ::libusb_close);
std::vector<LibusbDeviceType> findMatchingDevices(std::uint16_t vendorId, std::uint16_t productId);
void detachKernelDriverFromInterface(std::uint8_t interfaceNumber);
void close();
};