diff --git a/src/DebugToolDrivers/USB/UsbInterface.cpp b/src/DebugToolDrivers/USB/UsbInterface.cpp index 897e7ebd..45aeb935 100644 --- a/src/DebugToolDrivers/USB/UsbInterface.cpp +++ b/src/DebugToolDrivers/USB/UsbInterface.cpp @@ -1,5 +1,6 @@ #include "UsbInterface.hpp" +#include #include #include "src/Logger/Logger.hpp" @@ -84,29 +85,45 @@ namespace Usb return output; } - void UsbInterface::writeBulk(std::uint8_t endpointAddress, std::vector&& buffer) { - if (buffer.size() > std::numeric_limits::max()) { - throw DeviceCommunicationFailure{"Attempted to send too much data to bulk endpoint"}; - } + void UsbInterface::writeBulk( + std::uint8_t endpointAddress, + std::span buffer, + std::uint16_t maxPacketSize + ) { + assert(buffer.size() <= std::numeric_limits::max()); - const auto length = static_cast(buffer.size()); - auto bytesTransferred = int{0}; + const auto bufferSize = buffer.size(); + auto totalBytesTransferred = std::size_t{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) + while (totalBytesTransferred < bufferSize) { + auto bytesTransferred = int{0}; + const auto length = std::min( + static_cast(bufferSize - totalBytesTransferred), + static_cast(maxPacketSize) ); - throw DeviceCommunicationFailure{"Failed to write data to bulk endpoint"}; + + const auto statusCode = ::libusb_bulk_transfer( + this->deviceHandle, + endpointAddress, + /* + * I know, I know...this is horrible. I'm effectively lying about the constness of `buffer`. But libusb + * *shouldn't* write to `buffer` here, because we're not reading from the device. + */ + const_cast(buffer.data()) + totalBytesTransferred, + 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"}; + } + + totalBytesTransferred += static_cast(bytesTransferred); } } } diff --git a/src/DebugToolDrivers/USB/UsbInterface.hpp b/src/DebugToolDrivers/USB/UsbInterface.hpp index b812c972..2ced6497 100644 --- a/src/DebugToolDrivers/USB/UsbInterface.hpp +++ b/src/DebugToolDrivers/USB/UsbInterface.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -43,7 +44,11 @@ namespace Usb std::optional timeout = std::nullopt ); - void writeBulk(std::uint8_t endpointAddress, std::vector&& buffer); + void writeBulk( + std::uint8_t endpointAddress, + std::span buffer, + std::uint16_t maxPacketSize + ); private: ::libusb_device_handle* deviceHandle;