Added UsbInterface class to access non-HID USB interfaces
This commit is contained in:
@@ -2,6 +2,7 @@ target_sources(
|
|||||||
Bloom
|
Bloom
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/USB/UsbDevice.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/USB/UsbDevice.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/USB/UsbInterface.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/USB/HID/HidInterface.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/USB/HID/HidInterface.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Protocols/CMSIS-DAP/CmsisDapInterface.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Protocols/CMSIS-DAP/CmsisDapInterface.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Protocols/CMSIS-DAP/Command.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Protocols/CMSIS-DAP/Command.cpp
|
||||||
|
|||||||
112
src/DebugToolDrivers/USB/UsbInterface.cpp
Normal file
112
src/DebugToolDrivers/USB/UsbInterface.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "UsbInterface.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
||||||
|
#include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp"
|
||||||
|
|
||||||
|
namespace Usb
|
||||||
|
{
|
||||||
|
using namespace Exceptions;
|
||||||
|
|
||||||
|
UsbInterface::UsbInterface(
|
||||||
|
std::uint8_t interfaceNumber,
|
||||||
|
::libusb_device_handle* deviceHandle
|
||||||
|
)
|
||||||
|
: interfaceNumber(interfaceNumber)
|
||||||
|
, deviceHandle(deviceHandle)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void UsbInterface::init() {
|
||||||
|
Logger::debug("Claiming USB interface (number: " + std::to_string(this->interfaceNumber) + ")");
|
||||||
|
|
||||||
|
const auto statusCode = ::libusb_claim_interface(this->deviceHandle, this->interfaceNumber);
|
||||||
|
if (statusCode != 0) {
|
||||||
|
throw DeviceInitializationFailure(
|
||||||
|
"Failed to claim USB interface (number: " + std::to_string(this->interfaceNumber) + ") - error code: "
|
||||||
|
+ std::to_string(statusCode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->claimed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbInterface::close() {
|
||||||
|
if (this->claimed) {
|
||||||
|
const auto statusCode = ::libusb_release_interface(this->deviceHandle, this->interfaceNumber);
|
||||||
|
if (statusCode != 0) {
|
||||||
|
Logger::error(
|
||||||
|
"Failed to release USB interface (number: " + std::to_string(this->interfaceNumber)
|
||||||
|
+ ") - error code: " + std::to_string(statusCode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> UsbInterface::readBulk(
|
||||||
|
std::uint8_t endpointAddress,
|
||||||
|
std::optional<std::chrono::milliseconds> timeout
|
||||||
|
) {
|
||||||
|
auto output = std::vector<unsigned char>();
|
||||||
|
|
||||||
|
constexpr auto transferSize = 512;
|
||||||
|
auto bytesTransferred = int(0);
|
||||||
|
auto totalByteCount = std::size_t(0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
output.resize(totalByteCount + transferSize, 0x00);
|
||||||
|
|
||||||
|
const auto statusCode = ::libusb_bulk_transfer(
|
||||||
|
this->deviceHandle,
|
||||||
|
endpointAddress,
|
||||||
|
output.data() + totalByteCount,
|
||||||
|
transferSize,
|
||||||
|
&bytesTransferred,
|
||||||
|
timeout.has_value() ? static_cast<unsigned int>(timeout->count()) : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (statusCode != 0) {
|
||||||
|
throw DeviceCommunicationFailure("Failed to read from bulk endpoint");
|
||||||
|
}
|
||||||
|
|
||||||
|
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>(bytesTransferred);
|
||||||
|
|
||||||
|
} while (bytesTransferred >= transferSize);
|
||||||
|
|
||||||
|
output.resize(totalByteCount, 0x00);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbInterface::writeBulk(std::uint8_t endpointAddress, std::vector<unsigned char>&& buffer) {
|
||||||
|
if (buffer.size() > std::numeric_limits<int>::max()) {
|
||||||
|
throw DeviceCommunicationFailure("Attempted to send too much data to bulk endpoint");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto length = static_cast<int>(buffer.size());
|
||||||
|
auto bytesTransferred = int(0);
|
||||||
|
|
||||||
|
const auto statusCode = ::libusb_bulk_transfer(
|
||||||
|
this->deviceHandle,
|
||||||
|
endpointAddress,
|
||||||
|
buffer.data(),
|
||||||
|
length,
|
||||||
|
&bytesTransferred,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (statusCode != 0 || bytesTransferred != length) {
|
||||||
|
Logger::debug(
|
||||||
|
"Attempted to write " + std::to_string(length) + " bytes to USB bulk endpoint. Bytes written: "
|
||||||
|
+ std::to_string(bytesTransferred) + ". Status code: " + std::to_string(statusCode)
|
||||||
|
);
|
||||||
|
throw DeviceCommunicationFailure("Failed to write data to bulk endpoint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/DebugToolDrivers/USB/UsbInterface.hpp
Normal file
52
src/DebugToolDrivers/USB/UsbInterface.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
|
namespace Usb
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The UsbInterface provides access to a particular USB interface.
|
||||||
|
*/
|
||||||
|
class UsbInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::uint8_t interfaceNumber = 0;
|
||||||
|
|
||||||
|
UsbInterface(
|
||||||
|
std::uint8_t interfaceNumber,
|
||||||
|
::libusb_device_handle* deviceHandle
|
||||||
|
);
|
||||||
|
|
||||||
|
UsbInterface(const UsbInterface& other) = delete;
|
||||||
|
UsbInterface& operator = (const UsbInterface& other) = delete;
|
||||||
|
|
||||||
|
UsbInterface(UsbInterface&& other) = default;
|
||||||
|
UsbInterface& operator = (UsbInterface&& other) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to claim the interface
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the claimed interface
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
|
|
||||||
|
std::vector<unsigned char> readBulk(
|
||||||
|
std::uint8_t endpointAddress,
|
||||||
|
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||||
|
);
|
||||||
|
|
||||||
|
void writeBulk(std::uint8_t endpointAddress, std::vector<unsigned char>&& buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
::libusb_device_handle* deviceHandle;
|
||||||
|
bool claimed = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user