diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.cpp b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp index 16d82568..7de77861 100644 --- a/src/DebugToolDrivers/Microchip/EdbgDevice.cpp +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp @@ -40,7 +40,9 @@ namespace DebugToolDrivers::Microchip auto cmsisHidInterface = Usb::HidInterface( this->cmsisHidInterfaceNumber, - this->getCmsisHidReportSize(), + this->getEndpointMaxPacketSize( + this->getFirstEndpointAddress(this->cmsisHidInterfaceNumber, LIBUSB_ENDPOINT_IN) + ), this->vendorId, this->productId ); @@ -157,33 +159,4 @@ namespace DebugToolDrivers::Microchip this->sessionStarted = false; } - - std::uint16_t EdbgDevice::getCmsisHidReportSize() { - const auto activeConfigDescriptor = this->getConfigDescriptor(); - - for (auto interfaceIndex = 0; interfaceIndex < activeConfigDescriptor->bNumInterfaces; ++interfaceIndex) { - const auto* interfaceDescriptor = (activeConfigDescriptor->interface + interfaceIndex)->altsetting; - - if (interfaceDescriptor->bInterfaceNumber != this->cmsisHidInterfaceNumber) { - continue; - } - - for (auto endpointIndex = 0; endpointIndex < activeConfigDescriptor->bNumInterfaces; ++endpointIndex) { - const auto* endpointDescriptor = (interfaceDescriptor->endpoint + endpointIndex); - - if ((endpointDescriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) != LIBUSB_ENDPOINT_IN) { - // Not an IN endpoint - continue; - } - - return endpointDescriptor->wMaxPacketSize; - } - } - - throw DeviceInitializationFailure( - "Failed to obtain CMSIS-DAP HID report size via endpoint descriptor - could not find IN endpoint for " - "selected configuration value (" + std::to_string(activeConfigDescriptor->bConfigurationValue) - + ") and interface number (" + std::to_string(this->cmsisHidInterfaceNumber) + ")" - ); - } } diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.hpp b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp index 9d953d2f..73818daf 100644 --- a/src/DebugToolDrivers/Microchip/EdbgDevice.hpp +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp @@ -155,17 +155,6 @@ namespace DebugToolDrivers::Microchip bool sessionStarted = false; - /** - * Because EDBG devices require fixed-length reports to be transmitted to/from their HID interface, we must - * know the HID report size (as it differs across EDBG devices). - * - * This member function will obtain the report size from the endpoint descriptor of the IN endpoint, from the - * HID interface. - * - * @return - */ - std::uint16_t getCmsisHidReportSize(); - virtual void configureAvr8Interface() { return; } diff --git a/src/DebugToolDrivers/USB/UsbDevice.cpp b/src/DebugToolDrivers/USB/UsbDevice.cpp index cf47e736..c45e1c06 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.cpp +++ b/src/DebugToolDrivers/USB/UsbDevice.cpp @@ -4,6 +4,8 @@ #include #include "src/Logger/Logger.hpp" +#include "src/Services/StringService.hpp" + #include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" #include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp" #include "src/TargetController/Exceptions/DeviceNotFound.hpp" @@ -100,6 +102,53 @@ namespace Usb } } + std::uint8_t UsbDevice::getFirstEndpointAddress( + std::uint8_t interfaceNumber, + ::libusb_endpoint_direction direction + ) { + const auto activeConfigDescriptor = this->getConfigDescriptor(); + + for (auto interfaceIndex = 0; interfaceIndex < activeConfigDescriptor->bNumInterfaces; ++interfaceIndex) { + const auto* interfaceDescriptor = (activeConfigDescriptor->interface + interfaceIndex)->altsetting; + + if (interfaceDescriptor->bInterfaceNumber != interfaceNumber) { + continue; + } + + for (auto endpointIndex = 0; endpointIndex < interfaceDescriptor->bNumEndpoints; ++endpointIndex) { + const auto* endpointDescriptor = (interfaceDescriptor->endpoint + endpointIndex); + + if ((endpointDescriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) != direction) { + return endpointDescriptor->bEndpointAddress; + } + } + } + + throw DeviceInitializationFailure("Failed to obtain address of USB endpoint"); + } + + std::uint16_t UsbDevice::getEndpointMaxPacketSize(std::uint8_t endpointAddress) { + const auto activeConfigDescriptor = this->getConfigDescriptor(); + + for (auto interfaceIndex = 0; interfaceIndex < activeConfigDescriptor->bNumInterfaces; ++interfaceIndex) { + const auto* interfaceDescriptor = (activeConfigDescriptor->interface + interfaceIndex)->altsetting; + + for (auto endpointIndex = 0; endpointIndex < interfaceDescriptor->bNumEndpoints; ++endpointIndex) { + const auto* endpointDescriptor = (interfaceDescriptor->endpoint + endpointIndex); + + if (endpointDescriptor->bEndpointAddress == endpointAddress) { + return endpointDescriptor->wMaxPacketSize; + } + } + } + + throw DeviceInitializationFailure( + "Failed to obtain maximum packet size of USB endpoint (address: 0x" + + Services::StringService::toHex(endpointAddress) + "). Endpoint not found. Selected configuration " + "value (" + std::to_string(activeConfigDescriptor->bConfigurationValue) + ")" + ); + } + std::vector UsbDevice::findMatchingDevices(std::uint16_t vendorId, std::uint16_t productId) { ::libusb_device** devices = nullptr; ::libusb_device* device; diff --git a/src/DebugToolDrivers/USB/UsbDevice.hpp b/src/DebugToolDrivers/USB/UsbDevice.hpp index 1e0aed42..acccdea1 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.hpp +++ b/src/DebugToolDrivers/USB/UsbDevice.hpp @@ -38,6 +38,22 @@ namespace Usb */ std::string getSerialNumber() const; + /** + * Obtains the address of the first endpoint within a given interface and of a particular direction. + * + * @param endpointAddress + * @return + */ + std::uint8_t getFirstEndpointAddress(std::uint8_t interfaceNumber, ::libusb_endpoint_direction direction); + + /** + * Obtains the maximum packet size of an endpoint. + * + * @param endpointAddress + * @return + */ + std::uint16_t getEndpointMaxPacketSize(std::uint8_t endpointAddress); + /** * Selects a specific configuration on the device, using the configuration index. * diff --git a/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.cpp b/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.cpp index 59495440..067830e3 100644 --- a/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.cpp +++ b/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.cpp @@ -21,8 +21,10 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink using Targets::RiscV::DebugModule::DmiOperation; - WchLinkInterface::WchLinkInterface(Usb::UsbInterface& usbInterface) + WchLinkInterface::WchLinkInterface(Usb::UsbInterface& usbInterface, Usb::UsbDevice& usbDevice) : usbInterface(usbInterface) + , commandEndpointMaxPacketSize(usbDevice.getEndpointMaxPacketSize(WchLinkInterface::USB_COMMAND_ENDPOINT_OUT)) + , dataEndpointMaxPacketSize(usbDevice.getEndpointMaxPacketSize(WchLinkInterface::USB_DATA_ENDPOINT_OUT)) {} DeviceInfo WchLinkInterface::getDeviceInfo() { diff --git a/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.hpp b/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.hpp index 55d75b5d..3d18e400 100644 --- a/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.hpp +++ b/src/DebugToolDrivers/WCH/Protocols/WchLink/WchLinkInterface.hpp @@ -3,9 +3,11 @@ #include #include #include +#include #include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp" #include "src/DebugToolDrivers/USB/UsbInterface.hpp" +#include "src/DebugToolDrivers/USB/UsbDevice.hpp" #include "src/DebugToolDrivers/WCH/WchGeneric.hpp" #include "Commands/Command.hpp" @@ -23,7 +25,7 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink class WchLinkInterface: public TargetInterfaces::RiscV::RiscVDebugInterface { public: - explicit WchLinkInterface(Usb::UsbInterface& usbInterface); + WchLinkInterface(Usb::UsbInterface& usbInterface, Usb::UsbDevice& usbDevice); DeviceInfo getDeviceInfo(); @@ -43,11 +45,16 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink ) override; private: - static constexpr std::uint8_t USB_ENDPOINT_IN = 0x81; - static constexpr std::uint8_t USB_ENDPOINT_OUT = 0x01; + static constexpr std::uint8_t USB_COMMAND_ENDPOINT_IN = 0x81; + static constexpr std::uint8_t USB_COMMAND_ENDPOINT_OUT = 0x01; + static constexpr std::uint8_t USB_DATA_ENDPOINT_IN = 0x82; + static constexpr std::uint8_t USB_DATA_ENDPOINT_OUT = 0x02; Usb::UsbInterface& usbInterface; + std::uint16_t commandEndpointMaxPacketSize = 0; + std::uint16_t dataEndpointMaxPacketSize = 0; + /** * The 'target activation' command returns a payload of 5 bytes. * @@ -67,9 +74,17 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink template auto sendCommandAndWaitForResponse(const CommandType& command) { - this->usbInterface.writeBulk(WchLinkInterface::USB_ENDPOINT_OUT, command.getRawCommand()); + auto rawCommand = command.getRawCommand(); - const auto rawResponse = this->usbInterface.readBulk(WchLinkInterface::USB_ENDPOINT_IN); + if (rawCommand.size() > this->commandEndpointMaxPacketSize) { + throw Exceptions::DeviceCommunicationFailure( + "Raw command size exceeds maximum packet size for command endpoint" + ); + } + + this->usbInterface.writeBulk(WchLinkInterface::USB_COMMAND_ENDPOINT_OUT, std::move(rawCommand)); + + const auto rawResponse = this->usbInterface.readBulk(WchLinkInterface::USB_COMMAND_ENDPOINT_IN); if (rawResponse.size() < 3) { throw Exceptions::DeviceCommunicationFailure("Invalid response size from device"); diff --git a/src/DebugToolDrivers/WCH/WchLinkBase.cpp b/src/DebugToolDrivers/WCH/WchLinkBase.cpp index 4c5e38d4..28813d07 100644 --- a/src/DebugToolDrivers/WCH/WchLinkBase.cpp +++ b/src/DebugToolDrivers/WCH/WchLinkBase.cpp @@ -32,7 +32,8 @@ namespace DebugToolDrivers::Wch this->wchLinkUsbInterface->init(); this->wchLinkInterface = std::make_unique( - *(this->wchLinkUsbInterface.get()) + *(this->wchLinkUsbInterface.get()), + *this ); if (this->getDeviceInfo().variant != this->variant) {