2014-12-20 19:10:02 +00:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com>
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "gdbserverprovider.h"
|
|
|
|
|
#include "gdbserverprovidermanager.h"
|
2017-03-17 00:27:57 +02:00
|
|
|
#include "baremetaldevice.h"
|
2014-12-20 19:10:02 +00:00
|
|
|
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/environment.h>
|
|
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QUuid>
|
|
|
|
|
|
|
|
|
|
#include <QFormLayout>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QSpinBox>
|
|
|
|
|
#include <QPlainTextEdit>
|
|
|
|
|
|
|
|
|
|
namespace BareMetal {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
const char idKeyC[] = "BareMetal.GdbServerProvider.Id";
|
|
|
|
|
const char displayNameKeyC[] = "BareMetal.GdbServerProvider.DisplayName";
|
|
|
|
|
const char startupModeKeyC[] = "BareMetal.GdbServerProvider.Mode";
|
|
|
|
|
const char initCommandsKeyC[] = "BareMetal.GdbServerProvider.InitCommands";
|
|
|
|
|
const char resetCommandsKeyC[] = "BareMetal.GdbServerProvider.ResetCommands";
|
|
|
|
|
|
|
|
|
|
static QString createId(const QString &id)
|
|
|
|
|
{
|
|
|
|
|
QString newId = id.left(id.indexOf(QLatin1Char(':')));
|
|
|
|
|
newId.append(QLatin1Char(':') + QUuid::createUuid().toString());
|
|
|
|
|
return newId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::GdbServerProvider(const QString &id)
|
|
|
|
|
: m_id(createId(id))
|
|
|
|
|
, m_startupMode(NoStartup)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::GdbServerProvider(const GdbServerProvider &other)
|
2015-11-17 16:05:06 +02:00
|
|
|
: m_id(createId(other.m_id))
|
2014-12-20 19:10:02 +00:00
|
|
|
, m_startupMode(other.m_startupMode)
|
|
|
|
|
, m_initCommands(other.m_initCommands)
|
|
|
|
|
, m_resetCommands(other.m_resetCommands)
|
|
|
|
|
{
|
|
|
|
|
m_displayName = QCoreApplication::translate(
|
|
|
|
|
"BareMetal::GdbServerProvider", "Clone of %1")
|
|
|
|
|
.arg(other.displayName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::~GdbServerProvider()
|
|
|
|
|
{
|
2017-03-17 00:27:57 +02:00
|
|
|
const QSet<BareMetalDevice *> devices = m_devices;
|
|
|
|
|
for (BareMetalDevice *device : devices)
|
2017-03-23 09:06:41 +02:00
|
|
|
device->unregisterProvider(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProvider::displayName() const
|
|
|
|
|
{
|
|
|
|
|
if (m_displayName.isEmpty())
|
|
|
|
|
return typeDisplayName();
|
|
|
|
|
return m_displayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setDisplayName(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
if (m_displayName == name)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_displayName = name;
|
|
|
|
|
providerUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProvider::id() const
|
|
|
|
|
{
|
|
|
|
|
return m_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::StartupMode GdbServerProvider::startupMode() const
|
|
|
|
|
{
|
|
|
|
|
return m_startupMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setStartupMode(StartupMode m)
|
|
|
|
|
{
|
|
|
|
|
m_startupMode = m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProvider::initCommands() const
|
|
|
|
|
{
|
|
|
|
|
return m_initCommands;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setInitCommands(const QString &cmds)
|
|
|
|
|
{
|
|
|
|
|
m_initCommands = cmds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProvider::resetCommands() const
|
|
|
|
|
{
|
|
|
|
|
return m_resetCommands;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setResetCommands(const QString &cmds)
|
|
|
|
|
{
|
|
|
|
|
m_resetCommands = cmds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProvider::executable() const
|
|
|
|
|
{
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList GdbServerProvider::arguments() const
|
|
|
|
|
{
|
|
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::operator==(const GdbServerProvider &other) const
|
|
|
|
|
{
|
|
|
|
|
if (this == &other)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
const QString thisId = id().left(id().indexOf(QLatin1Char(':')));
|
|
|
|
|
const QString otherId = other.id().left(other.id().indexOf(QLatin1Char(':')));
|
|
|
|
|
|
|
|
|
|
// We ignore displayname
|
|
|
|
|
return thisId == otherId
|
|
|
|
|
&& m_startupMode == other.m_startupMode
|
|
|
|
|
&& m_initCommands == other.m_initCommands
|
2015-03-18 23:41:49 +01:00
|
|
|
&& m_resetCommands == other.m_resetCommands;
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap GdbServerProvider::toMap() const
|
|
|
|
|
{
|
2015-03-18 23:41:49 +01:00
|
|
|
return {
|
2017-02-22 15:09:35 +01:00
|
|
|
{QLatin1String(idKeyC), m_id},
|
|
|
|
|
{QLatin1String(displayNameKeyC), m_displayName},
|
|
|
|
|
{QLatin1String(startupModeKeyC), m_startupMode},
|
|
|
|
|
{QLatin1String(initCommandsKeyC), m_initCommands},
|
|
|
|
|
{QLatin1String(resetCommandsKeyC), m_resetCommands}
|
2015-03-18 23:41:49 +01:00
|
|
|
};
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::isValid() const
|
|
|
|
|
{
|
|
|
|
|
return !channel().isNull();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::canStartupMode(StartupMode m) const
|
|
|
|
|
{
|
|
|
|
|
return m == NoStartup;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 00:27:57 +02:00
|
|
|
void GdbServerProvider::registerDevice(BareMetalDevice *device)
|
|
|
|
|
{
|
|
|
|
|
m_devices.insert(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::unregisterDevice(BareMetalDevice *device)
|
|
|
|
|
{
|
|
|
|
|
m_devices.remove(device);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
void GdbServerProvider::providerUpdated()
|
|
|
|
|
{
|
2017-03-17 10:36:50 +02:00
|
|
|
GdbServerProviderManager::notifyAboutUpdate(this);
|
2018-04-08 23:40:00 +03:00
|
|
|
for (BareMetalDevice *device : qAsConst(m_devices))
|
2017-03-17 00:27:57 +02:00
|
|
|
device->providerUpdated(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::fromMap(const QVariantMap &data)
|
|
|
|
|
{
|
|
|
|
|
m_id = data.value(QLatin1String(idKeyC)).toString();
|
|
|
|
|
m_displayName = data.value(QLatin1String(displayNameKeyC)).toString();
|
|
|
|
|
m_startupMode = static_cast<StartupMode>(data.value(QLatin1String(startupModeKeyC)).toInt());
|
|
|
|
|
m_initCommands = data.value(QLatin1String(initCommandsKeyC)).toString();
|
|
|
|
|
m_resetCommands = data.value(QLatin1String(resetCommandsKeyC)).toString();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderFactory::id() const
|
|
|
|
|
{
|
|
|
|
|
return m_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderFactory::setId(const QString &id)
|
|
|
|
|
{
|
|
|
|
|
m_id = id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderFactory::displayName() const
|
|
|
|
|
{
|
|
|
|
|
return m_displayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderFactory::setDisplayName(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
m_displayName = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderFactory::idFromMap(const QVariantMap &data)
|
|
|
|
|
{
|
|
|
|
|
return data.value(QLatin1String(idKeyC)).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderFactory::idToMap(QVariantMap &data, const QString id)
|
|
|
|
|
{
|
|
|
|
|
data.insert(QLatin1String(idKeyC), id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProviderConfigWidget::GdbServerProviderConfigWidget(
|
|
|
|
|
GdbServerProvider *provider)
|
|
|
|
|
: m_provider(provider)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(provider);
|
|
|
|
|
|
|
|
|
|
m_mainLayout = new QFormLayout(this);
|
|
|
|
|
m_mainLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
|
|
|
|
|
|
|
|
|
m_nameLineEdit = new QLineEdit(this);
|
|
|
|
|
m_nameLineEdit->setToolTip(tr("Enter the name of the GDB server provider."));
|
|
|
|
|
m_mainLayout->addRow(tr("Name:"), m_nameLineEdit);
|
|
|
|
|
|
|
|
|
|
m_startupModeComboBox = new QComboBox(this);
|
|
|
|
|
m_startupModeComboBox->setToolTip(tr("Choose the desired startup mode "
|
|
|
|
|
"of the GDB server provider."));
|
|
|
|
|
m_mainLayout->addRow(tr("Startup mode:"), m_startupModeComboBox);
|
|
|
|
|
|
|
|
|
|
populateStartupModes();
|
|
|
|
|
setFromProvider();
|
|
|
|
|
|
2015-11-29 18:58:42 +03:00
|
|
|
connect(m_nameLineEdit, &QLineEdit::textChanged,
|
|
|
|
|
this, &GdbServerProviderConfigWidget::dirty);
|
|
|
|
|
connect(m_startupModeComboBox,
|
|
|
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
|
this, &GdbServerProviderConfigWidget::dirty);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::apply()
|
|
|
|
|
{
|
|
|
|
|
m_provider->setDisplayName(m_nameLineEdit->text());
|
|
|
|
|
m_provider->setStartupMode(startupMode());
|
|
|
|
|
|
|
|
|
|
applyImpl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::discard()
|
|
|
|
|
{
|
|
|
|
|
m_nameLineEdit->setText(m_provider->displayName());
|
|
|
|
|
discardImpl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider *GdbServerProviderConfigWidget::provider() const
|
|
|
|
|
{
|
|
|
|
|
return m_provider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::addErrorLabel()
|
|
|
|
|
{
|
|
|
|
|
if (!m_errorLabel) {
|
|
|
|
|
m_errorLabel = new QLabel;
|
|
|
|
|
m_errorLabel->setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
m_mainLayout->addRow(m_errorLabel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::StartupMode GdbServerProviderConfigWidget::startupModeFromIndex(
|
|
|
|
|
int idx) const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<GdbServerProvider::StartupMode>(
|
|
|
|
|
m_startupModeComboBox->itemData(idx).toInt());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::StartupMode GdbServerProviderConfigWidget::startupMode() const
|
|
|
|
|
{
|
|
|
|
|
const int idx = m_startupModeComboBox->currentIndex();
|
|
|
|
|
return startupModeFromIndex(idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::setStartupMode(GdbServerProvider::StartupMode m)
|
|
|
|
|
{
|
|
|
|
|
for (int idx = 0; idx < m_startupModeComboBox->count(); ++idx) {
|
|
|
|
|
if (m == startupModeFromIndex(idx)) {
|
|
|
|
|
m_startupModeComboBox->setCurrentIndex(idx);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::populateStartupModes()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < GdbServerProvider::StartupModesCount; ++i) {
|
|
|
|
|
const auto m = static_cast<GdbServerProvider::StartupMode>(i);
|
|
|
|
|
if (!m_provider->canStartupMode(m))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
const int idx = m_startupModeComboBox->count();
|
|
|
|
|
m_startupModeComboBox->insertItem(
|
|
|
|
|
idx,
|
|
|
|
|
(m == GdbServerProvider::NoStartup)
|
2015-03-16 14:53:19 +01:00
|
|
|
? tr("No Startup")
|
2014-12-20 19:10:02 +00:00
|
|
|
: ((m == GdbServerProvider::StartupOnNetwork)
|
2015-03-16 14:53:19 +01:00
|
|
|
? tr("Startup in TCP/IP Mode")
|
|
|
|
|
: tr("Startup in Pipe Mode")),
|
2014-12-20 19:10:02 +00:00
|
|
|
m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::setErrorMessage(const QString &m)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_errorLabel, return);
|
|
|
|
|
if (m.isEmpty()) {
|
|
|
|
|
clearErrorMessage();
|
|
|
|
|
} else {
|
|
|
|
|
m_errorLabel->setText(m);
|
|
|
|
|
m_errorLabel->setStyleSheet(QLatin1String("background-color: \"red\""));
|
|
|
|
|
m_errorLabel->setVisible(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::clearErrorMessage()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_errorLabel, return);
|
|
|
|
|
m_errorLabel->clear();
|
|
|
|
|
m_errorLabel->setStyleSheet(QString());
|
|
|
|
|
m_errorLabel->setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::setFromProvider()
|
|
|
|
|
{
|
2017-09-30 07:12:57 +02:00
|
|
|
QSignalBlocker blocker(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
m_nameLineEdit->setText(m_provider->displayName());
|
|
|
|
|
setStartupMode(m_provider->startupMode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderConfigWidget::defaultInitCommandsTooltip()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("BareMetal",
|
2015-03-23 14:17:57 +01:00
|
|
|
"Enter GDB commands to reset the board "
|
2014-12-20 19:10:02 +00:00
|
|
|
"and to write the nonvolatile memory.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderConfigWidget::defaultResetCommandsTooltip()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("BareMetal",
|
2015-03-16 12:38:31 +01:00
|
|
|
"Enter GDB commands to reset the hardware. "
|
2015-03-23 14:17:57 +01:00
|
|
|
"The MCU should be halted after these commands.");
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HostWidget::HostWidget(QWidget *parent)
|
|
|
|
|
: QWidget(parent)
|
|
|
|
|
{
|
|
|
|
|
m_hostLineEdit = new QLineEdit(this);
|
|
|
|
|
m_hostLineEdit->setToolTip(tr("Enter TCP/IP hostname of the GDB server provider, "
|
|
|
|
|
"like \"localhost\" or \"192.0.2.1\"."));
|
|
|
|
|
m_portSpinBox = new QSpinBox(this);
|
2015-02-09 23:04:12 +02:00
|
|
|
m_portSpinBox->setRange(0, 65535);
|
2014-12-20 19:10:02 +00:00
|
|
|
m_portSpinBox->setToolTip(tr("Enter TCP/IP port which will be listened by "
|
|
|
|
|
"the GDB server provider."));
|
|
|
|
|
auto layout = new QHBoxLayout(this);
|
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
layout->addWidget(m_hostLineEdit);
|
|
|
|
|
layout->addWidget(m_portSpinBox);
|
|
|
|
|
|
2015-11-29 18:58:42 +03:00
|
|
|
connect(m_hostLineEdit, &QLineEdit::textChanged,
|
|
|
|
|
this, &HostWidget::dataChanged);
|
|
|
|
|
connect(m_portSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
|
|
|
|
this, &HostWidget::dataChanged);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HostWidget::setHost(const QString &host)
|
|
|
|
|
{
|
2017-09-30 07:12:57 +02:00
|
|
|
QSignalBlocker blocker(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
m_hostLineEdit->setText(host);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString HostWidget::host() const
|
|
|
|
|
{
|
|
|
|
|
return m_hostLineEdit->text();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HostWidget::setPort(const quint16 &port)
|
|
|
|
|
{
|
2017-09-30 07:12:57 +02:00
|
|
|
QSignalBlocker blocker(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
m_portSpinBox->setValue(port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint16 HostWidget::port() const
|
|
|
|
|
{
|
|
|
|
|
return m_portSpinBox->value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace BareMetal
|