Tidying low-level debug tool driver code:

- Use automatic objects for libusb/hidapi resources, where possible (to reduce manual resource management)
- Removed unused/redundant code
- Tidied HidInterface class
- Tidied debug tool initialisation code
- Other bits of tidying
This commit is contained in:
Nav
2022-10-01 16:50:57 +01:00
parent ef4eb4f768
commit a5b0097036
36 changed files with 448 additions and 727 deletions

View File

@@ -2,7 +2,6 @@ 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/Interface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/USB/HID/HidInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/USB/HID/HidInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AtmelICE/AtmelIce.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AtmelICE/AtmelIce.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/PowerDebugger/PowerDebugger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/PowerDebugger/PowerDebugger.cpp

View File

@@ -8,22 +8,23 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
AtmelIce::AtmelIce()
: UsbDevice(AtmelIce::USB_VENDOR_ID, AtmelIce::USB_PRODUCT_ID)
{}
void AtmelIce::init() { void AtmelIce::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); this->setConfiguration(0);
this->setConfiguration(0); usbHidInterface.init();
usbHidInterface.init();
} this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
/* /*
* The Atmel-ICE EDBG/CMSIS-DAP interface doesn't operate properly when sending commands too quickly. * The Atmel-ICE EDBG/CMSIS-DAP interface doesn't operate properly when sending commands too quickly.
@@ -31,15 +32,15 @@ namespace Bloom::DebugToolDrivers
* Because of this, we have to enforce a minimum time gap between commands. See comment * Because of this, we have to enforce a minimum time gap between commands. See comment
* in CmsisDapInterface class declaration for more info. * in CmsisDapInterface class declaration for more info.
*/ */
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); 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. // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so.
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -49,7 +50,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -57,7 +58,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -67,7 +68,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -75,7 +76,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -91,7 +92,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -45,16 +45,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8513; static const std::uint16_t USB_PRODUCT_ID = 8513;
AtmelIce(): UsbDevice(AtmelIce::USB_VENDOR_ID, AtmelIce::USB_PRODUCT_ID) {} AtmelIce();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
return this->edbgAvr8Interface.get(); return this->edbgAvr8Interface.get();
} }
@@ -65,7 +61,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Atmel-ICE"; return "Atmel-ICE";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -93,7 +89,7 @@ namespace Bloom::DebugToolDrivers
* Any non-EDBG CMSIS-DAP commands for the Atmel-ICE can be sent through the EdbgInterface (as the * Any non-EDBG CMSIS-DAP commands for the Atmel-ICE can be sent through the EdbgInterface (as the
* EdbgInterface extends the CmsisDapInterface). * EdbgInterface extends the CmsisDapInterface).
*/ */
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
/** /**
* The Atmel-ICE employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is * The Atmel-ICE employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is

View File

@@ -8,36 +8,36 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface;
CuriosityNano::CuriosityNano()
: UsbDevice(CuriosityNano::USB_VENDOR_ID, CuriosityNano::USB_PRODUCT_ID)
{}
void CuriosityNano::init() { void CuriosityNano::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); usbHidInterface.init();
usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35));
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>( this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>(
this->edbgInterface this->edbgInterface.get()
); );
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -47,7 +47,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -55,7 +55,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -65,7 +65,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -73,7 +73,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -89,7 +89,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -35,16 +35,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8565; static const std::uint16_t USB_PRODUCT_ID = 8565;
CuriosityNano(): UsbDevice(CuriosityNano::USB_VENDOR_ID, CuriosityNano::USB_PRODUCT_ID) {} CuriosityNano();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override {
return this->targetPowerManagementInterface.get(); return this->targetPowerManagementInterface.get();
} }
@@ -59,7 +55,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Curiosity Nano"; return "Curiosity Nano";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -79,7 +75,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr;
std::unique_ptr< std::unique_ptr<

View File

@@ -8,32 +8,33 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
JtagIce3::JtagIce3()
: UsbDevice(JtagIce3::USB_VENDOR_ID, JtagIce3::USB_PRODUCT_ID)
{}
void JtagIce3::init() { void JtagIce3::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); this->setConfiguration(0);
this->setConfiguration(0); usbHidInterface.init();
usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(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. // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so.
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -43,7 +44,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -51,7 +52,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -61,7 +62,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -69,7 +70,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -85,7 +86,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -21,16 +21,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8512; static const std::uint16_t USB_PRODUCT_ID = 8512;
JtagIce3(): UsbDevice(JtagIce3::USB_VENDOR_ID, JtagIce3::USB_PRODUCT_ID) {} JtagIce3();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
return this->edbgAvr8Interface.get(); return this->edbgAvr8Interface.get();
} }
@@ -41,7 +37,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "JTAGICE3"; return "JTAGICE3";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -61,7 +57,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr;

View File

@@ -8,30 +8,32 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
MplabPickit4::MplabPickit4()
: UsbDevice(MplabPickit4::USB_VENDOR_ID, MplabPickit4::USB_PRODUCT_ID)
{}
void MplabPickit4::init() { void MplabPickit4::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.init(); usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(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. // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so.
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -41,7 +43,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -49,7 +51,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -59,7 +61,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -67,7 +69,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -83,7 +85,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -33,16 +33,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8567; static const std::uint16_t USB_PRODUCT_ID = 8567;
MplabPickit4(): UsbDevice(MplabPickit4::USB_VENDOR_ID, MplabPickit4::USB_PRODUCT_ID) {} MplabPickit4();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
return this->edbgAvr8Interface.get(); return this->edbgAvr8Interface.get();
} }
@@ -53,7 +49,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "MPLAB PICkit 4"; return "MPLAB PICkit 4";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -73,7 +69,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr;

View File

@@ -8,30 +8,32 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
MplabSnap::MplabSnap()
: UsbDevice(MplabSnap::USB_VENDOR_ID, MplabSnap::USB_PRODUCT_ID)
{}
void MplabSnap::init() { void MplabSnap::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.init(); usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(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. // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so.
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -41,7 +43,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -49,7 +51,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -59,7 +61,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -67,7 +69,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -83,7 +85,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -39,16 +39,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8576; static const std::uint16_t USB_PRODUCT_ID = 8576;
MplabSnap(): UsbDevice(MplabSnap::USB_VENDOR_ID, MplabSnap::USB_PRODUCT_ID) {} MplabSnap();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
return this->edbgAvr8Interface.get(); return this->edbgAvr8Interface.get();
} }
@@ -59,7 +55,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "MPLAB Snap"; return "MPLAB Snap";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -79,7 +75,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
/** /**
* The MPLAB Snap employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is * The MPLAB Snap employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is

View File

@@ -8,36 +8,32 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
PowerDebugger::PowerDebugger()
: UsbDevice(PowerDebugger::USB_VENDOR_ID, PowerDebugger::USB_PRODUCT_ID)
{}
void PowerDebugger::init() { void PowerDebugger::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.init(); usbHidInterface.init();
}
/* this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
* The Power Debugger EDBG/CMSIS-DAP interface doesn't operate properly when sending commands too quickly.
* this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35));
* Because of this, we have to enforce a minimum time gap between commands. See comment in
* CmsisDapInterface class declaration for more info.
*/
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35));
// We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so. // We don't need to claim the CMSISDAP interface here as the HIDAPI will have already done so.
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -47,7 +43,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -55,7 +51,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -65,7 +61,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -73,7 +69,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -91,7 +87,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -32,16 +32,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8516; static const std::uint16_t USB_PRODUCT_ID = 8516;
PowerDebugger(): UsbDevice(PowerDebugger::USB_VENDOR_ID, PowerDebugger::USB_PRODUCT_ID) {} PowerDebugger();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override { TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
return this->edbgAvr8Interface.get(); return this->edbgAvr8Interface.get();
} }
@@ -52,7 +48,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Power Debugger"; return "Power Debugger";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -80,7 +76,7 @@ namespace Bloom::DebugToolDrivers
* Any non-EDBG CMSIS-DAP commands for the Power Debugger can be sent through the EDBGInterface (as the * Any non-EDBG CMSIS-DAP commands for the Power Debugger can be sent through the EDBGInterface (as the
* EdbgInterface extends the CmsisDapInterface). * EdbgInterface extends the CmsisDapInterface).
*/ */
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
/** /**
* The Power Debugger employs the EDBG AVR8Generic protocol for interfacing with AVR8 targets. * The Power Debugger employs the EDBG AVR8Generic protocol for interfacing with AVR8 targets.

View File

@@ -8,36 +8,36 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface;
XplainedMini::XplainedMini()
: UsbDevice(XplainedMini::USB_VENDOR_ID, XplainedMini::USB_PRODUCT_ID)
{}
void XplainedMini::init() { void XplainedMini::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); usbHidInterface.init();
usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35));
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>( this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>(
this->edbgInterface this->edbgInterface.get()
); );
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface); this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -47,7 +47,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -55,7 +55,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -73,7 +73,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -89,7 +89,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -35,16 +35,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8517; static const std::uint16_t USB_PRODUCT_ID = 8517;
XplainedMini(): UsbDevice(XplainedMini::USB_VENDOR_ID, XplainedMini::USB_PRODUCT_ID) {} XplainedMini();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override {
return this->targetPowerManagementInterface.get(); return this->targetPowerManagementInterface.get();
} }
@@ -59,7 +55,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Xplained Mini"; return "Xplained Mini";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -79,7 +75,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvrIspInterface> edbgAvrIspInterface = nullptr;
std::unique_ptr< std::unique_ptr<

View File

@@ -8,35 +8,35 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface;
XplainedNano::XplainedNano()
: UsbDevice(XplainedNano::USB_VENDOR_ID, XplainedNano::USB_PRODUCT_ID)
{}
void XplainedNano::init() { void XplainedNano::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); usbHidInterface.init();
usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35));
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>( this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>(
this->edbgInterface this->edbgInterface.get()
); );
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
this->setInitialised(true); this->setInitialised(true);
} }
@@ -45,7 +45,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -53,7 +53,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -63,7 +63,7 @@ namespace Bloom::DebugToolDrivers
); );
} }
auto data = response.getPayloadData(); const auto data = response.getPayloadData();
return std::string(data.begin(), data.end()); return std::string(data.begin(), data.end());
} }
@@ -71,7 +71,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -87,7 +87,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -34,16 +34,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8517; static const std::uint16_t USB_PRODUCT_ID = 8517;
XplainedNano(): UsbDevice(XplainedNano::USB_VENDOR_ID, XplainedNano::USB_PRODUCT_ID) {} XplainedNano();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override {
return this->targetPowerManagementInterface.get(); return this->targetPowerManagementInterface.get();
} }
@@ -54,7 +50,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Xplained Nano"; return "Xplained Nano";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -74,7 +70,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr< std::unique_ptr<
Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface

View File

@@ -8,35 +8,35 @@ namespace Bloom::DebugToolDrivers
using namespace Protocols::CmsisDap::Edbg::Avr; using namespace Protocols::CmsisDap::Edbg::Avr;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Protocols::CmsisDap::Edbg::EdbgInterface;
using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface; using Protocols::CmsisDap::Edbg::EdbgTargetPowerManagementInterface;
XplainedPro::XplainedPro()
: UsbDevice(XplainedPro::USB_VENDOR_ID, XplainedPro::USB_PRODUCT_ID)
{}
void XplainedPro::init() { void XplainedPro::init() {
UsbDevice::init(); UsbDevice::init();
// TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number // TODO: Move away from hard-coding the CMSIS-DAP/EDBG interface number
auto& usbHidInterface = this->getEdbgInterface().getUsbHidInterface(); auto usbHidInterface = Usb::HidInterface(0, this->vendorId, this->productId);
usbHidInterface.setNumber(0);
usbHidInterface.setLibUsbDevice(this->libUsbDevice);
usbHidInterface.setLibUsbDeviceHandle(this->libUsbDeviceHandle);
usbHidInterface.setVendorId(this->vendorId);
usbHidInterface.setProductId(this->productId);
if (!usbHidInterface.isInitialised()) { this->detachKernelDriverFromInterface(usbHidInterface.interfaceNumber);
usbHidInterface.detachKernelDriver(); usbHidInterface.init();
usbHidInterface.init();
}
this->getEdbgInterface().setMinimumCommandTimeGap(std::chrono::milliseconds(35)); this->edbgInterface = std::make_unique<EdbgInterface>(std::move(usbHidInterface));
this->edbgInterface->setMinimumCommandTimeGap(std::chrono::milliseconds(35));
if (!this->sessionStarted) { if (!this->sessionStarted) {
this->startSession(); this->startSession();
} }
this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>( this->targetPowerManagementInterface = std::make_unique<EdbgTargetPowerManagementInterface>(
this->edbgInterface this->edbgInterface.get()
); );
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface); this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
/* /*
* The Xplained Pro debug tool returns incorrect data for any read memory command that exceeds 256 bytes in the * The Xplained Pro debug tool returns incorrect data for any read memory command that exceeds 256 bytes in the
@@ -54,7 +54,7 @@ namespace Bloom::DebugToolDrivers
this->endSession(); this->endSession();
} }
this->getEdbgInterface().getUsbHidInterface().close(); this->edbgInterface->getUsbHidInterface().close();
UsbDevice::close(); UsbDevice::close();
} }
@@ -62,7 +62,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::Discovery; using namespace CommandFrames::Discovery;
using ResponseFrames::Discovery::ResponseId; using ResponseFrames::Discovery::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Query(QueryContext::SERIAL_NUMBER) Query(QueryContext::SERIAL_NUMBER)
); );
@@ -80,7 +80,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
StartSession() StartSession()
); );
@@ -96,7 +96,7 @@ namespace Bloom::DebugToolDrivers
using namespace CommandFrames::HouseKeeping; using namespace CommandFrames::HouseKeeping;
using ResponseFrames::HouseKeeping::ResponseId; using ResponseFrames::HouseKeeping::ResponseId;
auto response = this->getEdbgInterface().sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EndSession() EndSession()
); );

View File

@@ -34,16 +34,12 @@ namespace Bloom::DebugToolDrivers
static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_VENDOR_ID = 1003;
static const std::uint16_t USB_PRODUCT_ID = 8465; static const std::uint16_t USB_PRODUCT_ID = 8465;
XplainedPro(): UsbDevice(XplainedPro::USB_VENDOR_ID, XplainedPro::USB_PRODUCT_ID) {} XplainedPro();
void init() override; void init() override;
void close() override; void close() override;
Protocols::CmsisDap::Edbg::EdbgInterface& getEdbgInterface() {
return this->edbgInterface;
}
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override { DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* getTargetPowerManagementInterface() override {
return this->targetPowerManagementInterface.get(); return this->targetPowerManagementInterface.get();
} }
@@ -54,7 +50,7 @@ namespace Bloom::DebugToolDrivers
std::string getName() override { std::string getName() override {
return "Xplained Pro"; return "Xplained Pro";
}; }
/** /**
* Retrieves the device serial number via the Discovery Protocol. * Retrieves the device serial number via the Discovery Protocol.
@@ -74,7 +70,7 @@ namespace Bloom::DebugToolDrivers
void endSession(); void endSession();
private: private:
Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); std::unique_ptr<Protocols::CmsisDap::Edbg::EdbgInterface> edbgInterface = nullptr;
std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr; std::unique_ptr<Protocols::CmsisDap::Edbg::Avr::EdbgAvr8Interface> edbgAvr8Interface = nullptr;
std::unique_ptr< std::unique_ptr<

View File

@@ -8,6 +8,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap
{ {
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
CmsisDapInterface::CmsisDapInterface(Usb::HidInterface&& usbHidInterface)
: usbHidInterface(std::move(usbHidInterface))
{}
void CmsisDapInterface::sendCommand(const Command& cmsisDapCommand) { void CmsisDapInterface::sendCommand(const Command& cmsisDapCommand) {
if (this->msSendCommandDelay.count() > 0) { if (this->msSendCommandDelay.count() > 0) {
using namespace std::chrono; using namespace std::chrono;

View File

@@ -21,14 +21,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap
class CmsisDapInterface class CmsisDapInterface
{ {
public: public:
explicit CmsisDapInterface() = default; explicit CmsisDapInterface(Usb::HidInterface&& usbHidInterface);
virtual ~CmsisDapInterface() = default; virtual ~CmsisDapInterface() = default;
CmsisDapInterface(const CmsisDapInterface& other) = default; CmsisDapInterface(const CmsisDapInterface& other) = delete;
CmsisDapInterface(CmsisDapInterface&& other) = default; CmsisDapInterface(CmsisDapInterface&& other) = delete;
CmsisDapInterface& operator = (const CmsisDapInterface& other) = delete;
CmsisDapInterface& operator = (const CmsisDapInterface& other) = default; CmsisDapInterface& operator = (CmsisDapInterface&& other) = delete;
CmsisDapInterface& operator = (CmsisDapInterface&& other) = default;
Usb::HidInterface& getUsbHidInterface() { Usb::HidInterface& getUsbHidInterface() {
return this->usbHidInterface; return this->usbHidInterface;
@@ -65,7 +65,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap
"CMSIS Response type must be derived from the Response class." "CMSIS Response type must be derived from the Response class."
); );
const auto rawResponse = this->getUsbHidInterface().read(15000); const auto rawResponse = this->getUsbHidInterface().read(std::chrono::milliseconds(15000));
if (rawResponse.empty()) { if (rawResponse.empty()) {
throw Exceptions::DeviceCommunicationFailure("Empty CMSIS-DAP response received"); throw Exceptions::DeviceCommunicationFailure("Empty CMSIS-DAP response received");
@@ -113,7 +113,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap
* amongst devices, so we'll need to be able to preActivationConfigure the CMSISDAPInterface from a * amongst devices, so we'll need to be able to preActivationConfigure the CMSISDAPInterface from a
* higher level. For an example, see the constructor of the AtmelIce device class. * higher level. For an example, see the constructor of the AtmelIce device class.
*/ */
Usb::HidInterface usbHidInterface = Usb::HidInterface(); Usb::HidInterface usbHidInterface;
/** /**
* Some CMSIS-DAP debug tools fail to operate properly when we send commands too quickly. Even if we've * Some CMSIS-DAP debug tools fail to operate properly when we send commands too quickly. Even if we've

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <cassert>
#include "EdbgControlCommandFrame.hpp" #include "EdbgControlCommandFrame.hpp"

View File

@@ -82,7 +82,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
using Bloom::Targets::TargetRegisterType; using Bloom::Targets::TargetRegisterType;
using Bloom::Targets::TargetRegisters; using Bloom::Targets::TargetRegisters;
EdbgAvr8Interface::EdbgAvr8Interface(EdbgInterface& edbgInterface) EdbgAvr8Interface::EdbgAvr8Interface(EdbgInterface* edbgInterface)
: edbgInterface(edbgInterface) : edbgInterface(edbgInterface)
{} {}
@@ -195,7 +195,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::stop() { void EdbgAvr8Interface::stop() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Stop() Stop()
); );
@@ -210,7 +210,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
void EdbgAvr8Interface::run() { void EdbgAvr8Interface::run() {
this->clearEvents(); this->clearEvents();
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Run() Run()
); );
@@ -223,7 +223,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
void EdbgAvr8Interface::runTo(TargetProgramCounter address) { void EdbgAvr8Interface::runTo(TargetProgramCounter address) {
this->clearEvents(); this->clearEvents();
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
RunTo(address) RunTo(address)
); );
@@ -235,7 +235,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::step() { void EdbgAvr8Interface::step() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Step() Step()
); );
@@ -247,7 +247,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::reset() { void EdbgAvr8Interface::reset() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Reset() Reset()
); );
@@ -335,7 +335,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
this->stop(); this->stop();
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
GetProgramCounter() GetProgramCounter()
); );
@@ -355,7 +355,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* The program counter will be given in byte address form, but the EDBG tool will be expecting it in word * The program counter will be given in byte address form, but the EDBG tool will be expecting it in word
* address (16-bit) form. This is why we divide it by 2. * address (16-bit) form. This is why we divide it by 2.
*/ */
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetProgramCounter(programCounter / 2) SetProgramCounter(programCounter / 2)
); );
@@ -390,7 +390,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]); return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]);
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
GetDeviceId() GetDeviceId()
); );
@@ -402,7 +402,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::setBreakpoint(TargetMemoryAddress address) { void EdbgAvr8Interface::setBreakpoint(TargetMemoryAddress address) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetSoftwareBreakpoints({address}) SetSoftwareBreakpoints({address})
); );
@@ -412,7 +412,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::clearBreakpoint(TargetMemoryAddress address) { void EdbgAvr8Interface::clearBreakpoint(TargetMemoryAddress address) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ClearSoftwareBreakpoints({address}) ClearSoftwareBreakpoints({address})
); );
@@ -422,7 +422,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::clearAllBreakpoints() { void EdbgAvr8Interface::clearAllBreakpoints() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ClearAllSoftwareBreakpoints() ClearAllSoftwareBreakpoints()
); );
@@ -750,7 +750,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
throw Exception("AVR8 erase command not supported for debugWire config variant."); throw Exception("AVR8 erase command not supported for debugWire config variant.");
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EraseMemory( EraseMemory(
section.has_value() section.has_value()
? section == ProgramMemorySection::BOOT ? section == ProgramMemorySection::BOOT
@@ -785,7 +785,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return; return;
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EnterProgrammingMode() EnterProgrammingMode()
); );
@@ -801,7 +801,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return; return;
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
LeaveProgrammingMode() LeaveProgrammingMode()
); );
@@ -909,7 +909,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) { void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetParameter(parameter, value) SetParameter(parameter, value)
); );
@@ -919,7 +919,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
std::vector<unsigned char> EdbgAvr8Interface::getParameter(const Avr8EdbgParameter& parameter, std::uint8_t size) { std::vector<unsigned char> EdbgAvr8Interface::getParameter(const Avr8EdbgParameter& parameter, std::uint8_t size) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
GetParameter(parameter, size) GetParameter(parameter, size)
); );
@@ -1371,7 +1371,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::activatePhysical(bool applyExternalReset) { void EdbgAvr8Interface::activatePhysical(bool applyExternalReset) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ActivatePhysical(applyExternalReset) ActivatePhysical(applyExternalReset)
); );
@@ -1390,7 +1390,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::deactivatePhysical() { void EdbgAvr8Interface::deactivatePhysical() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
DeactivatePhysical() DeactivatePhysical()
); );
@@ -1410,7 +1410,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* value of the breakAfterAttach flag. So we still expect a stop event to be received shortly after issuing * value of the breakAfterAttach flag. So we still expect a stop event to be received shortly after issuing
* the attach command. * the attach command.
*/ */
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Attach( Attach(
this->configVariant != Avr8ConfigVariant::MEGAJTAG this->configVariant != Avr8ConfigVariant::MEGAJTAG
) )
@@ -1434,7 +1434,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::detach() { void EdbgAvr8Interface::detach() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Detach() Detach()
); );
@@ -1684,7 +1684,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* that isn't actually the memory data (like the command ID, version bytes, etc). I could have sought the * that isn't actually the memory data (like the command ID, version bytes, etc). I could have sought the
* actual value but who has the time. It won't exceed 20 bytes. Bite me. * actual value but who has the time. It won't exceed 20 bytes. Bite me.
*/ */
auto singlePacketSize = static_cast<std::uint32_t>(this->edbgInterface.getUsbHidInputReportSize() - 20); auto singlePacketSize = static_cast<std::uint32_t>(this->edbgInterface->getUsbHidInputReportSize() - 20);
auto totalResponsePackets = std::ceil(static_cast<float>(bytes) / static_cast<float>(singlePacketSize)); auto totalResponsePackets = std::ceil(static_cast<float>(bytes) / static_cast<float>(singlePacketSize));
auto totalReadsRequired = std::ceil(static_cast<float>(totalResponsePackets) / 2); auto totalReadsRequired = std::ceil(static_cast<float>(totalResponsePackets) / 2);
@@ -1713,7 +1713,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ReadMemory( ReadMemory(
type, type,
startAddress, startAddress,
@@ -1780,7 +1780,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
} }
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
WriteMemory( WriteMemory(
type, type,
startAddress, startAddress,
@@ -1811,7 +1811,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::disableDebugWire() { void EdbgAvr8Interface::disableDebugWire() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
DisableDebugWire() DisableDebugWire()
); );

View File

@@ -27,7 +27,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
class EdbgAvr8Interface: public TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface class EdbgAvr8Interface: public TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface
{ {
public: public:
explicit EdbgAvr8Interface(EdbgInterface& edbgInterface); explicit EdbgAvr8Interface(EdbgInterface* edbgInterface);
/** /**
* Some EDBG devices don't seem to operate correctly when actioning the masked memory read EDBG command. The * Some EDBG devices don't seem to operate correctly when actioning the masked memory read EDBG command. The
@@ -276,7 +276,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* *
* Every EDBG based debug tool that utilises this implementation must provide access to its EDBG interface. * Every EDBG based debug tool that utilises this implementation must provide access to its EDBG interface.
*/ */
EdbgInterface& edbgInterface; EdbgInterface* edbgInterface = nullptr;
/** /**
* Project's AVR8 target configuration. * Project's AVR8 target configuration.

View File

@@ -26,12 +26,16 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
using Exceptions::TargetOperationFailure; using Exceptions::TargetOperationFailure;
EdbgAvrIspInterface::EdbgAvrIspInterface(EdbgInterface* edbgInterface)
: edbgInterface(edbgInterface)
{}
void EdbgAvrIspInterface::setIspParameters(const Targets::Microchip::Avr::IspParameters& ispParameters) { void EdbgAvrIspInterface::setIspParameters(const Targets::Microchip::Avr::IspParameters& ispParameters) {
this->ispParameters = ispParameters; this->ispParameters = ispParameters;
} }
void EdbgAvrIspInterface::activate() { void EdbgAvrIspInterface::activate() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
EnterProgrammingMode( EnterProgrammingMode(
this->ispParameters.programModeTimeout, this->ispParameters.programModeTimeout,
this->ispParameters.programModeStabilizationDelay, this->ispParameters.programModeStabilizationDelay,
@@ -52,7 +56,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvrIspInterface::deactivate() { void EdbgAvrIspInterface::deactivate() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
LeaveProgrammingMode( LeaveProgrammingMode(
this->ispParameters.programModePreDelay, this->ispParameters.programModePreDelay,
this->ispParameters.programModePostDelay this->ispParameters.programModePostDelay
@@ -74,7 +78,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
Fuse EdbgAvrIspInterface::readFuse(FuseType fuseType) { Fuse EdbgAvrIspInterface::readFuse(FuseType fuseType) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ReadFuse(fuseType, this->ispParameters.readFusePollIndex) ReadFuse(fuseType, this->ispParameters.readFusePollIndex)
); );
@@ -93,7 +97,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
unsigned char EdbgAvrIspInterface::readLockBitByte() { unsigned char EdbgAvrIspInterface::readLockBitByte() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ReadLock(this->ispParameters.readLockPollIndex) ReadLock(this->ispParameters.readLockPollIndex)
); );
@@ -112,7 +116,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvrIspInterface::programFuse(Targets::Microchip::Avr::Fuse fuse) { void EdbgAvrIspInterface::programFuse(Targets::Microchip::Avr::Fuse fuse) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ProgramFuse(fuse.type, fuse.value) ProgramFuse(fuse.type, fuse.value)
); );
@@ -125,7 +129,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
unsigned char EdbgAvrIspInterface::readSignatureByte(std::uint8_t signatureByteAddress) { unsigned char EdbgAvrIspInterface::readSignatureByte(std::uint8_t signatureByteAddress) {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ReadSignature(signatureByteAddress, this->ispParameters.readSignaturePollIndex) ReadSignature(signatureByteAddress, this->ispParameters.readSignaturePollIndex)
); );

View File

@@ -22,9 +22,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
class EdbgAvrIspInterface: public TargetInterfaces::Microchip::Avr::AvrIspInterface class EdbgAvrIspInterface: public TargetInterfaces::Microchip::Avr::AvrIspInterface
{ {
public: public:
explicit EdbgAvrIspInterface(EdbgInterface& edbgInterface) explicit EdbgAvrIspInterface(EdbgInterface* edbgInterface);
: edbgInterface(edbgInterface)
{};
/** /**
* The EdbgAvrIspInterface doesn't actually require any config from the user, at this point in time. So this * The EdbgAvrIspInterface doesn't actually require any config from the user, at this point in time. So this
@@ -89,7 +87,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* *
* Every EDBG based debug tool that utilises this implementation must provide access to its EDBG interface. * Every EDBG based debug tool that utilises this implementation must provide access to its EDBG interface.
*/ */
EdbgInterface& edbgInterface; EdbgInterface* edbgInterface;
Targets::Microchip::Avr::IspParameters ispParameters; Targets::Microchip::Avr::IspParameters ispParameters;

View File

@@ -8,6 +8,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
{ {
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
EdbgInterface::EdbgInterface(Usb::HidInterface&& usbHidInterface)
: CmsisDapInterface(std::move(usbHidInterface))
{}
Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandsAndWaitForResponse( Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandsAndWaitForResponse(
const std::vector<Avr::AvrCommand>& avrCommands const std::vector<Avr::AvrCommand>& avrCommands
) { ) {

View File

@@ -22,7 +22,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
class EdbgInterface: public CmsisDapInterface class EdbgInterface: public CmsisDapInterface
{ {
public: public:
explicit EdbgInterface() = default; explicit EdbgInterface(Usb::HidInterface&& usbHidInterface);
/** /**
* Send an AvrCommandFrame to the debug tool and wait for a response. * Send an AvrCommandFrame to the debug tool and wait for a response.

View File

@@ -12,8 +12,12 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
using Protocols::CmsisDap::Edbg::Avr::CommandFrames::EdbgControl::GetParameter; using Protocols::CmsisDap::Edbg::Avr::CommandFrames::EdbgControl::GetParameter;
using Protocols::CmsisDap::Edbg::Avr::CommandFrames::EdbgControl::SetParameter; using Protocols::CmsisDap::Edbg::Avr::CommandFrames::EdbgControl::SetParameter;
EdbgTargetPowerManagementInterface::EdbgTargetPowerManagementInterface(EdbgInterface* edbgInterface)
: edbgInterface(edbgInterface)
{}
void EdbgTargetPowerManagementInterface::enableTargetPower() { void EdbgTargetPowerManagementInterface::enableTargetPower() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetParameter(EdbgParameters::CONTROL_TARGET_POWER, 0x01) SetParameter(EdbgParameters::CONTROL_TARGET_POWER, 0x01)
); );
@@ -23,7 +27,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
} }
void EdbgTargetPowerManagementInterface::disableTargetPower() { void EdbgTargetPowerManagementInterface::disableTargetPower() {
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame( auto response = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetParameter(EdbgParameters::CONTROL_TARGET_POWER, 0x00) SetParameter(EdbgParameters::CONTROL_TARGET_POWER, 0x00)
); );

View File

@@ -10,8 +10,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
class EdbgTargetPowerManagementInterface: public TargetInterfaces::TargetPowerManagementInterface class EdbgTargetPowerManagementInterface: public TargetInterfaces::TargetPowerManagementInterface
{ {
public: public:
explicit EdbgTargetPowerManagementInterface(EdbgInterface& edbgInterface) explicit EdbgTargetPowerManagementInterface(EdbgInterface* edbgInterface);
: edbgInterface(edbgInterface) {};
/** /**
* Issues a Set Parameter command to the EDBG tool, to enable the target power. * Issues a Set Parameter command to the EDBG tool, to enable the target power.
@@ -24,6 +23,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
void disableTargetPower() override; void disableTargetPower() override;
private: private:
EdbgInterface& edbgInterface; EdbgInterface* edbgInterface;
}; };
} }

View File

@@ -9,65 +9,71 @@ namespace Bloom::Usb
{ {
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
HidInterface::HidInterface(std::uint8_t interfaceNumber, std::uint16_t vendorId, std::uint16_t productId)
: interfaceNumber(interfaceNumber)
, vendorId(vendorId)
, productId(productId)
{}
void HidInterface::init() { void HidInterface::init() {
if (this->libUsbDevice == nullptr) { ::hid_init();
throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer."); ::hid_device* hidDevice = nullptr;
}
hid_init(); const auto hidInterfacePath = this->getHidDevicePath();
hid_device* hidDevice = nullptr;
std::string hidInterfacePath = this->getDevicePathByInterfaceNumber(this->getNumber());
Logger::debug("HID device path: " + hidInterfacePath); Logger::debug("HID device path: " + hidInterfacePath);
if ((hidDevice = hid_open_path(hidInterfacePath.c_str())) == nullptr) { if ((hidDevice = ::hid_open_path(hidInterfacePath.c_str())) == nullptr) {
throw DeviceInitializationFailure("Failed to open HID device via hidapi."); throw DeviceInitializationFailure("Failed to open HID device via hidapi.");
} }
if (hidDevice->input_ep_max_packet_size < 1) { this->hidDevice.reset(hidDevice);
if (this->hidDevice->input_ep_max_packet_size < 1) {
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Invalid max packet size for USB endpoint, on interface " "Invalid max packet size for USB endpoint, on interface "
+ std::to_string(this->getNumber()) + std::to_string(this->interfaceNumber)
); );
} }
this->setHidDevice(hidDevice); this->inputReportSize = static_cast<std::size_t>(this->hidDevice->input_ep_max_packet_size);
this->setInputReportSize(static_cast<std::size_t>(hidDevice->input_ep_max_packet_size));
this->libUsbDeviceHandle = hidDevice->device_handle;
this->initialised = true;
} }
void HidInterface::close() { void HidInterface::close() {
auto* hidDevice = this->getHidDevice(); this->hidDevice.reset();
::hid_exit();
if (hidDevice != nullptr) {
this->libUsbDeviceHandle = nullptr;
hid_close(hidDevice);
// hid_close() releases the interface
this->claimed = false;
}
hid_exit();
Interface::close();
} }
std::vector<unsigned char> HidInterface::read(unsigned int timeout) { std::vector<unsigned char> HidInterface::read(std::optional<std::chrono::milliseconds> timeout) {
std::vector<unsigned char> output; auto output = std::vector<unsigned char>();
auto readSize = this->getInputReportSize();
// Attempt to read the first HID report packet, and whatever is left after that. const auto readSize = this->inputReportSize;
output.resize(readSize); auto transferredByteCount = int(0);
auto transferredByteCount = this->read(output.data(), readSize, timeout); auto totalByteCount = std::size_t(0);
auto totalByteCount = transferredByteCount;
while (transferredByteCount >= readSize) { do {
output.resize(totalByteCount + readSize); output.resize(totalByteCount + readSize, 0x00);
transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1); transferredByteCount = ::hid_read_timeout(
totalByteCount += transferredByteCount; this->hidDevice.get(),
} output.data() + totalByteCount,
readSize,
timeout.has_value() ? static_cast<int>(timeout->count()) : -1
);
output.resize(totalByteCount); if (transferredByteCount == -1) {
throw DeviceCommunicationFailure("Failed to read from HID device.");
}
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>(transferredByteCount);
} while (transferredByteCount >= readSize);
output.resize(totalByteCount, 0x00);
return output; return output;
} }
@@ -89,49 +95,35 @@ namespace Bloom::Usb
int transferred = 0; int transferred = 0;
const auto length = buffer.size(); const auto length = buffer.size();
if ((transferred = hid_write(this->getHidDevice(), buffer.data(), length)) != length) { if ((transferred = ::hid_write(this->hidDevice.get(), buffer.data(), length)) != length) {
Logger::debug("Attempted to write " + std::to_string(length) Logger::debug("Attempted to write " + std::to_string(length)
+ " bytes to HID interface. Bytes written: " + std::to_string(transferred)); + " bytes to HID interface. Bytes written: " + std::to_string(transferred));
throw DeviceCommunicationFailure("Failed to write data to HID interface."); throw DeviceCommunicationFailure("Failed to write data to HID interface.");
} }
} }
std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) { std::string HidInterface::getHidDevicePath() {
int transferred; const auto hidDeviceInfoList = std::unique_ptr<::hid_device_info, decltype(&::hid_free_enumeration)>(
::hid_enumerate(this->vendorId, this->productId),
if ((transferred = hid_read_timeout( ::hid_free_enumeration
this->hidDevice,
buffer,
maxLength,
timeout == 0 ? -1 : static_cast<int>(timeout))
) == -1
) {
throw DeviceCommunicationFailure("Failed to read from HID device.");
}
return static_cast<std::size_t>(transferred);
}
std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) {
hid_device_info* hidDeviceInfoList = hid_enumerate(
this->getVendorId(),
this->getProductId()
); );
while (hidDeviceInfoList != nullptr) { auto matchedDevice = std::optional<::hid_device_info*>();
if (hidDeviceInfoList->interface_number == interfaceNumber) {
auto* hidDeviceInfo = hidDeviceInfoList.get();
while (hidDeviceInfo != nullptr) {
if (hidDeviceInfo->interface_number == this->interfaceNumber) {
matchedDevice = hidDeviceInfo;
break; break;
} }
hidDeviceInfoList = hidDeviceInfoList->next; hidDeviceInfo = hidDeviceInfoList->next;
} }
if (hidDeviceInfoList == nullptr) { if (!matchedDevice.has_value()) {
throw DeviceInitializationFailure("Failed to match interface number with HID interface."); throw DeviceInitializationFailure("Failed to match interface number with HID interface.");
} }
auto path = std::string(hidDeviceInfoList->path); return std::string(matchedDevice.value()->path);
hid_free_enumeration(hidDeviceInfoList);
return path;
} }
} }

View File

@@ -1,11 +1,13 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <optional>
#include <chrono>
#include "hidapi.hpp" #include "hidapi.hpp"
#include "src/DebugToolDrivers/USB/Interface.hpp"
namespace Bloom::Usb namespace Bloom::Usb
{ {
@@ -15,35 +17,46 @@ namespace Bloom::Usb
* Currently, this interface only supports single-report HID implementations. HID interfaces with * Currently, this interface only supports single-report HID implementations. HID interfaces with
* multiple reports will be supported as-and-when we need it. * multiple reports will be supported as-and-when we need it.
*/ */
class HidInterface: public Interface class HidInterface
{ {
public: public:
std::uint8_t interfaceNumber = 0;
HidInterface(
std::uint8_t interfaceNumber,
std::uint16_t vendorId,
std::uint16_t productId
);
HidInterface(const HidInterface& other) = delete;
HidInterface& operator = (const HidInterface& other) = delete;
HidInterface(HidInterface&& other) = default;
HidInterface& operator = (HidInterface&& other) = default;
std::size_t getInputReportSize() const { std::size_t getInputReportSize() const {
return this->inputReportSize; return this->inputReportSize;
} }
/** /**
* Claims the USB HID interface and obtains a hid_device instance * Obtains a hid_device instance and claims the HID interface on the device.
*/ */
void init() override; void init();
/** /**
* Closes the hid_device and releases any claimed interfaces (via hid_close()) * Releases any claimed interfaces and closes the hid_device.
*/ */
void close() override; void close();
/** /**
* Reads as much data as the device has to offer, into a vector. * Reads as much data as the device has to offer, into a vector.
* *
* If `timeout` is set to 0, this method will block until at least one HID report
* packet is received.
*
* @param timeout * @param timeout
* *
* @return * @return
* A vector of the data received from the device. * A vector of the data received from the device.
*/ */
std::vector<unsigned char> read(unsigned int timeout = 0); std::vector<unsigned char> read(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
/** /**
* Writes buffer to HID output endpoint. * Writes buffer to HID output endpoint.
@@ -52,59 +65,20 @@ namespace Bloom::Usb
*/ */
void write(std::vector<unsigned char>&& buffer); void write(std::vector<unsigned char>&& buffer);
/** std::string getHidDevicePath();
* Resolves a device path from a USB interface number.
*
* @param interfaceNumber
* @return
*/
std::string getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber);
protected:
hid_device* getHidDevice() const {
return this->hidDevice;
}
private: private:
/** using HidDeviceType = std::unique_ptr<::hid_device, decltype(&::hid_close)>;
* The HIDAPI library provides a hid_device data structure to represent a USB HID interface.
* HidDeviceType hidDevice = HidDeviceType(nullptr, ::hid_close);
* @see hidapi.hpp or the HIDAPI documentation for more on this.
*/
hid_device* hidDevice = nullptr;
/** /**
* All HID reports have a fixed report length. This means that every packet * All HID reports have a fixed report length. This means that every packet we send or receive to/from an HID
* we send or receive to/from an HID endpoint must be equal to the report length in size. * endpoint must be equal (in size) to the report length.
*
* The default input report size is 64 bytes, but this is overridden at interface initialisation.
* @see definition of init() for more on this.
*/ */
std::size_t inputReportSize = 64; std::size_t inputReportSize = 64;
void setHidDevice(hid_device* hidDevice) { std::uint16_t vendorId = 0;
this->hidDevice = hidDevice; std::uint16_t productId = 0;
}
void setInputReportSize(const std::size_t& inputReportSize) {
this->inputReportSize = inputReportSize;
}
/**
* Reads a maximum of `maxLength` bytes into `buffer`, from the HID input endpoint.
*
* Keeping this in the private scope to enforce use of vector<unsigned char>. See read()
* method in public scope.
*
* @TODO: Do we really need this? Why not just have the one that accepts the vector. Review
*
* @param buffer
* @param maxLength
* @param timeout
*
* @return
* Number of bytes read.
*/
std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout);
}; };
} }

View File

@@ -1,123 +0,0 @@
#include "Interface.hpp"
#include <libusb-1.0/libusb.h>
#include "src/TargetController/Exceptions/DeviceFailure.hpp"
#include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp"
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
namespace Bloom::Usb
{
using namespace Bloom::Exceptions;
void Interface::init() {
if (this->libUsbDevice == nullptr) {
throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer.");
}
if (this->libUsbDeviceHandle == nullptr) {
throw DeviceInitializationFailure("Cannot initialise interface without libusb device handle.");
}
this->initialised = true;
}
void Interface::close() {
if (this->libUsbDeviceHandle != nullptr) {
this->release();
}
this->initialised = false;
}
void Interface::claim() {
int interfaceNumber = this->getNumber();
this->detachKernelDriver();
if (libusb_claim_interface(this->libUsbDeviceHandle, interfaceNumber) != 0) {
throw DeviceInitializationFailure(
"Failed to claim interface {" + std::to_string(interfaceNumber) + "} on USB device\n"
);
}
this->claimed = true;
}
void Interface::detachKernelDriver() {
int interfaceNumber = this->getNumber();
int libUsbStatusCode;
if ((libUsbStatusCode = libusb_kernel_driver_active(this->libUsbDeviceHandle, interfaceNumber)) != 0) {
if (libUsbStatusCode == 1) {
// A kernel driver is active on this interface. Attempt to detach it
if (libusb_detach_kernel_driver(this->libUsbDeviceHandle, interfaceNumber) != 0) {
throw DeviceInitializationFailure("Failed to detach kernel driver from interface " +
std::to_string(interfaceNumber) + "\n");
}
} else {
throw DeviceInitializationFailure("Failed to check for active kernel driver on USB interface.");
}
}
}
void Interface::release() {
if (this->isClaimed()) {
if (libusb_release_interface(this->libUsbDeviceHandle, this->getNumber()) != 0) {
throw DeviceFailure(
"Failed to release interface {" + std::to_string(this->getNumber())
+ "} on USB device\n"
);
}
this->claimed = false;
}
}
int Interface::read(unsigned char* buffer, unsigned char endPoint, size_t length, size_t timeout) {
int totalTransferred = 0;
int transferred = 0;
int libUsbStatusCode = 0;
while (length > totalTransferred) {
libUsbStatusCode = libusb_interrupt_transfer(
this->libUsbDeviceHandle,
endPoint,
buffer,
static_cast<int>(length),
&transferred,
static_cast<unsigned int>(timeout)
);
if (libUsbStatusCode != 0 && libUsbStatusCode != -7) {
throw DeviceCommunicationFailure(
"Failed to read from USB device. Error code returned: " + std::to_string(libUsbStatusCode)
);
}
totalTransferred += transferred;
}
return transferred;
}
void Interface::write(unsigned char* buffer, unsigned char endPoint, int length) {
int transferred = 0;
int libUsbStatusCode = 0;
libUsbStatusCode = libusb_interrupt_transfer(
this->libUsbDeviceHandle,
endPoint,
buffer,
length,
&transferred,
0
);
if (libUsbStatusCode != 0) {
throw DeviceCommunicationFailure(
"Failed to read from USB device. Error code returned: " + std::to_string(libUsbStatusCode)
);
}
}
}

View File

@@ -1,124 +0,0 @@
#pragma once
#include <cstdint>
#include <libusb-1.0/libusb.h>
#include <string>
#include "UsbDevice.hpp"
namespace Bloom::Usb
{
class Interface
{
public:
explicit Interface(const std::uint8_t& interfaceNumber = 0) {
this->setNumber(interfaceNumber);
}
virtual ~Interface() = default;
Interface(const Interface& other) = default;
Interface(Interface&& other) = default;
Interface& operator = (const Interface& other) = default;
Interface& operator = (Interface&& other) = default;
void setLibUsbDevice(libusb_device* libUsbDevice) {
this->libUsbDevice = libUsbDevice;
}
void setLibUsbDeviceHandle(libusb_device_handle* libUsbDeviceHandle) {
this->libUsbDeviceHandle = libUsbDeviceHandle;
}
std::uint8_t getNumber() const {
return this->number;
}
void setNumber(std::uint8_t number) {
this->number = number;
}
const std::string& getName() const {
return this->name;
}
void setName(const std::string& name) {
this->name = name;
}
bool isClaimed() const {
return this->claimed;
}
bool isInitialised() const {
return this->initialised;
}
std::uint16_t getVendorId() const {
return this->vendorId;
}
void setVendorId(std::uint16_t vendorId) {
this->vendorId = vendorId;
}
std::uint16_t getProductId() const {
return this->productId;
}
void setProductId(std::uint16_t productId) {
this->productId = productId;
}
/**
* Attempts to obtain a device descriptor and device handle via libusb.
*/
virtual void init();
/**
* Releases the interface and closes the device descriptor.
*/
virtual void close();
/**
* Attempts to claim the interface
*/
void claim();
/**
* If a kernel driver is attached to the interface, this method will detach it.
*/
void detachKernelDriver();
/**
* Releases the interface, if claimed.
*/
void release();
/**
* @TODO Remove or refactor these (read() and write()) - they're not currently used
*
* @param buffer
* @param endPoint
* @param length
* @param timeout
* @return
*/
virtual int read(unsigned char* buffer, unsigned char endPoint, std::size_t length, std::size_t timeout);
virtual void write(unsigned char* buffer, unsigned char endPoint, int length);
protected:
libusb_device* libUsbDevice = nullptr;
libusb_device_handle* libUsbDeviceHandle = nullptr;
std::uint16_t vendorId = 0;
std::uint16_t productId = 0;
std::uint8_t number = 0;
std::string name;
bool initialised = false;
bool claimed = false;
};
}

View File

@@ -1,5 +1,7 @@
#include "UsbDevice.hpp" #include "UsbDevice.hpp"
#include <libusb-1.0/libusb.h>
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" #include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
@@ -7,103 +9,134 @@ namespace Bloom::Usb
{ {
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
UsbDevice::UsbDevice(std::uint16_t vendorId, std::uint16_t productId)
: vendorId(vendorId)
, productId(productId)
{
if (!UsbDevice::libusbContext) {
::libusb_context* libusbContext = nullptr;
::libusb_init(&libusbContext);
UsbDevice::libusbContext.reset(libusbContext);
}
}
void UsbDevice::init() { void UsbDevice::init() {
libusb_init(&this->libUsbContext); // ::libusb_set_option(this->libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE); auto devices = this->findMatchingDevices(this->vendorId, this->productId);
auto devices = this->findMatchingDevices();
if (devices.empty()) { if (devices.empty()) {
throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID."); throw DeviceInitializationFailure(
"Failed to find USB device with matching vendor and product ID. Please examine the debug tool's USB "
"connection, as well as the selected environment's debug tool configuration in bloom.yaml"
);
} }
if (devices.size() > 1) { if (devices.size() > 1) {
// TODO: implement support for multiple devices (maybe via serial number?) // TODO: implement support for multiple devices via serial number matching?
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Numerous devices of matching vendor & product ID found.\n" "Numerous devices of matching vendor and product ID found.\n"
"Please ensure that only one debug tool is connected and then try again." "Please ensure that only one debug tool is connected and then try again."
); );
} }
// For now, just use the first device found. // For now, just use the first device found.
auto* device = devices.front(); this->libusbDevice.swap(devices.front());
this->setLibUsbDevice(device); ::libusb_device_handle* deviceHandle = nullptr;
const int libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle); const int libusbStatusCode = ::libusb_open(this->libusbDevice.get(), &deviceHandle);
// Obtain a device handle from libusb if (libusbStatusCode < 0) {
if (libUsbStatusCode < 0) { // Failed to a device handle from libusb
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned." "Failed to open USB device - error code " + std::to_string(libusbStatusCode) + " returned."
); );
} }
this->libusbDeviceHandle.reset(deviceHandle);
} }
void UsbDevice::setConfiguration(int configIndex) { void UsbDevice::setConfiguration(int configIndex) {
libusb_config_descriptor* configDescriptor = {}; ::libusb_config_descriptor* configDescriptor = {};
int libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor); int libusbStatusCode = ::libusb_get_config_descriptor(this->libusbDevice.get(), 0, &configDescriptor);
if (libUsbStatusCode < 0) { if (libusbStatusCode < 0) {
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode) "Failed to obtain USB configuration descriptor - error code " + std::to_string(libusbStatusCode)
+ " returned." + " returned."
); );
} }
libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue); libusbStatusCode = ::libusb_set_configuration(
if (libUsbStatusCode < 0) { this->libusbDeviceHandle.get(),
configDescriptor->bConfigurationValue
);
if (libusbStatusCode < 0) {
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned." "Failed to set USB configuration - error code " + std::to_string(libusbStatusCode) + " returned."
); );
} }
libusb_free_config_descriptor(configDescriptor); ::libusb_free_config_descriptor(configDescriptor);
} }
std::vector<libusb_device*> UsbDevice::findMatchingDevices( std::vector<LibusbDeviceType> UsbDevice::findMatchingDevices(
std::optional<std::uint16_t> vendorId, std::optional<std::uint16_t> productId std::uint16_t vendorId, std::uint16_t productId
) { ) {
auto* libUsbContext = this->libUsbContext; ::libusb_device** devices = nullptr;
libusb_device** devices = nullptr; ::libusb_device* device;
libusb_device* device; std::vector<LibusbDeviceType> matchedDevices;
std::vector<libusb_device*> matchedDevices;
auto vendorIdToMatch = vendorId.value_or(this->vendorId); auto libusbStatusCode = ::libusb_get_device_list(UsbDevice::libusbContext.get(), &devices);
auto productIdToMatch = productId.value_or(this->productId); if (libusbStatusCode < 0) {
ssize_t libUsbStatusCode = libusb_get_device_list(libUsbContext, &devices);
if (libUsbStatusCode < 0) {
throw DeviceInitializationFailure( throw DeviceInitializationFailure(
"Failed to retrieve USB devices - return code: '" + std::to_string(libUsbStatusCode) + "'" "Failed to retrieve USB devices - return code: '" + std::to_string(libusbStatusCode) + "'"
); );
} }
ssize_t i = 0; ssize_t i = 0;
while ((device = devices[i++]) != nullptr) { while ((device = devices[i++]) != nullptr) {
struct libusb_device_descriptor desc = {}; auto libusbDevice = LibusbDeviceType(device, ::libusb_unref_device);
struct ::libusb_device_descriptor desc = {};
if ((libUsbStatusCode = libusb_get_device_descriptor(device, &desc)) < 0) { if ((libusbStatusCode = ::libusb_get_device_descriptor(device, &desc)) < 0) {
Logger::warning("Failed to retrieve USB device descriptor - return code: '" Logger::warning("Failed to retrieve USB device descriptor - return code: '"
+ std::to_string(libUsbStatusCode) + "'"); + std::to_string(libusbStatusCode) + "'");
continue; continue;
} }
if (desc.idVendor == vendorIdToMatch && desc.idProduct == productIdToMatch) { if (desc.idVendor != vendorId || desc.idProduct != productId) {
matchedDevices.push_back(device); continue;
} }
matchedDevices.emplace_back(std::move(libusbDevice));
} }
libusb_free_device_list(devices, 1); ::libusb_free_device_list(devices, 0);
return matchedDevices; return matchedDevices;
} }
void UsbDevice::close() { void UsbDevice::detachKernelDriverFromInterface(std::uint8_t interfaceNumber) {
if (this->libUsbDeviceHandle != nullptr) { const auto libusbStatusCode = ::libusb_kernel_driver_active(this->libusbDeviceHandle.get(), interfaceNumber);
libusb_close(this->libUsbDeviceHandle);
this->libUsbDeviceHandle = nullptr;
}
if (this->libUsbContext != nullptr) { if (libusbStatusCode == 1) {
libusb_exit(this->libUsbContext); // A kernel driver is active on this interface. Attempt to detach it
if (::libusb_detach_kernel_driver(this->libusbDeviceHandle.get(), interfaceNumber) != 0) {
throw DeviceInitializationFailure("Failed to detach kernel driver from interface " +
std::to_string(interfaceNumber) + "\n");
}
} else if (libusbStatusCode != 0) {
throw DeviceInitializationFailure("Failed to check for active kernel driver on USB interface.");
} }
} }
void UsbDevice::close() {
this->libusbDeviceHandle.reset();
this->libusbDevice.reset();
}
UsbDevice::~UsbDevice() {
this->close();
}
} }

View File

@@ -10,37 +10,26 @@
namespace Bloom::Usb namespace Bloom::Usb
{ {
using LibusbContextType = std::unique_ptr<::libusb_context, decltype(&::libusb_exit)>;
using LibusbDeviceType = std::unique_ptr<::libusb_device, decltype(&::libusb_unref_device)>;
using LibusbDeviceHandleType = std::unique_ptr<::libusb_device_handle, decltype(&::libusb_close)>;
class UsbDevice class UsbDevice
{ {
public: public:
UsbDevice(std::uint16_t vendorId, std::uint16_t productId): vendorId(vendorId), productId(productId) {}; std::uint16_t vendorId;
std::uint16_t productId;
virtual ~UsbDevice() = default; UsbDevice(std::uint16_t vendorId, std::uint16_t productId);
UsbDevice(const UsbDevice& other) = delete;
UsbDevice& operator = (const UsbDevice& other) = delete;
UsbDevice(const UsbDevice& other) = default;
UsbDevice(UsbDevice&& other) = default; UsbDevice(UsbDevice&& other) = default;
UsbDevice& operator = (const UsbDevice& other) = default;
UsbDevice& operator = (UsbDevice&& other) = default; UsbDevice& operator = (UsbDevice&& other) = default;
void init(); void init();
[[nodiscard]] libusb_device* getLibUsbDevice() const {
return this->libUsbDevice;
}
void setLibUsbDevice(libusb_device* libUsbDevice) {
this->libUsbDevice = libUsbDevice;
}
[[nodiscard]] std::uint16_t getVendorId() const {
return this->vendorId;
}
[[nodiscard]] std::uint16_t getProductId() const {
return this->productId;
}
/** /**
* Selects a specific configuration on the device, using the configuration index. * Selects a specific configuration on the device, using the configuration index.
* *
@@ -48,16 +37,17 @@ namespace Bloom::Usb
*/ */
virtual void setConfiguration(int configIndex); virtual void setConfiguration(int configIndex);
protected: virtual ~UsbDevice();
libusb_context* libUsbContext = nullptr;
libusb_device* libUsbDevice = nullptr;
libusb_device_handle* libUsbDeviceHandle = nullptr;
std::uint16_t vendorId;
std::uint16_t productId;
std::vector<libusb_device*> findMatchingDevices( protected:
std::optional<std::uint16_t> vendorId = std::nullopt, std::optional<std::uint16_t> productId = std::nullopt static inline LibusbContextType libusbContext = LibusbContextType(nullptr, ::libusb_exit);
);
LibusbDeviceType libusbDevice = LibusbDeviceType(nullptr, ::libusb_unref_device);
LibusbDeviceHandleType libusbDeviceHandle = LibusbDeviceHandleType(nullptr, ::libusb_close);
std::vector<LibusbDeviceType> findMatchingDevices(std::uint16_t vendorId, std::uint16_t productId);
void detachKernelDriverFromInterface(std::uint8_t interfaceNumber);
void close(); void close();
}; };