Tidied structure of all classes within the entire code base
Also some other small bits of tidying
This commit is contained in:
@@ -1,36 +1,13 @@
|
||||
#include "HidInterface.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "hidapi.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
||||
#include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp"
|
||||
|
||||
using namespace Bloom::Usb;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) {
|
||||
hid_device_info* hidDeviceInfoList = hid_enumerate(this->getVendorId(), this->getProductId());
|
||||
|
||||
while (hidDeviceInfoList != nullptr) {
|
||||
if (hidDeviceInfoList->interface_number == interfaceNumber) {
|
||||
break;
|
||||
}
|
||||
|
||||
hidDeviceInfoList = hidDeviceInfoList->next;
|
||||
}
|
||||
|
||||
if (hidDeviceInfoList == nullptr) {
|
||||
throw DeviceInitializationFailure("Failed to match interface number with HID interface.");
|
||||
}
|
||||
|
||||
auto path = std::string(hidDeviceInfoList->path);
|
||||
hid_free_enumeration(hidDeviceInfoList);
|
||||
return path;
|
||||
}
|
||||
|
||||
void HidInterface::init() {
|
||||
if (this->libUsbDevice == nullptr) {
|
||||
throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer.");
|
||||
@@ -72,20 +49,24 @@ void HidInterface::close() {
|
||||
Interface::close();
|
||||
}
|
||||
|
||||
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) {
|
||||
int transferred;
|
||||
std::vector<unsigned char> HidInterface::read(unsigned int timeout) {
|
||||
std::vector<unsigned char> output;
|
||||
auto readSize = this->getInputReportSize();
|
||||
|
||||
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.");
|
||||
// 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;
|
||||
|
||||
while (transferredByteCount >= readSize) {
|
||||
output.resize(totalByteCount + readSize);
|
||||
|
||||
transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1);
|
||||
totalByteCount += transferredByteCount;
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>(transferred);
|
||||
output.resize(totalByteCount);
|
||||
return output;
|
||||
}
|
||||
|
||||
void HidInterface::write(std::vector<unsigned char> buffer) {
|
||||
@@ -107,27 +88,43 @@ void HidInterface::write(std::vector<unsigned char> buffer) {
|
||||
|
||||
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));
|
||||
+ " 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> output;
|
||||
auto readSize = this->getInputReportSize();
|
||||
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) {
|
||||
int transferred;
|
||||
|
||||
// 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;
|
||||
|
||||
while (transferredByteCount >= readSize) {
|
||||
output.resize(totalByteCount + readSize);
|
||||
|
||||
transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1);
|
||||
totalByteCount += transferredByteCount;
|
||||
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.");
|
||||
}
|
||||
|
||||
output.resize(totalByteCount);
|
||||
return output;
|
||||
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());
|
||||
|
||||
while (hidDeviceInfoList != nullptr) {
|
||||
if (hidDeviceInfoList->interface_number == interfaceNumber) {
|
||||
break;
|
||||
}
|
||||
|
||||
hidDeviceInfoList = hidDeviceInfoList->next;
|
||||
}
|
||||
|
||||
if (hidDeviceInfoList == nullptr) {
|
||||
throw DeviceInitializationFailure("Failed to match interface number with HID interface.");
|
||||
}
|
||||
|
||||
auto path = std::string(hidDeviceInfoList->path);
|
||||
hid_free_enumeration(hidDeviceInfoList);
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,54 @@ namespace Bloom::Usb
|
||||
*/
|
||||
class HidInterface: public Interface
|
||||
{
|
||||
public:
|
||||
std::size_t getInputReportSize() const {
|
||||
return this->inputReportSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims the USB HID interface and obtains a hid_device instance
|
||||
*/
|
||||
void init() override;
|
||||
|
||||
/**
|
||||
* Closes the hid_device and releases any claimed interfaces (via hid_close())
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Writes buffer to HID output endpoint.
|
||||
*
|
||||
* @param buffer
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* The HIDAPI library provides a hid_device data structure to represent a USB HID interface.
|
||||
@@ -58,53 +106,5 @@ namespace Bloom::Usb
|
||||
* Number of bytes read.
|
||||
*/
|
||||
std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout);
|
||||
|
||||
protected:
|
||||
hid_device* getHidDevice() const {
|
||||
return this->hidDevice;
|
||||
}
|
||||
|
||||
public:
|
||||
std::size_t getInputReportSize() const {
|
||||
return this->inputReportSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims the USB HID interface and obtains a hid_device instance
|
||||
*/
|
||||
void init() override;
|
||||
|
||||
/**
|
||||
* Closes the hid_device and releases any claimed interfaces (via hid_close())
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
/**
|
||||
* Writes buffer to HID output endpoint.
|
||||
*
|
||||
* @param buffer
|
||||
*/
|
||||
void write(std::vector<unsigned char> buffer);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Resolves a device path from a USB interface number.
|
||||
*
|
||||
* @param interfaceNumber
|
||||
* @return
|
||||
*/
|
||||
std::string getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,19 +10,6 @@ namespace Bloom::Usb
|
||||
{
|
||||
class Interface
|
||||
{
|
||||
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;
|
||||
|
||||
public:
|
||||
explicit Interface(const std::uint8_t& interfaceNumber = 0) {
|
||||
this->setNumber(interfaceNumber);
|
||||
@@ -112,5 +99,18 @@ namespace Bloom::Usb
|
||||
*/
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,61 @@
|
||||
#include "UsbDevice.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
||||
|
||||
using Bloom::Usb::UsbDevice;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
void UsbDevice::init() {
|
||||
libusb_init(&this->libUsbContext);
|
||||
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
|
||||
auto devices = this->findMatchingDevices();
|
||||
|
||||
if (devices.empty()) {
|
||||
throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID.");
|
||||
|
||||
} else if (devices.size() > 1) {
|
||||
// TODO: implement support for multiple devices (maybe via serial number?)
|
||||
throw DeviceInitializationFailure(
|
||||
"Numerous devices of matching vendor & 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);
|
||||
|
||||
int libUsbStatusCode;
|
||||
|
||||
// Obtain a device handle from libusb
|
||||
if ((libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle)) < 0) {
|
||||
throw DeviceInitializationFailure(
|
||||
"Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void UsbDevice::setConfiguration(int configIndex) {
|
||||
libusb_config_descriptor* configDescriptor = {};
|
||||
int libUsbStatusCode;
|
||||
|
||||
if ((libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor))) {
|
||||
throw DeviceInitializationFailure(
|
||||
"Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
|
||||
if ((libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue))) {
|
||||
throw DeviceInitializationFailure(
|
||||
"Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned."
|
||||
);
|
||||
}
|
||||
|
||||
libusb_free_config_descriptor(configDescriptor);
|
||||
}
|
||||
|
||||
std::vector<libusb_device*> UsbDevice::findMatchingDevices(
|
||||
std::optional<std::uint16_t> vendorId, std::optional<std::uint16_t> productId
|
||||
) {
|
||||
@@ -45,36 +92,6 @@ std::vector<libusb_device*> UsbDevice::findMatchingDevices(
|
||||
return matchedDevices;
|
||||
}
|
||||
|
||||
void UsbDevice::init() {
|
||||
libusb_init(&this->libUsbContext);
|
||||
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
|
||||
auto devices = this->findMatchingDevices();
|
||||
|
||||
if (devices.empty()) {
|
||||
throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID.");
|
||||
|
||||
} else if (devices.size() > 1) {
|
||||
// TODO: implement support for multiple devices (maybe via serial number?)
|
||||
throw DeviceInitializationFailure(
|
||||
"Numerous devices of matching vendor & 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);
|
||||
|
||||
int libUsbStatusCode;
|
||||
|
||||
// Obtain a device handle from libusb
|
||||
if ((libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle)) < 0) {
|
||||
throw DeviceInitializationFailure(
|
||||
"Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void UsbDevice::close() {
|
||||
if (this->libUsbDeviceHandle != nullptr) {
|
||||
libusb_close(this->libUsbDeviceHandle);
|
||||
@@ -85,23 +102,3 @@ void UsbDevice::close() {
|
||||
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 DeviceInitializationFailure(
|
||||
"Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
|
||||
if ((libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue))) {
|
||||
throw DeviceInitializationFailure(
|
||||
"Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned."
|
||||
);
|
||||
}
|
||||
|
||||
libusb_free_config_descriptor(configDescriptor);
|
||||
}
|
||||
|
||||
@@ -12,25 +12,8 @@ namespace Bloom::Usb
|
||||
{
|
||||
class UsbDevice
|
||||
{
|
||||
protected:
|
||||
libusb_context* libUsbContext = nullptr;
|
||||
libusb_device* libUsbDevice = nullptr;
|
||||
libusb_device_handle* libUsbDeviceHandle = nullptr;
|
||||
std::uint16_t vendorId;
|
||||
std::uint16_t productId;
|
||||
|
||||
std::vector<libusb_device*> findMatchingDevices(
|
||||
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt
|
||||
);
|
||||
|
||||
void close();
|
||||
|
||||
public:
|
||||
UsbDevice(std::uint16_t vendorId, std::uint16_t productId) {
|
||||
this->vendorId = vendorId;
|
||||
this->productId = productId;
|
||||
};
|
||||
|
||||
UsbDevice(std::uint16_t vendorId, std::uint16_t productId): vendorId(vendorId), productId(productId) {};
|
||||
~UsbDevice() = default;
|
||||
|
||||
void init();
|
||||
@@ -57,5 +40,18 @@ namespace Bloom::Usb
|
||||
* @param configIndex
|
||||
*/
|
||||
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;
|
||||
|
||||
std::vector<libusb_device*> findMatchingDevices(
|
||||
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt
|
||||
);
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user