diff --git a/src/DebugToolDrivers/CMakeLists.txt b/src/DebugToolDrivers/CMakeLists.txt index a1e6ad97..4d4a6a37 100755 --- a/src/DebugToolDrivers/CMakeLists.txt +++ b/src/DebugToolDrivers/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources( PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/USB/UsbDevice.cpp ${CMAKE_CURRENT_SOURCE_DIR}/USB/HID/HidInterface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/EdbgDevice.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AtmelICE/AtmelIce.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/PowerDebugger/PowerDebugger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/MplabSnap/MplabSnap.cpp diff --git a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.cpp b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.cpp index 7fe435b7..a062a767 100644 --- a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.cpp +++ b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.cpp @@ -1,106 +1,14 @@ #include "AtmelIce.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - AtmelIce::AtmelIce() - : UsbDevice(AtmelIce::USB_VENDOR_ID, AtmelIce::USB_PRODUCT_ID) + : EdbgDevice( + AtmelIce::USB_VENDOR_ID, + AtmelIce::USB_PRODUCT_ID, + AtmelIce::CMSIS_HID_INTERFACE_NUMBER, + false, + AtmelIce::USB_CONFIGURATION_INDEX + ) {} - - void AtmelIce::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - this->setConfiguration(0); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - /* - * The Atmel-ICE EDBG/CMSIS-DAP interface doesn't operate properly when sending commands too quickly. - * - * Because of this, we have to enforce a minimum time gap between commands. See comment - * in CmsisDapInterface class declaration for more info. - */ - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. - if (!this->sessionStarted) { - this->startSession(); - } - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void AtmelIce::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string AtmelIce::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void AtmelIce::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with Atmel-ICE!"); - } - - this->sessionStarted = true; - } - - void AtmelIce::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with Atmel-ICE!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp index c9b3f7e3..0102a05a 100644 --- a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp +++ b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp @@ -1,108 +1,31 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** - * The Atmel-ICE device is an EDBG (Embedded Debugger) device. It implements the CMSIS-DAP layer as well - * as an Atmel Data Gateway Interface (DGI). + * The Atmel-ICE device is an EDBG (Embedded Debugger) device. * - * Communication: - * Using the Atmel-ICE device for AVR debugging/programming requires the AVR communication protocol, which - * is a sub-protocol of the CMSIS-DAP (AVR communication protocol commands are wrapped in CMSIS-DAP vendor - * commands). AVR communication protocol commands contain AVR frames, in which commands for numerous - * sub-protocols are enveloped. - * - * So to summarise, issuing an AVR command to the EDBG device, involves: - * Actual command data -> AVR sub-protocol -> AVR Frames -> CMSIS-DAP Vendor commands -> EDBG Device - * - * For more information on protocols and sub-protocols employed by Microchip EDBG devices, see - * the 'Embedded Debugger-Based Tools Protocols User's Guide' document by Microchip. - * @link http://ww1.microchip.com/downloads/en/DeviceDoc/50002630A.pdf - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2141 (8513) - * - * The Atmel-ICE consists of two USB interfaces. One HID interface for CMSIS-DAP and one vendor specific - * interface for the DGI. We only work with the CMSIS-DAP interface, for now. */ - class AtmelIce: public DebugTool, public Usb::UsbDevice + class AtmelIce: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8513; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2141; + static const inline std::uint8_t USB_CONFIGURATION_INDEX = 0; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; AtmelIce(); - void init() override; - - void close() override; - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "Atmel-ICE"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - /** - * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. - * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool - * to support additional functionality, like AVR programming and debugging. - * - * Any non-EDBG CMSIS-DAP commands for the Atmel-ICE can be sent through the EdbgInterface (as the - * EdbgInterface extends the CmsisDapInterface). - */ - std::unique_ptr edbgInterface = nullptr; - - /** - * The Atmel-ICE employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is - * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. - */ - std::unique_ptr edbgAvr8Interface = nullptr; - - /** - * The Atmel-ICE employs the EDBG AVRISP protocol, for interfacing with AVR targets via the ISP interface. - * See the EdbgAvrIspInterface class for the protocol implementation. - */ - std::unique_ptr edbgAvrIspInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.cpp b/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.cpp index 164ff269..d39e1ffa 100644 --- a/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.cpp +++ b/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.cpp @@ -1,103 +1,13 @@ #include "CuriosityNano.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; - CuriosityNano::CuriosityNano() - : UsbDevice(CuriosityNano::USB_VENDOR_ID, CuriosityNano::USB_PRODUCT_ID) + : EdbgDevice( + CuriosityNano::USB_VENDOR_ID, + CuriosityNano::USB_PRODUCT_ID, + CuriosityNano::CMSIS_HID_INTERFACE_NUMBER, + true + ) {} - - void CuriosityNano::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - if (!this->sessionStarted) { - this->startSession(); - } - - this->targetPowerManagementInterface = std::make_unique( - this->edbgInterface.get() - ); - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void CuriosityNano::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string CuriosityNano::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void CuriosityNano::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with Curiosity Nano!"); - } - - this->sessionStarted = true; - } - - void CuriosityNano::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with Curiosity Nano!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.hpp b/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.hpp index f80fbafa..a1adbac0 100644 --- a/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.hpp +++ b/src/DebugToolDrivers/Microchip/CuriosityNano/CuriosityNano.hpp @@ -1,87 +1,30 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgTargetPowerManagementInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * The Curiosity Nano is an evaluation board featuring an on-board debugger. The debugger is EDBG-based. * - * Because the on-board debugger is EDBG-based, we can employ the same AVR8 driver implementation as we do with - * other EDBG-based debuggers. See the EdbgAvr8Interface class for more. - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2175 (8565) */ - class CuriosityNano: public DebugTool, public Usb::UsbDevice + class CuriosityNano: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8565; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2175; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; CuriosityNano(); - void init() override; - - void close() override; - - DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { - return this->targetPowerManagementInterface.get(); - } - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "Curiosity Nano"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the Housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - std::unique_ptr edbgAvrIspInterface = nullptr; - std::unique_ptr< - Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface - > targetPowerManagementInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.cpp b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp new file mode 100644 index 00000000..d4f361bd --- /dev/null +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp @@ -0,0 +1,128 @@ +#include "EdbgDevice.hpp" + +#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" +#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" + +#include "src/TargetController/Exceptions/DeviceFailure.hpp" +#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" + +namespace Bloom::DebugToolDrivers +{ + using namespace Protocols::CmsisDap::Edbg::Avr; + using namespace Bloom::Exceptions; + + using Protocols::CmsisDap::Edbg::EdbgInterface; + using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; + + EdbgDevice::EdbgDevice( + std::uint16_t vendorId, + std::uint16_t productId, + std::uint8_t cmsisHidInterfaceNumber, + bool supportsTargetPowerManagement, + std::optional configurationIndex + ) + : UsbDevice(vendorId, productId) + , cmsisHidInterfaceNumber(cmsisHidInterfaceNumber) + , supportsTargetPowerManagement(supportsTargetPowerManagement) + , configurationIndex(configurationIndex) + {} + + void EdbgDevice::init() { + UsbDevice::init(); + + auto usbHidInterface = Usb::HidInterface(this->cmsisHidInterfaceNumber, this->vendorId, this->productId); + + this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); + + if (this->configurationIndex.has_value()) { + this->setConfiguration(this->configurationIndex.value()); + } + + usbHidInterface.init(); + + this->edbgInterface = std::make_unique(std::move(usbHidInterface)); + + /* + * The EDBG/CMSIS-DAP interface doesn't operate properly when sending commands too quickly. + * + * Because of this, we have to enforce a minimum time gap between commands. See comment + * in CmsisDapInterface class declaration for more info. + */ + this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); + + // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. + if (!this->sessionStarted) { + this->startSession(); + } + + if (this->supportsTargetPowerManagement) { + this->targetPowerManagementInterface = std::make_unique( + this->edbgInterface.get() + ); + } + + this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); + this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); + + this->setInitialised(true); + } + + void EdbgDevice::close() { + if (this->sessionStarted) { + this->endSession(); + } + + this->edbgInterface->getUsbHidInterface().close(); + UsbDevice::close(); + } + + std::string EdbgDevice::getSerialNumber() { + using namespace CommandFrames::Discovery; + using ResponseFrames::Discovery::ResponseId; + + const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( + Query(QueryContext::SERIAL_NUMBER) + ); + + if (responseFrame.id != ResponseId::OK) { + throw DeviceInitializationFailure( + "Failed to fetch serial number from device - invalid Discovery Protocol response ID." + ); + } + + const auto data = responseFrame.getPayloadData(); + return std::string(data.begin(), data.end()); + } + + void EdbgDevice::startSession() { + using namespace CommandFrames::HouseKeeping; + using ResponseFrames::HouseKeeping::ResponseId; + + const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( + StartSession() + ); + + if (responseFrame.id == ResponseId::FAILED) { + // Failed response returned! + throw DeviceInitializationFailure("Failed to start session with EDBG device!"); + } + + this->sessionStarted = true; + } + + void EdbgDevice::endSession() { + using namespace CommandFrames::HouseKeeping; + using ResponseFrames::HouseKeeping::ResponseId; + + const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( + EndSession() + ); + + if (responseFrame.id == ResponseId::FAILED) { + // Failed response returned! + throw DeviceFailure("Failed to end session with EDBG device!"); + } + + this->sessionStarted = false; + } +} diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.hpp b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp new file mode 100644 index 00000000..00847405 --- /dev/null +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include +#include +#include + +#include "src/DebugToolDrivers/DebugTool.hpp" +#include "src/DebugToolDrivers/USB/UsbDevice.hpp" + +#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" +#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" +#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" +#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgTargetPowerManagementInterface.hpp" + +namespace Bloom::DebugToolDrivers +{ + /** + * Microchip EDBG (Embedded Debugger) devices implement the CMSIS-DAP interface. As well as the CMSIS-DAP protocol, + * they support communication protocols that are specific to Microchip and enable the debugging and programming + * of AVR microcontrollers. These protocols are sub-protocols of the CMSIS-DAP protocol (they are implemented as + * CMSIS-DAP vendor commands). + * + * For more information on protocols and sub-protocols employed by Microchip EDBG devices, see + * the 'Embedded Debugger-Based Tools Protocols User's Guide' document by Microchip. + * @link http://ww1.microchip.com/downloads/en/DeviceDoc/50002630A.pdf + * + * This class serves as an abstract base class for all Microchip EDBG devices supported by Bloom. + */ + class EdbgDevice: public DebugTool, public Usb::UsbDevice + { + public: + EdbgDevice( + std::uint16_t vendorId, + std::uint16_t productId, + std::uint8_t cmsisHidInterfaceNumber, + bool supportsTargetPowerManagement = false, + std::optional configurationIndex = std::nullopt + ); + + /** + * Will attempt to locate the EDBG (USB) device and claim the CMSIS-DAP USB interface. + * + * Upon claiming the USB interface, a connection will be established and a session will be started. + */ + void init() override; + + /** + * Terminates any active session with the device and releases the CMSIS-DAP USB interface, as well as any + * other USB device resources. + */ + void close() override; + + TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { + return this->edbgAvr8Interface.get(); + } + + TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { + return this->edbgAvrIspInterface.get(); + } + + DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { + return this->targetPowerManagementInterface.get(); + } + + /** + * Retrieves the device serial number via the "Discovery" EDBG sub-protocol. + * + * @return + */ + std::string getSerialNumber() override; + + /** + * Starts a session with the EDBG device using the "Housekeeping" EDBG sub-protocol. + */ + void startSession(); + + /** + * Ends the active session with the device. + */ + void endSession(); + + protected: + /** + * The USB interface number of the CMSIS-DAP HID interface. + */ + std::uint8_t cmsisHidInterfaceNumber; + + /** + * Some EDBG devices provide the means to manage target power. This functionality would typically be found on + * AVR evaluation boards with an on-board EDBG-based debugger (like the Xplained Mini or Curiosity Nano boards). + * + * If EdbgDevice::supportsTargetPowerManagement is set to true, we will instantiate an instance of the + * EdbgTargetPowerManagementInterface class upon device initialisation. The interface is exposed via + * the EdbgDevice::getTargetPowerManagementInterface() member function. + */ + bool supportsTargetPowerManagement = false; + + /** + * The USB configuration index to set on the EDBG device before attempting to claim the CMSIS-DAP USB + * interface. + * + * If not specified, we won't attempt to modify the USB configuration at all. + */ + std::optional configurationIndex = std::nullopt; + + /** + * The EdbgInterface class provides the ability to communicate with the EDBG device, using any of the EDBG + * sub-protocols. + */ + std::unique_ptr edbgInterface = nullptr; + + /** + * The EdbgAvr8Interface class implements the AVR8 Generic EDBG sub-protocol. This protocol is used to perform + * debugging and programming operations on 8-bit AVR targets. + * + * The class implements the Avr8DebugInterface. + */ + std::unique_ptr edbgAvr8Interface = nullptr; + + /** + * The EdbgAvrIspInterface class implements the AVRISP EDBG sub-protocol, for interfacing with AVR targets via + * their ISP physical interface. + * + * ISP cannot be used for debugging operations. The EdbgAvrIspInterface class does *not* implement + * the Avr8DebugInterface. + * + * Currently, Bloom will only use the ISP interface as a fallback when attempting to connect to debugWire + * targets. We use the interface to inspect and update the "debugWire enable" (DWEN) fuse-bit, before making a + * second connection attempt via the debugWire interface. + */ + std::unique_ptr edbgAvrIspInterface = nullptr; + + /** + * The EdbgTargetPowerManagementInterface class implements the "EDBG Control" (EDBG_CTRL) sub-protocol, to + * provide a means to manage the connected target's input power. + * + * The class implements the TargetPowerManagementInterface and is exposed via the + * EdbgDevice::getTargetPowerManagementInterface() member function. + */ + std::unique_ptr< + Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface + > targetPowerManagementInterface = nullptr; + + bool sessionStarted = false; + }; +} diff --git a/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.cpp b/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.cpp index 0bf12147..a1fbdb72 100644 --- a/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.cpp +++ b/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.cpp @@ -1,100 +1,14 @@ #include "JtagIce3.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - JtagIce3::JtagIce3() - : UsbDevice(JtagIce3::USB_VENDOR_ID, JtagIce3::USB_PRODUCT_ID) + : EdbgDevice( + JtagIce3::USB_VENDOR_ID, + JtagIce3::USB_PRODUCT_ID, + JtagIce3::CMSIS_HID_INTERFACE_NUMBER, + false, + JtagIce3::USB_CONFIGURATION_INDEX + ) {} - - void JtagIce3::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - this->setConfiguration(0); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. - if (!this->sessionStarted) { - this->startSession(); - } - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void JtagIce3::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string JtagIce3::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void JtagIce3::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with the JTAGICE3!"); - } - - this->sessionStarted = true; - } - - void JtagIce3::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with the JTAGICE3!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.hpp b/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.hpp index 66119834..f660dc68 100644 --- a/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.hpp +++ b/src/DebugToolDrivers/Microchip/JtagIce3/JtagIce3.hpp @@ -1,66 +1,31 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { - class JtagIce3: public DebugTool, public Usb::UsbDevice + /** + * The JTAGICE3, from firmware version 3.x+, is an EDBG device. + * + * USB: + * Vendor ID: 0x03eb (1003) + * Product ID: 0x2140 (8512) + */ + class JtagIce3: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8512; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2140; + static const inline std::uint8_t USB_CONFIGURATION_INDEX = 0; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; JtagIce3(); - void init() override; - - void close() override; - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "JTAGICE3"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - std::unique_ptr edbgAvrIspInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.cpp b/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.cpp index b04e1128..24ca00ff 100644 --- a/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.cpp +++ b/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.cpp @@ -1,99 +1,12 @@ #include "MplabPickit4.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - MplabPickit4::MplabPickit4() - : UsbDevice(MplabPickit4::USB_VENDOR_ID, MplabPickit4::USB_PRODUCT_ID) + : EdbgDevice( + MplabPickit4::USB_VENDOR_ID, + MplabPickit4::USB_PRODUCT_ID, + MplabPickit4::CMSIS_HID_INTERFACE_NUMBER + ) {} - - void MplabPickit4::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. - if (!this->sessionStarted) { - this->startSession(); - } - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void MplabPickit4::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string MplabPickit4::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void MplabPickit4::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with MPLAB PICkit 4!"); - } - - this->sessionStarted = true; - } - - void MplabPickit4::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with MPLAB PICkit 4!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.hpp b/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.hpp index 5acb7aed..63ca1f8a 100644 --- a/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.hpp +++ b/src/DebugToolDrivers/Microchip/MplabPickit4/MplabPickit4.hpp @@ -1,78 +1,35 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * Like the MPLAB Snap, the PICkit 4 is a hybrid device. It can present itself as an EDBG (Embedded Debugger) - * device via a firmware update, issued by Microchip software (the MPLAB IDE and IPE). + * device via firmware configuration, actioned by Microchip software (the MPLAB IDE and IPE). * * This debug tool driver currently only supports the device when in AVR mode. Because the device uses different - * vendor & product IDs depending on the mode, it is easy to determine which is which. In fact, Bloom will not even - * recognise the device if it's not in AVR mode. + * USB vendor and product IDs depending on the mode, it is trivial to determine which is which. In fact, Bloom will + * not even recognise the device if it's not in AVR mode. * - * USB Setup (when in AVR/EDBG mode): + * USB (when in AVR/EDBG mode): * Vendor ID: 0x03eb (1003) * Product ID: 0x2177 (8567) */ - class MplabPickit4: public DebugTool, public Usb::UsbDevice + class MplabPickit4: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8567; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2177; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; MplabPickit4(); - void init() override; - - void close() override; - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "MPLAB PICkit 4"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - std::unique_ptr edbgAvrIspInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.cpp b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.cpp index f7f1fbab..b513c847 100644 --- a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.cpp +++ b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.cpp @@ -1,99 +1,12 @@ #include "MplabSnap.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - MplabSnap::MplabSnap() - : UsbDevice(MplabSnap::USB_VENDOR_ID, MplabSnap::USB_PRODUCT_ID) + : EdbgDevice( + MplabSnap::USB_VENDOR_ID, + MplabSnap::USB_PRODUCT_ID, + MplabSnap::CMSIS_HID_INTERFACE_NUMBER + ) {} - - void MplabSnap::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. - if (!this->sessionStarted) { - this->startSession(); - } - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void MplabSnap::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string MplabSnap::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void MplabSnap::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with MPLAB Snap!"); - } - - this->sessionStarted = true; - } - - void MplabSnap::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with MPLAB Snap!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp index 272281af..4518cdc0 100644 --- a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp +++ b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp @@ -1,94 +1,37 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * The MPLAB Snap device is a hybrid device - that is, it can present itself as an "MPLAB Snap ICD" device, as well - * as an EDBG (Embedded Debugger) device. The device switches between these two modes via a firmware update, issued - * by Microchip software (the MPLAB IDE and IPE). It appears that it can only interface with AVR targets using the - * EDBG firmware, which, apparently, is why it is known to be in "AVR mode" when it presents itself as an EDBG - * device. + * as an EDBG (Embedded Debugger) device. The device switches between these two modes via firmware configuration. + * It appears that it can only interface with AVR targets using the EDBG firmware, which, apparently, is why it is + * known to be in "AVR mode" when it presents itself as an EDBG device. * * This debug tool driver currently only supports the device when in AVR mode. Because the device uses different - * vendor & product IDs depending on the mode, it is easy to determine which is which. In fact, Bloom will not even - * recognise the device if it's not in AVR mode. + * USB vendor and product IDs depending on the mode, it is trivial to determine which is which. In fact, Bloom will + * not even recognise the device if it's not in AVR mode. * - * Communication: - * Uses the same EDBG protocol as described in the AtmelIce driver. See the AtmelIce debug tool class for more. - * - * USB Setup (when in AVR/EDBG mode): + * USB (when in AVR/EDBG mode): * Vendor ID: 0x03eb (1003) * Product ID: 0x2180 (8576) */ - class MplabSnap: public DebugTool, public Usb::UsbDevice + class MplabSnap: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8576; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2180; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; MplabSnap(); - void init() override; - - void close() override; - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "MPLAB Snap"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - - /** - * The MPLAB Snap employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is - * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. - */ - std::unique_ptr edbgAvr8Interface = nullptr; - - /** - * The MPLAB Snap employs the EDBG AVRISP protocol, for interfacing with AVR targets via the ISP interface. - * See the EdbgAvrIspInterface class for the protocol implementation. - */ - std::unique_ptr edbgAvrIspInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.cpp b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.cpp index d04a6a7c..ae831885 100644 --- a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.cpp +++ b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.cpp @@ -1,103 +1,14 @@ #include "PowerDebugger.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - PowerDebugger::PowerDebugger() - : UsbDevice(PowerDebugger::USB_VENDOR_ID, PowerDebugger::USB_PRODUCT_ID) + : EdbgDevice( + PowerDebugger::USB_VENDOR_ID, + PowerDebugger::USB_PRODUCT_ID, + PowerDebugger::CMSIS_HID_INTERFACE_NUMBER, + false, + PowerDebugger::USB_CONFIGURATION_INDEX + ) {} - - void PowerDebugger::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. - if (!this->sessionStarted) { - this->startSession(); - } - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void PowerDebugger::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string PowerDebugger::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void PowerDebugger::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure( - "Failed to start session with the Power Debugger - device returned failed response ID" - ); - } - - this->sessionStarted = true; - } - - void PowerDebugger::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure( - "Failed to end session with the Power Debugger - device returned failed response ID" - ); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp index bdaf9331..5b53936d 100644 --- a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp +++ b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp @@ -1,90 +1,31 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** - * The Power Debugger device is very similar to the Atmel-ICE. It implements the CMSIS-DAP layer as well - * as an Atmel Data Gateway Interface (DGI). + * The Power Debugger device is very similar to the Atmel-ICE. It is an EDBG device. * - * Communication: - * Uses the same EDBG protocol as described in the AtmelIce driver. See the AtmelIce debug tool class for more. - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2141 (8513) */ - class PowerDebugger: public DebugTool, public Usb::UsbDevice + class PowerDebugger: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8516; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2141; + static const inline std::uint8_t USB_CONFIGURATION_INDEX = 0; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; PowerDebugger(); - void init() override; - - void close() override; - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "Power Debugger"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - /** - * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. - * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool - * to support additional functionality, like AVR programming and debugging. - * - * Any non-EDBG CMSIS-DAP commands for the Power Debugger can be sent through the EDBGInterface (as the - * EdbgInterface extends the CmsisDapInterface). - */ - std::unique_ptr edbgInterface = nullptr; - - /** - * The Power Debugger employs the EDBG AVR8Generic protocol for interfacing with AVR8 targets. - */ - std::unique_ptr edbgAvr8Interface; - - std::unique_ptr edbgAvrIspInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.cpp b/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.cpp index 7757c89d..131d4f6f 100644 --- a/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.cpp +++ b/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.cpp @@ -1,103 +1,13 @@ #include "XplainedMini.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; - XplainedMini::XplainedMini() - : UsbDevice(XplainedMini::USB_VENDOR_ID, XplainedMini::USB_PRODUCT_ID) + : EdbgDevice( + XplainedMini::USB_VENDOR_ID, + XplainedMini::USB_PRODUCT_ID, + XplainedMini::CMSIS_HID_INTERFACE_NUMBER, + true + ) {} - - void XplainedMini::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - if (!this->sessionStarted) { - this->startSession(); - } - - this->targetPowerManagementInterface = std::make_unique( - this->edbgInterface.get() - ); - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->edbgAvrIspInterface = std::make_unique(this->edbgInterface.get()); - - this->setInitialised(true); - } - - void XplainedMini::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string XplainedMini::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void XplainedMini::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with Xplained Mini!"); - } - - this->sessionStarted = true; - } - - void XplainedMini::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with Xplained Mini!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.hpp b/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.hpp index 28cef731..8f09961c 100644 --- a/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.hpp +++ b/src/DebugToolDrivers/Microchip/XplainedMini/XplainedMini.hpp @@ -1,87 +1,30 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgTargetPowerManagementInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * The Xplained Mini is an evaluation board featuring an on-board debugger. The debugger is EDBG-based. * - * Because the on-board debugger is EDBG-based, we can employ the same AVR8 driver implementation as we do with - * other EDBG-based debuggers. See the EdbgAvr8Interface class for more. - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2145 (8517) */ - class XplainedMini: public DebugTool, public Usb::UsbDevice + class XplainedMini: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8517; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2145; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; XplainedMini(); - void init() override; - - void close() override; - - DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { - return this->targetPowerManagementInterface.get(); - } - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - - TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override { - return this->edbgAvrIspInterface.get(); - } - std::string getName() override { return "Xplained Mini"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the Housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - std::unique_ptr edbgAvrIspInterface = nullptr; - std::unique_ptr< - Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface - > targetPowerManagementInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.cpp b/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.cpp index 4246b308..c2c7cb03 100644 --- a/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.cpp +++ b/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.cpp @@ -1,101 +1,13 @@ #include "XplainedNano.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; - XplainedNano::XplainedNano() - : UsbDevice(XplainedNano::USB_VENDOR_ID, XplainedNano::USB_PRODUCT_ID) + : EdbgDevice( + XplainedNano::USB_VENDOR_ID, + XplainedNano::USB_PRODUCT_ID, + XplainedNano::CMSIS_HID_INTERFACE_NUMBER, + true + ) {} - - void XplainedNano::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - if (!this->sessionStarted) { - this->startSession(); - } - - this->targetPowerManagementInterface = std::make_unique( - this->edbgInterface.get() - ); - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - this->setInitialised(true); - } - - void XplainedNano::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string XplainedNano::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - const auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void XplainedNano::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with Xplained Nano!"); - } - - this->sessionStarted = true; - } - - void XplainedNano::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with Xplained Nano!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.hpp b/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.hpp index 4f6bcf0b..d9e08514 100644 --- a/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.hpp +++ b/src/DebugToolDrivers/Microchip/XplainedNano/XplainedNano.hpp @@ -1,81 +1,30 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgTargetPowerManagementInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * The Xplained Nano is an evaluation board featuring an on-board debugger. The debugger is EDBG-based. * - * Because the on-board debugger is EDBG-based, we can employ the same AVR8 driver implementation as we do with - * other EDBG-based debuggers. See the EdbgAvr8Interface class for more. - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2145 (8517) */ - class XplainedNano: public DebugTool, public Usb::UsbDevice + class XplainedNano: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8517; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2145; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; XplainedNano(); - void init() override; - - void close() override; - - DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { - return this->targetPowerManagementInterface.get(); - } - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - std::string getName() override { return "Xplained Nano"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the Housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - std::unique_ptr< - Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface - > targetPowerManagementInterface = nullptr; - - bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.cpp b/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.cpp index cd33ec54..95d3e77e 100644 --- a/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.cpp +++ b/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.cpp @@ -1,110 +1,13 @@ #include "XplainedPro.hpp" -#include "src/TargetController/Exceptions/DeviceFailure.hpp" -#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" - namespace Bloom::DebugToolDrivers { - using namespace Protocols::CmsisDap::Edbg::Avr; - using namespace Bloom::Exceptions; - - using Protocols::CmsisDap::Edbg::EdbgInterface; - using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; - XplainedPro::XplainedPro() - : UsbDevice(XplainedPro::USB_VENDOR_ID, XplainedPro::USB_PRODUCT_ID) + : EdbgDevice( + XplainedPro::USB_VENDOR_ID, + XplainedPro::USB_PRODUCT_ID, + XplainedPro::CMSIS_HID_INTERFACE_NUMBER, + true + ) {} - - void XplainedPro::init() { - UsbDevice::init(); - - // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number - auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber); - usbHidInterface.init(); - - this->edbgInterface = std::make_unique(std::move(usbHidInterface)); - - this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35)); - - if (!this->sessionStarted) { - this->startSession(); - } - - this->targetPowerManagementInterface = std::make_unique( - this->edbgInterface.get() - ); - - this->edbgAvr8Interface = std::make_unique(this->edbgInterface.get()); - - /* - * The Xplained Pro debug tool returns incorrect data for any read memory command that exceeds 256 bytes in the - * size of the read request, despite the fact that the HID report size is 512 bytes. The debug tool doesn't - * report any error, it just returns incorrect data. - * - * This means we must enforce a hard limit on the number of bytes we attempt to access, per request. - */ - this->edbgAvr8Interface->setMaximumMemoryAccessSizePerRequest(256); - this->setInitialised(true); - } - - void XplainedPro::close() { - if (this->sessionStarted) { - this->endSession(); - } - - this->edbgInterface->getUsbHidInterface().close(); - UsbDevice::close(); - } - - std::string XplainedPro::getSerialNumber() { - using namespace CommandFrames::Discovery; - using ResponseFrames::Discovery::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - Query(QueryContext::SERIAL_NUMBER) - ); - - if (responseFrame.id != ResponseId::OK) { - throw DeviceInitializationFailure( - "Failed to fetch serial number from device - invalid Discovery Protocol response ID." - ); - } - - auto data = responseFrame.getPayloadData(); - return std::string(data.begin(), data.end()); - } - - void XplainedPro::startSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - StartSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceInitializationFailure("Failed to start session with Xplained Pro!"); - } - - this->sessionStarted = true; - } - - void XplainedPro::endSession() { - using namespace CommandFrames::HouseKeeping; - using ResponseFrames::HouseKeeping::ResponseId; - - const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( - EndSession() - ); - - if (responseFrame.id == ResponseId::FAILED) { - // Failed response returned! - throw DeviceFailure("Failed to end session with Xplained Pro!"); - } - - this->sessionStarted = false; - } } diff --git a/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.hpp b/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.hpp index 0df57601..76b1fd19 100644 --- a/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.hpp +++ b/src/DebugToolDrivers/Microchip/XplainedPro/XplainedPro.hpp @@ -1,82 +1,30 @@ #pragma once #include -#include -#include +#include -#include "src/DebugToolDrivers/DebugTool.hpp" -#include "src/DebugToolDrivers/USB/UsbDevice.hpp" -#include "src/DebugToolDrivers/USB/HID/HidInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgTargetPowerManagementInterface.hpp" - -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp" -#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrames.hpp" +#include "src/DebugToolDrivers/Microchip/EdbgDevice.hpp" namespace Bloom::DebugToolDrivers { /** * The Xplained Pro is an evaluation board featuring an on-board debugger. The debugger is EDBG-based. * - * Because the on-board debugger is EDBG-based, we can employ the same AVR8 driver implementation as we do with - * other EDBG-based debuggers. See the EdbgAvr8Interface class for more. - * - * USB Setup: + * USB: * Vendor ID: 0x03eb (1003) * Product ID: 0x2111 (8465) */ - class XplainedPro: public DebugTool, public Usb::UsbDevice + class XplainedPro: public EdbgDevice { public: - static const std::uint16_t USB_VENDOR_ID = 1003; - static const std::uint16_t USB_PRODUCT_ID = 8465; + static const inline std::uint16_t USB_VENDOR_ID = 0x03eb; + static const inline std::uint16_t USB_PRODUCT_ID = 0x2111; + static const inline std::uint8_t CMSIS_HID_INTERFACE_NUMBER = 0; XplainedPro(); - void init() override; - - void close() override; - - DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { - return this->targetPowerManagementInterface.get(); - } - - TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { - return this->edbgAvr8Interface.get(); - } - std::string getName() override { return "Xplained Pro"; } - - /** - * Retrieves the device serial number via the Discovery Protocol. - * - * @return - */ - std::string getSerialNumber() override; - - /** - * Starts a session with the EDBG-based tool using the Housekeeping protocol. - */ - void startSession(); - - /** - * Ends the active session with the debug tool. - */ - void endSession(); - - private: - std::unique_ptr edbgInterface = nullptr; - std::unique_ptr edbgAvr8Interface = nullptr; - - std::unique_ptr< - Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface - > targetPowerManagementInterface = nullptr; - - bool sessionStarted = false; }; }