Retry DMI operations when BUSY status returned in WCH-Link driver

This commit is contained in:
Nav
2024-09-04 00:18:24 +01:00
parent ecf0bd8919
commit 9daa53ed45
2 changed files with 46 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
#include "WchLinkInterface.hpp" #include "WchLinkInterface.hpp"
#include <cassert> #include <cassert>
#include <thread>
#include "Commands/Control/GetDeviceInfo.hpp" #include "Commands/Control/GetDeviceInfo.hpp"
#include "Commands/Control/AttachTarget.hpp" #include "Commands/Control/AttachTarget.hpp"
@@ -79,15 +80,29 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
DebugModule::RegisterValue WchLinkInterface::readDebugModuleRegister(DebugModule::RegisterAddress address) { DebugModule::RegisterValue WchLinkInterface::readDebugModuleRegister(DebugModule::RegisterAddress address) {
using DebugModule::DmiOperationStatus; using DebugModule::DmiOperationStatus;
auto attempt = std::uint8_t{0};
while (attempt < WchLinkInterface::DMI_OP_MAX_RETRY) {
if (attempt > 0) {
std::this_thread::sleep_for(this->dmiOpRetryDelay);
}
const auto response = this->sendCommandAndWaitForResponse( const auto response = this->sendCommandAndWaitForResponse(
Commands::DebugModuleInterfaceOperation{DmiOperation::READ, address} Commands::DebugModuleInterfaceOperation{DmiOperation::READ, address}
); );
if (response.operationStatus != DmiOperationStatus::SUCCESS) { if (response.operationStatus == DmiOperationStatus::SUCCESS) {
return response.value;
}
if (response.operationStatus == DmiOperationStatus::FAILED) {
throw Exceptions::DeviceCommunicationFailure{"DMI operation failed"}; throw Exceptions::DeviceCommunicationFailure{"DMI operation failed"};
} }
return response.value; // Busy response...
++attempt;
}
throw Exceptions::DeviceCommunicationFailure{"DMI operation timed out"};
} }
void WchLinkInterface::writeDebugModuleRegister( void WchLinkInterface::writeDebugModuleRegister(
@@ -96,13 +111,29 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
) { ) {
using DebugModule::DmiOperationStatus; using DebugModule::DmiOperationStatus;
auto attempt = std::uint8_t{0};
while (attempt < WchLinkInterface::DMI_OP_MAX_RETRY) {
if (attempt > 0) {
std::this_thread::sleep_for(this->dmiOpRetryDelay);
}
const auto response = this->sendCommandAndWaitForResponse( const auto response = this->sendCommandAndWaitForResponse(
Commands::DebugModuleInterfaceOperation{DmiOperation::WRITE, address, value} Commands::DebugModuleInterfaceOperation{DmiOperation::WRITE, address, value}
); );
if (response.operationStatus != DmiOperationStatus::SUCCESS) { if (response.operationStatus == DmiOperationStatus::SUCCESS) {
return;
}
if (response.operationStatus == DmiOperationStatus::FAILED) {
throw Exceptions::DeviceCommunicationFailure{"DMI operation failed"}; throw Exceptions::DeviceCommunicationFailure{"DMI operation failed"};
} }
// Busy response...
++attempt;
}
throw Exceptions::DeviceCommunicationFailure{"DMI operation timed out"};
} }
void WchLinkInterface::writeFlashMemory( void WchLinkInterface::writeFlashMemory(

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <chrono>
#include <optional> #include <optional>
#include <vector> #include <vector>
#include <utility> #include <utility>
@@ -61,11 +62,14 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
static constexpr std::uint8_t USB_COMMAND_ENDPOINT_OUT = 0x01; 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_IN = 0x82;
static constexpr std::uint8_t USB_DATA_ENDPOINT_OUT = 0x02; static constexpr std::uint8_t USB_DATA_ENDPOINT_OUT = 0x02;
static constexpr std::uint8_t DMI_OP_MAX_RETRY = 10;
Usb::UsbInterface& usbInterface; Usb::UsbInterface& usbInterface;
std::uint16_t commandEndpointMaxPacketSize = 0; std::uint16_t commandEndpointMaxPacketSize = 0;
std::uint16_t dataEndpointMaxPacketSize = 0; std::uint16_t dataEndpointMaxPacketSize = 0;
// TODO: Move this into a config param
std::chrono::microseconds dmiOpRetryDelay = std::chrono::microseconds{10};
/** /**
* The 'target activation' command returns a payload of 5 bytes. * The 'target activation' command returns a payload of 5 bytes.