diff --git a/src/plugins/baremetal/CMakeLists.txt b/src/plugins/baremetal/CMakeLists.txt index 7783e91ec8c..0a6721c4e76 100644 --- a/src/plugins/baremetal/CMakeLists.txt +++ b/src/plugins/baremetal/CMakeLists.txt @@ -20,6 +20,7 @@ add_qtc_plugin(BareMetal debugservers/gdb/eblinkgdbserverprovider.cpp debugservers/gdb/eblinkgdbserverprovider.h debugservers/uvsc/simulatoruvscserverprovider.cpp debugservers/uvsc/simulatoruvscserverprovider.h debugservers/uvsc/stlinkuvscserverprovider.cpp debugservers/uvsc/stlinkuvscserverprovider.h + debugservers/uvsc/jlinkuvscserverprovider.cpp debugservers/uvsc/jlinkuvscserverprovider.h debugservers/uvsc/uvproject.cpp debugservers/uvsc/uvproject.h debugservers/uvsc/uvprojectwriter.cpp debugservers/uvsc/uvprojectwriter.h debugservers/uvsc/uvscserverprovider.cpp debugservers/uvsc/uvscserverprovider.h diff --git a/src/plugins/baremetal/baremetal.qbs b/src/plugins/baremetal/baremetal.qbs index c5fc6985976..c1942018002 100644 --- a/src/plugins/baremetal/baremetal.qbs +++ b/src/plugins/baremetal/baremetal.qbs @@ -55,6 +55,7 @@ QtcPlugin { files: [ "simulatoruvscserverprovider.cpp", "simulatoruvscserverprovider.h", "stlinkuvscserverprovider.cpp", "stlinkuvscserverprovider.h", + "jlinkuvscserverprovider.cpp", "jlinkuvscserverprovider.h", "uvproject.cpp", "uvproject.h", "uvprojectwriter.cpp", "uvprojectwriter.h", "uvscserverprovider.cpp", "uvscserverprovider.h", diff --git a/src/plugins/baremetal/baremetalconstants.h b/src/plugins/baremetal/baremetalconstants.h index 3519a3c50c9..816aa0a51a2 100644 --- a/src/plugins/baremetal/baremetalconstants.h +++ b/src/plugins/baremetal/baremetalconstants.h @@ -45,6 +45,7 @@ const char GDBSERVER_EBLINK_PROVIDER_ID[] = "BareMetal.GdbServerProvider.EBlink" // uVision Debugger Server Provider Ids. const char UVSC_SIMULATOR_PROVIDER_ID[] = "BareMetal.UvscServerProvider.Simulator"; const char UVSC_STLINK_PROVIDER_ID[] = "BareMetal.UvscServerProvider.StLink"; +const char UVSC_JLINK_PROVIDER_ID[] = "BareMetal.UvscServerProvider.JLink"; // Toolchain types. const char IAREW_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Iar"; diff --git a/src/plugins/baremetal/debugserverprovidermanager.cpp b/src/plugins/baremetal/debugserverprovidermanager.cpp index 6a9bbad8a28..52969600fbc 100644 --- a/src/plugins/baremetal/debugserverprovidermanager.cpp +++ b/src/plugins/baremetal/debugserverprovidermanager.cpp @@ -35,6 +35,7 @@ // UVSC debug servers. #include "debugservers/uvsc/simulatoruvscserverprovider.h" #include "debugservers/uvsc/stlinkuvscserverprovider.h" +#include "debugservers/uvsc/jlinkuvscserverprovider.h" #include @@ -65,7 +66,8 @@ DebugServerProviderManager::DebugServerProviderManager() new StLinkUtilGdbServerProviderFactory, new EBlinkGdbServerProviderFactory, new SimulatorUvscServerProviderFactory, - new StLinkUvscServerProviderFactory}) + new StLinkUvscServerProviderFactory, + new JLinkUvscServerProviderFactory}) { m_instance = this; m_writer = new Utils::PersistentSettingsWriter( diff --git a/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp new file mode 100644 index 00000000000..5a37ece6706 --- /dev/null +++ b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "jlinkuvscserverprovider.h" + +#include "uvproject.h" +#include "uvprojectwriter.h" + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include // for std::ofstream + +using namespace Debugger; +using namespace ProjectExplorer; +using namespace Utils; + +namespace BareMetal { +namespace Internal { + +using namespace Uv; + +constexpr char adapterOptionsKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterOptions"; +constexpr char adapterPortKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterPort"; +constexpr char adapterSpeedKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterSpeed"; + +static int decodeSpeedCode(JLinkUvscAdapterOptions::Speed speed) +{ + switch (speed) { + case JLinkUvscAdapterOptions::Speed_50MHz: + return 8; + case JLinkUvscAdapterOptions::Speed_33MHz: + return 9; + case JLinkUvscAdapterOptions::Speed_25MHz: + return 10; + case JLinkUvscAdapterOptions::Speed_20MHz: + return 0; + case JLinkUvscAdapterOptions::Speed_10MHz: + return 1; + case JLinkUvscAdapterOptions::Speed_5MHz: + return 2; + case JLinkUvscAdapterOptions::Speed_3MHz: + return 3; + case JLinkUvscAdapterOptions::Speed_2MHz: + return 4; + case JLinkUvscAdapterOptions::Speed_1MHz: + return 5; + case JLinkUvscAdapterOptions::Speed_500kHz: + return 6; + case JLinkUvscAdapterOptions::Speed_200kHz: + return 7; + default: + return 8; + } +} + +static QString buildAdapterOptions(const JLinkUvscAdapterOptions &opts) +{ + QString s; + if (opts.port == JLinkUvscAdapterOptions::JTAG) + s += "-O14"; + else if (opts.port == JLinkUvscAdapterOptions::SWD) + s += "-O78"; + + const int code = decodeSpeedCode(opts.speed); + s += " -S" + QString::number(code) + " -ZTIFSpeedSel" + QString::number(opts.speed); + return s; +} + +static QString buildDllRegistryKey(const DriverSelection &driver) +{ + const QFileInfo fi(driver.dll); + return fi.baseName(); +} + +static QString buildDllRegistryName(const DeviceSelection &device, + const JLinkUvscAdapterOptions &opts) +{ + if (device.algorithmIndex < 0 || device.algorithmIndex >= int(device.algorithms.size())) + return {}; + const DeviceSelection::Algorithm algorithm = device.algorithms.at(device.algorithmIndex); + const QFileInfo path(algorithm.path); + const QString start = algorithm.start.startsWith("0x") ? algorithm.start.mid(2) + : algorithm.start; + const QString size = algorithm.size.startsWith("0x") ? algorithm.size.mid(2) + : algorithm.size; + const QString adaptOpts = buildAdapterOptions(opts); + return QStringLiteral(" %6 -FN1 -FF0%1 -FS0%2 -FL0%3 -FP0($$Device:%4$%5)") + .arg(path.fileName(), start, size, device.name, path.filePath(), adaptOpts); +} + +// JLinkUvProjectOptions + +class JLinkUvProjectOptions final : public Uv::ProjectOptions +{ +public: + explicit JLinkUvProjectOptions(const JLinkUvscServerProvider *provider) + : Uv::ProjectOptions(provider) + { + const DriverSelection driver = provider->driverSelection(); + const DeviceSelection device = provider->deviceSelection(); + m_debugOpt->appendProperty("nTsel", driver.index); + m_debugOpt->appendProperty("pMon", driver.dll); + + // Fill 'TargetDriverDllRegistry' (required for dedugging). + const auto dllRegistry = m_targetOption->appendPropertyGroup("TargetDriverDllRegistry"); + const auto setRegEntry = dllRegistry->appendPropertyGroup("SetRegEntry"); + setRegEntry->appendProperty("Number", 0); + const QString key = buildDllRegistryKey(driver); + setRegEntry->appendProperty("Key", key); + const QString name = buildDllRegistryName(device, provider->m_adapterOpts); + setRegEntry->appendProperty("Name", name); + } +}; + +// JLinkUvscAdapterOptions + +QVariantMap JLinkUvscAdapterOptions::toMap() const +{ + QVariantMap map; + map.insert(adapterPortKeyC, port); + map.insert(adapterSpeedKeyC, speed); + return map; +} + +bool JLinkUvscAdapterOptions::fromMap(const QVariantMap &data) +{ + port = static_cast(data.value(adapterPortKeyC, SWD).toInt()); + speed = static_cast(data.value(adapterSpeedKeyC, Speed_1MHz).toInt()); + return true; +} + +bool JLinkUvscAdapterOptions::operator==(const JLinkUvscAdapterOptions &other) const +{ + return port == other.port && speed == other.speed; +} + +// JLinkUvscServerProvider + +JLinkUvscServerProvider::JLinkUvscServerProvider() + : UvscServerProvider(Constants::UVSC_JLINK_PROVIDER_ID) +{ + setTypeDisplayName(tr("uVision JLink")); + setConfigurationWidgetCreator([this] { return new JLinkUvscServerProviderConfigWidget(this); }); + setSupportedDrivers({"Segger\\JL2CM3.dll"}); +} + +QVariantMap JLinkUvscServerProvider::toMap() const +{ + QVariantMap data = UvscServerProvider::toMap(); + data.insert(adapterOptionsKeyC, m_adapterOpts.toMap()); + return data; +} + +bool JLinkUvscServerProvider::fromMap(const QVariantMap &data) +{ + if (!UvscServerProvider::fromMap(data)) + return false; + m_adapterOpts.fromMap(data.value(adapterOptionsKeyC).toMap()); + return true; +} + +bool JLinkUvscServerProvider::operator==(const IDebugServerProvider &other) const +{ + if (!UvscServerProvider::operator==(other)) + return false; + const auto p = static_cast(&other); + return m_adapterOpts == p->m_adapterOpts; + return true; +} + +FilePath JLinkUvscServerProvider::optionsFilePath(DebuggerRunTool *runTool, + QString &errorMessage) const +{ + const FilePath optionsPath = buildOptionsFilePath(runTool); + std::ofstream ofs(optionsPath.toString().toStdString(), std::ofstream::out); + Uv::ProjectOptionsWriter writer(&ofs); + const JLinkUvProjectOptions projectOptions(this); + if (!writer.write(&projectOptions)) { + errorMessage = BareMetalDebugSupport::tr( + "Unable to create an uVision project options template"); + return {}; + } + return optionsPath; +} + +// JLinkUvscServerProviderFactory + +JLinkUvscServerProviderFactory::JLinkUvscServerProviderFactory() +{ + setId(Constants::UVSC_JLINK_PROVIDER_ID); + setDisplayName(UvscServerProvider::tr("uVision JLink")); + setCreator([] { return new JLinkUvscServerProvider; }); +} + +// JLinkUvscServerProviderConfigWidget + +JLinkUvscServerProviderConfigWidget::JLinkUvscServerProviderConfigWidget( + JLinkUvscServerProvider *p) + : UvscServerProviderConfigWidget(p) +{ + Q_ASSERT(p); + + m_adapterOptionsWidget = new JLinkUvscAdapterOptionsWidget; + m_mainLayout->addRow(tr("Adapter options:"), m_adapterOptionsWidget); + + setFromProvider(); + + connect(m_adapterOptionsWidget, &JLinkUvscAdapterOptionsWidget::optionsChanged, + this, &JLinkUvscServerProviderConfigWidget::dirty); +} + +void JLinkUvscServerProviderConfigWidget::apply() +{ + const auto p = static_cast(m_provider); + Q_ASSERT(p); + p->m_adapterOpts = adapterOptions(); + UvscServerProviderConfigWidget::apply(); +} + +void JLinkUvscServerProviderConfigWidget::discard() +{ + setFromProvider(); + UvscServerProviderConfigWidget::discard(); +} + +void JLinkUvscServerProviderConfigWidget::setAdapterOpitons( + const JLinkUvscAdapterOptions &adapterOpts) +{ + m_adapterOptionsWidget->setAdapterOptions(adapterOpts); +} + +JLinkUvscAdapterOptions JLinkUvscServerProviderConfigWidget::adapterOptions() const +{ + return m_adapterOptionsWidget->adapterOptions(); +} + +void JLinkUvscServerProviderConfigWidget::setFromProvider() +{ + const auto p = static_cast(m_provider); + Q_ASSERT(p); + const QSignalBlocker blocker(this); + setAdapterOpitons(p->m_adapterOpts); +} + +// JLinkUvscAdapterOptionsWidget + +JLinkUvscAdapterOptionsWidget::JLinkUvscAdapterOptionsWidget(QWidget *parent) + : QWidget(parent) +{ + const auto layout = new QHBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(new QLabel(tr("Port:"))); + m_portBox = new QComboBox; + layout->addWidget(m_portBox); + layout->addWidget(new QLabel(tr("Speed:"))); + m_speedBox = new QComboBox; + layout->addWidget(m_speedBox); + setLayout(layout); + + populatePorts(); + + connect(m_portBox, QOverload::of(&QComboBox::currentIndexChanged), + this, [this](int index) { + Q_UNUSED(index); + populateSpeeds(); + emit optionsChanged(); + }); + connect(m_speedBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &JLinkUvscAdapterOptionsWidget::optionsChanged); +} + +void JLinkUvscAdapterOptionsWidget::setAdapterOptions( + const JLinkUvscAdapterOptions &adapterOpts) +{ + for (auto index = 0; m_portBox->count(); ++index) { + const JLinkUvscAdapterOptions::Port port = portAt(index); + if (port == adapterOpts.port) { + m_portBox->setCurrentIndex(index); + break; + } + } + + populateSpeeds(); + + for (auto index = 0; m_speedBox->count(); ++index) { + const JLinkUvscAdapterOptions::Speed speed = speedAt(index); + if (speed == adapterOpts.speed) { + m_speedBox->setCurrentIndex(index); + break; + } + } +} + +JLinkUvscAdapterOptions JLinkUvscAdapterOptionsWidget::adapterOptions() const +{ + const auto port = portAt(m_portBox->currentIndex()); + const auto speed = speedAt(m_speedBox->currentIndex()); + return {port, speed}; +} + +JLinkUvscAdapterOptions::Port JLinkUvscAdapterOptionsWidget::portAt(int index) const +{ + return static_cast(m_portBox->itemData(index).toInt()); +} + +JLinkUvscAdapterOptions::Speed JLinkUvscAdapterOptionsWidget::speedAt(int index) const +{ + return static_cast(m_speedBox->itemData(index).toInt()); +} + +void JLinkUvscAdapterOptionsWidget::populatePorts() +{ + m_portBox->addItem(tr("JTAG"), JLinkUvscAdapterOptions::JTAG); + m_portBox->addItem(tr("SWD"), JLinkUvscAdapterOptions::SWD); +} + +void JLinkUvscAdapterOptionsWidget::populateSpeeds() +{ + m_speedBox->clear(); + m_speedBox->addItem(tr("50MHz"), JLinkUvscAdapterOptions::Speed_50MHz); + m_speedBox->addItem(tr("33MHz"), JLinkUvscAdapterOptions::Speed_33MHz); + m_speedBox->addItem(tr("25MHz"), JLinkUvscAdapterOptions::Speed_25MHz); + m_speedBox->addItem(tr("20MHz"), JLinkUvscAdapterOptions::Speed_20MHz); + m_speedBox->addItem(tr("10MHz"), JLinkUvscAdapterOptions::Speed_10MHz); + m_speedBox->addItem(tr("5MHz"), JLinkUvscAdapterOptions::Speed_5MHz); + m_speedBox->addItem(tr("3MHz"), JLinkUvscAdapterOptions::Speed_3MHz); + m_speedBox->addItem(tr("2MHz"), JLinkUvscAdapterOptions::Speed_2MHz); + m_speedBox->addItem(tr("1MHz"), JLinkUvscAdapterOptions::Speed_1MHz); + m_speedBox->addItem(tr("500kHz"), JLinkUvscAdapterOptions::Speed_500kHz); + m_speedBox->addItem(tr("200kHz"), JLinkUvscAdapterOptions::Speed_200kHz); + m_speedBox->addItem(tr("100kHz"), JLinkUvscAdapterOptions::Speed_100kHz); +} + +} // namespace Internal +} // namespace BareMetal diff --git a/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h new file mode 100644 index 00000000000..aae713d8ad5 --- /dev/null +++ b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "uvscserverprovider.h" + +QT_BEGIN_NAMESPACE +class QComboBox; +QT_END_NAMESPACE + +namespace BareMetal { +namespace Internal { + +// JLinkUvscAdapterOptions + +class JLinkUvscAdapterOptions final +{ +public: + enum Port { JTAG, SWD }; + enum Speed { + Speed_50MHz = 50000, Speed_33MHz = 33000, Speed_25MHz = 25000, + Speed_20MHz = 20000, Speed_10MHz = 10000, Speed_5MHz = 5000, + Speed_3MHz = 3000, Speed_2MHz = 2000, Speed_1MHz = 1000, + Speed_500kHz = 500, Speed_200kHz = 200, Speed_100kHz = 100, + }; + Port port = Port::SWD; + Speed speed = Speed::Speed_1MHz; + + QVariantMap toMap() const; + bool fromMap(const QVariantMap &data); + bool operator==(const JLinkUvscAdapterOptions &other) const; +}; + +// JLinkUvscServerProvider + +class JLinkUvscServerProvider final : public UvscServerProvider +{ +public: + QVariantMap toMap() const final; + bool fromMap(const QVariantMap &data) final; + + bool operator==(const IDebugServerProvider &other) const final; + Utils::FilePath optionsFilePath(Debugger::DebuggerRunTool *runTool, + QString &errorMessage) const final; +private: + explicit JLinkUvscServerProvider(); + + JLinkUvscAdapterOptions m_adapterOpts; + + friend class JLinkUvscServerProviderConfigWidget; + friend class JLinkUvscServerProviderFactory; + friend class JLinkUvProjectOptions; +}; + +// JLinkUvscServerProviderFactory + +class JLinkUvscServerProviderFactory final : public IDebugServerProviderFactory +{ +public: + JLinkUvscServerProviderFactory(); +}; + +// JLinkUvscServerProviderConfigWidget + +class JLinkUvscAdapterOptionsWidget; +class JLinkUvscServerProviderConfigWidget final : public UvscServerProviderConfigWidget +{ + Q_OBJECT + +public: + explicit JLinkUvscServerProviderConfigWidget(JLinkUvscServerProvider *provider); + +private: + void apply() override; + void discard() override; + + void setAdapterOpitons(const JLinkUvscAdapterOptions &adapterOpts); + JLinkUvscAdapterOptions adapterOptions() const; + void setFromProvider(); + + JLinkUvscAdapterOptionsWidget *m_adapterOptionsWidget = nullptr; +}; + +// JLinkUvscAdapterOptionsWidget + +class JLinkUvscAdapterOptionsWidget final : public QWidget +{ + Q_OBJECT + +public: + explicit JLinkUvscAdapterOptionsWidget(QWidget *parent = nullptr); + void setAdapterOptions(const JLinkUvscAdapterOptions &adapterOpts); + JLinkUvscAdapterOptions adapterOptions() const; + +signals: + void optionsChanged(); + +private: + JLinkUvscAdapterOptions::Port portAt(int index) const; + JLinkUvscAdapterOptions::Speed speedAt(int index) const; + + void populatePorts(); + void populateSpeeds(); + + QComboBox *m_portBox = nullptr; + QComboBox *m_speedBox = nullptr; +}; + +} // namespace Internal +} // namespace BareMetal diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri b/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri index 1b1ce579f34..0d5cba4113a 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri +++ b/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri @@ -1,6 +1,7 @@ HEADERS += \ $$PWD/simulatoruvscserverprovider.h \ $$PWD/stlinkuvscserverprovider.h \ + $$PWD/jlinkuvscserverprovider.h \ $$PWD/uvproject.h \ $$PWD/uvprojectwriter.h \ $$PWD/uvscserverprovider.h \ @@ -19,6 +20,7 @@ HEADERS += \ SOURCES += \ $$PWD/simulatoruvscserverprovider.cpp \ $$PWD/stlinkuvscserverprovider.cpp \ + $$PWD/jlinkuvscserverprovider.cpp \ $$PWD/uvproject.cpp \ $$PWD/uvprojectwriter.cpp \ $$PWD/uvscserverprovider.cpp \