BareMetal: Long live support for KEIL uVision v5.x debugger

This patch adds debugger integration from the KEIL uVision IDE:

* http://www2.keil.com/mdk5/uvision/

This IDE has the uVision Socket Interface (UVSC) that allows
to the applications configuration, building and debugging:

* http://www.keil.com/appnotes/docs/apnt_198.asp

Besides, it provides a binary client libraries for Windows, which
are implements some API which we are use in this patch.

Currently implemented the following features:

* Enumeration of a stack frames.
* Enumeration of a threads (tasks).
* Registers view (read/write).
* Local variables view (read/write).
* Watchers view (read/write).
* Disassembler view.
* Current location marker.
* Break-points.
* Step-in.
* Step-over.
* Step-out.
* Step-by-instruction.
* Start/stop/pause/continue debugger.
* Auto-detection for the installed uVision instances (as debuggers).
* Wizard for choosing and configuring of the UVSC debug providers.

At this moment added support only for the 32-bit ARM devices, provided
by the STMicroelectronics:

https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html

For this are implemented two debugger providers:

* Simulator - allow to simulate the target device.
* ST-Link v2 - it is a HW debugger.

This implementation tested only with the QBS using the following
target boards:

* NUCLEO-F767ZI (based on STM32F767ZIT6 MCU).
* STM32F4DISCOVERY (based on STM32F407VG MCU).
* STM32F103x (based on STM32F103C8T6 MCU).

A more detailed information about this patch can be found in a
bug-tracker.

Fixes: QTCREATORBUG-23426
Change-Id: Ie36a1f7430b56c33d6665cc35e43fe9bd95d28f1
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Denis Shienkov
2020-01-24 17:08:27 +03:00
parent 13c6e5df28
commit 96c1fbcd0a
60 changed files with 8992 additions and 16 deletions
+16
View File
@@ -19,6 +19,22 @@ add_qtc_plugin(BareMetal
debugservers/gdb/stlinkutilgdbserverprovider.cpp debugservers/gdb/stlinkutilgdbserverprovider.h
debugservers/gdb/jlinkgdbserverprovider.cpp debugservers/gdb/jlinkgdbserverprovider.h
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/uvproject.cpp debugservers/uvsc/uvproject.h
debugservers/uvsc/uvprojectwriter.cpp debugservers/uvsc/uvprojectwriter.h
debugservers/uvsc/uvscserverprovider.cpp debugservers/uvsc/uvscserverprovider.h
debugservers/uvsc/uvtargetdevicemodel.cpp debugservers/uvsc/uvtargetdevicemodel.h
debugservers/uvsc/uvtargetdeviceselection.cpp debugservers/uvsc/uvtargetdeviceselection.h
debugservers/uvsc/uvtargetdeviceviewer.cpp debugservers/uvsc/uvtargetdeviceviewer.h
debugservers/uvsc/uvtargetdrivermodel.cpp debugservers/uvsc/uvtargetdrivermodel.h
debugservers/uvsc/uvtargetdriverselection.cpp debugservers/uvsc/uvtargetdriverselection.h
debugservers/uvsc/uvtargetdriverviewer.cpp debugservers/uvsc/uvtargetdriverviewer.h
debugservers/uvsc/xmlnodevisitor.h
debugservers/uvsc/xmlproject.cpp debugservers/uvsc/xmlproject.h
debugservers/uvsc/xmlprojectwriter.cpp debugservers/uvsc/xmlprojectwriter.h
debugservers/uvsc/xmlproperty.cpp debugservers/uvsc/xmlproperty.h
debugservers/uvsc/xmlpropertygroup.cpp debugservers/uvsc/xmlpropertygroup.h
iarewparser.cpp iarewparser.h
iarewtoolchain.cpp iarewtoolchain.h
idebugserverprovider.cpp idebugserverprovider.h
+2
View File
@@ -3,6 +3,8 @@ include(../../qtcreatorplugin.pri)
# GDB debug servers
include(debugservers/gdb/gdbservers.pri)
# UVSC debug servers
include(debugservers/uvsc/uvscservers.pri)
# BareMetal files
+23
View File
@@ -48,4 +48,27 @@ QtcPlugin {
"eblinkgdbserverprovider.cpp", "eblinkgdbserverprovider.h",
]
}
Group {
name: "UVSC Servers"
prefix: "debugservers/uvsc/"
files: [
"simulatoruvscserverprovider.cpp", "simulatoruvscserverprovider.h",
"stlinkuvscserverprovider.cpp", "stlinkuvscserverprovider.h",
"uvproject.cpp", "uvproject.h",
"uvprojectwriter.cpp", "uvprojectwriter.h",
"uvscserverprovider.cpp", "uvscserverprovider.h",
"uvtargetdevicemodel.cpp", "uvtargetdevicemodel.h",
"uvtargetdeviceselection.cpp", "uvtargetdeviceselection.h",
"uvtargetdeviceviewer.cpp", "uvtargetdeviceviewer.h",
"uvtargetdrivermodel.cpp", "uvtargetdrivermodel.h",
"uvtargetdriverselection.cpp", "uvtargetdriverselection.h",
"uvtargetdriverviewer.cpp", "uvtargetdriverviewer.h",
"xmlnodevisitor.h",
"xmlproject.cpp", "xmlproject.h",
"xmlprojectwriter.cpp", "xmlprojectwriter.h",
"xmlproperty.cpp", "xmlproperty.h",
"xmlpropertygroup.cpp", "xmlpropertygroup.h",
]
}
}
+5 -1
View File
@@ -36,12 +36,16 @@ const char MENU_ID[] = "BareMetal.Menu";
const char DEBUG_SERVER_PROVIDERS_SETTINGS_ID[] = "EE.BareMetal.DebugServerProvidersOptions";
// Debugger Server Provider Ids
// GDB Debugger Server Provider Ids.
const char GDBSERVER_OPENOCD_PROVIDER_ID[] = "BareMetal.GdbServerProvider.OpenOcd";
const char GDBSERVER_JLINK_PROVIDER_ID[] = "BareMetal.GdbServerProvider.JLink";
const char GDBSERVER_STLINK_UTIL_PROVIDER_ID[] = "BareMetal.GdbServerProvider.STLinkUtil";
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";
// Toolchain types.
const char IAREW_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Iar";
const char KEIL_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Keil";
@@ -29,8 +29,6 @@
#include "debugserverprovidermanager.h"
#include "idebugserverprovider.h"
#include "debugservers/gdb/gdbserverprovider.h"
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerruncontrol.h>
@@ -32,6 +32,10 @@
#include "debugservers/gdb/jlinkgdbserverprovider.h"
#include "debugservers/gdb/eblinkgdbserverprovider.h"
// UVSC debug servers.
#include "debugservers/uvsc/simulatoruvscserverprovider.h"
#include "debugservers/uvsc/stlinkuvscserverprovider.h"
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
@@ -59,7 +63,9 @@ DebugServerProviderManager::DebugServerProviderManager()
, m_factories({new JLinkGdbServerProviderFactory,
new OpenOcdGdbServerProviderFactory,
new StLinkUtilGdbServerProviderFactory,
new EBlinkGdbServerProviderFactory})
new EBlinkGdbServerProviderFactory,
new SimulatorUvscServerProviderFactory,
new StLinkUvscServerProviderFactory})
{
m_instance = this;
m_writer = new Utils::PersistentSettingsWriter(
@@ -72,6 +72,8 @@ static QString engineTypeName(DebuggerEngineType engineType)
return DebugServerProviderModel::tr("Not recognized");
case GdbEngineType:
return DebugServerProviderModel::tr("GDB");
case UvscEngineType:
return DebugServerProviderModel::tr("UVSC");
default:
return {};
}
@@ -85,6 +87,9 @@ static QString engineTypeDescription(DebuggerEngineType engineType)
case GdbEngineType:
return DebugServerProviderModel::tr("GDB compatible provider engine\n" \
"(used together with the GDB debuggers).");
case UvscEngineType:
return DebugServerProviderModel::tr("UVSC compatible provider engine\n" \
"(used together with the KEIL uVision).");
default:
return {};
}
@@ -0,0 +1,178 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "simulatoruvscserverprovider.h"
#include "uvproject.h"
#include "uvprojectwriter.h"
#include <baremetal/baremetalconstants.h>
#include <baremetal/baremetaldebugsupport.h>
#include <baremetal/debugserverprovidermanager.h>
#include <debugger/debuggerruncontrol.h>
#include <utils/qtcassert.h>
#include <QCheckBox>
#include <QFormLayout>
#include <fstream> // for std::ofstream
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
namespace BareMetal {
namespace Internal {
using namespace Uv;
const char limitSpeedKeyC[] = "BareMetal.SimulatorUvscServerProvider.LimitSpeed";
static DriverSelection defaultSimulatorDriverSelection()
{
DriverSelection selection;
// We don't use any driver DLL for a simulator,
// we just use only one CPU DLL (yes?).
selection.name = "None";
selection.dll = "None";
selection.index = 0;
selection.cpuDlls = QStringList{"SARMCM3.DLL"};
selection.cpuDllIndex = 0;
return selection;
}
// SimulatorUvProjectOptionsWriter
class SimulatorUvProjectOptions final : public Uv::ProjectOptions
{
public:
explicit SimulatorUvProjectOptions(const SimulatorUvscServerProvider *provider)
: Uv::ProjectOptions(provider)
{
m_debugOpt->appendProperty("sLrtime", int(provider->m_limitSpeed));
}
};
// SimulatorUvscServerProvider
SimulatorUvscServerProvider::SimulatorUvscServerProvider()
: UvscServerProvider(Constants::UVSC_SIMULATOR_PROVIDER_ID)
{
setTypeDisplayName(tr("uVision Simulator"));
setConfigurationWidgetCreator([this] { return new SimulatorUvscServerProviderConfigWidget(this); });
setDriverSelection(defaultSimulatorDriverSelection());
}
QVariantMap SimulatorUvscServerProvider::toMap() const
{
QVariantMap data = UvscServerProvider::toMap();
data.insert(limitSpeedKeyC, m_limitSpeed);
return data;
}
bool SimulatorUvscServerProvider::fromMap(const QVariantMap &data)
{
if (!UvscServerProvider::fromMap(data))
return false;
m_limitSpeed = data.value(limitSpeedKeyC).toBool();
return true;
}
bool SimulatorUvscServerProvider::operator==(const IDebugServerProvider &other) const
{
if (!UvscServerProvider::operator==(other))
return false;
const auto p = static_cast<const SimulatorUvscServerProvider *>(&other);
return m_limitSpeed == p->m_limitSpeed;
}
FilePath SimulatorUvscServerProvider::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 SimulatorUvProjectOptions projectOptions(this);
if (!writer.write(&projectOptions)) {
errorMessage = BareMetalDebugSupport::tr(
"Unable to create an uVision project options template");
return {};
}
return optionsPath;
}
// SimulatorUvscServerProviderFactory
SimulatorUvscServerProviderFactory::SimulatorUvscServerProviderFactory()
{
setId(Constants::UVSC_SIMULATOR_PROVIDER_ID);
setDisplayName(UvscServerProvider::tr("uVision Simulator"));
setCreator([] { return new SimulatorUvscServerProvider; });
}
// SimulatorUvscServerProviderConfigWidget
SimulatorUvscServerProviderConfigWidget::SimulatorUvscServerProviderConfigWidget(
SimulatorUvscServerProvider *p)
: UvscServerProviderConfigWidget(p)
{
Q_ASSERT(p);
m_limitSpeedCheckBox = new QCheckBox;
m_limitSpeedCheckBox->setToolTip(tr("Limit speed to real-time"));
m_mainLayout->addRow(tr("Limit speed to real-time:"), m_limitSpeedCheckBox);
setFromProvider();
connect(m_limitSpeedCheckBox, &QAbstractButton::clicked,
this, &SimulatorUvscServerProviderConfigWidget::dirty);
}
void SimulatorUvscServerProviderConfigWidget::apply()
{
const auto p = static_cast<SimulatorUvscServerProvider *>(m_provider);
Q_ASSERT(p);
p->m_limitSpeed = m_limitSpeedCheckBox->isChecked();
UvscServerProviderConfigWidget::apply();
}
void SimulatorUvscServerProviderConfigWidget::discard()
{
setFromProvider();
UvscServerProviderConfigWidget::discard();
}
void SimulatorUvscServerProviderConfigWidget::setFromProvider()
{
const auto p = static_cast<SimulatorUvscServerProvider *>(m_provider);
Q_ASSERT(p);
const QSignalBlocker blocker(this);
m_limitSpeedCheckBox->setChecked(p->m_limitSpeed);
}
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,88 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 QCheckBox;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
// SimulatorUvscServerProvider
class SimulatorUvscServerProvider final : public UvscServerProvider
{
public:
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
bool operator==(const IDebugServerProvider &other) const final;
bool isSimulator() const final { return true; }
Utils::FilePath optionsFilePath(Debugger::DebuggerRunTool *runTool,
QString &errorMessage) const final;
private:
explicit SimulatorUvscServerProvider();
bool m_limitSpeed = false;
friend class SimulatorUvscServerProviderConfigWidget;
friend class SimulatorUvscServerProviderFactory;
friend class SimulatorUvProjectOptions;
};
// SimulatorUvscServerProviderFactory
class SimulatorUvscServerProviderFactory final : public IDebugServerProviderFactory
{
public:
SimulatorUvscServerProviderFactory();
};
// SimulatorUvscServerProviderConfigWidget
class SimulatorUvscServerProviderConfigWidget final : public UvscServerProviderConfigWidget
{
Q_OBJECT
public:
explicit SimulatorUvscServerProviderConfigWidget(SimulatorUvscServerProvider *provider);
private:
void apply() override;
void discard() override;
void setFromProvider();
QCheckBox *m_limitSpeedCheckBox = nullptr;
};
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,348 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "stlinkuvscserverprovider.h"
#include "uvproject.h"
#include "uvprojectwriter.h"
#include <baremetal/baremetalconstants.h>
#include <baremetal/baremetaldebugsupport.h>
#include <baremetal/debugserverprovidermanager.h>
#include <debugger/debuggerruncontrol.h>
#include <utils/qtcassert.h>
#include <QComboBox>
#include <QFileInfo>
#include <QFormLayout>
#include <QLabel>
#include <fstream> // for std::ofstream
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
namespace BareMetal {
namespace Internal {
using namespace Uv;
constexpr char adapterOptionsKeyC[] = "BareMetal.StLinkUvscServerProvider.AdapterOptions";
constexpr char adapterPortKeyC[] = "BareMetal.StLinkUvscServerProvider.AdapterPort";
constexpr char adapterSpeedKeyC[] = "BareMetal.StLinkUvscServerProvider.AdapterSpeed";
static QString buildAdapterOptions(const StLinkUvscAdapterOptions &opts)
{
QString s;
if (opts.port == StLinkUvscAdapterOptions::JTAG)
s += "-0142";
else if (opts.port == StLinkUvscAdapterOptions::SWD)
s += "-0206";
s += " -S" + 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 StLinkUvscAdapterOptions &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);
}
// StLinkUvProjectOptions
class StLinkUvProjectOptions final : public Uv::ProjectOptions
{
public:
explicit StLinkUvProjectOptions(const StLinkUvscServerProvider *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);
}
};
// StLinkUvscAdapterOptions
QVariantMap StLinkUvscAdapterOptions::toMap() const
{
QVariantMap map;
map.insert(adapterPortKeyC, port);
map.insert(adapterSpeedKeyC, speed);
return map;
}
bool StLinkUvscAdapterOptions::fromMap(const QVariantMap &data)
{
port = static_cast<Port>(data.value(adapterPortKeyC, SWD).toInt());
speed = static_cast<Speed>(data.value(adapterSpeedKeyC, Speed_4MHz).toInt());
return true;
}
bool StLinkUvscAdapterOptions::operator==(const StLinkUvscAdapterOptions &other) const
{
return port == other.port && speed == other.speed;
}
// StLinkUvscServerProvider
StLinkUvscServerProvider::StLinkUvscServerProvider()
: UvscServerProvider(Constants::UVSC_STLINK_PROVIDER_ID)
{
setTypeDisplayName(tr("uVision St-Link"));
setConfigurationWidgetCreator([this] { return new StLinkUvscServerProviderConfigWidget(this); });
setSupportedDrivers({"STLink\\ST-LINKIII-KEIL_SWO.dll"});
}
QVariantMap StLinkUvscServerProvider::toMap() const
{
QVariantMap data = UvscServerProvider::toMap();
data.insert(adapterOptionsKeyC, m_adapterOpts.toMap());
return data;
}
bool StLinkUvscServerProvider::fromMap(const QVariantMap &data)
{
if (!UvscServerProvider::fromMap(data))
return false;
m_adapterOpts.fromMap(data.value(adapterOptionsKeyC).toMap());
return true;
}
bool StLinkUvscServerProvider::operator==(const IDebugServerProvider &other) const
{
if (!UvscServerProvider::operator==(other))
return false;
const auto p = static_cast<const StLinkUvscServerProvider *>(&other);
return m_adapterOpts == p->m_adapterOpts;
return true;
}
FilePath StLinkUvscServerProvider::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 StLinkUvProjectOptions projectOptions(this);
if (!writer.write(&projectOptions)) {
errorMessage = BareMetalDebugSupport::tr(
"Unable to create an uVision project options template");
return {};
}
return optionsPath;
}
// StLinkUvscServerProviderFactory
StLinkUvscServerProviderFactory::StLinkUvscServerProviderFactory()
{
setId(Constants::UVSC_STLINK_PROVIDER_ID);
setDisplayName(UvscServerProvider::tr("uVision St-Link"));
setCreator([] { return new StLinkUvscServerProvider; });
}
// StLinkUvscServerProviderConfigWidget
StLinkUvscServerProviderConfigWidget::StLinkUvscServerProviderConfigWidget(
StLinkUvscServerProvider *p)
: UvscServerProviderConfigWidget(p)
{
Q_ASSERT(p);
m_adapterOptionsWidget = new StLinkUvscAdapterOptionsWidget;
m_mainLayout->addRow(tr("Adapter options:"), m_adapterOptionsWidget);
setFromProvider();
connect(m_adapterOptionsWidget, &StLinkUvscAdapterOptionsWidget::optionsChanged,
this, &StLinkUvscServerProviderConfigWidget::dirty);
}
void StLinkUvscServerProviderConfigWidget::apply()
{
const auto p = static_cast<StLinkUvscServerProvider *>(m_provider);
Q_ASSERT(p);
p->m_adapterOpts = adapterOptions();
UvscServerProviderConfigWidget::apply();
}
void StLinkUvscServerProviderConfigWidget::discard()
{
setFromProvider();
UvscServerProviderConfigWidget::discard();
}
void StLinkUvscServerProviderConfigWidget::setAdapterOpitons(
const StLinkUvscAdapterOptions &adapterOpts)
{
m_adapterOptionsWidget->setAdapterOptions(adapterOpts);
}
StLinkUvscAdapterOptions StLinkUvscServerProviderConfigWidget::adapterOptions() const
{
return m_adapterOptionsWidget->adapterOptions();
}
void StLinkUvscServerProviderConfigWidget::setFromProvider()
{
const auto p = static_cast<StLinkUvscServerProvider *>(m_provider);
Q_ASSERT(p);
const QSignalBlocker blocker(this);
setAdapterOpitons(p->m_adapterOpts);
}
// StLinkUvscAdapterOptionsWidget
StLinkUvscAdapterOptionsWidget::StLinkUvscAdapterOptionsWidget(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<int>::of(&QComboBox::currentIndexChanged),
this, [this](int index) {
Q_UNUSED(index);
populateSpeeds();
emit optionsChanged();
});
connect(m_speedBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &StLinkUvscAdapterOptionsWidget::optionsChanged);
}
void StLinkUvscAdapterOptionsWidget::setAdapterOptions(
const StLinkUvscAdapterOptions &adapterOpts)
{
for (auto index = 0; m_portBox->count(); ++index) {
const StLinkUvscAdapterOptions::Port port = portAt(index);
if (port == adapterOpts.port) {
m_portBox->setCurrentIndex(index);
break;
}
}
populateSpeeds();
for (auto index = 0; m_speedBox->count(); ++index) {
const StLinkUvscAdapterOptions::Speed speed = speedAt(index);
if (speed == adapterOpts.speed) {
m_speedBox->setCurrentIndex(index);
break;
}
}
}
StLinkUvscAdapterOptions StLinkUvscAdapterOptionsWidget::adapterOptions() const
{
const auto port = portAt(m_portBox->currentIndex());
const auto speed = speedAt(m_speedBox->currentIndex());
return {port, speed};
}
StLinkUvscAdapterOptions::Port StLinkUvscAdapterOptionsWidget::portAt(int index) const
{
return static_cast<StLinkUvscAdapterOptions::Port>(m_portBox->itemData(index).toInt());
}
StLinkUvscAdapterOptions::Speed StLinkUvscAdapterOptionsWidget::speedAt(int index) const
{
return static_cast<StLinkUvscAdapterOptions::Speed>(m_speedBox->itemData(index).toInt());
}
void StLinkUvscAdapterOptionsWidget::populatePorts()
{
m_portBox->addItem(tr("JTAG"), StLinkUvscAdapterOptions::JTAG);
m_portBox->addItem(tr("SWD"), StLinkUvscAdapterOptions::SWD);
}
void StLinkUvscAdapterOptionsWidget::populateSpeeds()
{
m_speedBox->clear();
const auto port = portAt(m_portBox->currentIndex());
if (port == StLinkUvscAdapterOptions::JTAG) {
m_speedBox->addItem(tr("9MHz"), StLinkUvscAdapterOptions::Speed_9MHz);
m_speedBox->addItem(tr("4.5MHz"), StLinkUvscAdapterOptions::Speed_4_5MHz);
m_speedBox->addItem(tr("2.25MHz"), StLinkUvscAdapterOptions::Speed_2_25MHz);
m_speedBox->addItem(tr("1.12MHz"), StLinkUvscAdapterOptions::Speed_1_12MHz);
m_speedBox->addItem(tr("560kHz"), StLinkUvscAdapterOptions::Speed_560kHz);
m_speedBox->addItem(tr("280kHz"), StLinkUvscAdapterOptions::Speed_280kHz);
m_speedBox->addItem(tr("140kHz"), StLinkUvscAdapterOptions::Speed_140kHz);
} else if (port == StLinkUvscAdapterOptions::SWD) {
m_speedBox->addItem(tr("4MHz"), StLinkUvscAdapterOptions::Speed_4MHz);
m_speedBox->addItem(tr("1.8MHz"), StLinkUvscAdapterOptions::Speed_1_8MHz);
m_speedBox->addItem(tr("950kHz"), StLinkUvscAdapterOptions::Speed_950kHz);
m_speedBox->addItem(tr("480kHz"), StLinkUvscAdapterOptions::Speed_480kHz);
m_speedBox->addItem(tr("240kHz"), StLinkUvscAdapterOptions::Speed_240kHz);
m_speedBox->addItem(tr("125kHz"), StLinkUvscAdapterOptions::Speed_125kHz);
m_speedBox->addItem(tr("100kHz"), StLinkUvscAdapterOptions::Speed_100kHz);
m_speedBox->addItem(tr("50kHz"), StLinkUvscAdapterOptions::Speed_50kHz);
m_speedBox->addItem(tr("25kHz"), StLinkUvscAdapterOptions::Speed_25kHz);
m_speedBox->addItem(tr("15kHz"), StLinkUvscAdapterOptions::Speed_15kHz);
m_speedBox->addItem(tr("5kHz"), StLinkUvscAdapterOptions::Speed_5kHz);
}
}
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,136 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 {
// StLinkUvscAdapterOptions
class StLinkUvscAdapterOptions final
{
public:
enum Port { JTAG, SWD };
enum Speed {
// SWD speeds.
Speed_4MHz = 0, Speed_1_8MHz, Speed_950kHz, Speed_480kHz,
Speed_240kHz, Speed_125kHz, Speed_100kHz, Speed_50kHz,
Speed_25kHz, Speed_15kHz, Speed_5kHz,
// JTAG speeds.
Speed_9MHz = 256, Speed_4_5MHz, Speed_2_25MHz, Speed_1_12MHz,
Speed_560kHz, Speed_280kHz, Speed_140kHz,
};
Port port = Port::SWD;
Speed speed = Speed::Speed_4MHz;
QVariantMap toMap() const;
bool fromMap(const QVariantMap &data);
bool operator==(const StLinkUvscAdapterOptions &other) const;
};
// StLinkUvscServerProvider
class StLinkUvscServerProvider 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 StLinkUvscServerProvider();
StLinkUvscAdapterOptions m_adapterOpts;
friend class StLinkUvscServerProviderConfigWidget;
friend class StLinkUvscServerProviderFactory;
friend class StLinkUvProjectOptions;
};
// StLinkUvscServerProviderFactory
class StLinkUvscServerProviderFactory final : public IDebugServerProviderFactory
{
public:
StLinkUvscServerProviderFactory();
};
// StLinkUvscServerProviderConfigWidget
class StLinkUvscAdapterOptionsWidget;
class StLinkUvscServerProviderConfigWidget final : public UvscServerProviderConfigWidget
{
Q_OBJECT
public:
explicit StLinkUvscServerProviderConfigWidget(StLinkUvscServerProvider *provider);
private:
void apply() override;
void discard() override;
void setAdapterOpitons(const StLinkUvscAdapterOptions &adapterOpts);
StLinkUvscAdapterOptions adapterOptions() const;
void setFromProvider();
StLinkUvscAdapterOptionsWidget *m_adapterOptionsWidget = nullptr;
};
// StLinkUvscAdapterOptionsWidget
class StLinkUvscAdapterOptionsWidget final : public QWidget
{
Q_OBJECT
public:
explicit StLinkUvscAdapterOptionsWidget(QWidget *parent = nullptr);
void setAdapterOptions(const StLinkUvscAdapterOptions &adapterOpts);
StLinkUvscAdapterOptions adapterOptions() const;
signals:
void optionsChanged();
private:
StLinkUvscAdapterOptions::Port portAt(int index) const;
StLinkUvscAdapterOptions::Speed speedAt(int index) const;
void populatePorts();
void populateSpeeds();
QComboBox *m_portBox = nullptr;
QComboBox *m_speedBox = nullptr;
};
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,288 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h"
#include "uvscserverprovider.h"
#include <cpptools/cppmodelmanager.h>
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerruncontrol.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <QFileInfo>
#include <QDir>
using namespace CppTools;
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
namespace BareMetal {
namespace Internal {
namespace Uv {
const char kProjectSchema[] = "2.1";
// Helpers
QString toolsFilePath(const QString &uVisionFilePath)
{
const QFileInfo fi(uVisionFilePath);
QDir dir = fi.dir();
if (!dir.cdUp())
return {};
return dir.absoluteFilePath("tools.ini");
}
QString targetUVisionPath()
{
if (const Target *target = SessionManager::startupTarget()) {
if (const Kit *kit = target->kit()) {
const Runnable runnable = DebuggerKitAspect::runnable(kit);
return runnable.executable.toString();
}
}
return {};
}
static QString buildToolsetNumber(int number)
{
return QStringLiteral("0x%1").arg(QString::number(number, 16));
}
static QString buildVendor(const QString &vendor)
{
// Remove the colon symbol.
const int colonIndex = vendor.lastIndexOf(':');
return vendor.mid(0, colonIndex);
}
static QString buildPackageId(const DeviceSelection::Package &package)
{
return QStringLiteral("%1.%2.%3").arg(package.vendor, package.name, package.version);
}
static QString buildCpu(const DeviceSelection &device)
{
QString cpu;
for (const DeviceSelection::Memory &memory : device.memories) {
const QString id = (memory.id == "IRAM1")
? "IRAM" : ((memory.id == "IROM1") ? "IROM" : memory.id);
cpu += id + '(' + memory.start + ',' + memory.size + ") ";
}
cpu += "CPUTYPE(\"" + device.cpu.core + "\")";
return cpu;
}
static QString buildCpuDllName(const DriverSelection &driver)
{
if (driver.cpuDllIndex < 0 || driver.cpuDllIndex >= driver.cpuDlls.count())
return {};
return driver.cpuDlls.at(driver.cpuDllIndex);
}
static QString buildCpuDllParameters(bool isSimulator)
{
QString params = " -MPU";
if (isSimulator)
params.prepend(" -REMAP");
return params;
}
static void extractAllFiles(const DebuggerRunTool *runTool, QStringList &includes,
FilePaths &headers, FilePaths &sources, FilePaths &assemblers)
{
const auto project = runTool->runControl()->project();
const CppTools::ProjectInfo info = CppModelManager::instance()->projectInfo(project);
const QVector<ProjectPart::Ptr> parts = info.projectParts();
for (const ProjectPart::Ptr &part : parts) {
for (const ProjectFile &file : part->files) {
if (!file.active)
continue;
const auto path = FilePath::fromString(file.path);
if (file.isHeader() && !headers.contains(path))
headers.push_back(path);
else if (file.isSource() && !sources.contains(path))
sources.push_back(path);
else if (file.path.endsWith(".s") && !assemblers.contains(path))
assemblers.push_back(path);
}
for (const HeaderPath &include : part->headerPaths) {
if (!includes.contains(include.path))
includes.push_back(include.path);
}
}
}
// Project
Project::Project(const UvscServerProvider *provider, DebuggerRunTool *runTool)
{
appendProperty("SchemaVersion", kProjectSchema);
appendProperty("Header", "### uVision Project, generated by QtCreator");
const auto targets = appendChild<Gen::Xml::PropertyGroup>("Targets");
// Fill 'Target' group.
m_target = targets->appendPropertyGroup("Target");
m_target->appendProperty("TargetName", "Template");
const int toolsetNo = provider->toolsetNumber();
const QString toolsetNumber = buildToolsetNumber(toolsetNo);
m_target->appendProperty("ToolsetNumber", toolsetNumber);
// Fill 'TargetOption' group.
const auto targetOption = m_target->appendPropertyGroup("TargetOption");
// Fill 'TargetCommonOption' group.
const auto targetCommonOption = targetOption->appendPropertyGroup("TargetCommonOption");
const DeviceSelection device = provider->deviceSelection();
targetCommonOption->appendProperty("Device", device.name);
const QString vendor = buildVendor(device.vendor);
targetCommonOption->appendProperty("Vendor", vendor);
const QString packageId = buildPackageId(device.package);
targetCommonOption->appendProperty("PackID", packageId);
targetCommonOption->appendProperty("PackURL", device.package.url);
const QString cpu = buildCpu(device);
targetCommonOption->appendProperty("Cpu", cpu);
// Fill 'DllOption' group (required for debugging).
const auto dllOption = targetOption->appendPropertyGroup("DllOption");
const DriverSelection driver = provider->driverSelection();
const QString cpuDllName = buildCpuDllName(driver);
const QString simulatorCpuDllParameters = buildCpuDllParameters(true);
const QString targetCpuDllParameters = buildCpuDllParameters(false);
dllOption->appendProperty("SimDllName", cpuDllName);
dllOption->appendProperty("SimDllArguments", simulatorCpuDllParameters);
dllOption->appendProperty("TargetDllName", cpuDllName);
dllOption->appendProperty("TargetDllArguments", targetCpuDllParameters);
QStringList includes;
FilePaths headers;
FilePaths sources;
FilePaths assemblers;
extractAllFiles(runTool, includes, headers, sources, assemblers);
if (toolsetNo == UvscServerProvider::ArmAdsToolsetNumber) {
// Fill 'TargetArmAds' group (required for debugging).
const auto targetArmAds = targetOption->appendPropertyGroup("TargetArmAds");
// Fill 'ArmAdsMisc' group.
const auto armAdsMisc = targetArmAds->appendPropertyGroup("ArmAdsMisc");
// Fill 'OnChipMemories' group.
const auto onChipMemories = armAdsMisc->appendPropertyGroup("OnChipMemories");
static const struct OnChipEntry {
QString id;
QByteArray name;
int type = -1;
} entries[] = {
{"IROM1", "OCR_RVCT4", 1},
{"IROM2", "OCR_RVCT5", 1},
{"IRAM1", "OCR_RVCT9", 0},
{"IRAM2", "OCR_RVCT10", 0},
};
const auto entryBegin = std::cbegin(entries);
const auto entryEnd = std::cend(entries);
for (const DeviceSelection::Memory &memory : device.memories) {
const auto entryIt = std::find_if(entryBegin, entryEnd,
[memory](const OnChipEntry &entry) {
return memory.id == entry.id;
});
if (entryIt == entryEnd)
continue;
// Fill 'OCR_RVCTn' group.
const auto ocrRvct = onChipMemories->appendPropertyGroup(entryIt->name);
ocrRvct->appendProperty("Type", entryIt->type);
ocrRvct->appendProperty("StartAddress", memory.start);
ocrRvct->appendProperty("Size", memory.size);
}
// Fill 'Cads' group.
const auto cAds = targetArmAds->appendPropertyGroup("Cads");
const auto variousControls = cAds->appendPropertyGroup("VariousControls");
variousControls->appendMultiLineProperty("IncludePath", includes, ';');
}
fillAllFiles(headers, sources, assemblers);
}
void Project::fillAllFiles(const FilePaths &headers, const FilePaths &sources,
const FilePaths &assemblers)
{
// Add headers, seources, and assembler files.
const auto groups = m_target->appendPropertyGroup("Groups");
const auto group = groups->appendPropertyGroup("Group");
group->appendProperty("GroupName", "All Files");
const auto filesGroup = group->appendPropertyGroup("Files");
enum FileType { SourceFile = 1, AssemblerFile = 2, HeaderFile = 5 };
auto fillFile = [filesGroup](const FilePath &filePath, FileType fileType) {
const auto fileGroup = filesGroup->appendPropertyGroup("File");
fileGroup->appendProperty("FileName", filePath.fileName());
fileGroup->appendProperty("FileType", fileType);
fileGroup->appendProperty("FilePath", filePath.toString());
};
// Add headers.
for (const auto &header : headers)
fillFile(header, FileType::HeaderFile);
// Add sources.
for (const auto &source : sources)
fillFile(source, FileType::SourceFile);
// Add assemblers.
for (const auto &assembler : assemblers)
fillFile(assembler, FileType::AssemblerFile);
}
// ProjectOptions
ProjectOptions::ProjectOptions(const UvscServerProvider *provider)
{
appendProperty("SchemaVersion", kProjectSchema);
appendProperty("Header", "### uVision Project, generated by QtCreator");
// Fill 'Target' group.
const auto target = appendChild<Gen::Xml::PropertyGroup>("Target");
target->appendProperty("TargetName", "Template");
const int toolsetNo = provider->toolsetNumber();
const QString toolsetNumber = buildToolsetNumber(toolsetNo);
target->appendProperty("ToolsetNumber", toolsetNumber);
m_targetOption = target->appendPropertyGroup("TargetOption");
// Fill 'DebugOpt' group (required for dedugging).
m_debugOpt = m_targetOption->appendPropertyGroup("DebugOpt");
const bool useSimulator = provider->isSimulator();
m_debugOpt->appendProperty("uSim", int(useSimulator));
m_debugOpt->appendProperty("uTrg", int(!useSimulator));
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlproject.h"
#include "xmlpropertygroup.h"
#include <utils/fileutils.h>
namespace Debugger { class DebuggerRunTool; }
namespace BareMetal {
namespace Internal {
class UvscServerProvider;
namespace Uv {
// Helpers
QString toolsFilePath(const QString &uVisionFilePath);
QString targetUVisionPath();
// UvProject
class Project final : public Gen::Xml::Project
{
public:
explicit Project(const UvscServerProvider *provider, Debugger::DebuggerRunTool *runTool);
protected:
Gen::Xml::PropertyGroup *m_target = nullptr;
private:
void fillAllFiles(const Utils::FilePaths &headers, const Utils::FilePaths &sources,
const Utils::FilePaths &assemblers);
};
// ProjectOptions
class ProjectOptions : public Gen::Xml::ProjectOptions
{
public:
explicit ProjectOptions(const UvscServerProvider *provider);
protected:
Gen::Xml::PropertyGroup *m_targetOption = nullptr;
Gen::Xml::PropertyGroup *m_debugOpt = nullptr;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvprojectwriter.h"
namespace BareMetal {
namespace Internal {
namespace Uv {
// ProjectWriter
ProjectWriter::ProjectWriter(std::ostream *device)
: Gen::Xml::ProjectWriter(device)
{
}
void ProjectWriter::visitProjectStart(const Gen::Xml::Project *project)
{
Q_UNUSED(project)
writer()->writeStartElement("Project");
writer()->writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
writer()->writeAttribute("xsi:noNamespaceSchemaLocation", "project_proj.xsd");
}
void ProjectWriter::visitProjectEnd(const Gen::Xml::Project *project)
{
Q_UNUSED(project)
writer()->writeEndElement();
}
// ProjectOptionsWriter
ProjectOptionsWriter::ProjectOptionsWriter(std::ostream *device)
: Gen::Xml::ProjectOptionsWriter(device)
{
}
void ProjectOptionsWriter::visitProjectOptionsStart(
const Gen::Xml::ProjectOptions *projectOptions)
{
Q_UNUSED(projectOptions)
writer()->writeStartElement("ProjectOpt");
writer()->writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
writer()->writeAttribute("xsi:noNamespaceSchemaLocation", "project_optx.xsd");
}
void ProjectOptionsWriter::visitProjectOptionsEnd(
const Gen::Xml::ProjectOptions *projectOptions)
{
Q_UNUSED(projectOptions)
writer()->writeEndElement();
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlprojectwriter.h"
namespace BareMetal {
namespace Internal {
namespace Uv {
// ProjectWriter
class ProjectWriter final : public Gen::Xml::ProjectWriter
{
Q_DISABLE_COPY(ProjectWriter)
public:
explicit ProjectWriter(std::ostream *device);
private:
void visitProjectStart(const Gen::Xml::Project *project) final;
void visitProjectEnd(const Gen::Xml::Project *project) final;
};
// ProjectOptionsWriter
class ProjectOptionsWriter final : public Gen::Xml::ProjectOptionsWriter
{
Q_DISABLE_COPY(ProjectOptionsWriter)
public:
explicit ProjectOptionsWriter(std::ostream *device);
private:
void visitProjectOptionsStart(const Gen::Xml::ProjectOptions *projectOptions) final;
void visitProjectOptionsEnd(const Gen::Xml::ProjectOptions *projectOptions) final;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,367 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h"
#include "uvprojectwriter.h"
#include "uvtargetdeviceviewer.h"
#include "uvtargetdriverviewer.h"
#include "uvscserverprovider.h"
#include <baremetal/baremetaldebugsupport.h>
#include <baremetal/baremetaldevice.h>
#include <baremetal/debugserverprovidermanager.h>
#include <debugger/debuggerkitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <utils/qtcassert.h>
#include <QComboBox>
#include <QFormLayout>
#include <QRegularExpressionValidator>
#include <fstream> // for std::ofstream
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
namespace BareMetal {
namespace Internal {
using namespace Uv;
// Whole software package selection keys.
constexpr char deviceSelectionKeyC[] = "BareMetal.UvscServerProvider.DeviceSelection";
constexpr char driverSelectionKeyC[] = "BareMetal.UvscServerProvider.DriverSelection";
constexpr int defaultPortNumber = 5101;
// UvscServerProvider
UvscServerProvider::UvscServerProvider(const QString &id)
: IDebugServerProvider(id)
{
setEngineType(UvscEngineType);
setChannel("localhost", defaultPortNumber);
setToolsetNumber(ArmAdsToolsetNumber);
}
UvscServerProvider::UvscServerProvider(const UvscServerProvider &other)
: IDebugServerProvider(other.id())
{
setEngineType(UvscEngineType);
}
void UvscServerProvider::setDeviceSelection(const DeviceSelection &deviceSelection)
{
m_deviceSelection = deviceSelection;
}
DeviceSelection UvscServerProvider::deviceSelection() const
{
return m_deviceSelection;
}
void UvscServerProvider::setDriverSelection(const DriverSelection &driverSelection)
{
m_driverSelection = driverSelection;
}
DriverSelection UvscServerProvider::driverSelection() const
{
return m_driverSelection;
}
void UvscServerProvider::setToolsetNumber(ToolsetNumber toolsetNumber)
{
m_toolsetNumber = toolsetNumber;
}
UvscServerProvider::ToolsetNumber UvscServerProvider::toolsetNumber() const
{
return m_toolsetNumber;
}
void UvscServerProvider::setSupportedDrivers(const QStringList &supportedDrivers)
{
m_supportedDrivers = supportedDrivers;
}
QStringList UvscServerProvider::supportedDrivers() const
{
return m_supportedDrivers;
}
bool UvscServerProvider::operator==(const IDebugServerProvider &other) const
{
if (!IDebugServerProvider::operator==(other))
return false;
const auto p = static_cast<const UvscServerProvider *>(&other);
return m_deviceSelection == p->m_deviceSelection
&& m_driverSelection == p->m_driverSelection
&& m_toolsetNumber == p->m_toolsetNumber;
}
FilePath UvscServerProvider::buildProjectFilePath(DebuggerRunTool *runTool) const
{
const RunControl *control = runTool->runControl();
const QString projectName = control->project()->displayName() + ".uvprojx";
const FilePath path = control->buildDirectory().pathAppended(projectName);
return path;
}
FilePath UvscServerProvider::buildOptionsFilePath(DebuggerRunTool *runTool) const
{
const RunControl *control = runTool->runControl();
const QString projectName = control->project()->displayName() + ".uvoptx";
const FilePath path = control->buildDirectory().pathAppended(projectName);
return path;
}
QVariantMap UvscServerProvider::toMap() const
{
QVariantMap data = IDebugServerProvider::toMap();
data.insert(deviceSelectionKeyC, m_deviceSelection.toMap());
data.insert(driverSelectionKeyC, m_driverSelection.toMap());
return data;
}
bool UvscServerProvider::isValid() const
{
return m_channel.isValid();
}
QString UvscServerProvider::channelString() const
{
return m_channel.toString();
}
bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const
{
QTC_ASSERT(runTool, return false);
const RunControl *runControl = runTool->runControl();
const auto exeAspect = runControl->aspect<ExecutableAspect>();
QTC_ASSERT(exeAspect, return false);
const FilePath bin = exeAspect->executable();
if (bin.isEmpty()) {
errorMessage = BareMetalDebugSupport::tr("Cannot debug: Local executable is not set.");
return false;
} else if (!bin.exists()) {
errorMessage = BareMetalDebugSupport::tr(
"Cannot debug: Could not find executable for \"%1\".").arg(bin.toString());
return false;
}
const FilePath projFilePath = projectFilePath(runTool, errorMessage);
if (!projFilePath.exists())
return false;
const FilePath optFilePath = optionsFilePath(runTool, errorMessage);
if (!optFilePath.exists())
return false;
Runnable inferior;
inferior.executable = bin;
inferior.extraData.insert(Debugger::Constants::kUVisionProjectFilePath, projFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionOptionsFilePath, optFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionSimulator, isSimulator());
runTool->setInferior(inferior);
runTool->setSymbolFile(bin);
runTool->setStartMode(AttachToRemoteServer);
runTool->setRemoteChannel(channelString());
runTool->setUseContinueInsteadOfRun(true);
return true;
}
ProjectExplorer::RunWorker *UvscServerProvider::targetRunner(RunControl *runControl) const
{
// Get uVision executable path.
const Runnable uv = DebuggerKitAspect::runnable(runControl->kit());
CommandLine server(uv.executable);
server.addArg("-j0");
server.addArg(QStringLiteral("-s%1").arg(m_channel.port()));
Runnable r;
r.setCommandLine(server);
return new UvscServerProviderRunner(runControl, r);
}
bool UvscServerProvider::fromMap(const QVariantMap &data)
{
if (!IDebugServerProvider::fromMap(data))
return false;
m_deviceSelection.fromMap(data.value(deviceSelectionKeyC).toMap());
m_driverSelection.fromMap(data.value(driverSelectionKeyC).toMap());
return true;
}
Utils::FilePath UvscServerProvider::projectFilePath(DebuggerRunTool *runTool,
QString &errorMessage) const
{
const FilePath projectPath = buildProjectFilePath(runTool);
std::ofstream ofs(projectPath.toString().toStdString(), std::ofstream::out);
Uv::ProjectWriter writer(&ofs);
const Uv::Project project(this, runTool);
if (!writer.write(&project)) {
errorMessage = BareMetalDebugSupport::tr(
"Unable to create an uVision project template");
return {};
}
return projectPath;
}
// HexValueValidator
class HexValueValidator final : public QRegularExpressionValidator
{
public:
explicit HexValueValidator(QObject *parent = nullptr)
: QRegularExpressionValidator(parent)
{
const QRegularExpression re("^0x[0-9a-fA-F]{1,8}");
setRegularExpression(re);
}
};
// UvscServerProviderConfigWidget
UvscServerProviderConfigWidget::UvscServerProviderConfigWidget(UvscServerProvider *provider)
: IDebugServerProviderConfigWidget(provider)
{
m_hostWidget = new HostWidget;
m_mainLayout->addRow(tr("Host:"), m_hostWidget);
m_deviceSelector = new DeviceSelector;
m_mainLayout->addRow(tr("Target device:"), m_deviceSelector);
m_driverSelector = new DriverSelector(provider->supportedDrivers());
m_mainLayout->addRow(tr("Target driver:"), m_driverSelector);
setFromProvider();
connect(m_hostWidget, &HostWidget::dataChanged,
this, &UvscServerProviderConfigWidget::dirty);
connect(m_deviceSelector, &DeviceSelector::selectionChanged,
this, &UvscServerProviderConfigWidget::dirty);
connect(m_driverSelector, &DriverSelector::selectionChanged,
this, &UvscServerProviderConfigWidget::dirty);
}
void UvscServerProviderConfigWidget::apply()
{
const auto p = static_cast<UvscServerProvider *>(m_provider);
p->setDeviceSelection(deviceSelection());
p->setDriverSelection(driverSelection());
IDebugServerProviderConfigWidget::apply();
}
void UvscServerProviderConfigWidget::discard()
{
setFromProvider();
IDebugServerProviderConfigWidget::discard();
}
void UvscServerProviderConfigWidget::setDeviceSelection(const DeviceSelection &deviceSelection)
{
m_deviceSelector->setSelection(deviceSelection);
}
DeviceSelection UvscServerProviderConfigWidget::deviceSelection() const
{
return m_deviceSelector->selection();
}
void UvscServerProviderConfigWidget::setDriverSelection(const DriverSelection &driverSelection)
{
m_driverSelector->setSelection(driverSelection);
}
DriverSelection UvscServerProviderConfigWidget::driverSelection() const
{
return m_driverSelector->selection();
}
void UvscServerProviderConfigWidget::setFromProvider()
{
const auto p = static_cast<UvscServerProvider *>(m_provider);
m_hostWidget->setChannel(p->channel());
m_deviceSelector->setSelection(p->deviceSelection());
m_driverSelector->setSelection(p->driverSelection());
}
// UvscServerProviderRunner
UvscServerProviderRunner::UvscServerProviderRunner(ProjectExplorer::RunControl *runControl,
const Runnable &runnable)
: RunWorker(runControl)
{
setId("BareMetalUvscServer");
const QString program = runnable.executable.toString();
const QStringList args = runnable.commandLineArguments.split(' ');
m_process.setProgram(program);
m_process.setArguments(args);
connect(&m_process, &QtcProcess::started, this, [this]() {
ProcessHandle pid(m_process.processId());
this->runControl()->setApplicationProcessHandle(pid);
reportStarted();
});
connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QtcProcess::finished),
this, [this] (int exitCode, QProcess::ExitStatus status) {
const QString msg = (status == QProcess::CrashExit)
? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode);
appendMessage(msg.arg(m_process.program()), Utils::NormalMessageFormat);
reportStopped();
});
connect(&m_process, &QtcProcess::errorOccurred, this, [this] (QProcess::ProcessError error) {
if (error == QProcess::Timedout)
return; // No actual change on the process side.
const QString msg = userMessageForProcessError(
error, FilePath::fromString(m_process.program()));
appendMessage(msg, Utils::NormalMessageFormat);
reportStopped();
});
}
void UvscServerProviderRunner::start()
{
const QString msg = RunControl::tr("Starting %1 %2...")
.arg(m_process.program()).arg(m_process.arguments().join(' '));
appendMessage(msg, Utils::NormalMessageFormat);
m_process.start();
}
void UvscServerProviderRunner::stop()
{
m_process.terminate();
}
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,144 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdeviceselection.h"
#include "uvtargetdriverselection.h"
#include <baremetal/idebugserverprovider.h>
#include <projectexplorer/runcontrol.h> // for RunWorker
namespace BareMetal {
namespace Internal {
namespace Uv {
class DeviceSelection;
class DeviceSelector;
class DriverSelection;
class DriverSelector;
}
// UvscServerProvider
class UvscServerProvider : public IDebugServerProvider
{
Q_DECLARE_TR_FUNCTIONS(BareMetal::Internal::UvscServerProvider)
public:
enum ToolsetNumber {
UnknownToolsetNumber = -1,
ArmAdsToolsetNumber = 4 // ARM-ADS toolset
};
void setDeviceSelection(const Uv::DeviceSelection &deviceSelection);
Uv::DeviceSelection deviceSelection() const;
void setDriverSelection(const Uv::DriverSelection &driverSelection);
Uv::DriverSelection driverSelection() const;
ToolsetNumber toolsetNumber() const;
QStringList supportedDrivers() const;
bool operator==(const IDebugServerProvider &other) const override;
QVariantMap toMap() const override;
bool aboutToRun(Debugger::DebuggerRunTool *runTool, QString &errorMessage) const final;
ProjectExplorer::RunWorker *targetRunner(ProjectExplorer::RunControl *runControl) const final;
bool isValid() const override;
QString channelString() const final;
protected:
explicit UvscServerProvider(const QString &id);
explicit UvscServerProvider(const UvscServerProvider &other);
void setToolsetNumber(ToolsetNumber toolsetNumber);
void setSupportedDrivers(const QStringList &supportedDrivers);
Utils::FilePath buildProjectFilePath(Debugger::DebuggerRunTool *runTool) const;
Utils::FilePath buildOptionsFilePath(Debugger::DebuggerRunTool *runTool) const;
bool fromMap(const QVariantMap &data) override;
// uVision specific stuff.
virtual Utils::FilePath projectFilePath(Debugger::DebuggerRunTool *runTool,
QString &errorMessage) const;
virtual Utils::FilePath optionsFilePath(Debugger::DebuggerRunTool *runTool,
QString &errorMessage) const = 0;
Uv::DeviceSelection m_deviceSelection;
Uv::DriverSelection m_driverSelection;
// Note: Don't store it to the map!
ToolsetNumber m_toolsetNumber = UnknownToolsetNumber;
QStringList m_supportedDrivers;
friend class UvscServerProviderConfigWidget;
};
// UvscServerProviderConfigWidget
class UvscServerProviderConfigWidget : public IDebugServerProviderConfigWidget
{
Q_OBJECT
public:
explicit UvscServerProviderConfigWidget(UvscServerProvider *provider);
void apply() override;
void discard() override;
protected:
void setDeviceSelection(const Uv::DeviceSelection &deviceSelection);
Uv::DeviceSelection deviceSelection() const;
void setDriverSelection(const Uv::DriverSelection &driverSelection);
Uv::DriverSelection driverSelection() const;
void setFromProvider();
HostWidget *m_hostWidget = nullptr;
Uv::DeviceSelector *m_deviceSelector = nullptr;
Uv::DriverSelector *m_driverSelector = nullptr;
};
// UvscServerProviderRunner
class UvscServerProviderRunner final : public ProjectExplorer::RunWorker
{
public:
explicit UvscServerProviderRunner(ProjectExplorer::RunControl *runControl,
const ProjectExplorer::Runnable &runnable);
private:
void start() final;
void stop() final;
QProcess m_process;
};
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,34 @@
HEADERS += \
$$PWD/simulatoruvscserverprovider.h \
$$PWD/stlinkuvscserverprovider.h \
$$PWD/uvproject.h \
$$PWD/uvprojectwriter.h \
$$PWD/uvscserverprovider.h \
$$PWD/uvtargetdevicemodel.h \
$$PWD/uvtargetdeviceselection.h \
$$PWD/uvtargetdeviceviewer.h \
$$PWD/uvtargetdrivermodel.h \
$$PWD/uvtargetdriverselection.h \
$$PWD/uvtargetdriverviewer.h \
$$PWD/xmlnodevisitor.h \
$$PWD/xmlproject.h \
$$PWD/xmlprojectwriter.h \
$$PWD/xmlproperty.h \
$$PWD/xmlpropertygroup.h \
SOURCES += \
$$PWD/simulatoruvscserverprovider.cpp \
$$PWD/stlinkuvscserverprovider.cpp \
$$PWD/uvproject.cpp \
$$PWD/uvprojectwriter.cpp \
$$PWD/uvscserverprovider.cpp \
$$PWD/uvtargetdevicemodel.cpp \
$$PWD/uvtargetdeviceselection.cpp \
$$PWD/uvtargetdeviceviewer.cpp \
$$PWD/uvtargetdrivermodel.cpp \
$$PWD/uvtargetdriverselection.cpp \
$$PWD/uvtargetdriverviewer.cpp \
$$PWD/xmlproject.cpp \
$$PWD/xmlprojectwriter.cpp \
$$PWD/xmlproperty.cpp \
$$PWD/xmlpropertygroup.cpp \
@@ -0,0 +1,506 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h" // for toolsFilePath()
#include "uvtargetdevicemodel.h"
#include <QDirIterator>
#include <QFile>
#include <QTextStream>
#include <QXmlStreamReader>
using namespace Utils;
namespace BareMetal {
namespace Internal {
namespace Uv {
static QString extractPacksPath(const QString &uVisionFilePath)
{
QFile f(toolsFilePath(uVisionFilePath));
if (!f.open(QIODevice::ReadOnly))
return {};
QTextStream in(&f);
while (!in.atEnd()) {
const QByteArray line = f.readLine().trimmed();
const auto startIndex = line.indexOf("RTEPATH=\"");
const auto stopIndex = line.lastIndexOf('"');
if (startIndex != 0 || (stopIndex + 1) != line.size())
continue;
const QFileInfo path(QString::fromUtf8(line.mid(startIndex + 9,
stopIndex - startIndex - 9)));
if (!path.exists())
return {};
return path.absoluteFilePath();
}
return {};
}
static QString extractPackVersion(const QString &packFilePath)
{
return QFileInfo(packFilePath).dir().dirName();
}
static QStringList findKeilPackFiles(const QString &path)
{
QStringList files;
// Search for the STMicroelectronics devices.
QDirIterator it(path, {"STM*_DFP"}, QDir::Dirs);
while (it.hasNext()) {
const QDir dfpDir(it.next());
const QFileInfoList entries = dfpDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
QDir::Name);
if (entries.isEmpty())
continue;
QDirIterator fit(entries.last().absoluteFilePath(), {"*.pdsc"},
QDir::Files | QDir::NoSymLinks);
while (fit.hasNext())
files.push_back(fit.next());
}
return files;
}
static void fillCpu(QXmlStreamReader &in, DeviceSelection::Cpu &cpu)
{
const QXmlStreamAttributes attrs = in.attributes();
in.skipCurrentElement();
cpu.core = attrs.hasAttribute("Dcore") ? attrs.value("Dcore").toString() : cpu.core;
cpu.clock = attrs.hasAttribute("Dclock") ? attrs.value("Dclock").toString() : cpu.clock;
cpu.fpu = attrs.hasAttribute("Dfpu") ? attrs.value("Dfpu").toString() : cpu.fpu;
cpu.mpu = attrs.hasAttribute("Dmpu") ? attrs.value("Dmpu").toString() : cpu.mpu;
}
static void fillMemories(QXmlStreamReader &in, DeviceSelection::Memories &memories)
{
const QXmlStreamAttributes attrs = in.attributes();
in.skipCurrentElement();
DeviceSelection::Memory memory;
memory.id = attrs.value("id").toString();
memory.start = attrs.value("start").toString();
memory.size = attrs.value("size").toString();
memories.push_back(memory);
}
static void fillAlgorithms(QXmlStreamReader &in, DeviceSelection::Algorithms &algorithms)
{
const QXmlStreamAttributes attrs = in.attributes();
in.skipCurrentElement();
DeviceSelection::Algorithm algorithm;
algorithm.path = attrs.value("name").toString();
algorithm.start = attrs.value("start").toString();
algorithm.size = attrs.value("size").toString();
algorithms.push_back(algorithm);
}
// DeviceSelectionItem
class DeviceSelectionItem : public TreeItem
{
public:
enum class Type { Unknown, Package, Family, SubFamily, Device, DeviceVariant };
enum Column { NameColumn, VersionColumn, VendorColumn };
explicit DeviceSelectionItem(Type type = Type::Unknown)
: m_type(type)
{}
QVariant data(int column, int role) const override
{
if (role == Qt::DisplayRole && column == NameColumn)
return m_name;
return {};
}
Qt::ItemFlags flags(int column) const override
{
Q_UNUSED(column)
return Qt::ItemIsEnabled;
}
DeviceSelectionItem *parentPackItem() const
{
return static_cast<DeviceSelectionItem *>(parent());
}
QString m_name;
const Type m_type;
};
// PackageItem
class PackageItem final : public DeviceSelectionItem
{
public:
explicit PackageItem(const QString &file)
: DeviceSelectionItem(Type::Package), m_file(file), m_version(extractPackVersion(file))
{}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole) {
if (column == NameColumn)
return m_name;
else if (column == VersionColumn)
return m_version;
else if (column == VendorColumn)
return m_vendor;
}
return {};
}
QString m_version;
QString m_file;
QString m_desc;
QString m_vendor;
QString m_url;
};
// FamilyItem
class FamilyItem final : public DeviceSelectionItem
{
public:
explicit FamilyItem()
: DeviceSelectionItem(Type::Family)
{}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole) {
if (column == NameColumn) {
return m_name;
} else if (column == VendorColumn) {
const auto colonIndex = m_vendor.lastIndexOf(':');
return m_vendor.mid(0, colonIndex);
}
}
return {};
}
QString m_desc;
QString m_vendor;
};
// SubFamilyItem
class SubFamilyItem final : public DeviceSelectionItem
{
public:
explicit SubFamilyItem()
: DeviceSelectionItem(Type::SubFamily)
{}
QString m_svd;
};
// DeviceItem
class DeviceItem final : public DeviceSelectionItem
{
public:
explicit DeviceItem()
: DeviceSelectionItem(Type::Device)
{}
Qt::ItemFlags flags(int column) const final
{
Q_UNUSED(column)
return hasChildren() ? Qt::ItemIsEnabled : (Qt::ItemIsEnabled | Qt::ItemIsSelectable);
}
DeviceSelection::Cpu m_cpu;
DeviceSelection::Memories m_memories;
DeviceSelection::Algorithms m_algorithms;
};
// DeviceVariantItem
class DeviceVariantItem final : public DeviceSelectionItem
{
public:
explicit DeviceVariantItem()
: DeviceSelectionItem(Type::DeviceVariant)
{}
Qt::ItemFlags flags(int column) const final
{
Q_UNUSED(column)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
};
// DeviceSelectionModel
DeviceSelectionModel::DeviceSelectionModel(QObject *parent)
: TreeModel<DeviceSelectionItem>(parent)
{
setHeader({tr("Name"), tr("Version"), tr("Vendor")});
}
void DeviceSelectionModel::fillAllPacks(const QString &uVisionFilePath)
{
if (m_uVisionFilePath == uVisionFilePath)
return;
clear();
m_uVisionFilePath = uVisionFilePath;
const QString packsPath = extractPacksPath(m_uVisionFilePath);
if (packsPath.isEmpty())
return;
QStringList allPackFiles;
QDirIterator it(packsPath, {"Keil"}, QDir::Dirs | QDir::NoDotAndDotDot);
while (it.hasNext()) {
const QString path = it.next();
if (path.endsWith("/Keil"))
allPackFiles << findKeilPackFiles(path);
}
if (allPackFiles.isEmpty())
return;
for (const QString &packFile : qAsConst(allPackFiles))
parsePackage(packFile);
}
void DeviceSelectionModel::parsePackage(const QString &packageFile)
{
QFile f(packageFile);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QXmlStreamReader in(&f);
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "package")
parsePackage(in, packageFile);
else
in.skipCurrentElement();
}
}
void DeviceSelectionModel::parsePackage(QXmlStreamReader &in, const QString &file)
{
const auto child = new PackageItem(file);
rootItem()->appendChild(child);
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "name") {
child->m_name = in.readElementText().trimmed();
} else if (elementName == "description") {
child->m_desc = in.readElementText().trimmed();
} else if (elementName == "vendor") {
child->m_vendor = in.readElementText().trimmed();
} else if (elementName == "url") {
child->m_url = in.readElementText().trimmed();
} else if (elementName == "devices") {
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "family")
parseFamily(in, child);
else
in.skipCurrentElement();
}
} else {
in.skipCurrentElement();
}
}
}
void DeviceSelectionModel::parseFamily(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
const auto child = new FamilyItem;
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->m_name = attrs.value("Dfamily").toString();
child->m_vendor = attrs.value("Dvendor").toString();
DeviceSelection::Cpu cpu;
DeviceSelection::Memories memories;
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "processor") {
fillCpu(in, cpu);
} else if (elementName == "memory") {
fillMemories(in, memories);
} else if (elementName == "description") {
child->m_desc = in.readElementText().trimmed();
} else if (elementName == "subFamily") {
parseSubFamily(in, child, cpu);
} else if (elementName == "device") {
parseDevice(in, child, cpu, memories);
} else {
in.skipCurrentElement();
}
}
}
void DeviceSelectionModel::parseSubFamily(QXmlStreamReader &in, DeviceSelectionItem *parent,
DeviceSelection::Cpu &cpu)
{
const auto child = new SubFamilyItem;
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->m_name = attrs.value("DsubFamily").toString();
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "processor") {
fillCpu(in, cpu);
} else if (elementName == "debug") {
const QXmlStreamAttributes attrs = in.attributes();
in.skipCurrentElement();
child->m_svd = attrs.value("svd").toString();
} else if (elementName == "device") {
DeviceSelection::Memories memories;
parseDevice(in, child, cpu, memories);
} else {
in.skipCurrentElement();
}
}
}
void DeviceSelectionModel::parseDevice(QXmlStreamReader &in, DeviceSelectionItem *parent,
DeviceSelection::Cpu &cpu,
DeviceSelection::Memories &memories)
{
const auto child = new DeviceItem;
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->m_name = attrs.value("Dname").toString();
DeviceSelection::Algorithms algorithms;
while (in.readNextStartElement()) {
const QStringRef elementName = in.name();
if (elementName == "processor") {
fillCpu(in, cpu);
} else if (elementName == "memory") {
fillMemories(in, memories);
} else if (elementName == "algorithm") {
fillAlgorithms(in, algorithms);
} else if (elementName == "variant") {
parseDeviceVariant(in, child);
} else {
in.skipCurrentElement();
}
}
child->m_cpu = cpu;
child->m_memories = memories;
child->m_algorithms = algorithms;
}
void DeviceSelectionModel::parseDeviceVariant(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
const auto child = new DeviceVariantItem;
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
in.skipCurrentElement();
child->m_name = attrs.value("Dvariant").toString();
}
// DeviceSelectionView
DeviceSelectionView::DeviceSelectionView(QWidget *parent)
: TreeView(parent)
{
setRootIsDecorated(true);
setSelectionMode(QAbstractItemView::SingleSelection);
}
void DeviceSelectionView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous)
if (!current.isValid())
return;
const auto selectionModel = qobject_cast<DeviceSelectionModel *>(model());
if (!selectionModel)
return;
const DeviceSelectionItem *item = selectionModel->itemForIndex(current);
if (isValidItem(item)) {
const auto selection = buildSelection(item);
if (!selection.name.isEmpty())
emit deviceSelected(selection);
}
}
bool DeviceSelectionView::isValidItem(const DeviceSelectionItem *item) const
{
if (!item)
return false;
if (item->m_type == DeviceSelectionItem::Type::DeviceVariant)
return true;
if (item->m_type == DeviceSelectionItem::Type::Device && !item->hasChildren())
return true;
return false;
}
DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *item) const
{
DeviceSelection selection;
// We need to iterate from the lower 'Device|DeviceVariant' items to
// the upper 'Package' item to fill whole information.
do {
switch (item->m_type) {
case DeviceSelectionItem::Type::DeviceVariant:
selection.name = item->m_name;
break;
case DeviceSelectionItem::Type::Device: {
const auto deviceItem = static_cast<const DeviceItem *>(item);
if (!deviceItem->hasChildren())
selection.name = item->m_name;
selection.cpu = deviceItem->m_cpu;
selection.memories = deviceItem->m_memories;
selection.algorithms = deviceItem->m_algorithms;
}
break;
case DeviceSelectionItem::Type::SubFamily: {
const auto subFamilyItem = static_cast<const SubFamilyItem *>(item);
selection.subfamily = subFamilyItem->m_name;
selection.svd = subFamilyItem->m_svd;
}
break;
case DeviceSelectionItem::Type::Family: {
const auto familyItem = static_cast<const FamilyItem *>(item);
selection.family = familyItem->m_name;
selection.desc = familyItem->m_desc;
selection.vendor = familyItem->m_vendor;
}
break;
case DeviceSelectionItem::Type::Package: {
const auto packageItem = static_cast<const PackageItem *>(item);
selection.package.desc = packageItem->m_desc;
selection.package.file = packageItem->m_file;
selection.package.name = packageItem->m_name;
selection.package.url = packageItem->m_url;
selection.package.vendor = packageItem->m_vendor;
selection.package.version = packageItem->m_version;
}
break;
default:
break;
}
} while (item = item->parentPackItem());
return selection;
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdeviceselection.h"
#include <utils/basetreeview.h>
#include <utils/treemodel.h>
QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
namespace Uv {
// DeviceSelectionModel
class DeviceSelectionItem;
class DeviceSelectionModel final : public Utils::TreeModel<DeviceSelectionItem>
{
Q_OBJECT
public:
explicit DeviceSelectionModel(QObject *parent = nullptr);
void fillAllPacks(const QString &uVisionFilePath);
private:
void parsePackage(const QString &packageFile);
void parsePackage(QXmlStreamReader &in, const QString &file);
void parseFamily(QXmlStreamReader &in, DeviceSelectionItem *parent);
void parseSubFamily(QXmlStreamReader &in, DeviceSelectionItem *parent,
DeviceSelection::Cpu &cpu);
void parseDevice(QXmlStreamReader &in, DeviceSelectionItem *parent,
DeviceSelection::Cpu &cpu, DeviceSelection::Memories &memories);
void parseDeviceVariant(QXmlStreamReader &in, DeviceSelectionItem *parent);
QString m_uVisionFilePath;
};
// DeviceSelectionView
class DeviceSelectionView final : public Utils::TreeView
{
Q_OBJECT
public:
explicit DeviceSelectionView(QWidget *parent = nullptr);
signals:
void deviceSelected(const DeviceSelection &selection);
private:
void currentChanged(const QModelIndex &current, const QModelIndex &previous) final;
bool isValidItem(const DeviceSelectionItem *item) const;
DeviceSelection buildSelection(const DeviceSelectionItem *item) const;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,415 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdeviceselection.h"
#include <QComboBox>
#include <QDataWidgetMapper>
#include <QHBoxLayout>
#include <QLineEdit>
using namespace Utils;
namespace BareMetal {
namespace Internal {
namespace Uv {
// Software package data keys.
constexpr char packageDescrKeyC[] = "BareMetal.UvscServerProvider.PackageDescription";
constexpr char packageFileKeyC[] = "BareMetal.UvscServerProvider.PackageFile";
constexpr char packageNameKeyC[] = "BareMetal.UvscServerProvider.PackageName";
constexpr char packageUrlKeyC[] = "BareMetal.UvscServerProvider.PackageUrl";
constexpr char packageVendorKeyC[] = "BareMetal.UvscServerProvider.PackageVendor";
constexpr char packageVersionKeyC[] = "BareMetal.UvscServerProvider.PackageVersion";
// Device data keys.
constexpr char deviceNameKeyC[] = "BareMetal.UvscServerProvider.DeviceName";
constexpr char deviceDescrKeyC[] = "BareMetal.UvscServerProvider.DeviceDescription";
constexpr char deviceFamilyKeyC[] = "BareMetal.UvscServerProvider.DeviceFamily";
constexpr char deviceSubFamilyKeyC[] = "BareMetal.UvscServerProvider.DeviceSubFamily";
constexpr char deviceVendorKeyC[] = "BareMetal.UvscServerProvider.DeviceVendor";
constexpr char deviceSvdKeyC[] = "BareMetal.UvscServerProvider.DeviceSVD";
// Device CPU data keys.
constexpr char deviceClockKeyC[] = "BareMetal.UvscServerProvider.DeviceClock";
constexpr char deviceCoreKeyC[] = "BareMetal.UvscServerProvider.DeviceCore";
constexpr char deviceFpuKeyC[] = "BareMetal.UvscServerProvider.DeviceFPU";
constexpr char deviceMpuKeyC[] = "BareMetal.UvscServerProvider.DeviceMPU";
// Device MEMORY data keys.
constexpr char deviceMemoryKeyC[] = "BareMetal.UvscServerProvider.DeviceMemory";
constexpr char deviceMemoryIdKeyC[] = "BareMetal.UvscServerProvider.DeviceMemoryId";
constexpr char deviceMemoryStartKeyC[] = "BareMetal.UvscServerProvider.DeviceMemoryStart";
constexpr char deviceMemorySizeKeyC[] = "BareMetal.UvscServerProvider.DeviceMemorySize";
// Device ALGORITHM data keys.
constexpr char deviceAlgorithmKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithm";
constexpr char deviceAlgorithmPathKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmPath";
constexpr char deviceAlgorithmStartKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmStart";
constexpr char deviceAlgorithmSizeKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmSize";
constexpr char deviceAlgorithmIndexKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmIndex";
// DeviceSelection
QVariantMap DeviceSelection::toMap() const
{
QVariantMap map;
// Software package.
map.insert(packageDescrKeyC, package.desc);
map.insert(packageFileKeyC, package.file);
map.insert(packageNameKeyC, package.name);
map.insert(packageUrlKeyC, package.url);
map.insert(packageVendorKeyC, package.vendor);
map.insert(packageVersionKeyC, package.version);
// Device.
map.insert(deviceNameKeyC, name);
map.insert(deviceDescrKeyC, desc);
map.insert(deviceFamilyKeyC, family);
map.insert(deviceSubFamilyKeyC, subfamily);
map.insert(deviceVendorKeyC, vendor);
map.insert(deviceSvdKeyC, svd);
// Device CPU.
map.insert(deviceClockKeyC, cpu.clock);
map.insert(deviceCoreKeyC, cpu.core);
map.insert(deviceFpuKeyC, cpu.fpu);
map.insert(deviceMpuKeyC, cpu.mpu);
// Device MEMORY.
QVariantList memoryList;
for (const DeviceSelection::Memory &memory : qAsConst(memories)) {
QVariantMap m;
m.insert(deviceMemoryIdKeyC, memory.id);
m.insert(deviceMemoryStartKeyC, memory.start);
m.insert(deviceMemorySizeKeyC, memory.size);
memoryList.push_back(m);
}
map.insert(deviceMemoryKeyC, memoryList);
// Device ALGORITHM.
QVariantList algorithmList;
for (const DeviceSelection::Algorithm &algorithm : qAsConst(algorithms)) {
QVariantMap m;
m.insert(deviceAlgorithmPathKeyC, algorithm.path);
m.insert(deviceAlgorithmStartKeyC, algorithm.start);
m.insert(deviceAlgorithmSizeKeyC, algorithm.size);
algorithmList.push_back(m);
}
map.insert(deviceAlgorithmKeyC, algorithmList);
map.insert(deviceAlgorithmIndexKeyC, algorithmIndex);
return map;
}
void DeviceSelection::fromMap(const QVariantMap &map)
{
// Software package.
package.desc = map.value(packageDescrKeyC).toString();
package.file = map.value(packageFileKeyC).toString();
package.name = map.value(packageNameKeyC).toString();
package.url = map.value(packageUrlKeyC).toString();
package.vendor = map.value(packageVendorKeyC).toString();
package.version = map.value(packageVersionKeyC).toString();
// Device.
name = map.value(deviceNameKeyC).toString();
desc = map.value(deviceDescrKeyC).toString();
family = map.value(deviceFamilyKeyC).toString();
subfamily = map.value(deviceSubFamilyKeyC).toString();
vendor = map.value(deviceVendorKeyC).toString();
svd = map.value(deviceSvdKeyC).toString();
// Device CPU.
cpu.clock = map.value(deviceClockKeyC).toString();
cpu.core = map.value(deviceCoreKeyC).toString();
cpu.fpu = map.value(deviceFpuKeyC).toString();
cpu.mpu = map.value(deviceMpuKeyC).toString();
// Device MEMORY.
const QVariantList memoryList = map.value(deviceMemoryKeyC).toList();
for (const auto &entry : memoryList) {
const auto m = entry.toMap();
DeviceSelection::Memory memory;
memory.id = m.value(deviceMemoryIdKeyC).toString();
memory.start = m.value(deviceMemoryStartKeyC).toString();
memory.size = m.value(deviceMemorySizeKeyC).toString();
memories.push_back(memory);
}
// Device ALGORITHM.
algorithmIndex = map.value(deviceAlgorithmIndexKeyC).toInt();
const QVariantList algorithmList = map.value(deviceAlgorithmKeyC).toList();
for (const auto &entry : algorithmList) {
const auto m = entry.toMap();
DeviceSelection::Algorithm algorithm;
algorithm.path = m.value(deviceAlgorithmPathKeyC).toString();
algorithm.start = m.value(deviceAlgorithmStartKeyC).toString();
algorithm.size = m.value(deviceAlgorithmSizeKeyC).toString();
algorithms.push_back(algorithm);
}
}
bool DeviceSelection::Package::operator==(const Package &other) const
{
return desc == other.desc && file == other.file
&& name == other.name && url == other.url
&& vendor == other.vendor && version == other.version;
}
bool DeviceSelection::Cpu::operator==(const Cpu &other) const
{
return core == other.core && clock == other.clock
&& fpu == other.fpu && mpu == other.mpu;
}
bool DeviceSelection::Memory::operator==(const Memory &other) const
{
return id == other.id && start == other.start && size == other.size;
}
bool DeviceSelection::Algorithm::operator==(const Algorithm &other) const
{
return path == other.path && start == other.start && size == other.size;
}
bool DeviceSelection::operator==(const DeviceSelection &other) const
{
return package == other.package && name == other.name && desc == other.desc
&& family == other.family && subfamily == other.subfamily
&& vendor == other.vendor && svd == other.svd && cpu == other.cpu
&& memories == other.memories && algorithms == other.algorithms
&& algorithmIndex == other.algorithmIndex;
}
// DeviceSelectionMemoryItem
class DeviceSelectionMemoryItem final : public TreeItem
{
public:
enum Column { IdColumn, StartColumn, SizeColumn};
explicit DeviceSelectionMemoryItem(int index, DeviceSelection &selection)
: m_index(index), m_selection(selection)
{}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole || role == Qt::EditRole) {
const auto &memory = m_selection.memories.at(m_index);
switch (column) {
case IdColumn: return memory.id;
case StartColumn: return memory.start;
case SizeColumn: return memory.size;
}
}
return {};
}
bool setData(int column, const QVariant &data, int role) final
{
if (role == Qt::EditRole) {
auto &memory = m_selection.memories.at(m_index);
switch (column) {
case StartColumn:
memory.start = data.toString();
return true;
case SizeColumn:
memory.size = data.toString();
return true;
}
}
return false;
}
Qt::ItemFlags flags(int column) const final
{
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if (column == StartColumn || column == SizeColumn)
flags |= Qt::ItemIsEditable;
return flags;
}
private:
const int m_index;
DeviceSelection &m_selection;
};
// DeviceSelectionMemoryModel
DeviceSelectionMemoryModel::DeviceSelectionMemoryModel(DeviceSelection &selection, QObject *parent)
: TreeModel<TreeItem, DeviceSelectionMemoryItem>(parent), m_selection(selection)
{
setHeader({tr("ID"), tr("Start"), tr("Size")});
refresh();
}
void DeviceSelectionMemoryModel::refresh()
{
clear();
const auto begin = m_selection.memories.begin();
for (auto it = begin; it < m_selection.memories.end(); ++it) {
const auto index = std::distance(begin, it);
const auto item = new DeviceSelectionMemoryItem(index, m_selection);
rootItem()->appendChild(item);
}
}
// DeviceSelectionMemoryView
DeviceSelectionMemoryView::DeviceSelectionMemoryView(DeviceSelection &selection, QWidget *parent)
: TreeView(parent)
{
setRootIsDecorated(true);
setSelectionMode(QAbstractItemView::SingleSelection);
const auto model = new DeviceSelectionMemoryModel(selection, this);
setModel(model);
connect(model, &DeviceSelectionMemoryModel::dataChanged,
this, &DeviceSelectionMemoryView::memoryChanged);
}
void DeviceSelectionMemoryView::refresh()
{
qobject_cast<DeviceSelectionMemoryModel *>(model())->refresh();
}
// DeviceSelectionAlgorithmItem
class DeviceSelectionAlgorithmItem final : public TreeItem
{
public:
enum Column { PathColumn, StartColumn, SizeColumn };
explicit DeviceSelectionAlgorithmItem(int index, DeviceSelection &selection)
: m_index(index), m_selection(selection)
{}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole || role == Qt::EditRole) {
const auto &algorithm = m_selection.algorithms.at(m_index);
switch (column) {
case PathColumn: return algorithm.path;
case StartColumn: return algorithm.start;
case SizeColumn: return algorithm.size;
}
}
return {};
}
bool setData(int column, const QVariant &data, int role) final
{
if (role == Qt::EditRole) {
auto &algorithm = m_selection.algorithms.at(m_index);
switch (column) {
case StartColumn:
algorithm.start = data.toString();
return true;
case SizeColumn:
algorithm.size = data.toString();
return true;
}
}
return false;
}
Qt::ItemFlags flags(int column) const final
{
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if (column == StartColumn || column == SizeColumn)
flags |= Qt::ItemIsEditable;
return flags;
}
private:
const int m_index;
DeviceSelection &m_selection;
};
// DeviceSelectionAlgorithmModel
DeviceSelectionAlgorithmModel::DeviceSelectionAlgorithmModel(DeviceSelection &selection,
QObject *parent)
: TreeModel<TreeItem, DeviceSelectionAlgorithmItem>(parent), m_selection(selection)
{
setHeader({tr("Name"), tr("Start"), tr("Size")});
refresh();
}
void DeviceSelectionAlgorithmModel::refresh()
{
clear();
const auto begin = m_selection.algorithms.begin();
for (auto it = begin; it < m_selection.algorithms.end(); ++it) {
const auto index = std::distance(begin, it);
const auto item = new DeviceSelectionAlgorithmItem(index, m_selection);
rootItem()->appendChild(item);
}
}
// DeviceSelectionAlgorithmView
DeviceSelectionAlgorithmView::DeviceSelectionAlgorithmView(DeviceSelection &selection,
QWidget *parent)
: QWidget(parent)
{
const auto model = new DeviceSelectionAlgorithmModel(selection, this);
const auto layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
m_comboBox = new QComboBox;
m_comboBox->setToolTip(tr("Algorithm path."));
m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_comboBox->setModel(model);
layout->addWidget(m_comboBox);
const auto startEdit = new QLineEdit;
startEdit->setToolTip(tr("Start address."));
layout->addWidget(startEdit);
const auto sizeEdit = new QLineEdit;
sizeEdit->setToolTip(tr("Size."));
layout->addWidget(sizeEdit);
setLayout(layout);
const auto mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->addMapping(startEdit, DeviceSelectionAlgorithmItem::StartColumn);
mapper->addMapping(sizeEdit, DeviceSelectionAlgorithmItem::SizeColumn);
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [mapper, this](int index) {
mapper->setCurrentIndex(index);
emit algorithmChanged(index);
});
connect(model, &DeviceSelectionAlgorithmModel::dataChanged, this, [this]() {
emit algorithmChanged(-1);
});
connect(startEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
connect(sizeEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
}
void DeviceSelectionAlgorithmView::setAlgorithm(int index)
{
m_comboBox->setCurrentIndex(index);
}
void DeviceSelectionAlgorithmView::refresh()
{
const QSignalBlocker blocker(this);
qobject_cast<DeviceSelectionAlgorithmModel *>(m_comboBox->model())->refresh();
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,167 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <utils/basetreeview.h>
#include <utils/treemodel.h>
QT_BEGIN_NAMESPACE
class QComboBox;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
namespace Uv {
// DeviceSelection
class DeviceSelection final
{
public:
struct Package {
QString desc;
QString file;
QString name;
QString url;
QString vendor;
QString version;
bool operator==(const Package &other) const;
};
struct Cpu {
QString clock;
QString core;
QString fpu;
QString mpu;
bool operator==(const Cpu &other) const;
};
struct Memory {
QString id;
QString size;
QString start;
bool operator==(const Memory &other) const;
};
using Memories = std::vector<Memory>;
struct Algorithm {
QString path;
QString size;
QString start;
bool operator==(const Algorithm &other) const;
};
using Algorithms = std::vector<Algorithm>;
Package package;
QString name;
QString desc;
QString family;
QString subfamily;
QString vendor;
QString svd;
Cpu cpu;
Memories memories;
Algorithms algorithms;
int algorithmIndex = 0;
QVariantMap toMap() const;
void fromMap(const QVariantMap &map);
bool operator==(const DeviceSelection &other) const;
};
// DeviceSelectionMemoryModel
class DeviceSelectionMemoryItem;
class DeviceSelectionMemoryModel final
: public Utils::TreeModel<Utils::TreeItem, DeviceSelectionMemoryItem>
{
Q_OBJECT
public:
explicit DeviceSelectionMemoryModel(DeviceSelection &selection, QObject *parent = nullptr);
void refresh();
private:
DeviceSelection &m_selection;
};
// DeviceSelectionMemoryView
class DeviceSelectionMemoryView final : public Utils::TreeView
{
Q_OBJECT
public:
explicit DeviceSelectionMemoryView(DeviceSelection &selection, QWidget *parent = nullptr);
void refresh();
signals:
void memoryChanged();
};
// DeviceSelectionAlgorithmModel
class DeviceSelectionAlgorithmItem;
class DeviceSelectionAlgorithmModel final
: public Utils::TreeModel<Utils::TreeItem, DeviceSelectionAlgorithmItem>
{
Q_OBJECT
public:
explicit DeviceSelectionAlgorithmModel(DeviceSelection &selection, QObject *parent = nullptr);
void refresh();
private:
DeviceSelection &m_selection;
};
// DeviceSelectionAlgorithmView
class DeviceSelectionAlgorithmView final : public QWidget
{
Q_OBJECT
public:
explicit DeviceSelectionAlgorithmView(DeviceSelection &selection, QWidget *parent = nullptr);
void setAlgorithm(int index);
void refresh();
signals:
void algorithmChanged(int index = -1);
private:
QComboBox *m_comboBox = nullptr;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
Q_DECLARE_METATYPE(BareMetal::Internal::Uv::DeviceSelection)
@@ -0,0 +1,206 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h" // for targetUVisionPath()
#include "uvtargetdevicemodel.h"
#include "uvtargetdeviceviewer.h"
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
namespace BareMetal {
namespace Internal {
namespace Uv {
// DeviceSelectorToolPanel
DeviceSelectorToolPanel::DeviceSelectorToolPanel(QWidget *parent)
: FadingPanel(parent)
{
const auto layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
const auto button = new QPushButton(tr("Manage..."));
layout->addWidget(button);
setLayout(layout);
connect(button, &QPushButton::clicked, this, &DeviceSelectorToolPanel::clicked);
}
void DeviceSelectorToolPanel::fadeTo(qreal value)
{
Q_UNUSED(value)
}
void DeviceSelectorToolPanel::setOpacity(qreal value)
{
Q_UNUSED(value)
}
// DeviceSelectorDetailsPanel
DeviceSelectorDetailsPanel::DeviceSelectorDetailsPanel(DeviceSelection &selection,
QWidget *parent)
: QWidget(parent), m_selection(selection)
{
const auto layout = new QFormLayout;
m_vendorEdit = new QLineEdit;
m_vendorEdit->setReadOnly(true);
layout->addRow(tr("Vendor:"), m_vendorEdit);
m_fimilyEdit = new QLineEdit;;
m_fimilyEdit->setReadOnly(true);
layout->addRow(tr("Family:"), m_fimilyEdit);
m_descEdit = new QPlainTextEdit;;
m_descEdit->setReadOnly(true);
layout->addRow(tr("Description:"), m_descEdit);
m_memoryView = new DeviceSelectionMemoryView(m_selection);
layout->addRow(tr("Memory:"), m_memoryView);
m_algorithmView = new DeviceSelectionAlgorithmView(m_selection);
layout->addRow(tr("Flash algorithm"), m_algorithmView);
setLayout(layout);
refresh();
connect(m_memoryView, &DeviceSelectionMemoryView::memoryChanged,
this, &DeviceSelectorDetailsPanel::selectionChanged);
connect(m_algorithmView, &DeviceSelectionAlgorithmView::algorithmChanged,
this, [this](int index) {
if (index >= 0)
m_selection.algorithmIndex = index;
emit selectionChanged();
});
}
static QString trimVendor(const QString &vendor)
{
const int colonIndex = vendor.lastIndexOf(':');
return vendor.mid(0, colonIndex);
}
void DeviceSelectorDetailsPanel::refresh()
{
m_vendorEdit->setText(trimVendor(m_selection.vendor));
m_fimilyEdit->setText(m_selection.family);
m_descEdit->setPlainText(m_selection.desc);
m_memoryView->refresh();
m_algorithmView->refresh();
m_algorithmView->setAlgorithm(m_selection.algorithmIndex);
}
// DeviceSelector
DeviceSelector::DeviceSelector(QWidget *parent)
: DetailsWidget(parent)
{
const auto toolPanel = new DeviceSelectorToolPanel;
setToolWidget(toolPanel);
const auto detailsPanel = new DeviceSelectorDetailsPanel(m_selection);
setWidget(detailsPanel);
connect(toolPanel, &DeviceSelectorToolPanel::clicked, this, [this]() {
const QString uVisionPath = targetUVisionPath();
if (uVisionPath.isEmpty()) {
QMessageBox::warning(this,
tr("uVision path not found"),
tr("Please open a configured project before\n"
"the target device selection."),
QMessageBox::Ok);
} else {
DeviceSelectionDialog dialog(uVisionPath, this);
const int result = dialog.exec();
if (result != QDialog::Accepted)
return;
DeviceSelection selection;
selection = dialog.selection();
setSelection(selection);
}
});
connect(detailsPanel, &DeviceSelectorDetailsPanel::selectionChanged,
this, &DeviceSelector::selectionChanged);
}
void DeviceSelector::setSelection(const DeviceSelection &selection)
{
m_selection = selection;
const auto summary = m_selection.name.isEmpty()
? tr("Target device not selected.") : m_selection.name;
setSummaryText(summary);
setExpandable(!m_selection.name.isEmpty());
if (const auto detailsPanel = qobject_cast<DeviceSelectorDetailsPanel *>(widget()))
detailsPanel->refresh();
emit selectionChanged();
}
DeviceSelection DeviceSelector::selection() const
{
return m_selection;
}
// DeviceSelectionDialog
DeviceSelectionDialog::DeviceSelectionDialog(const QString &uVisionPath, QWidget *parent)
: QDialog(parent), m_model(new DeviceSelectionModel(this)), m_view(new DeviceSelectionView(this))
{
setWindowTitle(tr("Available target devices"));
const auto layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_view);
const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
layout->addWidget(buttonBox);
setLayout(layout);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DeviceSelectionDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DeviceSelectionDialog::reject);
connect(m_view, &DeviceSelectionView::deviceSelected, this,
[this](const DeviceSelection &selection) {
m_selection = selection;
});
m_model->fillAllPacks(uVisionPath);
m_view->setModel(m_model);
}
void DeviceSelectionDialog::setSelection(const DeviceSelection &selection)
{
m_selection = selection;
}
DeviceSelection DeviceSelectionDialog::selection() const
{
return m_selection;
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,127 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdeviceselection.h"
#include <utils/detailsbutton.h>
#include <utils/detailswidget.h>
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLineEdit;
class QPlainTextEdit;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
namespace Uv {
class DeviceSelectionModel;
class DeviceSelectionView;
class DeviceSelectionMemoryView;
class DeviceSelectionAlgorithmView;
// DeviceSelector
class DeviceSelector final : public Utils::DetailsWidget
{
Q_OBJECT
public:
explicit DeviceSelector(QWidget *parent = nullptr);
void setSelection(const DeviceSelection &selection);
DeviceSelection selection() const;
signals:
void selectionChanged();
private:
DeviceSelection m_selection;
};
// DeviceSelectorToolPanel
class DeviceSelectorToolPanel final : public Utils::FadingPanel
{
Q_OBJECT
public:
explicit DeviceSelectorToolPanel(QWidget *parent = nullptr);
signals:
void clicked();
private:
void fadeTo(qreal value) final;
void setOpacity(qreal value) final;
};
// DeviceSelectorDetailsPanel
class DeviceSelectorDetailsPanel final : public QWidget
{
Q_OBJECT
public:
explicit DeviceSelectorDetailsPanel(DeviceSelection &selection, QWidget *parent = nullptr);
void refresh();
signals:
void selectionChanged();
private:
DeviceSelection &m_selection;
QLineEdit *m_vendorEdit = nullptr;
QLineEdit *m_fimilyEdit = nullptr;
QPlainTextEdit *m_descEdit = nullptr;
DeviceSelectionMemoryView *m_memoryView = nullptr;
DeviceSelectionAlgorithmView *m_algorithmView = nullptr;
};
// DeviceSelectionDialog
class DeviceSelectionDialog final : public QDialog
{
Q_OBJECT
public:
explicit DeviceSelectionDialog(const QString &uVisionPath, QWidget *parent = nullptr);
DeviceSelection selection() const;
private:
void setSelection(const DeviceSelection &selection);
DeviceSelection m_selection;
DeviceSelectionModel *m_model = nullptr;
DeviceSelectionView *m_view = nullptr;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,209 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h" // for toolsFilePath()
#include "uvtargetdrivermodel.h"
#include <QFile>
#include <QTextStream>
using namespace Utils;
namespace BareMetal {
namespace Internal {
namespace Uv {
constexpr char cpuDllKey[] = "CPUDLL";
constexpr char driverKey[] = "TDRV";
struct Dll
{
int index = -1;
QString mnemonic;
QString path;
QString content;
};
using Dlls = std::vector<Dll>;
// Parse the lines in a forms like:
// "CPUDLL0=SARM.DLL(TDRV16,TDRV17,TDRV18)"
// "TDRV1=BIN\ULP2CM3.DLL("ULINK Pro Cortex Debugger")"
static Dll extractDll(const QString &line, const QString &pattern)
{
const int equalIndex = line.indexOf('=');
const int leftBracketIndex = line.indexOf('(', equalIndex + 1);
const int rightBracketIndex = line.indexOf(')', leftBracketIndex + 1);
if (equalIndex < 0 || leftBracketIndex < 0 || rightBracketIndex < 0)
return {};
Dll dll;
dll.index = line.mid(pattern.size(), equalIndex - pattern.size()).toInt();
dll.mnemonic = line.mid(0, equalIndex).trimmed();
dll.path = line.mid(equalIndex + 1, leftBracketIndex - equalIndex - 1).trimmed();
dll.content = line.mid(leftBracketIndex + 1,
rightBracketIndex - leftBracketIndex - 1).trimmed();
return dll;
}
static bool collectCpuDllsAndDrivers(QIODevice *file, Dlls &allCpuDlls, Dlls &allDrivers)
{
QTextStream in(file);
bool armadsFound = false;
while (!in.atEnd()) {
const QString line = in.readLine().trimmed();
if (!armadsFound) {
if (line == "[ARMADS]")
armadsFound = true;
} else if (line.startsWith('[') && line.endsWith(']')) {
break;
} else if (line.startsWith(cpuDllKey)) {
const Dll dll = extractDll(line, cpuDllKey);
if (dll.index >= 0)
allCpuDlls.push_back(dll);
} else if (line.startsWith(driverKey)) {
const Dll dll = extractDll(line, driverKey);
if (dll.index >= 0)
allDrivers.push_back(dll);
}
}
return armadsFound;
}
// DriverSelectionItem
class DriverSelectionItem final : public TreeItem
{
public:
enum Column { PathColumn };
explicit DriverSelectionItem(int index = -1)
: m_index(index)
{}
DriverSelection toSelection() const
{
DriverSelection selection;
selection.index = m_index;
selection.dll = m_dll;
selection.name = m_name;
selection.cpuDlls = m_cpuDlls;
return selection;
}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole && column == PathColumn)
return m_name;
return {};
}
const int m_index;
QString m_name;
QString m_dll;
QStringList m_cpuDlls;
};
// DriverSelectionModel
DriverSelectionModel::DriverSelectionModel(QObject *parent)
: TreeModel<DriverSelectionItem>(parent)
{
setHeader({tr("Path")});
}
void DriverSelectionModel::fillDrivers(const QString &uVisionFilePath,
const QStringList &supportedDrivers)
{
clear();
QFile f(toolsFilePath(uVisionFilePath));
if (!f.open(QIODevice::ReadOnly))
return;
Dlls allCpuDlls;
Dlls allDrivers;
if (!collectCpuDllsAndDrivers(&f, allCpuDlls, allDrivers))
return;
for (const Dll &dll : qAsConst(allDrivers)) {
if (!supportedDrivers.contains(dll.path))
continue;
const auto item = new DriverSelectionItem(dll.index);
item->m_dll = dll.path;
item->m_name = dll.content;
for (const Dll &cpu : qAsConst(allCpuDlls)) {
const QStringList mnemonics = cpu.content.split(',');
if (mnemonics.contains(dll.mnemonic))
item->m_cpuDlls.push_back(cpu.path);
}
rootItem()->appendChild(item);
}
}
// DriverSelectionView
DriverSelectionView::DriverSelectionView(QWidget *parent)
: TreeView(parent)
{
setRootIsDecorated(true);
setSelectionMode(QAbstractItemView::SingleSelection);
}
void DriverSelectionView::setCurrentSelection(const QString &driverDll)
{
const auto selectionModel = qobject_cast<DriverSelectionModel *>(model());
if (!selectionModel)
return;
const DriverSelectionItem *item = selectionModel->findNonRootItem(
[driverDll](const DriverSelectionItem *item) {
return item->m_dll == driverDll;
});
if (!item)
return;
const QModelIndex index = selectionModel->indexForItem(item);
setCurrentIndex(index);
}
void DriverSelectionView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous)
if (!current.isValid())
return;
const auto selectionModel = qobject_cast<DriverSelectionModel *>(model());
if (!selectionModel)
return;
const DriverSelectionItem *item = selectionModel->itemForIndex(current);
if (!item)
return;
const auto selection = item->toSelection();
if (selection.index >= 0)
emit driverSelected(selection);
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdriverselection.h"
#include <utils/basetreeview.h>
#include <utils/treemodel.h>
namespace BareMetal {
namespace Internal {
namespace Uv {
// DriverSelectionModel
class DriverSelectionItem;
class DriverSelectionModel final : public Utils::TreeModel<DriverSelectionItem>
{
Q_OBJECT
public:
explicit DriverSelectionModel(QObject *parent = nullptr);
void fillDrivers(const QString &uVisionFilePath, const QStringList &supportedDrivers);
};
// DriverSelectionView
class DriverSelectionView final : public Utils::TreeView
{
Q_OBJECT
public:
explicit DriverSelectionView(QWidget *parent = nullptr);
void setCurrentSelection(const QString &driverDll);
signals:
void driverSelected(const DriverSelection &selection);
private:
void currentChanged(const QModelIndex &current, const QModelIndex &previous) final;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,152 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdriverselection.h"
#include <QComboBox>
#include <QHBoxLayout>
#include <QLineEdit>
using namespace Utils;
namespace BareMetal {
namespace Internal {
namespace Uv {
// Driver data keys.
constexpr char driverIndexKeyC[] = "BareMetal.UvscServerProvider.DriverIndex";
constexpr char driverCpuDllIndexKeyC[] = "BareMetal.UvscServerProvider.DriverCpuDllIndex";
constexpr char driverDllKeyC[] = "BareMetal.UvscServerProvider.DriverDll";
constexpr char driverCpuDllsKeyC[] = "BareMetal.UvscServerProvider.DriverCpuDlls";
constexpr char driverNameKeyC[] = "BareMetal.UvscServerProvider.DriverName";
// DriverSelection
QVariantMap DriverSelection::toMap() const
{
QVariantMap map;
map.insert(driverIndexKeyC, index);
map.insert(driverCpuDllIndexKeyC, cpuDllIndex);
map.insert(driverDllKeyC, dll);
map.insert(driverCpuDllsKeyC, cpuDlls);
map.insert(driverNameKeyC, name);
return map;
}
void DriverSelection::fromMap(const QVariantMap &map)
{
index = map.value(driverIndexKeyC).toInt();
cpuDllIndex = map.value(driverCpuDllIndexKeyC).toInt();
dll = map.value(driverDllKeyC).toString();
cpuDlls = map.value(driverCpuDllsKeyC).toStringList();
name = map.value(driverNameKeyC).toString();
}
bool DriverSelection::operator==(const DriverSelection &other) const
{
return index == other.index && cpuDllIndex == other.cpuDllIndex
&& dll == other.dll && cpuDlls == other.cpuDlls && name == other.name;
}
// DriverSelectionCpuDllItem
class DriverSelectionCpuDllItem final : public TreeItem
{
public:
enum Column { DllNameColumn };
explicit DriverSelectionCpuDllItem(int index, DriverSelection &selection)
: m_index(index), m_selection(selection)
{}
QVariant data(int column, int role) const final
{
if (role == Qt::DisplayRole) {
const auto &dll = m_selection.cpuDlls.at(m_index);
switch (column) {
case DllNameColumn: return dll;
}
}
return {};
}
private:
const int m_index;
DriverSelection &m_selection;
};
// DriverSelectionCpuDllModel
DriverSelectionCpuDllModel::DriverSelectionCpuDllModel(DriverSelection &selection, QObject *parent)
: TreeModel<TreeItem, DriverSelectionCpuDllItem>(parent), m_selection(selection)
{
setHeader({tr("Name")});
refresh();
}
void DriverSelectionCpuDllModel::refresh()
{
clear();
const auto begin = m_selection.cpuDlls.begin();
for (auto it = begin; it < m_selection.cpuDlls.end(); ++it) {
const auto index = std::distance(begin, it);
const auto item = new DriverSelectionCpuDllItem(index, m_selection);
rootItem()->appendChild(item);
}
}
// DriverSelectionCpuDllView
DriverSelectionCpuDllView::DriverSelectionCpuDllView(DriverSelection &selection, QWidget *parent)
: QWidget(parent)
{
const auto model = new DriverSelectionCpuDllModel(selection, this);
const auto layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
m_comboBox = new QComboBox;
m_comboBox->setToolTip(tr("Debugger CPU library (depends on a CPU core."));
m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_comboBox->setModel(model);
layout->addWidget(m_comboBox);
setLayout(layout);
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &DriverSelectionCpuDllView::dllChanged);
}
void DriverSelectionCpuDllView::setCpuDll(int index)
{
m_comboBox->setCurrentIndex(index);
}
void DriverSelectionCpuDllView::refresh()
{
const QSignalBlocker blocker(this);
qobject_cast<DriverSelectionCpuDllModel *>(m_comboBox->model())->refresh();
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <utils/basetreeview.h>
#include <utils/treemodel.h>
QT_BEGIN_NAMESPACE
class QComboBox;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
namespace Uv {
// DriverSelection
class DriverSelection final
{
public:
QString name;
QString dll;
QStringList cpuDlls;
int index = 0;
int cpuDllIndex = 0;
QVariantMap toMap() const;
void fromMap(const QVariantMap &map);
bool operator==(const DriverSelection &other) const;
};
// DriverSelectionCpuDllModel
class DriverSelectionCpuDllItem;
class DriverSelectionCpuDllModel final
: public Utils::TreeModel<Utils::TreeItem, DriverSelectionCpuDllItem>
{
Q_OBJECT
public:
explicit DriverSelectionCpuDllModel(DriverSelection &selection, QObject *parent = nullptr);
void refresh();
private:
DriverSelection &m_selection;
};
// DriverSelectionCpuDllView
class DriverSelectionCpuDllView final : public QWidget
{
Q_OBJECT
public:
explicit DriverSelectionCpuDllView(DriverSelection &selection, QWidget *parent = nullptr);
void setCpuDll(int index);
void refresh();
signals:
void dllChanged(int index = -1);
private:
QComboBox *m_comboBox = nullptr;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
Q_DECLARE_METATYPE(BareMetal::Internal::Uv::DriverSelection)
@@ -0,0 +1,190 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvproject.h" // for targetUVisionPath()
#include "uvtargetdrivermodel.h"
#include "uvtargetdriverviewer.h"
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
namespace BareMetal {
namespace Internal {
namespace Uv {
// DriverSelectorToolPanel
DriverSelectorToolPanel::DriverSelectorToolPanel(QWidget *parent)
: FadingPanel(parent)
{
const auto layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
const auto button = new QPushButton(tr("Manage..."));
layout->addWidget(button);
setLayout(layout);
connect(button, &QPushButton::clicked, this, &DriverSelectorToolPanel::clicked);
}
void DriverSelectorToolPanel::fadeTo(qreal value)
{
Q_UNUSED(value)
}
void DriverSelectorToolPanel::setOpacity(qreal value)
{
Q_UNUSED(value)
}
// DriverSelectorDetailsPanel
DriverSelectorDetailsPanel::DriverSelectorDetailsPanel(DriverSelection &selection, QWidget *parent)
: QWidget(parent), m_selection(selection)
{
const auto layout = new QFormLayout;
m_dllEdit = new QLineEdit;;
m_dllEdit->setReadOnly(true);
m_dllEdit->setToolTip(tr("Debugger driver library"));
layout->addRow(tr("Driver library:"), m_dllEdit);
m_cpuDllView = new DriverSelectionCpuDllView(m_selection);
layout->addRow(tr("CPU library:"), m_cpuDllView);
setLayout(layout);
refresh();
connect(m_cpuDllView, &DriverSelectionCpuDllView::dllChanged, this, [this](int index) {
if (index >= 0)
m_selection.cpuDllIndex = index;
emit selectionChanged();
});
}
void DriverSelectorDetailsPanel::refresh()
{
m_dllEdit->setText((m_selection.dll));
m_cpuDllView->refresh();
m_cpuDllView->setCpuDll(m_selection.cpuDllIndex);
}
// DriverSelector
DriverSelector::DriverSelector(const QStringList &supportedDrivers, QWidget *parent)
: DetailsWidget(parent)
{
const auto toolPanel = new DriverSelectorToolPanel;
toolPanel->setEnabled(!supportedDrivers.isEmpty());
setToolWidget(toolPanel);
const auto detailsPanel = new DriverSelectorDetailsPanel(m_selection);
setWidget(detailsPanel);
connect(toolPanel, &DriverSelectorToolPanel::clicked, this, [=]() {
const QString uVisionPath = targetUVisionPath();
if (uVisionPath.isEmpty()) {
QMessageBox::warning(this,
tr("uVision path not found"),
tr("Please open a configured project before\n"
"the target driver selection."),
QMessageBox::Ok);
} else {
DriverSelectionDialog dialog(uVisionPath, supportedDrivers, this);
const int result = dialog.exec();
if (result != QDialog::Accepted)
return;
DriverSelection selection;
selection = dialog.selection();
setSelection(selection);
}
});
connect(detailsPanel, &DriverSelectorDetailsPanel::selectionChanged,
this, &DriverSelector::selectionChanged);
}
void DriverSelector::setSelection(const DriverSelection &selection)
{
m_selection = selection;
const auto summary = m_selection.name.isEmpty()
? tr("Target driver not selected.") : m_selection.name;
setSummaryText(summary);
setExpandable(!m_selection.name.isEmpty());
if (const auto detailsPanel = qobject_cast<DriverSelectorDetailsPanel *>(widget()))
detailsPanel->refresh();
emit selectionChanged();
}
DriverSelection DriverSelector::selection() const
{
return m_selection;
}
// DriverSelectionDialog
DriverSelectionDialog::DriverSelectionDialog(const QString &uVisionPath,
const QStringList &supportedDrivers,
QWidget *parent)
: QDialog(parent), m_model(new DriverSelectionModel(this)),
m_view(new DriverSelectionView(this))
{
setWindowTitle(tr("Available target drivers"));
const auto layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_view);
const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
layout->addWidget(buttonBox);
setLayout(layout);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DriverSelectionDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DriverSelectionDialog::reject);
connect(m_view, &DriverSelectionView::driverSelected, this,
[this](const DriverSelection &selection) {
m_selection = selection;
});
m_model->fillDrivers(uVisionPath, supportedDrivers);
m_view->setModel(m_model);
}
void DriverSelectionDialog::setSelection(const DriverSelection &selection)
{
m_selection = selection;
}
DriverSelection DriverSelectionDialog::selection() const
{
return m_selection;
}
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,123 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvtargetdriverselection.h"
#include <utils/detailsbutton.h>
#include <utils/detailswidget.h>
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLineEdit;
QT_END_NAMESPACE
namespace BareMetal {
namespace Internal {
namespace Uv {
class DriverSelectionModel;
class DriverSelectionView;
class DriverSelectionCpuDllView;
// DriverSelector
class DriverSelector final : public Utils::DetailsWidget
{
Q_OBJECT
public:
explicit DriverSelector(const QStringList &supportedDrivers, QWidget *parent = nullptr);
void setSelection(const DriverSelection &selection);
DriverSelection selection() const;
signals:
void selectionChanged();
private:
DriverSelection m_selection;
};
// DriverSelectorToolPanel
class DriverSelectorToolPanel final : public Utils::FadingPanel
{
Q_OBJECT
public:
explicit DriverSelectorToolPanel(QWidget *parent = nullptr);
signals:
void clicked();
private:
void fadeTo(qreal value) final;
void setOpacity(qreal value) final;
};
// DriverSelectorDetailsPanel
class DriverSelectorDetailsPanel final : public QWidget
{
Q_OBJECT
public:
explicit DriverSelectorDetailsPanel(DriverSelection &selection, QWidget *parent = nullptr);
void refresh();
signals:
void selectionChanged();
private:
DriverSelection &m_selection;
QLineEdit *m_dllEdit = nullptr;
DriverSelectionCpuDllView *m_cpuDllView = nullptr;
};
// DriverSelectionDialog
class DriverSelectionDialog final : public QDialog
{
Q_OBJECT
public:
explicit DriverSelectionDialog(const QString &uVisionPath,
const QStringList &supportedDrivers,
QWidget *parent = nullptr);
DriverSelection selection() const;
private:
void setSelection(const DriverSelection &selection);
DriverSelection m_selection;
DriverSelectionModel *m_model = nullptr;
DriverSelectionView *m_view = nullptr;
};
} // namespace Uv
} // namespace Internal
} // namespace BareMetal
@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <QXmlStreamAttribute>
namespace BareMetal {
namespace Gen {
namespace Xml {
class Project;
class ProjectOptions;
class Property;
class PropertyGroup;
class INodeVisitor
{
public:
virtual ~INodeVisitor() {}
virtual void visitProjectOptionsStart(const ProjectOptions *projectOptions)
{ Q_UNUSED(projectOptions) }
virtual void visitProjectOptionsEnd(const ProjectOptions *projectOptions)
{ Q_UNUSED(projectOptions) }
virtual void visitProjectStart(const Project *project) { Q_UNUSED(project) }
virtual void visitProjectEnd(const Project *project) { Q_UNUSED(project) }
virtual void visitPropertyStart(const Property *property) = 0;
virtual void visitPropertyEnd(const Property *property) = 0;
virtual void visitPropertyGroupStart(const PropertyGroup *propertyGroup) = 0;
virtual void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) = 0;
};
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,59 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlnodevisitor.h"
#include "xmlproject.h"
namespace BareMetal {
namespace Gen {
namespace Xml {
// Project
void Project::accept(INodeVisitor *visitor) const
{
visitor->visitProjectStart(this);
for (const auto &child : children())
child->accept(visitor);
visitor->visitProjectEnd(this);
}
// ProjectOptions
void ProjectOptions::accept(INodeVisitor *visitor) const
{
visitor->visitProjectOptionsStart(this);
for (const auto &child : children())
child->accept(visitor);
visitor->visitProjectOptionsEnd(this);
}
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlproperty.h"
#include <memory>
namespace BareMetal {
namespace Gen {
namespace Xml {
// Project
class Project : public Property
{
public:
void accept(INodeVisitor *visitor) const final;
};
// ProjectOptions
class ProjectOptions : public Property
{
public:
void accept(INodeVisitor *visitor) const final;
};
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlproject.h"
#include "xmlprojectwriter.h"
#include "xmlproperty.h"
#include "xmlpropertygroup.h"
#include <ostream>
namespace BareMetal {
namespace Gen {
namespace Xml {
// ProjectWriter
ProjectWriter::ProjectWriter(std::ostream *device)
: m_device(device)
{
m_writer.reset(new QXmlStreamWriter(&m_buffer));
m_writer->setAutoFormatting(true);
m_writer->setAutoFormattingIndent(2);
}
bool ProjectWriter::write(const Project *project)
{
m_buffer.clear();
m_writer->writeStartDocument();
project->accept(this);
m_writer->writeEndDocument();
if (m_writer->hasError())
return false;
m_device->write(&*std::cbegin(m_buffer), m_buffer.size());
return m_device->good();
}
void ProjectWriter::visitPropertyStart(const Property *property)
{
const QString value = property->value().toString();
const QString name = QString::fromUtf8(property->name());
m_writer->writeTextElement(name, value);
}
void ProjectWriter::visitPropertyEnd(const Property *property)
{
Q_UNUSED(property)
}
void ProjectWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup)
{
const QString name = QString::fromUtf8(propertyGroup->name());
m_writer->writeStartElement(name);
}
void ProjectWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup)
{
Q_UNUSED(propertyGroup)
m_writer->writeEndElement();
}
QXmlStreamWriter *ProjectWriter::writer() const
{
return m_writer.get();
}
// ProjectOptionsWriter
ProjectOptionsWriter::ProjectOptionsWriter(std::ostream *device)
: m_device(device)
{
m_writer.reset(new QXmlStreamWriter(&m_buffer));
m_writer->setAutoFormatting(true);
m_writer->setAutoFormattingIndent(2);
}
bool ProjectOptionsWriter::write(const ProjectOptions *projectOptions)
{
m_buffer.clear();
m_writer->writeStartDocument();
projectOptions->accept(this);
m_writer->writeEndDocument();
if (m_writer->hasError())
return false;
m_device->write(&*std::cbegin(m_buffer), m_buffer.size());
return m_device->good();
}
void ProjectOptionsWriter::visitPropertyStart(const Property *property)
{
const QString value = property->value().toString();
const QString name = QString::fromUtf8(property->name());
m_writer->writeTextElement(name, value);
}
void ProjectOptionsWriter::visitPropertyEnd(const Property *property)
{
Q_UNUSED(property)
}
void ProjectOptionsWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup)
{
const QString name = QString::fromUtf8(propertyGroup->name());
m_writer->writeStartElement(name);
}
void ProjectOptionsWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup)
{
Q_UNUSED(propertyGroup)
m_writer->writeEndElement();
}
QXmlStreamWriter *ProjectOptionsWriter::writer() const
{
return m_writer.get();
}
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlnodevisitor.h"
#include <memory>
namespace BareMetal {
namespace Gen {
namespace Xml {
// ProjectWriter
class ProjectWriter : public INodeVisitor
{
Q_DISABLE_COPY(ProjectWriter)
public:
explicit ProjectWriter(std::ostream *device);
bool write(const Project *project);
protected:
QXmlStreamWriter *writer() const;
private:
void visitPropertyStart(const Property *property) final;
void visitPropertyEnd(const Property *property) final;
void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final;
void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final;
std::ostream *m_device = nullptr;
QByteArray m_buffer;
std::unique_ptr<QXmlStreamWriter> m_writer;
};
// ProjectOptionsWriter
class ProjectOptionsWriter : public INodeVisitor
{
Q_DISABLE_COPY(ProjectOptionsWriter)
public:
explicit ProjectOptionsWriter(std::ostream *device);
bool write(const ProjectOptions *projectOptions);
protected:
QXmlStreamWriter *writer() const;
private:
void visitPropertyStart(const Property *property) final;
void visitPropertyEnd(const Property *property) final;
void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final;
void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final;
std::ostream *m_device = nullptr;
QByteArray m_buffer;
std::unique_ptr<QXmlStreamWriter> m_writer;
};
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlnodevisitor.h"
#include "xmlproperty.h"
namespace BareMetal {
namespace Gen {
namespace Xml {
Property::Property(QByteArray name, QVariant value)
{
setName(std::move(name));
setValue(std::move(value));
}
void Property::appendProperty(QByteArray name, QVariant value)
{
appendChild<Property>(std::move(name), std::move(value));
}
void Property::appendMultiLineProperty(QByteArray key, QStringList values, QChar sep)
{
const QString line = values.join(std::move(sep));
appendProperty(std::move(key), QVariant::fromValue(line));
}
void Property::accept(INodeVisitor *visitor) const
{
visitor->visitPropertyStart(this);
for (const auto &child : children())
child->accept(visitor);
visitor->visitPropertyEnd(this);
}
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <QVariant>
#include <memory>
namespace BareMetal {
namespace Gen {
namespace Xml {
class INodeVisitor;
class Property
{
Q_DISABLE_COPY(Property)
public:
Property() = default;
explicit Property(QByteArray name, QVariant value);
virtual ~Property() = default;
QByteArray name() const { return m_name; }
void setName(QByteArray name) { m_name = std::move(name); }
QVariant value() const { return m_value; }
void setValue(QVariant value) { m_value = std::move(value); }
template<class T>
T *appendChild(std::unique_ptr<T> child) {
const auto p = child.get();
m_children.push_back(std::move(child));
return p;
}
template<class T, class... Args>
T *appendChild(Args&&... args) {
return appendChild(std::make_unique<T>(std::forward<Args>(args)...));
}
void appendProperty(QByteArray name, QVariant value = QVariant());
void appendMultiLineProperty(QByteArray key, QStringList values,
QChar sep = QLatin1Char(','));
virtual void accept(INodeVisitor *visitor) const;
protected:
const std::vector<std::unique_ptr<Property>> &children() const
{ return m_children; }
private:
QByteArray m_name;
QVariant m_value;
std::vector<std::unique_ptr<Property>> m_children;
};
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlnodevisitor.h"
#include "xmlpropertygroup.h"
namespace BareMetal {
namespace Gen {
namespace Xml {
PropertyGroup::PropertyGroup(QByteArray name)
{
setName(std::move(name));
}
PropertyGroup *PropertyGroup::appendPropertyGroup(QByteArray name)
{
return appendChild<PropertyGroup>(std::move(name));
}
void PropertyGroup::accept(INodeVisitor *visitor) const
{
visitor->visitPropertyGroupStart(this);
for (const auto &child : children())
child->accept(visitor);
visitor->visitPropertyGroupEnd(this);
}
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -0,0 +1,53 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "xmlproperty.h"
#include <projectexplorer/abi.h>
#include <memory>
namespace BareMetal {
class ProductData;
class Project;
namespace Gen {
namespace Xml {
class PropertyGroup : public Property
{
public:
explicit PropertyGroup(QByteArray name);
PropertyGroup *appendPropertyGroup(QByteArray name);
void accept(INodeVisitor *visitor) const final;
};
} // namespace Xml
} // namespace Gen
} // namespace BareMetal
@@ -37,6 +37,9 @@
#include <QSpinBox>
#include <QUuid>
using namespace Debugger;
using namespace ProjectExplorer;
namespace BareMetal {
namespace Internal {
@@ -123,12 +126,12 @@ void IDebugServerProvider::setTypeDisplayName(const QString &typeDisplayName)
m_typeDisplayName = typeDisplayName;
}
Debugger::DebuggerEngineType IDebugServerProvider::engineType() const
DebuggerEngineType IDebugServerProvider::engineType() const
{
return m_engineType;
}
void IDebugServerProvider::setEngineType(Debugger::DebuggerEngineType engineType)
void IDebugServerProvider::setEngineType(DebuggerEngineType engineType)
{
if (m_engineType == engineType)
return;
@@ -196,8 +199,8 @@ bool IDebugServerProvider::fromMap(const QVariantMap &data)
{
m_id = data.value(idKeyC).toString();
m_displayName = data.value(displayNameKeyC).toString();
m_engineType = static_cast<Debugger::DebuggerEngineType>(
data.value(engineTypeKeyC, Debugger::NoEngineType).toInt());
m_engineType = static_cast<DebuggerEngineType>(
data.value(engineTypeKeyC, NoEngineType).toInt());
m_channel.setHost(data.value(m_settingsBase + hostKeySuffixC).toString());
m_channel.setPort(data.value(m_settingsBase + portKeySuffixC).toInt());
return true;
+6 -5
View File
@@ -25,15 +25,16 @@
#pragma once
#include <coreplugin/id.h>
#include <debugger/debuggerconstants.h>
#include <projectexplorer/abi.h>
#include <utils/fileutils.h>
#include <QObject>
#include <QSet>
#include <QVariantMap>
#include <QWidget>
#include <coreplugin/id.h>
#include <debugger/debuggerconstants.h>
#include <utils/fileutils.h>
QT_BEGIN_NAMESPACE
class QFormLayout;
class QLabel;
@@ -46,7 +47,6 @@ class DebuggerRunTool;
}
namespace ProjectExplorer {
class IDevice;
class RunControl;
class RunWorker;
}
@@ -97,6 +97,7 @@ public:
ProjectExplorer::RunControl *runControl) const = 0;
virtual bool isValid() const = 0;
virtual bool isSimulator() const { return false; }
void registerDevice(BareMetalDevice *device);
void unregisterDevice(BareMetalDevice *device);
+5
View File
@@ -89,6 +89,11 @@ add_qtc_plugin(Debugger
threaddata.h
threadshandler.cpp threadshandler.h
unstartedappwatcherdialog.cpp unstartedappwatcherdialog.h
uvsc/uvscclient.cpp uvsc/uvscclient.h
uvsc/uvscdatatypes.h
uvsc/uvscengine.cpp uvsc/uvscengine.h
uvsc/uvscfunctions.h
uvsc/uvscutils.cpp uvsc/uvscutils.h
watchdata.cpp watchdata.h
watchdelegatewidgets.cpp watchdelegatewidgets.h
watchhandler.cpp watchhandler.h
+1
View File
@@ -133,6 +133,7 @@ include(cdb/cdb.pri)
include(gdb/gdb.pri)
include(pdb/pdb.pri)
include(lldb/lldb.pri)
include(uvsc/uvsc.pri)
include(qml/qml.pri)
include(namedemangler/namedemangler.pri)
include(console/console.pri)
+12
View File
@@ -126,6 +126,18 @@ Project {
files: ["pdbengine.cpp", "pdbengine.h"]
}
Group {
name: "uvsc"
prefix: "uvsc/"
files: [
"uvscclient.cpp", "uvscclient.h",
"uvscdatatypes.h",
"uvscengine.cpp", "uvscengine.h",
"uvscfunctions.h",
"uvscutils.cpp", "uvscutils.h",
]
}
Group {
name: "Name Demangler"
prefix: "namedemangler/"
+7 -1
View File
@@ -36,6 +36,11 @@ const char MODE_DEBUG[] = "Mode.Debug";
// Debug mode context
const char C_DEBUGMODE[] = "Debugger.DebugMode";
// UVSC-specific debugger constants.
const char kUVisionProjectFilePath[] = "UVisionProjectFilePath";
const char kUVisionOptionsFilePath[] = "UVisionOptionsFilePath";
const char kUVisionSimulator[] = "UVisionSimulator";
} // namespace Constants
// Keep in sync with dumper.py
@@ -120,7 +125,8 @@ enum DebuggerEngineType
GdbEngineType = 0x001,
CdbEngineType = 0x004,
PdbEngineType = 0x008,
LldbEngineType = 0x100
LldbEngineType = 0x100,
UvscEngineType = 0x1000
};
enum DebuggerLanguage
+2 -1
View File
@@ -2567,7 +2567,8 @@ bool DebuggerRunParameters::isCppDebugging() const
{
return cppEngineType == GdbEngineType
|| cppEngineType == LldbEngineType
|| cppEngineType == CdbEngineType;
|| cppEngineType == CdbEngineType
|| cppEngineType == UvscEngineType;
}
bool DebuggerRunParameters::isNativeMixedDebugging() const
+23
View File
@@ -37,6 +37,7 @@
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
#include <utils/winutils.h>
#include <QFileInfo>
#include <QProcess>
@@ -138,6 +139,14 @@ void DebuggerItem::createId()
m_id = QUuid::createUuid().toString();
}
static bool isUVisionExecutable(const QFileInfo &fileInfo)
{
if (!HostOsInfo::isWindowsHost())
return false;
const QString baseName = fileInfo.baseName();
return baseName == "UV4";
}
void DebuggerItem::reinitializeFromFile()
{
// CDB only understands the single-dash -version, whereas GDB and LLDB are
@@ -149,6 +158,18 @@ void DebuggerItem::reinitializeFromFile()
if (fileInfo.baseName().toLower().contains("lldb-mi"))
version = "--version";
// We don't need to start the uVision executable to
// determine its version.
if (isUVisionExecutable(fileInfo)) {
QString errorMessage;
m_version = winGetDLLVersion(WinDLLFileVersion,
fileInfo.absoluteFilePath(),
&errorMessage);
m_engineType = UvscEngineType;
m_abis.clear();
return;
}
SynchronousProcess proc;
SynchronousProcessResponse response = proc.runBlocking({m_command, {version}});
if (response.result != SynchronousProcessResponse::Finished) {
@@ -236,6 +257,8 @@ QString DebuggerItem::engineTypeName() const
return QLatin1String("CDB");
case LldbEngineType:
return QLatin1String("LLDB");
case UvscEngineType:
return QLatin1String("UVSC");
default:
return QString();
}
@@ -92,6 +92,7 @@ public:
void readDebuggers(const FilePath &fileName, bool isSystem);
void autoDetectCdbDebuggers();
void autoDetectGdbOrLldbDebuggers();
void autoDetectUvscDebuggers();
QString uniqueDisplayName(const QString &base);
PersistentSettingsWriter m_writer;
@@ -788,6 +789,47 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers()
}
}
void DebuggerItemManagerPrivate::autoDetectUvscDebuggers()
{
if (!HostOsInfo::isWindowsHost())
return;
// Registry token for the "KEIL uVision" instance.
static const char kRegistryToken[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \
"Windows\\CurrentVersion\\Uninstall\\Keil \u00B5Vision4";
QSettings registry(QLatin1String(kRegistryToken), QSettings::NativeFormat);
const auto productGroups = registry.childGroups();
for (const QString &productKey : productGroups) {
if (!productKey.startsWith("App"))
continue;
registry.beginGroup(productKey);
const QDir rootPath(registry.value("Directory").toString());
registry.endGroup();
const FilePath uVision = FilePath::fromString(
rootPath.absoluteFilePath("UV4/UV4.exe"));
if (!uVision.exists())
continue;
if (DebuggerItemManager::findByCommand(uVision))
continue;
QString errorMsg;
const QString uVisionVersion = winGetDLLVersion(
WinDLLFileVersion, uVision.toString(), &errorMsg);
DebuggerItem item;
item.createId();
item.setAutoDetected(true);
item.setCommand(uVision);
item.setVersion(uVisionVersion);
item.setEngineType(UvscEngineType);
item.setUnexpandedDisplayName(
uniqueDisplayName(tr("Auto-detected uVision at %1")
.arg(uVision.toUserOutput())));
m_model->addDebugger(item);
}
}
static FilePath userSettingsFileName()
{
return FilePath::fromString(ICore::userResourcePath() + DEBUGGER_FILENAME);
@@ -894,6 +936,7 @@ void DebuggerItemManagerPrivate::restoreDebuggers()
// Auto detect current.
autoDetectCdbDebuggers();
autoDetectGdbOrLldbDebuggers();
autoDetectUvscDebuggers();
}
void DebuggerItemManagerPrivate::saveDebuggers()
@@ -93,6 +93,7 @@ DebuggerEngine *createGdbEngine();
DebuggerEngine *createPdbEngine();
DebuggerEngine *createQmlEngine();
DebuggerEngine *createLldbEngine();
DebuggerEngine *createUvscEngine();
class LocalProcessRunner : public RunWorker
{
@@ -598,6 +599,9 @@ void DebuggerRunTool::start()
QTC_CHECK(false); // Called from DebuggerRunTool constructor already.
// m_engine = createPdbEngine();
break;
case UvscEngineType:
m_engine = createUvscEngine();
break;
default:
if (!m_runParameters.isQmlDebugging) {
reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine. "
+11
View File
@@ -0,0 +1,11 @@
HEADERS += \
$$PWD/uvscclient.h \
$$PWD/uvscdatatypes.h \
$$PWD/uvscengine.h \
$$PWD/uvscfunctions.h \
$$PWD/uvscutils.h
SOURCES += \
$$PWD/uvscclient.cpp \
$$PWD/uvscengine.cpp \
$$PWD/uvscutils.cpp
File diff suppressed because it is too large Load Diff
+148
View File
@@ -0,0 +1,148 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <debugger/debuggerprotocol.h>
#include <debugger/registerhandler.h>
#include <QObject>
QT_BEGIN_NAMESPACE
class QDir;
QT_END_NAMESPACE
// From UVSC api.
struct STACKENUM;
namespace Utils { class FilePath; }
namespace Debugger {
namespace Internal {
// UvscClient
class UvscClient final : public QObject
{
Q_OBJECT
public:
using Registers = std::map<int, Register>;
enum UvscError {
NoError,
InitializationError,
ConnectionError,
ConfigurationError,
RuntimeError,
};
explicit UvscClient(const QDir &uvscDir);
~UvscClient() final;
void version(QString &uvscVersion, QString &uvsockVersion);
bool connectSession(qint32 uvscPort);
void disconnectSession();
bool startSession(bool extendedStack);
bool stopSession();
bool executeStepOver();
bool executeStepIn();
bool executeStepOut();
bool executeStepInstruction();
bool startExecution();
bool stopExecution();
bool fetchThreads(bool showNames, GdbMi &data);
bool fetchStackFrames(quint32 taskId, quint64 address, GdbMi &data);
bool fetchRegisters(Registers &registers);
bool fetchLocals(const QStringList &expandedLocalINames, qint32 taskId,
qint32 frameId, GdbMi &data);
bool fetchWatchers(const QStringList &expandedWatcherINames,
const std::vector<std::pair<QString, QString>> &rootWatchers, GdbMi &data);
bool disassemblyAddress(quint64 address, QByteArray &result);
bool setRegisterValue(int index, const QString &value);
bool setLocalValue(qint32 localId, qint32 taskId, qint32 frameId, const QString &value);
bool setWatcherValue(qint32 watcherId, const QString &value);
bool createBreakpoint(const QString &exp, quint32 &tickMark, quint64 &address,
quint32 &line, QString &function, QString &fileName);
bool deleteBreakpoint(quint32 tickMark);
bool enableBreakpoint(quint32 tickMark);
bool disableBreakpoint(quint32 tickMark);
bool calculateExpression(const QString &exp, QByteArray &);
bool openProject(const Utils::FilePath &projectFile);
void closeProject();
bool setProjectSources(const Utils::FilePath &sourceDirectory,
const Utils::FilePaths &sourceFiles);
bool setProjectDebugTarget(bool simulator);
bool setProjectOutputTarget(const Utils::FilePath &outputFile);
// Helper functions (for testing purposes only).
void showWindow();
void hideWindow();
UvscError error() const;
QString errorString() const;
signals:
void errorOccurred(UvscError error);
void executionStarted();
void executionStopped();
void projectClosed();
void locationUpdated(quint64 address);
private:
void customEvent(QEvent *event) final;
bool checkConnection();
bool enumerateStack(quint32 taskId, std::vector<STACKENUM> &stackenums);
bool inspectLocal(const QStringList &expandedLocalINames, const QString &localIName,
qint32 localId, qint32 taskId, qint32 frameId, GdbMi &data);
bool fetchWatcher(const QStringList &expandedWatcherINames,
const std::pair<QString, QString> &rootWatcher, GdbMi &data);
bool inspectWatcher(const QStringList &expandedWatcherINames, qint32 watcherId,
const QString &watcherIName, GdbMi &parent);
void setError(UvscError error, const QString &errorString = QString());
void handleMsgEvent(QEvent *event);
void updateLocation(const QByteArray &bpreason);
bool addressToFileLine(quint64 address, QString &fileName, QString &function, quint32 &line);
qint32 m_descriptor = -1;
quint64 m_exitAddress = 0;
UvscError m_error = NoError;
QString m_errorString;
};
} // namespace Internal
} // namespace Debugger
File diff suppressed because it is too large Load Diff
+828
View File
@@ -0,0 +1,828 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvscengine.h"
#include "uvscutils.h"
#include <debugger/breakhandler.h>
#include <debugger/debuggercore.h>
#include <debugger/disassembleragent.h>
#include <debugger/disassemblerlines.h>
#include <debugger/memoryagent.h>
#include <debugger/moduleshandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/threadshandler.h>
#include <debugger/watchhandler.h>
#include <coreplugin/messagebox.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <utils/fileutils.h>
#include <QDir>
#include <QFileInfo>
#include <QJsonArray>
#include <QTextStream>
#include <utility>
using namespace Core;
using namespace ProjectExplorer;
using namespace Utils;
namespace Debugger {
namespace Internal {
constexpr int kRootStackFrameLevel = 1;
// This is a workaround to enable the enumeration of a locals
// in a main/root stack. We need to remove a file in a form
// of 'projectname.uvguix.username' which are creates by uVision.
// Yes, it is a magic!
static void allowRootLocals(const FilePath &projectFile)
{
const QFileInfo fi(projectFile.toFileInfo());
if (!fi.exists())
return;
const QString baseName = fi.baseName();
const QDir dir(fi.dir());
const QString filter = QStringLiteral("%1.uvguix.*").arg(baseName);
const QFileInfoList trashFileInfos = dir.entryInfoList({filter}, QDir::Files);
for (const QFileInfo &trashFileInfo : trashFileInfos) {
QFile f(trashFileInfo.absoluteFilePath());
f.remove();
}
}
// Accessed by DebuggerRunTool.
DebuggerEngine *createUvscEngine()
{
return new UvscEngine;
}
// UvscEngine
UvscEngine::UvscEngine()
{
setObjectName("UvscEngine");
setDebuggerName("UVSC");
}
void UvscEngine::setupEngine()
{
showMessage("TRYING TO INITIALIZE UVSC");
const DebuggerRunParameters &rp = runParameters();
// Extract the TCP/IP port for running uVision server.
const QUrl channel(rp.remoteChannel);
const int port = channel.port();
if (port <= 0) {
handleSetupFailure(tr("Internal error: Invalid TCP/IP port specified %1.")
.arg(port));
return;
}
// Check for valid uVision executable.
if (rp.debugger.executable.isEmpty()) {
handleSetupFailure(tr("Internal error: There is no uVision executable specified."));
return;
} else if (!rp.debugger.executable.exists()) {
handleSetupFailure(tr("Internal error: There is no uVision executable exists."));
return;
}
showMessage("UVSC: RESOLVING LIBRARY SYMBOLS...");
m_client.reset(new UvscClient(rp.debugger.executable.parentDir().toString()));
if (m_client->error() != UvscClient::NoError) {
handleSetupFailure(tr("Internal error: Cannot resolve the library: %1.")
.arg(m_client->errorString()));
return;
} else {
// Show the client API version.
QString uvscVersion;
QString uvsockVersion;
m_client->version(uvscVersion, uvsockVersion);
const QString msg = tr("UVSC Version: %1, UVSOCK Version: %2.")
.arg(uvscVersion, uvsockVersion);
showMessage(msg, LogMisc);
// Conenct to the client signals.
connect(m_client.get(), &UvscClient::errorOccurred,
this, [this](UvscClient::UvscError error) {
// Handle errors if required.
Q_UNUSED(error)
Q_UNUSED(this)
});
connect(m_client.get(), &UvscClient::executionStarted,
this, &UvscEngine::handleStartExecution);
connect(m_client.get(), &UvscClient::executionStopped,
this, &UvscEngine::handleStopExecution);
connect(m_client.get(), &UvscClient::projectClosed,
this, &UvscEngine::handleProjectClosed);
connect(m_client.get(), &UvscClient::locationUpdated,
this, &UvscEngine::handleUpdateLocation);
}
showMessage("UVSC: CONNECTING SESSION...");
if (!m_client->connectSession(port)) {
handleSetupFailure(tr("Internal error: Cannot open the session: %1.")
.arg(m_client->errorString()));
return;
} else {
showMessage("UVSC: SESSION OPENED.");
// Show window (fot testing only).
//m_client->showWindow();
}
if (!configureProject(rp))
return;
}
void UvscEngine::runEngine()
{
showMessage("UVSC: STARTING DEBUGGER...");
if (!m_client->startSession(true)) {
showStatusMessage(tr("Internal error: Failed to start the debugger: %1")
.arg(m_client->errorString()));
notifyEngineRunFailed();
return;
} else {
showMessage("UVSC: DEBUGGER STARTED");
showMessage(tr("Application started."), StatusBar);
}
// Initial attempt to set breakpoints.
showStatusMessage(tr("Setting breakpoints..."));
showMessage(tr("Setting breakpoints..."));
BreakpointManager::claimBreakpointsForEngine(this);
showMessage("UVSC RUNNING SUCCESSFULLY.");
notifyEngineRunAndInferiorStopOk();
}
void UvscEngine::shutdownInferior()
{
showMessage("UVSC: STOPPING DEBUGGER...");
if (!m_client->stopSession()) {
AsynchronousMessageBox::critical(tr("Failed to Shut Down Application"),
m_client->errorString());
} else {
showMessage("UVSC: DEBUGGER STOPPED");
}
notifyInferiorShutdownFinished();
}
void UvscEngine::shutdownEngine()
{
showMessage("INITIATE UVSC SHUTDOWN");
m_client->disconnectSession();
notifyEngineShutdownFinished();
}
bool UvscEngine::hasCapability(unsigned cap) const
{
return cap & (DisassemblerCapability
| RegisterCapability
| AddWatcherCapability
| WatchWidgetsCapability
| CreateFullBacktraceCapability
| OperateByInstructionCapability);
}
void UvscEngine::setRegisterValue(const QString &name, const QString &value)
{
const auto registerBegin = m_registers.cbegin();
const auto registerEnd = m_registers.cend();
const auto registerIt = std::find_if(registerBegin, registerEnd,
[name](const std::pair<int, Register> &reg) {
return reg.second.name == name;
});
if (registerIt == registerEnd)
return; // Register not found.
if (!m_client->setRegisterValue(registerIt->first, value))
return;
reloadRegisters();
}
void UvscEngine::executeStepOver(bool byInstruction)
{
notifyInferiorRunRequested();
const quint32 frameLevel = currentFrameLevel();
// UVSC does not support the 'step-over' from the main
// stack frame (seems, it is UVSC bug), so, falling back
// to the 'step-by-instruction' in this case.
const bool result = (frameLevel == kRootStackFrameLevel || byInstruction)
? m_client->executeStepInstruction() : m_client->executeStepOver();
if (!result)
handleExecutionFailure(m_client->errorString());
}
void UvscEngine::executeStepIn(bool byInstruction)
{
notifyInferiorRunRequested();
const quint32 frameLevel = currentFrameLevel();
// UVSC does not support the 'step-over' from the main
// stack frame (seems, it is UVSC bug), so, falling back
// to the 'step-by-instruction' in this case.
const bool result = (frameLevel == kRootStackFrameLevel || byInstruction)
? m_client->executeStepInstruction() : m_client->executeStepIn();
if (!result)
handleExecutionFailure(m_client->errorString());
}
void UvscEngine::executeStepOut()
{
notifyInferiorRunRequested();
if (!m_client->executeStepOut())
handleExecutionFailure(m_client->errorString());
}
void UvscEngine::continueInferior()
{
if (state() != InferiorStopOk)
return;
notifyInferiorRunRequested();
showStatusMessage(tr("Running requested..."), 5000);
if (!m_client->startExecution()) {
showMessage(tr("UVSC: Starting execution failed"), LogMisc);
handleExecutionFailure(m_client->errorString());
}
}
void UvscEngine::interruptInferior()
{
if (state() != InferiorStopRequested)
return;
if (!m_client->stopExecution()) {
showMessage(tr("UVSC: Stopping execution failed"), LogMisc);
handleStoppingFailure(m_client->errorString());
}
}
void UvscEngine::assignValueInDebugger(WatchItem *item, const QString &expr,
const QVariant &value)
{
Q_UNUSED(expr)
if (item->isLocal()) {
const int taskId = currentThreadId();
const int frameId = currentFrameLevel();
if (!m_client->setLocalValue(item->id, taskId, frameId, value.toString()))
showMessage(tr("UVSC: Setting local value failed"), LogMisc);
} else if (item->isWatcher()) {
if (!m_client->setWatcherValue(item->id, value.toString()))
showMessage(tr("UVSC: Setting watcher value failed"), LogMisc);
}
updateLocals();
}
void UvscEngine::selectThread(const Thread &thread)
{
Q_UNUSED(thread)
// We don't support this feature, because we always have
// only one main thread.
}
void UvscEngine::activateFrame(int index)
{
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return;
StackHandler *handler = stackHandler();
if (handler->isSpecialFrame(index)) {
reloadFullStack();
return;
}
QTC_ASSERT(index < handler->stackSize(), return);
handler->setCurrentIndex(index);
gotoCurrentLocation();
updateLocals();
reloadRegisters();
}
bool UvscEngine::stateAcceptsBreakpointChanges() const
{
switch (state()) {
case InferiorRunOk:
case InferiorStopOk:
return true;
default:
break;
}
return false;
}
bool UvscEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
if (bp.isCppBreakpoint()) {
switch (bp.type) {
case BreakpointByFileAndLine:
return true;
default:
break;
}
}
return false;
}
void UvscEngine::insertBreakpoint(const Breakpoint &bp)
{
if (!bp || bp->state() != BreakpointInsertionRequested)
return;
notifyBreakpointInsertProceeding(bp);
const BreakpointParameters &requested = bp->requestedParameters();
QString expression;
if (requested.type == BreakpointByFileAndLine) {
// Add target executable name.
const DebuggerRunParameters &rp = runParameters();
QString exe = rp.inferior.executable.toFileInfo().baseName();
exe.replace('-', '_');
expression += "\\\\" + exe;
// Add file name.
expression += "\\" + requested.fileName.toString();
// Add line number.
expression += "\\" + QString::number(requested.lineNumber);
}
handleInsertBreakpoint(expression, bp);
}
void UvscEngine::removeBreakpoint(const Breakpoint &bp)
{
if (!bp || bp->state() != BreakpointRemoveRequested || bp->responseId().isEmpty())
return;
notifyBreakpointRemoveProceeding(bp);
handleRemoveBreakpoint(bp);
}
void UvscEngine::updateBreakpoint(const Breakpoint &bp)
{
if (!bp || bp->state() != BreakpointUpdateRequested || bp->responseId().isEmpty())
return;
const BreakpointParameters &requested = bp->requestedParameters();
if (requested.type == UnknownBreakpointType)
return;
notifyBreakpointChangeProceeding(bp);
handleChangeBreakpoint(bp);
}
void UvscEngine::fetchDisassembler(DisassemblerAgent *agent)
{
QByteArray data;
const Location location = agent->location();
if (const quint64 address = location.address()) {
if (!m_client->disassemblyAddress(address, data))
showMessage(tr("UVSC: Disassembling by address failed"), LogMisc);
}
DisassemblerLines result;
QTextStream in(data);
while (!in.atEnd()) {
const QString line = in.readLine();
if (line.startsWith("0x")) {
// Instruction line, like:
// "0x08000210 9101 STR r1,[sp,#0x04]".
const int oneSpaceIndex = line.indexOf(' ');
if (oneSpaceIndex < 0)
continue;
const QString address = line.mid(0, oneSpaceIndex);
const int sixSpaceIndex = line.indexOf(" ", oneSpaceIndex);
if (sixSpaceIndex < 0)
continue;
const QString bytes = line.mid(oneSpaceIndex + 1, sixSpaceIndex - oneSpaceIndex - 1);
const QString content = line.mid(sixSpaceIndex + 6);
DisassemblerLine dline;
dline.address = address.toULongLong(nullptr, 0);
dline.bytes = bytes;
dline.data = content;
result.appendLine(dline);
} else {
// Comment or code line, like:
// " 25: struct foo foo = {0}; ".
const int colonIndex = line.indexOf(':');
if (colonIndex < 0) {
result.appendComment(line);
} else {
const QString number = line.mid(0, colonIndex).trimmed();
const QString content = line.mid(colonIndex + 1);
DisassemblerLine dline;
dline.lineNumber = number.toInt();
dline.data = content;
result.appendLine(dline);
}
}
}
if (result.coversAddress(agent->address())) {
// We need to force cleanup a cache to make a location
// marker work correctly in disassembly view.
agent->cleanup();
agent->setContents(result);
}
}
void UvscEngine::reloadRegisters()
{
if (!isRegistersWindowVisible())
return;
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return;
handleReloadRegisters();
}
void UvscEngine::reloadFullStack()
{
resetLocation();
handleReloadStack(true);
}
void UvscEngine::doUpdateLocals(const UpdateParameters &params)
{
if (m_inUpdateLocals)
return;
m_inUpdateLocals = true;
watchHandler()->notifyUpdateStarted(params);
const bool partial = !params.partialVariable.isEmpty();
// This is a workaround to avoid a strange QVector index assertion
// inside of the watch model.
QMetaObject::invokeMethod(this, "handleUpdateLocals", Qt::QueuedConnection,
Q_ARG(bool, partial));
}
void UvscEngine::updateAll()
{
QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk);
handleThreadInfo();
reloadRegisters();
updateLocals();
}
bool UvscEngine::configureProject(const DebuggerRunParameters &rp)
{
// Fetch patchs for the generated uVision project files.
const FilePath optionsPath = FilePath::fromString(rp.inferior.extraData.value(
Constants::kUVisionOptionsFilePath).toString());
const FilePath projectPath = FilePath::fromString(rp.inferior.extraData.value(
Constants::kUVisionProjectFilePath).toString());
showMessage("UVSC: LOADING PROJECT...");
if (!optionsPath.exists()) {
handleSetupFailure(tr("Internal error: No uVision project options file exists."));
return false;
} else if (!projectPath.exists()) {
handleSetupFailure(tr("Internal error: No uVision project file exists."));
return false;
} else if (!m_client->openProject(projectPath)) {
handleSetupFailure(tr("Internal error: Unable to open the uVision project %1: %2.")
.arg(projectPath.toString(), m_client->errorString()));
return false;
} else {
showMessage("UVSC: PROJECT LOADED");
}
showMessage("UVSC: SETTING PROJECT DEBUG TARGET...");
m_simulator = rp.inferior.extraData.value(Constants::kUVisionSimulator).toBool();
if (!m_client->setProjectDebugTarget(m_simulator)) {
handleSetupFailure(tr("Internal error: Unable to set the uVision debug target: %1.")
.arg(m_client->errorString()));
return false;
} else {
showMessage("UVSC: PROJECT DEBUG TARGET SET");
}
// We need to use the relative output target path.
showMessage("UVSC: SETTING PROJECT OUTPUT TARGET...");
const FilePath targetPath = rp.inferior.executable.relativeChildPath(
projectPath.parentDir());
if (!rp.inferior.executable.exists()) {
handleSetupFailure(tr("Internal error: No output file exists."));
return false;
} else if (!m_client->setProjectOutputTarget(targetPath)) {
handleSetupFailure(tr("Internal error: Unable to set the uVision output file %1: %2.")
.arg(targetPath.toString(), m_client->errorString()));
return false;
} else {
showMessage("UVSC: PROJECT OUTPUT TARGET SET");
}
// Close the project to flush all changes to the
// specific uVision project files.
m_loadingRequired = true;
m_client->closeProject();
return true;
}
quint32 UvscEngine::currentThreadId() const
{
const Thread thread = threadsHandler()->currentThread();
return thread ? thread->id().toUInt() : -1;
}
quint32 UvscEngine::currentFrameLevel() const
{
const StackFrame frame = stackHandler()->currentFrame();
return frame.level.toUInt();
}
void UvscEngine::handleProjectClosed()
{
if (!m_loadingRequired)
return;
m_loadingRequired = false;
const DebuggerRunParameters &rp = runParameters();
const FilePath projectPath = FilePath::fromString(rp.inferior.extraData.value(
Constants::kUVisionProjectFilePath).toString());
// This magic function removes specific files from the uVision
// project directory. Without of this we can't enumerate the local
// variables on a root/main stack (yes, it is a magic)!
allowRootLocals(projectPath);
// Re-open the project again.
if (!m_client->openProject(projectPath)) {
handleSetupFailure(tr("Internal error: Unable to open the uVision project %1: %2.")
.arg(projectPath.toString(), m_client->errorString()));
return;
}
// Adding executable to modules list.
Module module;
module.startAddress = 0;
module.endAddress = 0;
module.modulePath = rp.inferior.executable.toString();
module.moduleName = "<executable>";
modulesHandler()->updateModule(module);
showMessage("UVSC: ALL INITIALIZED SUCCESSFULLY.");
notifyEngineSetupOk();
}
void UvscEngine::handleUpdateLocation(quint64 address)
{
m_address = address;
}
void UvscEngine::handleStartExecution()
{
notifyInferiorRunOk();
}
void UvscEngine::handleStopExecution()
{
if (state() == InferiorRunOk) {
notifyInferiorSpontaneousStop();
} else if (state() == InferiorRunRequested) {
notifyInferiorRunOk();
notifyInferiorSpontaneousStop();
} else if (state() == InferiorStopOk) {
// That's expected.
} else if (state() == InferiorStopRequested) {
notifyInferiorStopOk();
} else if (state() == EngineRunRequested) {
// This is gdb 7+'s initial *stopped in response to attach that
// appears before the ^done is seen for local setups.
notifyEngineRunAndInferiorStopOk();
} else {
QTC_CHECK(false);
}
QTC_CHECK(state() == InferiorStopOk);
handleThreadInfo();
}
void UvscEngine::handleThreadInfo()
{
const bool showNames = true;
GdbMi data;
if (!m_client->fetchThreads(showNames, data))
return;
ThreadsHandler *handler = threadsHandler();
handler->setThreads(data);
updateState();
handleReloadStack(false);
}
void UvscEngine::handleReloadStack(bool isFull)
{
GdbMi data;
const quint32 taskId = currentThreadId();
if (!m_client->fetchStackFrames(taskId, m_address, data)) {
m_address = 0;
reloadRegisters();
return;
}
const GdbMi stack = data["stack"];
const GdbMi frames = stack["frames"];
if (!frames.isValid())
isFull = true;
stackHandler()->setFramesAndCurrentIndex(frames, isFull);
activateFrame(stackHandler()->currentIndex());
}
void UvscEngine::handleReloadRegisters()
{
m_registers.clear();
if (!m_client->fetchRegisters(m_registers)) {
showMessage(tr("UVSC: Registers reading failed"), LogMisc);
} else {
RegisterHandler *handler = registerHandler();
for (const auto &reg : qAsConst(m_registers))
handler->updateRegister(reg.second);
handler->commitUpdates();
}
}
void UvscEngine::handleUpdateLocals(bool partial)
{
m_inUpdateLocals = false;
// Build result entry.
GdbMi all = UvscUtils::buildResultTemplateEntry(partial);
// Build data entry.
GdbMi data = UvscUtils::buildEntry("data", "", GdbMi::List);
const int taskId = currentThreadId();
const int frameId = currentFrameLevel();
DebuggerCommand cmd;
watchHandler()->appendFormatRequests(&cmd);
watchHandler()->appendWatchersAndTooltipRequests(&cmd);
auto enumerateExpandedINames = [&cmd]() {
QStringList inames;
const QJsonArray array = cmd.args["expanded"].toArray();
for (const QJsonValue &value : array)
inames.push_back(value.toString());
return inames;
};
auto enumerateRootWatchers = [&cmd]() {
std::vector<std::pair<QString, QString>> inames;
const QJsonArray array = cmd.args["watchers"].toArray();
for (const QJsonValue &value : array) {
if (!value.isObject())
continue;
const QJsonObject object = value.toObject();
inames.push_back({object.value("iname").toString(),
object.value("exp").toString()});
}
return inames;
};
const QStringList expandedINames = enumerateExpandedINames();
const std::vector<std::pair<QString, QString>> rootWatchers = enumerateRootWatchers();
QStringList expandedLocalINames;
QStringList expandedWatcherINames;
for (const QString &iname : expandedINames) {
if (iname.startsWith("local."))
expandedLocalINames.push_back(iname);
else if (iname.startsWith("watch."))
expandedWatcherINames.push_back(iname);
}
if (!m_client->fetchLocals(expandedLocalINames, taskId, frameId, data))
showMessage(tr("UVSC: Locals enumeration failed"), LogMisc);
if (!m_client->fetchWatchers(expandedWatcherINames, rootWatchers, data))
showMessage(tr("UVSC: Watchers enumeration failed"), LogMisc);
all.addChild(data);
updateLocalsView(all);
watchHandler()->notifyUpdateFinished();
}
void UvscEngine::handleInsertBreakpoint(const QString &exp, const Breakpoint &bp)
{
quint32 tickMark = 0;
quint64 address = 0;
quint32 line = -1;
QString function;
QString fileName;
if (!m_client->createBreakpoint(exp, tickMark, address, line, function, fileName)) {
showMessage(tr("UVSC: Inserting breakpoint failed"), LogMisc);
notifyBreakpointInsertFailed(bp);
} else {
bp->setPending(false);
bp->setResponseId(QString::number(tickMark));
bp->setAddress(address);
bp->setLineNumber(line);
bp->setFileName(FilePath::fromString(fileName));
bp->setFunctionName(function);
notifyBreakpointInsertOk(bp);
}
}
void UvscEngine::handleRemoveBreakpoint(const Breakpoint &bp)
{
const quint32 tickMark = bp->responseId().toULong();
if (!m_client->deleteBreakpoint(tickMark)) {
showMessage(tr("UVSC: Removing breakpoint failed"), LogMisc);
notifyBreakpointRemoveFailed(bp);
} else {
notifyBreakpointRemoveOk(bp);
}
}
void UvscEngine::handleChangeBreakpoint(const Breakpoint &bp)
{
const quint32 tickMark = bp->responseId().toULong();
const BreakpointParameters &requested = bp->requestedParameters();
if (requested.enabled && !bp->isEnabled()) {
if (!m_client->enableBreakpoint(tickMark)) {
showMessage(tr("UVSC: Enabling breakpoint failed"), LogMisc);
notifyBreakpointChangeFailed(bp);
return;
}
} else if (!requested.enabled && bp->isEnabled()) {
if (!m_client->disableBreakpoint(tickMark)) {
showMessage(tr("UVSC: Disabling breakpoint failed"), LogMisc);
notifyBreakpointChangeFailed(bp);
return;
}
}
notifyBreakpointChangeOk(bp);
}
void UvscEngine::handleSetupFailure(const QString &errorMessage)
{
showMessage("UVSC INITIALIZATION FAILED");
AsynchronousMessageBox::critical(tr("Failed to initialize the UVSC"), errorMessage);
notifyEngineSetupFailed();
}
void UvscEngine::handleShutdownFailure(const QString &errorMessage)
{
showMessage("UVSC SHUTDOWN FAILED");
AsynchronousMessageBox::critical(tr("Failed to de-initialize the UVSC"), errorMessage);
}
void UvscEngine::handleRunFailure(const QString &errorMessage)
{
showMessage("UVSC RUN FAILED");
AsynchronousMessageBox::critical(tr("Failed to run the UVSC"), errorMessage);
notifyEngineSetupFailed();
}
void UvscEngine::handleExecutionFailure(const QString &errorMessage)
{
AsynchronousMessageBox::critical(tr("Execution Error"),
tr("Cannot continue debugged process:\n") + errorMessage);
notifyInferiorRunFailed();
}
void UvscEngine::handleStoppingFailure(const QString &errorMessage)
{
AsynchronousMessageBox::critical(tr("Execution Error"),
tr("Cannot stop debugged process:\n") + errorMessage);
notifyInferiorStopFailed();
}
} // namespace Internal
} // namespace Debugger
+117
View File
@@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvscclient.h"
#include <debugger/debuggerengine.h>
namespace Utils { class FilePath; }
namespace Debugger {
namespace Internal {
class UvscEngine final : public CppDebuggerEngine
{
Q_OBJECT
public:
explicit UvscEngine();
void setupEngine() final;
void runEngine() final;
void shutdownInferior() final;
void shutdownEngine() final;
bool hasCapability(unsigned cap) const final;
void setRegisterValue(const QString &name, const QString &value) final;
void executeStepOver(bool byInstruction) final;
void executeStepIn(bool byInstruction) final;
void executeStepOut() final;
void continueInferior() final;
void interruptInferior() final;
void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value) final;
void selectThread(const Thread &thread) final;
void activateFrame(int index) final;
bool stateAcceptsBreakpointChanges() const final;
bool acceptsBreakpoint(const BreakpointParameters &params) const final;
void insertBreakpoint(const Breakpoint &bp) final;
void removeBreakpoint(const Breakpoint &bp) final;
void updateBreakpoint(const Breakpoint &bp) final;
void fetchDisassembler(DisassemblerAgent *agent) final;
void reloadRegisters() final;
void reloadFullStack() final;
private slots:
void handleProjectClosed();
void handleUpdateLocation(quint64 address);
void handleStartExecution();
void handleStopExecution();
void handleThreadInfo();
void handleReloadStack(bool isFull);
void handleReloadRegisters();
void handleUpdateLocals(bool partial);
void handleInsertBreakpoint(const QString &exp, const Breakpoint &bp);
void handleRemoveBreakpoint(const Breakpoint &bp);
void handleChangeBreakpoint(const Breakpoint &bp);
void handleSetupFailure(const QString &errorMessage);
void handleShutdownFailure(const QString &errorMessage);
void handleRunFailure(const QString &errorMessage);
void handleExecutionFailure(const QString &errorMessage);
void handleStoppingFailure(const QString &errorMessage);
private:
void doUpdateLocals(const UpdateParameters &params) final;
void updateAll() final;
bool configureProject(const DebuggerRunParameters &rp);
Utils::FilePaths enabledSourceFiles() const;
quint32 currentThreadId() const;
quint32 currentFrameLevel() const;
bool m_simulator = false;
bool m_loadingRequired = false;
bool m_inUpdateLocals = false;
quint64 m_address = 0;
UvscClient::Registers m_registers;
std::unique_ptr<UvscClient> m_client;
};
} // namespace Internal
} // namespace Debugger
+382
View File
@@ -0,0 +1,382 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvscdatatypes.h"
#include <QDir>
#include <QLibrary>
#if defined(Q_OS_WIN)
#include <qt_windows.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Maximum number of clients UVSC can support.
#define UVSC_MAX_CLIENTS 10
// Maximum string size.
#define UVSC_MAX_API_STR_SIZE 1024
// Auto port.
#define UVSC_PORT_AUTO 0
// Minimum auto port value.
#define UVSC_MIN_AUTO_PORT 1
// Maximum auto port value.
#define UVSC_MAX_AUTO_PORT 65535
// UVSC status codes.
enum UVSC_STATUS {
UVSC_STATUS_SUCCESS = 0,
UVSC_STATUS_FAILED = 1,
UVSC_STATUS_NOT_SUPPORTED = 2,
UVSC_STATUS_NOT_INIT = 3,
UVSC_STATUS_TIMEOUT = 4,
UVSC_STATUS_INVALID_CONTEXT = 5,
UVSC_STATUS_INVALID_PARAM = 6,
UVSC_STATUS_BUFFER_TOO_SMALL = 7,
UVSC_STATUS_CALLBACK_IN_USE = 8,
UVSC_STATUS_COMMAND_ERROR = 9,
UVSC_STATUS_END
};
// uVision run modes.
enum UVSC_RUNMODE {
UVSC_RUNMODE_NORMAL = 0,
UVSC_RUNMODE_LABVIEW = 1,
UVSC_RUNMODE_END = 2,
};
// Progress bar operations.
enum UVSC_PBAR {
UVSC_PBAR_INIT = 0,
UVSC_PBAR_TEXT = 1,
UVSC_PBAR_POS = 2,
UVSC_PBAR_STOP = 3,
};
// UVSC callback types.
enum UVSC_CB_TYPE {
UVSC_CB_ERROR = 0,
UVSC_CB_ASYNC_MSG = 1,
UVSC_CB_DISCONNECTED = 2,
UVSC_CB_BUILD_OUTPUT_MSG = 3,
UVSC_CB_PROGRESS_BAR_MSG = 4,
UVSC_CB_CMD_OUTPUT_MSG = 5,
};
// UVSC callback data.
union UVSC_CB_DATA {
UVSOCK_CMD msg;
UVSC_STATUS error;
qint32 connectionHandle;
};
static_assert(sizeof(UVSC_CB_DATA) == 32800, "UVSC_CB_DATA size is not 32800 bytes");
// UVSC callback function.
typedef void (*uvsc_cb)(void *cb_custom, UVSC_CB_TYPE type, UVSC_CB_DATA *data);
// UVSC logging callback function.
typedef void (*log_cb)(const char *msg, int msgLen);
// Macro to generate functions && symbols.
#define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \
typedef returnType (*fp_##symbolName)(__VA_ARGS__); \
static fp_##symbolName symbolName;
// Macro to resolve functions && symbols.
#define RESOLVE_SYMBOL(symbolName) \
symbolName = reinterpret_cast<fp_##symbolName>(uvscLibrary->resolve(#symbolName)); \
if (!symbolName) \
return false;
// Control functions.
GENERATE_SYMBOL_VARIABLE(void, UVSC_Version, quint32 *, quint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_Init, qint32, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_UnInit, void)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_OpenConnection, qint8 *, qint32 *, qint32 *, \
qint8 *, UVSC_RUNMODE, uvsc_cb, void *, qint8 *, quint8, log_cb)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_CloseConnection, qint32, quint8)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_ConnHandleFromConnName, qint8 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GetLastError, qint32, \
UV_OPERATION *, UV_STATUS *, qint8 *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_LogControl, qint32, quint8, quint8)
// Messaging functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_SET_OPTIONS, qint32, UVSOCK_OPTIONS *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_UVSOCK_VERSION, qint32, qint32 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_EXT_VERSION, qint32, EXTVERS *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_HIDE, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_SHOW, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_MAXIMIZE, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_MINIMIZE, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_RESTORE, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_UI_LOCK, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_UI_UNLOCK, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GEN_CHECK_LICENSE, qint32, UVLICINFO *)
// Project functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_LOAD, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_CLOSE, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ADD_FILE, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_DEL_FILE, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ENUM_FILES, qint32, SSTR *, \
qint32, SSTR *, qint32 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ADD_GROUP, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_DEL_GROUP, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_SET_TARGET, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_SET_OUTPUTNAME, qint32, PRJDATA *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ENUM_GROUPS, qint32, \
SSTR *, qint32 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ENUM_TARGETS, qint32, \
SSTR *, qint32 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_ACTIVE_FILES, qint32, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_BUILD, qint32, quint8)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_BUILD_CANCEL, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_CLEAN, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_FLASH_DOWNLOAD, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_GET_OPTITEM, qint32, TRNOPT *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_SET_OPTITEM, qint32, TRNOPT *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_GET_DEBUG_TARGET, qint32, DBGTGTOPT *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_SET_DEBUG_TARGET, qint32, DBGTGTOPT *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_CMD_PROGRESS, qint32, PGRESS *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_GET_OUTPUTNAME, qint32, \
iPATHREQ *, SSTR *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_PRJ_GET_CUR_TARGET, qint32, \
iPATHREQ *, SSTR *, qint32)
// Debug functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENTER, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EXIT, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_START_EXECUTION, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_RUN_TO_ADDRESS, qint32, quint64)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STOP_EXECUTION, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STATUS, qint32, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_HLL, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_HLL_N, qint32, quint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_INSTRUCTION, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_INSTRUCTION_N, qint32, quint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_INTO, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_INTO_N, qint32, quint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_STEP_OUT, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_RESET, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_MEM_READ, qint32, AMEM *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_MEM_WRITE, qint32, AMEM *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_CREATE_BP, qint32, \
BKPARM *, qint32, BKRSP *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_CHANGE_BP, qint32, \
BKCHG *, qint32, BKRSP *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUMERATE_BP, qint32, \
BKRSP *, qint32 *, qint32*)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_SERIAL_GET, qint32, SERIO *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_SERIAL_PUT, qint32, SERIO *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_CALC_EXPRESSION, qint32, VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EVAL_WATCH_EXPRESSION, qint32, \
VSET *, qint32, VARINFO *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_REMOVE_WATCH_EXPRESSION, qint32, \
VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_VARIABLES, qint32, \
IVARENUM *, VARINFO *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_VARIABLE_SET, qint32, VARVAL *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_VTR, qint32, \
iVTRENUM *, AVTR *, qint32 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_VTR_GET, qint32, VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_VTR_SET, qint32, VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ITM_REGISTER, qint32, ITMOUT *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ITM_UNREGISTER, qint32, ITMOUT *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_STACK, qint32, \
iSTKENUM *, STACKENUM *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_TASKS, qint32, TASKENUM *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_MENUS, qint32, \
MENUID *, MENUENUM *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_MENU_EXEC, qint32, MENUID *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ADR_TOFILELINE, qint32, \
ADRMTFL *, AFLMAP *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ADR_SHOWCODE, qint32, iSHOWSYNC *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_POWERSCALE_SHOWCODE, qint32, UVSC_PSTAMP *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_WAKE, qint32, iINTERVAL *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_SLEEP, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EXEC_CMD, qint32, EXECCMD *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EVAL_EXPRESSION_TO_STR, qint32, \
VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_FILELINE_TO_ADR, qint32, \
AFLMAP *, qint32, VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_REGISTER_GROUPS, qint32, \
SSTR *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_ENUM_REGISTERS, qint32, \
REGENUM *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_READ_REGISTERS, qint32, qint8 *, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_REGISTER_SET, qint32, VSET *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_DSM_READ, qint32, AMEM *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EVTR_REGISTER, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EVTR_UNREGISTER, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_DBG_EVTR_ENUMSCVDFILES, qint32, \
SSTR *, qint32 *)
// Build output functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GetBuildOutputSize, qint32, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GetBuildOutput, qint32, qint8 *, qint32)
// Command output functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GetCmdOutputSize, qint32, qint32 *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_GetCmdOutput, qint32, qint8 *, qint32)
// Queue functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_ReadBuildQ, qint32, qint8 *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_ReadPBarQ, qint32, \
UVSC_PBAR *, qint8 *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_ReadAsyncQ, qint32, \
qint32, UVSOCK_CMD *, qint32)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_FlushAsyncQ, qint32, qint32)
// Advanced functions.
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_TxRxRaw, qint32, UVSOCK_CMD *)
GENERATE_SYMBOL_VARIABLE(UVSC_STATUS, UVSC_CreateMsg, UVSOCK_CMD *, UV_OPERATION, \
qint32, const void *)
inline bool resolveUvscSymbols(const QDir &dir, QLibrary *uvscLibrary)
{
if (!uvscLibrary->isLoaded()) {
#ifdef Q_PROCESSOR_X86_64
uvscLibrary->setFileName(dir.absoluteFilePath(QStringLiteral("uvsc64")));
#else
uvscLibrary->setFileName(dir.absoluteFilePath(QStringLiteral("uvsc")));
#endif
if (!uvscLibrary->load())
return false;
}
// Control functions.
RESOLVE_SYMBOL(UVSC_Version)
RESOLVE_SYMBOL(UVSC_Init)
RESOLVE_SYMBOL(UVSC_UnInit)
RESOLVE_SYMBOL(UVSC_OpenConnection)
RESOLVE_SYMBOL(UVSC_CloseConnection)
RESOLVE_SYMBOL(UVSC_ConnHandleFromConnName)
RESOLVE_SYMBOL(UVSC_GetLastError)
RESOLVE_SYMBOL(UVSC_LogControl)
// Messaging functions.
RESOLVE_SYMBOL(UVSC_GEN_SET_OPTIONS)
RESOLVE_SYMBOL(UVSC_GEN_UVSOCK_VERSION)
RESOLVE_SYMBOL(UVSC_GEN_EXT_VERSION)
RESOLVE_SYMBOL(UVSC_GEN_HIDE)
RESOLVE_SYMBOL(UVSC_GEN_SHOW)
RESOLVE_SYMBOL(UVSC_GEN_MAXIMIZE)
RESOLVE_SYMBOL(UVSC_GEN_MINIMIZE)
RESOLVE_SYMBOL(UVSC_GEN_RESTORE)
RESOLVE_SYMBOL(UVSC_GEN_UI_LOCK)
RESOLVE_SYMBOL(UVSC_GEN_UI_UNLOCK)
RESOLVE_SYMBOL(UVSC_GEN_CHECK_LICENSE)
// Project functions.
RESOLVE_SYMBOL(UVSC_PRJ_LOAD)
RESOLVE_SYMBOL(UVSC_PRJ_CLOSE)
RESOLVE_SYMBOL(UVSC_PRJ_ADD_FILE)
RESOLVE_SYMBOL(UVSC_PRJ_DEL_FILE)
RESOLVE_SYMBOL(UVSC_PRJ_ENUM_FILES)
RESOLVE_SYMBOL(UVSC_PRJ_ADD_GROUP)
RESOLVE_SYMBOL(UVSC_PRJ_DEL_GROUP)
RESOLVE_SYMBOL(UVSC_PRJ_SET_TARGET)
RESOLVE_SYMBOL(UVSC_PRJ_SET_OUTPUTNAME)
RESOLVE_SYMBOL(UVSC_PRJ_ENUM_GROUPS)
RESOLVE_SYMBOL(UVSC_PRJ_ENUM_TARGETS)
RESOLVE_SYMBOL(UVSC_PRJ_ACTIVE_FILES)
RESOLVE_SYMBOL(UVSC_PRJ_BUILD)
RESOLVE_SYMBOL(UVSC_PRJ_BUILD_CANCEL)
RESOLVE_SYMBOL(UVSC_PRJ_CLEAN)
RESOLVE_SYMBOL(UVSC_PRJ_FLASH_DOWNLOAD)
RESOLVE_SYMBOL(UVSC_PRJ_GET_OPTITEM)
RESOLVE_SYMBOL(UVSC_PRJ_SET_OPTITEM)
RESOLVE_SYMBOL(UVSC_PRJ_GET_DEBUG_TARGET)
RESOLVE_SYMBOL(UVSC_PRJ_SET_DEBUG_TARGET)
RESOLVE_SYMBOL(UVSC_PRJ_CMD_PROGRESS)
RESOLVE_SYMBOL(UVSC_PRJ_GET_OUTPUTNAME)
RESOLVE_SYMBOL(UVSC_PRJ_GET_CUR_TARGET)
// Debug functions.
RESOLVE_SYMBOL(UVSC_DBG_ENTER)
RESOLVE_SYMBOL(UVSC_DBG_EXIT)
RESOLVE_SYMBOL(UVSC_DBG_START_EXECUTION)
RESOLVE_SYMBOL(UVSC_DBG_RUN_TO_ADDRESS)
RESOLVE_SYMBOL(UVSC_DBG_STOP_EXECUTION)
RESOLVE_SYMBOL(UVSC_DBG_STATUS)
RESOLVE_SYMBOL(UVSC_DBG_STEP_HLL)
RESOLVE_SYMBOL(UVSC_DBG_STEP_HLL_N)
RESOLVE_SYMBOL(UVSC_DBG_STEP_INSTRUCTION)
RESOLVE_SYMBOL(UVSC_DBG_STEP_INSTRUCTION_N)
RESOLVE_SYMBOL(UVSC_DBG_STEP_INTO)
RESOLVE_SYMBOL(UVSC_DBG_STEP_INTO_N)
RESOLVE_SYMBOL(UVSC_DBG_STEP_OUT)
RESOLVE_SYMBOL(UVSC_DBG_RESET)
RESOLVE_SYMBOL(UVSC_DBG_MEM_READ)
RESOLVE_SYMBOL(UVSC_DBG_MEM_WRITE)
RESOLVE_SYMBOL(UVSC_DBG_CREATE_BP)
RESOLVE_SYMBOL(UVSC_DBG_CHANGE_BP)
RESOLVE_SYMBOL(UVSC_DBG_ENUMERATE_BP)
RESOLVE_SYMBOL(UVSC_DBG_SERIAL_GET)
RESOLVE_SYMBOL(UVSC_DBG_SERIAL_PUT)
RESOLVE_SYMBOL(UVSC_DBG_CALC_EXPRESSION)
RESOLVE_SYMBOL(UVSC_DBG_EVAL_WATCH_EXPRESSION)
RESOLVE_SYMBOL(UVSC_DBG_REMOVE_WATCH_EXPRESSION)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_VARIABLES)
RESOLVE_SYMBOL(UVSC_DBG_VARIABLE_SET)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_VTR)
RESOLVE_SYMBOL(UVSC_DBG_VTR_GET)
RESOLVE_SYMBOL(UVSC_DBG_VTR_SET)
RESOLVE_SYMBOL(UVSC_DBG_ITM_REGISTER)
RESOLVE_SYMBOL(UVSC_DBG_ITM_UNREGISTER)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_STACK)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_TASKS)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_MENUS)
RESOLVE_SYMBOL(UVSC_DBG_MENU_EXEC)
RESOLVE_SYMBOL(UVSC_DBG_ADR_TOFILELINE)
RESOLVE_SYMBOL(UVSC_DBG_ADR_SHOWCODE)
RESOLVE_SYMBOL(UVSC_POWERSCALE_SHOWCODE)
RESOLVE_SYMBOL(UVSC_DBG_WAKE)
RESOLVE_SYMBOL(UVSC_DBG_SLEEP)
RESOLVE_SYMBOL(UVSC_DBG_EXEC_CMD)
RESOLVE_SYMBOL(UVSC_DBG_EVAL_EXPRESSION_TO_STR)
RESOLVE_SYMBOL(UVSC_DBG_FILELINE_TO_ADR)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_REGISTER_GROUPS)
RESOLVE_SYMBOL(UVSC_DBG_ENUM_REGISTERS)
RESOLVE_SYMBOL(UVSC_DBG_READ_REGISTERS)
RESOLVE_SYMBOL(UVSC_DBG_REGISTER_SET)
RESOLVE_SYMBOL(UVSC_DBG_DSM_READ)
RESOLVE_SYMBOL(UVSC_DBG_EVTR_REGISTER)
RESOLVE_SYMBOL(UVSC_DBG_EVTR_UNREGISTER)
RESOLVE_SYMBOL(UVSC_DBG_EVTR_ENUMSCVDFILES)
// Build output functions.
RESOLVE_SYMBOL(UVSC_GetBuildOutputSize)
RESOLVE_SYMBOL(UVSC_GetBuildOutput)
// Command output functions.
RESOLVE_SYMBOL(UVSC_GetCmdOutputSize)
RESOLVE_SYMBOL(UVSC_GetCmdOutput)
// Queue functions.
RESOLVE_SYMBOL(UVSC_ReadBuildQ)
RESOLVE_SYMBOL(UVSC_ReadPBarQ)
RESOLVE_SYMBOL(UVSC_ReadAsyncQ)
RESOLVE_SYMBOL(UVSC_FlushAsyncQ)
// Advanced functions.
RESOLVE_SYMBOL(UVSC_TxRxRaw)
RESOLVE_SYMBOL(UVSC_CreateMsg)
return true;
}
#ifdef __cplusplus
}
#endif
+345
View File
@@ -0,0 +1,345 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvscutils.h"
#include <QDataStream>
#include <QVariant>
namespace Debugger {
namespace Internal {
namespace UvscUtils {
// Utils
SSTR encodeSstr(const QString &value)
{
SSTR sstr = {};
// Note: UVSC API support only ASCII!
const QByteArray data = value.toLocal8Bit();
if (sizeof(sstr.data) < size_t(data.size()))
return sstr;
sstr.length = data.size();
::memcpy(sstr.data, data.constData(), sstr.length);
return sstr;
}
QString decodeSstr(const SSTR &sstr)
{
// Note: UVSC API support only ASCII!
return QString::fromLocal8Bit(reinterpret_cast<const char *>(sstr.data),
sstr.length);
}
QString decodeAscii(const qint8 *ascii)
{
// Note: UVSC API support only ASCII!
return QString::fromLocal8Bit(reinterpret_cast<const char *>(ascii));
}
QByteArray encodeProjectData(const QStringList &someNames)
{
QByteArray buffer(sizeof(PRJDATA) - 1, 0);
// Note: UVSC API support only ASCII!
quint32 namesLength = 0;
for (const QString &someName : someNames) {
const QByteArray asciiName = someName.toLocal8Bit();
buffer.append(asciiName);
buffer.append('\0');
namesLength += asciiName.size() + 1;
}
buffer.append('\0');
namesLength += 1;
const auto dataPtr = reinterpret_cast<PRJDATA *>(buffer.data());
dataPtr->code = 0;
dataPtr->length = namesLength;
return buffer;
}
QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd)
{
QByteArray buffer(sizeof(BKPARM) - 1, 0);
// Note: UVSC API support only ASCII!
const QByteArray asciiExp = exp.toLocal8Bit();
buffer.append(asciiExp);
buffer.append('\0');
const QByteArray asciiCmd = cmd.toLocal8Bit();
buffer.append(asciiCmd);
buffer.append('\0');
const auto bkPtr = reinterpret_cast<BKPARM *>(buffer.data());
bkPtr->type = type;
bkPtr->count = 1;
bkPtr->accessSize = 0;
bkPtr->expressionLength = asciiExp.count() + 1;
bkPtr->commandLength = asciiCmd.count() + 1;
return buffer;
}
QByteArray encodeAmem(quint64 address, quint32 bytesCount)
{
QByteArray buffer(sizeof(AMEM) - 1, 0);
buffer.resize(buffer.size() + bytesCount);
const auto amem = reinterpret_cast<AMEM *>(buffer.data());
amem->address = address;
amem->bytesCount = bytesCount;
return buffer;
}
TVAL encodeVoidTval()
{
TVAL tval = {};
tval.type = VTT_void;
return tval;
}
TVAL encodeIntTval(int value)
{
TVAL tval = {};
tval.type = VTT_int;
tval.v.i = value;
return tval;
}
TVAL encodeU64Tval(quint64 value)
{
TVAL tval = {};
tval.type = VTT_uint64;
tval.v.u64 = value;
return tval;
}
VSET encodeVoidVset(const QString &value)
{
VSET vset = {};
vset.value = encodeVoidTval();
vset.name = encodeSstr(value);
return vset;
}
VSET encodeIntVset(int index, const QString &value)
{
VSET vset = {};
vset.value = encodeIntTval(index);
vset.name = encodeSstr(value);
return vset;
}
VSET encodeU64Vset(quint64 index, const QString &value)
{
VSET vset = {};
vset.value = encodeU64Tval(index);
vset.name = encodeSstr(value);
return vset;
}
bool isKnownRegister(int type)
{
if (type >= MinimumGeneralPurposeRegister && type <= MaximumGeneralPurposeRegister)
return true;
else if (type >= MinimumBankedRegister && type <= MaximumBankedRegister)
return true;
else if (type >= MinimumSystemRegister && type <= MaximumSystemRegister)
return true;
else if (type == ProgramStatusRegister)
return true;
return false;
}
QString adjustHexValue(QString hex, const QString &type)
{
if (!hex.startsWith("0x"))
return hex;
hex.remove(0, 2);
const QByteArray data = QByteArray::fromHex(hex.toLatin1());
QDataStream in(data);
if (type == "float") {
float v = 0;
in >> v;
return QString::number(v);
} else if (type == "double") {
double v = 0;
in >> v;
return QString::number(v);
} else {
const bool isUnsigned = type.startsWith("unsigned");
switch (data.count()) {
case 1:
if (isUnsigned) {
quint8 v = 0;
in >> v;
return QString::number(v);
} else {
qint8 v = 0;
in >> v;
return QString::number(v);
}
case 2:
if (isUnsigned) {
quint16 v = 0;
in >> v;
return QString::number(v);
} else {
qint16 v = 0;
in >> v;
return QString::number(v);
}
case 4:
if (isUnsigned) {
quint32 v = 0;
in >> v;
return QString::number(v);
} else {
qint32 v = 0;
in >> v;
return QString::number(v);
}
case 8:
if (isUnsigned) {
quint64 v = 0;
in >> v;
return QString::number(v);
} else {
qint64 v = 0;
in >> v;
return QString::number(v);
}
default:
break;
}
}
return {};
}
QString buildLocalId(const VARINFO &varinfo)
{
return QString::number(varinfo.id);
}
QString buildLocalEditable(const VARINFO &varinfo)
{
return QVariant(bool(varinfo.isEditable)).toString();
}
QString buildLocalNumchild(const VARINFO &varinfo)
{
return QString::number(varinfo.count);
}
QString buildLocalName(const VARINFO &varinfo)
{
return decodeSstr(varinfo.name);
}
QString buildLocalIName(const QString &parentIName, const QString &name)
{
if (name.isEmpty())
return parentIName;
return parentIName + '.' + name;
}
QString buildLocalWName(const QString &exp)
{
return QString::fromLatin1(exp.toLatin1().toHex());
}
QString buildLocalType(const VARINFO &varinfo)
{
QString type = decodeSstr(varinfo.type);
// Remove the 'auto - ' and 'param - ' prefixes.
if (type.startsWith("auto - "))
type.remove(0, 7);
else if (type.startsWith("param - "))
type.remove(0, 8);
return type;
}
QString buildLocalValue(const VARINFO &varinfo, const QString &type)
{
QString value = decodeSstr(varinfo.value);
// Adjust value to the desired form.
if (value.startsWith("0x")) {
const int spaceIndex = value.indexOf(" ");
const QString hex = value.mid(0, spaceIndex);
if (type == "char") {
value = adjustHexValue(hex, type);
} else if (type.startsWith("enum") && spaceIndex != -1) {
const QString name = value.mid(spaceIndex + 1);
value = QStringLiteral("%1 (%2)").arg(name).arg(hex.toInt(nullptr, 16));
} else if (type.startsWith("struct")) {
value = QStringLiteral("@%1").arg(hex);
} else {
value = adjustHexValue(hex, type);
}
}
return value;
}
GdbMi buildEntry(const QString &name, const QString &data, GdbMi::Type type)
{
GdbMi result;
result.m_name = name;
result.m_data = data;
result.m_type = type;
return result;
}
GdbMi buildChildrenEntry(const std::vector<GdbMi> &locals)
{
GdbMi children = buildEntry("children", "", GdbMi::List);
for (const GdbMi &local : locals)
children.addChild(local);
return children;
}
GdbMi buildResultTemplateEntry(bool partial)
{
GdbMi all = UvscUtils::buildEntry("result", "", GdbMi::Tuple);
// FIXME: Do we need in 'token', 'typeinfo', 'counts' and 'timings'
// entries?
// Build token entry.
all.addChild(UvscUtils::buildEntry("token", "0", GdbMi::Const));
// Build typeinfo entry.
all.addChild(UvscUtils::buildEntry("typeinfo", "", GdbMi::List));
// Build counts entry.
all.addChild(UvscUtils::buildEntry("counts", "", GdbMi::Tuple));
// Build timings entry.
all.addChild(UvscUtils::buildEntry("timings", "", GdbMi::List));
// Build partial entry.
all.addChild(UvscUtils::buildEntry("partial", QString::number(partial),
GdbMi::Const));
return all;
}
} // namespace UvscUtils
} // namespace Internal
} // namespace Debugger
+83
View File
@@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "uvscfunctions.h"
#include <debugger/debuggerprotocol.h>
namespace Debugger {
namespace Internal {
namespace UvscUtils {
enum RegisterType {
// General purpose registers (R0-R15).
MinimumGeneralPurposeRegister = 0,
MaximumGeneralPurposeRegister = 15,
// Banked registers.
MinimumBankedRegister = 17,
MaximumBankedRegister = 18,
// System registers.
MinimumSystemRegister = 32,
MaximumSystemRegister = 35,
// Program status register.
ProgramStatusRegister = 256,
};
SSTR encodeSstr(const QString &value);
QString decodeSstr(const SSTR &sstr);
QString decodeAscii(const qint8 *ascii);
QByteArray encodeProjectData(const QStringList &someNames);
QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString());
QByteArray encodeAmem(quint64 address, quint32 bytesCount);
TVAL encodeVoidTval();
TVAL encodeIntTval(int value);
TVAL encodeU64Tval(quint64 value);
VSET encodeVoidVset(const QString &value);
VSET encodeIntVset(int index, const QString &value);
VSET encodeU64Vset(quint64 index, const QString &value);
bool isKnownRegister(int type);
QString adjustHexValue(QString hex, const QString &type);
QString buildLocalId(const VARINFO &varinfo);
QString buildLocalEditable(const VARINFO &varinfo);
QString buildLocalNumchild(const VARINFO &varinfo);
QString buildLocalName(const VARINFO &varinfo);
QString buildLocalIName(const QString &parentIName, const QString &name = QString());
QString buildLocalWName(const QString &exp);
QString buildLocalType(const VARINFO &varinfo);
QString buildLocalValue(const VARINFO &varinfo, const QString &type);
GdbMi buildEntry(const QString &name, const QString &data, GdbMi::Type type);
GdbMi buildChildrenEntry(const std::vector<GdbMi> &locals);
GdbMi buildResultTemplateEntry(bool partial);
} // namespace UvscUtils
} // namespace Internal
} // namespace Debugger
+5
View File
@@ -317,6 +317,11 @@ void WatchItem::parseHelper(const GdbMi &input, bool maySort)
editformat = input["editformat"].data();
editencoding = DebuggerEncoding(input["editencoding"].data());
// We need it for UVSC engine!
mi = input["id"];
if (mi.isValid())
id = mi.toInt();
mi = input["valueelided"];
if (mi.isValid())
elided = mi.toInt();