Refactored some of the USB device (libusb wrapper) & interface code
This commit is contained in:
@@ -11,11 +11,14 @@ void AtmelIce::init() {
|
|||||||
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
|
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
|
||||||
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface();
|
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface();
|
||||||
usbHidInterface.setNumber(0);
|
usbHidInterface.setNumber(0);
|
||||||
usbHidInterface.setUSBDevice(this->getLibUsbDevice());
|
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
|
||||||
usbHidInterface.setVendorId(this->getVendorId());
|
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
|
||||||
usbHidInterface.setProductId(this->getProductId());
|
usbHidInterface.setVendorId(this->vendorId);
|
||||||
|
usbHidInterface.setProductId(this->productId);
|
||||||
|
|
||||||
if (!usbHidInterface.isInitialised()) {
|
if (!usbHidInterface.isInitialised()) {
|
||||||
|
usbHidInterface.detachKernelDriver();
|
||||||
|
UsbDevice::setConfiguration(0);
|
||||||
usbHidInterface.init();
|
usbHidInterface.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ void PowerDebugger::init() {
|
|||||||
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
|
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
|
||||||
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface();
|
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface();
|
||||||
usbHidInterface.setNumber(0);
|
usbHidInterface.setNumber(0);
|
||||||
usbHidInterface.setUSBDevice(this->getLibUsbDevice());
|
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
|
||||||
usbHidInterface.setVendorId(this->getVendorId());
|
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
|
||||||
usbHidInterface.setProductId(this->getProductId());
|
usbHidInterface.setVendorId(this->vendorId);
|
||||||
|
usbHidInterface.setProductId(this->productId);
|
||||||
|
|
||||||
if (!usbHidInterface.isInitialised()) {
|
if (!usbHidInterface.isInitialised()) {
|
||||||
usbHidInterface.init();
|
usbHidInterface.init();
|
||||||
|
|||||||
@@ -26,10 +26,7 @@ namespace Bloom::DebugToolDrivers
|
|||||||
* as an Atmel Data Gateway Interface (DGI).
|
* as an Atmel Data Gateway Interface (DGI).
|
||||||
*
|
*
|
||||||
* Communication:
|
* Communication:
|
||||||
* Like the Atmel-ICE, using the Power Debugger device for AVR debugging/programming requires the AVR
|
* Uses the same EDBG protocol as described in the AtmelIce driver. See the AtmelIce debug tool class for more.
|
||||||
* communication protocol, which is a sub-protocol of the CMSIS-DAP.
|
|
||||||
*
|
|
||||||
* For more information on the communication protocol, see the DebugToolDrivers::AtmelIce class.
|
|
||||||
*
|
*
|
||||||
* USB Setup:
|
* USB Setup:
|
||||||
* Vendor ID: 0x03eb (1003)
|
* Vendor ID: 0x03eb (1003)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "HidInterface.hpp"
|
#include "HidInterface.hpp"
|
||||||
#include "hidapi.hpp"
|
#include "hidapi.hpp"
|
||||||
@@ -12,45 +11,37 @@ using namespace Bloom::Usb;
|
|||||||
using namespace Bloom::Exceptions;
|
using namespace Bloom::Exceptions;
|
||||||
|
|
||||||
std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) {
|
std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) {
|
||||||
hid_device_info* HIDDeviceInfoList = hid_enumerate(this->getVendorId(), this->getProductId());
|
hid_device_info* hidDeviceInfoList = hid_enumerate(this->getVendorId(), this->getProductId());
|
||||||
|
|
||||||
while (HIDDeviceInfoList != nullptr) {
|
while (hidDeviceInfoList != nullptr) {
|
||||||
if (HIDDeviceInfoList->interface_number == interfaceNumber) {
|
if (hidDeviceInfoList->interface_number == interfaceNumber) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HIDDeviceInfoList = HIDDeviceInfoList->next;
|
hidDeviceInfoList = hidDeviceInfoList->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HIDDeviceInfoList == nullptr) {
|
if (hidDeviceInfoList == nullptr) {
|
||||||
throw std::runtime_error("Failed to match interface number with HID interface.");
|
throw Exception("Failed to match interface number with HID interface.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto path = std::string(HIDDeviceInfoList->path);
|
auto path = std::string(hidDeviceInfoList->path);
|
||||||
hid_free_enumeration(HIDDeviceInfoList);
|
hid_free_enumeration(hidDeviceInfoList);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HidInterface::init() {
|
void HidInterface::init() {
|
||||||
/*
|
if (this->libUsbDevice == nullptr) {
|
||||||
* Because we use the HIDAPI with libusb for our HID interfaces, we must allow the HIDAPI to own the device
|
throw Exception("Cannot initialise interface without libusb device pointer.");
|
||||||
* resources (device handle and the interface). However, the HIDAPI does not provide any means to ensure that a
|
}
|
||||||
* specific configuration is set against the device. This is why we first open the device via libusb (by calling
|
|
||||||
* the generic init() method), so that we can set the correct configuration. We then close the device to allow
|
|
||||||
* the HIDAPI to take ownership.
|
|
||||||
*/
|
|
||||||
Interface::init();
|
|
||||||
Interface::detachKernelDriver();
|
|
||||||
Interface::setConfiguration(0);
|
|
||||||
Interface::close();
|
|
||||||
|
|
||||||
hid_init();
|
hid_init();
|
||||||
hid_device* hidDevice;
|
hid_device* hidDevice;
|
||||||
|
|
||||||
std::string HIDInterfacePath = this->getDevicePathByInterfaceNumber(this->getNumber());
|
std::string hidInterfacePath = this->getDevicePathByInterfaceNumber(this->getNumber());
|
||||||
Logger::debug("HID device path: " + HIDInterfacePath);
|
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 Exception("Failed to open HID device via hidapi.");
|
throw Exception("Failed to open HID device via hidapi.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,17 +51,18 @@ void HidInterface::init() {
|
|||||||
|
|
||||||
this->setHidDevice(hidDevice);
|
this->setHidDevice(hidDevice);
|
||||||
this->setInputReportSize(static_cast<std::size_t>(hidDevice->input_ep_max_packet_size));
|
this->setInputReportSize(static_cast<std::size_t>(hidDevice->input_ep_max_packet_size));
|
||||||
this->setLibUsbDeviceHandle(hidDevice->device_handle);
|
this->libUsbDeviceHandle = hidDevice->device_handle;
|
||||||
|
this->initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HidInterface::close() {
|
void HidInterface::close() {
|
||||||
auto hidDevice = this->getHidDevice();
|
auto hidDevice = this->getHidDevice();
|
||||||
|
|
||||||
if (hidDevice != nullptr) {
|
if (hidDevice != nullptr) {
|
||||||
this->setLibUsbDeviceHandle(nullptr);
|
this->libUsbDeviceHandle = nullptr;
|
||||||
hid_close(hidDevice);
|
hid_close(hidDevice);
|
||||||
// hid_close() releases the interface
|
// hid_close() releases the interface
|
||||||
Interface::setClaimed(false);
|
this->claimed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hid_exit();
|
hid_exit();
|
||||||
@@ -80,8 +72,12 @@ void HidInterface::close() {
|
|||||||
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) {
|
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) {
|
||||||
int transferred;
|
int transferred;
|
||||||
|
|
||||||
if ((transferred = hid_read_timeout(this->getHidDevice(), buffer, maxLength,
|
if ((transferred = hid_read_timeout(
|
||||||
timeout == 0 ? -1 : static_cast<int>(timeout))) == -1
|
this->hidDevice,
|
||||||
|
buffer,
|
||||||
|
maxLength,
|
||||||
|
timeout == 0 ? -1 : static_cast<int>(timeout))
|
||||||
|
) == -1
|
||||||
) {
|
) {
|
||||||
throw DeviceCommunicationFailure("Failed to read from HID device.");
|
throw DeviceCommunicationFailure("Failed to read from HID device.");
|
||||||
}
|
}
|
||||||
@@ -89,16 +85,6 @@ std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, uns
|
|||||||
return static_cast<std::size_t>(transferred);
|
return static_cast<std::size_t>(transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HidInterface::write(unsigned char* buffer, std::size_t length) {
|
|
||||||
int transferred;
|
|
||||||
|
|
||||||
if ((transferred = hid_write(this->getHidDevice(), buffer, 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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidInterface::write(std::vector<unsigned char> buffer) {
|
void HidInterface::write(std::vector<unsigned char> buffer) {
|
||||||
if (buffer.size() > this->getInputReportSize()) {
|
if (buffer.size() > this->getInputReportSize()) {
|
||||||
throw Exception("Cannot send data via HID interface - data exceeds maximum packet size.");
|
throw Exception("Cannot send data via HID interface - data exceeds maximum packet size.");
|
||||||
@@ -111,7 +97,14 @@ void HidInterface::write(std::vector<unsigned char> buffer) {
|
|||||||
buffer.resize(this->getInputReportSize(), 0);
|
buffer.resize(this->getInputReportSize(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->write(buffer.data(), buffer.size());
|
int transferred;
|
||||||
|
auto length = buffer.size();
|
||||||
|
|
||||||
|
if ((transferred = hid_write(this->getHidDevice(), 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::vector<unsigned char> HidInterface::read(unsigned int timeout) {
|
std::vector<unsigned char> HidInterface::read(unsigned int timeout) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
namespace Bloom::Usb
|
namespace Bloom::Usb
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The HIDInterface uses the HIDAPI library to implement communication with HID endpoints.
|
* The HidInterface uses the HIDAPI library to implement communication with HID endpoints.
|
||||||
*
|
*
|
||||||
* Currently, this interface only supports single-report HID implementations. HID interfaces with
|
* Currently, this interface only supports single-report HID implementations. HID interfaces with
|
||||||
* multiple reports will be supported as-and-when we need it.
|
* multiple reports will be supported as-and-when we need it.
|
||||||
@@ -48,6 +48,8 @@ namespace Bloom::Usb
|
|||||||
* Keeping this in the private scope to enforce use of vector<unsigned char>. See read()
|
* Keeping this in the private scope to enforce use of vector<unsigned char>. See read()
|
||||||
* method in public scope.
|
* method in public scope.
|
||||||
*
|
*
|
||||||
|
* @TODO: Do we really need this? Why not just have the one that accepts the vector. Review
|
||||||
|
*
|
||||||
* @param buffer
|
* @param buffer
|
||||||
* @param maxLength
|
* @param maxLength
|
||||||
* @param timeout
|
* @param timeout
|
||||||
@@ -57,17 +59,6 @@ namespace Bloom::Usb
|
|||||||
*/
|
*/
|
||||||
std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout);
|
std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout);
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes `length` bytes from `buffer` to HID output endpoint.
|
|
||||||
*
|
|
||||||
* Keeping this in the private scope to enforce use of vector<unsigned char>.
|
|
||||||
* @see write(std::vector<unsigned char> buffer);
|
|
||||||
*
|
|
||||||
* @param buffer
|
|
||||||
* @param length
|
|
||||||
*/
|
|
||||||
void write(unsigned char* buffer, std::size_t length);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
hid_device* getHidDevice() const {
|
hid_device* getHidDevice() const {
|
||||||
return this->hidDevice;
|
return this->hidDevice;
|
||||||
@@ -79,14 +70,17 @@ namespace Bloom::Usb
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Claims the USB HID interface, obtains a hid_device instance and configures
|
* Claims the USB HID interface and obtains a hid_device instance
|
||||||
*/
|
*/
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the hid_device and releases any claimed interfaces (via hid_close())
|
||||||
|
*/
|
||||||
void close() override;
|
void close() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for write(unsigned char *buffer, int length)
|
* Writes buffer to HID output endpoint.
|
||||||
*
|
*
|
||||||
* @param buffer
|
* @param buffer
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,82 +11,45 @@ using namespace Bloom::Exceptions;
|
|||||||
|
|
||||||
|
|
||||||
void Interface::init() {
|
void Interface::init() {
|
||||||
libusb_device_descriptor deviceDescriptor = {};
|
if (this->libUsbDevice == nullptr) {
|
||||||
auto deviceHandle = this->getLibUsbDeviceHandle();
|
throw Exception("Cannot initialise interface without libusb device pointer.");
|
||||||
auto libUsbDevice = this->getUSBDevice();
|
|
||||||
int libUsbStatusCode;
|
|
||||||
|
|
||||||
if (libUsbDevice == nullptr) {
|
|
||||||
throw Exception("Cannot open USB device without libusb device pointer.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceHandle == nullptr) {
|
if (this->libUsbDeviceHandle == nullptr) {
|
||||||
// Obtain a device handle from libusb
|
throw Exception("Cannot initialise interface without libusb device handle.");
|
||||||
if ((libUsbStatusCode = libusb_open(libUsbDevice, &deviceHandle)) < 0) {
|
|
||||||
throw Exception("Failed to open USB device - error code "
|
|
||||||
+ std::to_string(libUsbStatusCode) + " returned.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((libUsbStatusCode = libusb_get_device_descriptor(libUsbDevice, &deviceDescriptor))) {
|
this->initialised = true;
|
||||||
throw Exception("Failed to obtain USB device descriptor - error code "
|
|
||||||
+ std::to_string(libUsbStatusCode) + " returned.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->setLibUsbDeviceHandle(deviceHandle);
|
|
||||||
this->setInitialised(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::setConfiguration(int configIndex) {
|
|
||||||
libusb_config_descriptor* configDescriptor = {};
|
|
||||||
int libUsbStatusCode;
|
|
||||||
|
|
||||||
if ((libUsbStatusCode = libusb_get_config_descriptor(this->getUSBDevice(), 0, &configDescriptor))) {
|
|
||||||
throw Exception("Failed to obtain USB configuration descriptor - error code "
|
|
||||||
+ std::to_string(libUsbStatusCode) + " returned.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((libUsbStatusCode = libusb_set_configuration(this->getLibUsbDeviceHandle(), configDescriptor->bConfigurationValue))) {
|
|
||||||
throw Exception("Failed to set USB configuration - error code "
|
|
||||||
+ std::to_string(libUsbStatusCode) + " returned.");
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_free_config_descriptor(configDescriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::close() {
|
void Interface::close() {
|
||||||
auto deviceHandle = this->getLibUsbDeviceHandle();
|
if (this->libUsbDeviceHandle != nullptr) {
|
||||||
this->release();
|
this->release();
|
||||||
|
|
||||||
if (deviceHandle != nullptr) {
|
|
||||||
libusb_close(deviceHandle);
|
|
||||||
this->setLibUsbDeviceHandle(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setInitialised(false);
|
this->initialised = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::claim() {
|
void Interface::claim() {
|
||||||
int interfaceNumber = this->getNumber();
|
int interfaceNumber = this->getNumber();
|
||||||
int libUsbStatusCode = 0;
|
|
||||||
|
|
||||||
this->detachKernelDriver();
|
this->detachKernelDriver();
|
||||||
|
|
||||||
if (libusb_claim_interface(this->getLibUsbDeviceHandle(), interfaceNumber) != 0) {
|
if (libusb_claim_interface(this->libUsbDeviceHandle, interfaceNumber) != 0) {
|
||||||
throw Exception("Failed to claim interface {" + std::to_string(interfaceNumber) + "} on USB device\n");
|
throw Exception("Failed to claim interface {" + std::to_string(interfaceNumber) + "} on USB device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setClaimed(true);
|
this->claimed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::detachKernelDriver() {
|
void Interface::detachKernelDriver() {
|
||||||
int interfaceNumber = this->getNumber();
|
int interfaceNumber = this->getNumber();
|
||||||
int libUsbStatusCode;
|
int libUsbStatusCode;
|
||||||
|
|
||||||
if ((libUsbStatusCode = libusb_kernel_driver_active(this->getLibUsbDeviceHandle(), interfaceNumber)) != 0) {
|
if ((libUsbStatusCode = libusb_kernel_driver_active(this->libUsbDeviceHandle, interfaceNumber)) != 0) {
|
||||||
if (libUsbStatusCode == 1) {
|
if (libUsbStatusCode == 1) {
|
||||||
// A kernel driver is active on this interface. Attempt to detach it
|
// A kernel driver is active on this interface. Attempt to detach it
|
||||||
if (libusb_detach_kernel_driver(this->getLibUsbDeviceHandle(), interfaceNumber) != 0) {
|
if (libusb_detach_kernel_driver(this->libUsbDeviceHandle, interfaceNumber) != 0) {
|
||||||
throw Exception("Failed to detach kernel driver from interface " +
|
throw Exception("Failed to detach kernel driver from interface " +
|
||||||
std::to_string(interfaceNumber) + "\n");
|
std::to_string(interfaceNumber) + "\n");
|
||||||
}
|
}
|
||||||
@@ -98,11 +61,11 @@ void Interface::detachKernelDriver() {
|
|||||||
|
|
||||||
void Interface::release() {
|
void Interface::release() {
|
||||||
if (this->isClaimed()) {
|
if (this->isClaimed()) {
|
||||||
if (libusb_release_interface(this->getLibUsbDeviceHandle(), this->getNumber()) != 0) {
|
if (libusb_release_interface(this->libUsbDeviceHandle, this->getNumber()) != 0) {
|
||||||
throw Exception("Failed to release interface {" + std::to_string(this->getNumber()) + "} on USB device\n");
|
throw Exception("Failed to release interface {" + std::to_string(this->getNumber()) + "} on USB device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setClaimed(false);
|
this->claimed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +76,7 @@ int Interface::read(unsigned char* buffer, unsigned char endPoint, size_t length
|
|||||||
|
|
||||||
while (length > totalTransferred) {
|
while (length > totalTransferred) {
|
||||||
libUsbStatusCode = libusb_interrupt_transfer(
|
libUsbStatusCode = libusb_interrupt_transfer(
|
||||||
this->getLibUsbDeviceHandle(),
|
this->libUsbDeviceHandle,
|
||||||
endPoint,
|
endPoint,
|
||||||
buffer,
|
buffer,
|
||||||
static_cast<int>(length),
|
static_cast<int>(length),
|
||||||
@@ -136,7 +99,7 @@ void Interface::write(unsigned char* buffer, unsigned char endPoint, int length)
|
|||||||
int libUsbStatusCode = 0;
|
int libUsbStatusCode = 0;
|
||||||
|
|
||||||
libUsbStatusCode = libusb_interrupt_transfer(
|
libUsbStatusCode = libusb_interrupt_transfer(
|
||||||
this->getLibUsbDeviceHandle(),
|
this->libUsbDeviceHandle,
|
||||||
endPoint,
|
endPoint,
|
||||||
buffer,
|
buffer,
|
||||||
length,
|
length,
|
||||||
|
|||||||
@@ -10,46 +10,26 @@ namespace Bloom::Usb
|
|||||||
{
|
{
|
||||||
class Interface
|
class Interface
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
libusb_device* USBDevice = nullptr;
|
libusb_device* libUsbDevice = nullptr;
|
||||||
|
libusb_device_handle* libUsbDeviceHandle = nullptr;
|
||||||
|
|
||||||
std::uint16_t vendorId = 0;
|
std::uint16_t vendorId = 0;
|
||||||
std::uint16_t productId = 0;
|
std::uint16_t productId = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* With libusb, we can only claim a single USB interface per device handle. For this reason,
|
|
||||||
* device handles are stored against the interface. Each interface must obtain a new handle before
|
|
||||||
* claiming.
|
|
||||||
*/
|
|
||||||
libusb_device_handle* libUsbDeviceHandle = nullptr;
|
|
||||||
std::uint8_t number = 0;
|
std::uint8_t number = 0;
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
|
|
||||||
bool initialised = false;
|
bool initialised = false;
|
||||||
bool claimed = false;
|
bool claimed = false;
|
||||||
|
|
||||||
void setInitialised(bool initialised) {
|
|
||||||
this->initialised = initialised;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setClaimed(bool claimed) {
|
|
||||||
this->claimed = claimed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Interface(const std::uint8_t& interfaceNumber = 0) {
|
explicit Interface(const std::uint8_t& interfaceNumber = 0) {
|
||||||
this->setNumber(interfaceNumber);
|
this->setNumber(interfaceNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
libusb_device* getUSBDevice() const {
|
void setLibUsbDevice(libusb_device* libUsbDevice) {
|
||||||
return this->USBDevice;
|
this->libUsbDevice = libUsbDevice;
|
||||||
}
|
|
||||||
|
|
||||||
void setUSBDevice(libusb_device* USBDevice) {
|
|
||||||
this->USBDevice = USBDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_device_handle* getLibUsbDeviceHandle() const {
|
|
||||||
return this->libUsbDeviceHandle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLibUsbDeviceHandle(libusb_device_handle* libUsbDeviceHandle) {
|
void setLibUsbDeviceHandle(libusb_device_handle* libUsbDeviceHandle) {
|
||||||
@@ -101,8 +81,6 @@ namespace Bloom::Usb
|
|||||||
*/
|
*/
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
virtual void setConfiguration(int configIndex);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the interface and closes the device descriptor.
|
* Releases the interface and closes the device descriptor.
|
||||||
*/
|
*/
|
||||||
@@ -112,7 +90,15 @@ namespace Bloom::Usb
|
|||||||
* Attempts to claim the interface
|
* Attempts to claim the interface
|
||||||
*/
|
*/
|
||||||
void claim();
|
void claim();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a kernel driver is attached to the interface, this method will detach it.
|
||||||
|
*/
|
||||||
void detachKernelDriver();
|
void detachKernelDriver();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the interface, if claimed.
|
||||||
|
*/
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <filesystem>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <linux/usbdevice_fs.h>
|
|
||||||
#include <libusb-1.0/libusb.h>
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
#include "UsbDevice.hpp"
|
#include "UsbDevice.hpp"
|
||||||
@@ -48,8 +43,7 @@ std::vector<libusb_device*> UsbDevice::findMatchingDevices(
|
|||||||
return matchedDevices;
|
return matchedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsbDevice::init()
|
void UsbDevice::init() {
|
||||||
{
|
|
||||||
libusb_init(&this->libUsbContext);
|
libusb_init(&this->libUsbContext);
|
||||||
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
|
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
|
||||||
auto devices = this->findMatchingDevices();
|
auto devices = this->findMatchingDevices();
|
||||||
@@ -66,12 +60,42 @@ void UsbDevice::init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For now, just use the first device found.
|
// For now, just use the first device found.
|
||||||
this->setLibUsbDevice(devices.front());
|
auto device = devices.front();
|
||||||
|
this->setLibUsbDevice(device);
|
||||||
|
|
||||||
|
int libUsbStatusCode;
|
||||||
|
|
||||||
|
// Obtain a device handle from libusb
|
||||||
|
if ((libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle)) < 0) {
|
||||||
|
throw Exception("Failed to open USB device - error code " + std::to_string(libUsbStatusCode)
|
||||||
|
+ " returned.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsbDevice::close()
|
void UsbDevice::close() {
|
||||||
{
|
if (this->libUsbDeviceHandle != nullptr) {
|
||||||
|
libusb_close(this->libUsbDeviceHandle);
|
||||||
|
this->libUsbDeviceHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->libUsbContext != nullptr) {
|
if (this->libUsbContext != nullptr) {
|
||||||
libusb_exit(this->libUsbContext);
|
libusb_exit(this->libUsbContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UsbDevice::setConfiguration(int configIndex) {
|
||||||
|
libusb_config_descriptor* configDescriptor = {};
|
||||||
|
int libUsbStatusCode;
|
||||||
|
|
||||||
|
if ((libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor))) {
|
||||||
|
throw Exception("Failed to obtain USB configuration descriptor - error code "
|
||||||
|
+ std::to_string(libUsbStatusCode) + " returned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue))) {
|
||||||
|
throw Exception("Failed to set USB configuration - error code "
|
||||||
|
+ std::to_string(libUsbStatusCode) + " returned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_free_config_descriptor(configDescriptor);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ namespace Bloom::Usb
|
|||||||
{
|
{
|
||||||
class UsbDevice
|
class UsbDevice
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
libusb_context* libUsbContext = nullptr;
|
libusb_context* libUsbContext = nullptr;
|
||||||
libusb_device* libUsbDevice = nullptr;
|
libusb_device* libUsbDevice = nullptr;
|
||||||
|
libusb_device_handle* libUsbDeviceHandle = nullptr;
|
||||||
std::uint16_t vendorId;
|
std::uint16_t vendorId;
|
||||||
std::uint16_t productId;
|
std::uint16_t productId;
|
||||||
|
|
||||||
@@ -22,7 +23,6 @@ namespace Bloom::Usb
|
|||||||
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt
|
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt
|
||||||
);
|
);
|
||||||
|
|
||||||
protected:
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -50,5 +50,12 @@ namespace Bloom::Usb
|
|||||||
std::uint16_t getProductId() const {
|
std::uint16_t getProductId() const {
|
||||||
return this->productId;
|
return this->productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects a specific configuration on the device, using the configuration index.
|
||||||
|
*
|
||||||
|
* @param configIndex
|
||||||
|
*/
|
||||||
|
virtual void setConfiguration(int configIndex);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user