summaryrefslogtreecommitdiffstats
path: root/src/progs/manager
diff options
context:
space:
mode:
Diffstat (limited to 'src/progs/manager')
-rw-r--r--src/progs/manager/Makefile.am5
-rw-r--r--src/progs/manager/breakpoint.cpp74
-rw-r--r--src/progs/manager/breakpoint.h70
-rw-r--r--src/progs/manager/debug_manager.cpp392
-rw-r--r--src/progs/manager/debug_manager.h99
-rw-r--r--src/progs/manager/manager.pro6
-rw-r--r--src/progs/manager/prog_manager.cpp217
-rw-r--r--src/progs/manager/prog_manager.h74
8 files changed, 937 insertions, 0 deletions
diff --git a/src/progs/manager/Makefile.am b/src/progs/manager/Makefile.am
new file mode 100644
index 0000000..565dae5
--- /dev/null
+++ b/src/progs/manager/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+libprogmanager_la_LDFLAGS = $(all_libraries)
+noinst_LTLIBRARIES = libprogmanager.la
+libprogmanager_la_SOURCES = breakpoint.cpp debug_manager.cpp prog_manager.cpp
diff --git a/src/progs/manager/breakpoint.cpp b/src/progs/manager/breakpoint.cpp
new file mode 100644
index 0000000..15e08e0
--- /dev/null
+++ b/src/progs/manager/breakpoint.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "breakpoint.h"
+
+#include "coff/base/coff.h"
+
+//----------------------------------------------------------------------------
+namespace Breakpoint
+{
+ List *_list = 0;
+}
+Breakpoint::List &Breakpoint::list()
+{
+ if ( _list==0 ) _list = new List;
+ return *_list;
+}
+
+void Breakpoint::List::append(const Data &data)
+{
+ Q_ASSERT( !contains(data) );
+ StateData sdata;
+ sdata.data = data;
+ _list.append(sdata);
+ delayedChanged();
+}
+
+void Breakpoint::List::remove(const Data &data)
+{
+ Q_ASSERT( contains(data) );
+ _list.remove(find(data));
+ delayedChanged();
+}
+
+void Breakpoint::List::clear()
+{
+ _list.clear();
+ delayedChanged();
+}
+
+QValueList<Breakpoint::List::StateData>::iterator Breakpoint::List::find(const Data &data)
+{
+ QValueList<StateData>::iterator it;
+ for (it=_list.begin(); it!=_list.end(); ++it)
+ if ( (*it).data==data ) return it;
+ return _list.end();
+}
+
+QValueList<Breakpoint::List::StateData>::const_iterator Breakpoint::List::find(const Data &data) const
+{
+ QValueList<StateData>::const_iterator it;
+ for (it=_list.begin(); it!=_list.end(); ++it)
+ if ( (*it).data==data ) return it;
+ return _list.end();
+}
+
+void Breakpoint::List::setState(const Data &data, State state)
+{
+ Q_ASSERT( contains(data) );
+ (*find(data)).state = state;
+ delayedChanged();
+}
+
+void Breakpoint::List::setAddress(const Data &data, Address address)
+{
+ Q_ASSERT( contains(data) );
+ (*find(data)).address = address;
+ delayedChanged();
+}
diff --git a/src/progs/manager/breakpoint.h b/src/progs/manager/breakpoint.h
new file mode 100644
index 0000000..fca0570
--- /dev/null
+++ b/src/progs/manager/breakpoint.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef BREAKPOINT_H
+#define BREAKPOINT_H
+
+#include "common/common/storage.h"
+#include "common/global/purl.h"
+#include "devices/base/generic_device.h"
+
+namespace Breakpoint
+{
+class List;
+enum State { Unknown, Active, Disabled };
+enum MarkType { ProgramCounterActive = 0, ProgramCounterDisabled,
+ BreakpointActive, BreakpointDisabled, BreakpointReached,
+ BreakpointInvalid, Nb_MarkTypes };
+
+//----------------------------------------------------------------------------
+class Data {
+public:
+ Data(const PURL::Url &purl = PURL::Url(), uint pline = 0) : url(purl), line(pline) {}
+ bool operator <(const Data &data) const { return ( url<data.url || line<data.line ); }
+ bool operator ==(const Data &data) const { return ( url==data.url && line==data.line ); }
+ PURL::Url url;
+ uint line;
+};
+extern void updateActions(const Data *data);
+
+//----------------------------------------------------------------------------
+class List;
+extern List &list();
+
+class List : public GenericStorage
+{
+Q_OBJECT
+public:
+ List() {}
+ void append(const Data &data);
+ void remove(const Data &data);
+ void clear();
+ uint count() const { return _list.count(); }
+ const Data &data(uint i) const { return _list[i].data; }
+ bool contains(const Data &data) const { return find(data)!=_list.end(); }
+ State state(const Data &data) const { return (*find(data)).state; }
+ Address address(const Data &data) const { return (*find(data)).address; }
+ void setState(const Data &data, State state);
+ void setAddress(const Data &data, Address address);
+
+private:
+ class StateData {
+ public:
+ StateData() : state(Unknown) {}
+ Data data;
+ Address address;
+ State state;
+ };
+ QValueList<StateData> _list;
+ QValueList<StateData>::const_iterator find(const Data &data) const;
+ QValueList<StateData>::iterator find(const Data &data);
+};
+
+} // namespace
+
+#endif
diff --git a/src/progs/manager/debug_manager.cpp b/src/progs/manager/debug_manager.cpp
new file mode 100644
index 0000000..7889432
--- /dev/null
+++ b/src/progs/manager/debug_manager.cpp
@@ -0,0 +1,392 @@
+/***************************************************************************
+ * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "debug_manager.h"
+
+#include <qtimer.h>
+#include <qeventloop.h>
+
+#include "coff/base/text_coff.h"
+#include "coff/base/cdb_parser.h"
+#include "progs/base/generic_prog.h"
+#include "progs/base/generic_debug.h"
+#include "progs/base/prog_group.h"
+#include "devices/base/register.h"
+#include "progs/base/debug_config.h"
+#include "prog_manager.h"
+
+Debugger::Manager *Debugger::manager = 0;
+
+Debugger::Manager::Manager()
+ : QObject(Programmer::manager, "debug_manager"), Log::Base(Programmer::manager), GenericView(Breakpoint::list()),
+ _coff(0), _data(0)
+{
+ connect(&_runTimer, SIGNAL(timeout()), SLOT(slotRunTimeout()));
+ connect(&_stepTimer, SIGNAL(timeout()), SLOT(doStep()));
+}
+
+Debugger::Manager::~Manager()
+{
+ delete _coff;
+}
+
+bool Debugger::Manager::isStepping() const
+{
+ return (programmer() ? programmer()->state()==Programmer::Halted : false) && _stepTimer.isActive();
+}
+
+Debugger::Base *Debugger::Manager::debugger() const
+{
+ return (programmer() ? programmer()->debugger() : 0);
+}
+
+void Debugger::Manager::updateDevice()
+{
+ const Device::Data *data = deviceData();
+ if ( data==_data ) return;
+ _data = data;
+ Register::list().clearWatched();
+ clear();
+}
+
+bool Debugger::Manager::checkState(bool &first)
+{
+ if ( programmer()->state()==Programmer::NotConnected ) {
+ if ( !prepareDebugging() ) return false;
+ if ( !programmer()->connectHardware() ) return false;
+ }
+ first = ( debugger()->hasError() || programmer()->state()==Programmer::Stopped );
+ if (first) {
+ log(Log::LineType::Normal, "--------------------------------------------------");
+ programmer()->debugger()->setCoff(_coff);
+ if ( !programmer()->debugger()->init() ) return false;
+ }
+ return true;
+}
+
+bool Debugger::Manager::init()
+{
+ if ( !internalInit() ) return false;
+ return update(true);
+}
+
+bool Debugger::Manager::internalInit()
+{
+ clear();
+ if ( !coffUrl().exists() ) return false;
+ Log::Base log;
+ log.setView(compileView());
+ log.log(Log::LineType::Information, i18n("Parsing COFF file: %1").arg(coffUrl().pretty()));
+ _coff = new Coff::TextObject(_data, coffUrl());
+ if ( !_coff->parse(log) ) {
+ delete _coff;
+ _coff = 0;
+ return false;
+ }
+ computeBreakpointAddresses();
+ return true;
+}
+
+void Debugger::Manager::clearBreakpoints()
+{
+ Breakpoint::list().clear();
+}
+
+void Debugger::Manager::freeActiveBreakpoint()
+{
+ uint nb = 0;
+ Breakpoint::Data last;
+ for (uint i=0; i<Breakpoint::list().count(); i++) {
+ const Breakpoint::Data &data = Breakpoint::list().data(i);
+ if ( Breakpoint::list().state(data)!=Breakpoint::Active ) continue;
+ nb++;
+ last = data;
+ }
+ uint max = programmerGroup()->maxNbBreakpoints(deviceData());
+ Q_ASSERT( nb<=max && max!=0 );
+ if ( nb==max ) {
+ log(Log::LineType::Warning, i18n("The number of active breakpoints is higher than the maximum for the current debugger (%1): disabling the last breakpoint.").arg(max));
+ Breakpoint::list().setState(last, Breakpoint::Disabled);
+ }
+}
+
+BitValue Debugger::Manager::pc() const
+{
+ return (debugger() ? debugger()->pc() : BitValue());
+}
+
+Breakpoint::MarkType Debugger::Manager::breakpointType(const Breakpoint::Data &data) const
+{
+ if ( _coff==0 ) return Breakpoint::BreakpointDisabled;
+ Address address = Breakpoint::list().address(data);
+ if ( !address.isValid() ) return Breakpoint::BreakpointInvalid;
+ if ( Breakpoint::list().state(data)!=Breakpoint::Active ) return Breakpoint::BreakpointDisabled;
+ if ( address==pc() ) {
+ if ( programmer()->state()==::Programmer::Halted ) return Breakpoint::BreakpointReached;
+ return Breakpoint::ProgramCounterDisabled;
+ }
+ return Breakpoint::BreakpointActive;
+}
+
+bool Debugger::Manager::checkBreakpoint(const Breakpoint::Data &bdata, bool onlyWarn, Address &address)
+{
+ address = Address();
+ if ( _coff==0 ) return true;
+ QValueVector<Address> addresses = _coff->addresses(bdata.url, bdata.line);
+ if ( addresses.isEmpty() ) {
+ QString s = i18n("Breakpoint at non-code line.");
+ if (onlyWarn) log(Log::LineType::Warning, s);
+ else sorry(s);
+ return false;
+ }
+ if ( addresses.count()>1 ) log(Log::LineType::Warning, i18n("Breakpoint corresponds to several addresses. Using the first one."));
+ address = addresses[0];
+ return true;
+}
+
+void Debugger::Manager::computeBreakpointAddresses()
+{
+ if ( programmerGroup()==0 ) return;
+ int nb = programmerGroup()->maxNbBreakpoints(deviceData());
+ for (int i=Breakpoint::list().count()-1; i>=0; i--) {
+ const Breakpoint::Data &data = Breakpoint::list().data(i);
+ Address address;
+ checkBreakpoint(data, true, address);
+ Breakpoint::list().setAddress(data, address);
+ if ( _coff==0 ) Breakpoint::list().setState(data, Breakpoint::Unknown);
+ else if ( Breakpoint::list().address(data).isValid() && nb>0 ) {
+ Breakpoint::list().setState(data, Breakpoint::Active);
+ nb--;
+ }
+ }
+}
+
+QValueList<Address> Debugger::Manager::activeBreakpointAddresses() const
+{
+ QValueList<Address> addresses;
+ for (uint i=0; i<Breakpoint::list().count(); i++) {
+ const Breakpoint::Data &data = Breakpoint::list().data(i);
+ if ( Breakpoint::list().state(data)==Breakpoint::Active ) addresses.append(Breakpoint::list().address(data));
+ }
+ return addresses;
+}
+
+void Debugger::Manager::clear()
+{
+ _runTimer.stop();
+ _stepTimer.stop();
+ if ( programmer() ) programmer()->clear();
+ delete _coff;
+ _coff = 0;
+ _currentSourceLines.clear();
+ computeBreakpointAddresses();
+ update(true);
+}
+
+bool Debugger::Manager::update(bool gotoPC)
+{
+ _readRegisters.clear();
+ if ( !updateRegisters() ) return false;
+ if ( debugger() ) emit statusChanged(debugger()->statusString());
+ else emit statusChanged(QString::null);
+ _currentSourceLines.clear();
+ if (_coff) _currentSourceLines = _coff->sourceLinesForAddress(pc().toUInt());
+ updateView(gotoPC);
+ return true;
+}
+
+bool Debugger::Manager::updateRegister(const Register::TypeData &data)
+{
+ // read related registers
+ const Device::RegistersData *rdata = deviceData()->registersData();
+ Q_ASSERT(rdata);
+ QValueList<Register::TypeData> related = rdata->relatedRegisters(data);
+ for (uint k=0; k<uint(related.count()); k++)
+ if ( !readRegister(related[k]) ) return false;
+ // read port status
+ if ( data.type()==Register::Regular ) {
+ int index = rdata->portIndex(data.address());
+ if ( index!=-1 ) {
+ QMap<uint, Device::PortBitData> data;
+ if ( !debugger()->updatePortStatus(index, data) ) return false;
+ Register::list().setPortData(index, data);
+ }
+ }
+ return true;
+}
+
+bool Debugger::Manager::updateRegisters()
+{
+ if ( programmer()==0 || programmer()->state()!=Programmer::Halted ) return true;
+ QValueList<Register::TypeData> watched = Register::list().watched();
+ for (uint i=0; i<uint(watched.count()); i++)
+ if ( !updateRegister(watched[i]) ) return false;
+ return true;
+}
+
+bool Debugger::Manager::run()
+{
+ _stepTimer.stop();
+ _runTimer.stop();
+ bool first;
+ if ( !checkState(first) ) return false;
+ if ( !debugger()->setBreakpoints(activeBreakpointAddresses()) ) return false;
+ if ( !debugger()->run() ) return false;
+ log(Log::LineType::Information, i18n("Running..."));
+ if ( !update(true) ) return false;
+ _runTimer.start(programmer()->runUpdateWait());
+ return true;
+}
+
+bool Debugger::Manager::halt()
+{
+ _stepTimer.stop();
+ _runTimer.stop();
+ if ( !debugger()->halt() ) return false;
+ return update(true);
+}
+
+bool Debugger::Manager::reset()
+{
+ _stepTimer.stop();
+ _runTimer.stop();
+ log(Log::LineType::Normal, "--------------------------------------------------");
+ if ( !debugger()->reset() ) return false;
+ return doStep(true, false);
+}
+
+bool Debugger::Manager::checkIfContinueStepping(bool &continueStepping)
+{
+ continueStepping = false;
+ if ( !readConfigEntry(Config::OnlyStopOnSourceLine).toBool() ) return true;
+ if ( !update(false) ) return false;
+ QMap<PURL::Url, uint>::const_iterator it;
+ for (it=_currentSourceLines.begin(); it!=_currentSourceLines.end(); ++it) {
+ PURL::FileGroup group = it.key().fileType().data().group;
+ if ( group!=PURL::Source && group!=PURL::Header ) continue;
+ if ( !it.key().exists() ) continue;
+ if ( readConfigEntry(Config::OnlyStopOnProjectSourceLine).toBool() && !isProjectSource(it.key()) ) continue;
+ QValueVector<Address> addresses = _coff->addresses(it.key(), it.data());
+ qHeapSort(addresses);
+ Q_ASSERT( addresses.count()!=0 );
+ if ( pc()!=addresses[0] ) continue; // we only break if pc is on the first instruction of the source line
+ break;
+ }
+ continueStepping = ( it==_currentSourceLines.end() );
+ return true;
+}
+
+bool Debugger::Manager::doStep(bool first, bool continued)
+{
+ if ( programmer()->state()!=Programmer::Halted ) return true; // has been stopped
+ if ( continued && !_stepTimer.isActive() ) return true; // has been stopped
+ _stepTimer.stop();
+ if ( !first && !debugger()->step() ) return false;
+ bool continueStepping;
+ if ( !checkIfContinueStepping(continueStepping) ) return false;
+ if (continueStepping) _stepTimer.start(0);
+ else updateView(true);
+ return true;
+}
+
+bool Debugger::Manager::step()
+{
+ bool first;
+ if ( !checkState(first) ) return false;
+ if ( !debugger()->setBreakpoints(activeBreakpointAddresses()) ) return false;
+ log(Log::LineType::Information, i18n("Step"));
+ programmer()->setState(Programmer::Halted);
+ return doStep(first, false);
+}
+
+void Debugger::Manager::slotRunTimeout()
+{
+ if ( programmer()->state()!=Programmer::Running ) return; // has been stopped
+ if ( !_runTimer.isActive() ) return; // has been stopped
+ _runTimer.stop();
+ if ( !debugger()->update() ) return;
+ if ( programmer()->state()==Programmer::Running ) {
+ _runTimer.start(programmer()->runUpdateWait());
+ return;
+ }
+ log(Log::LineType::Information, i18n("Reached breakpoint."));
+ update(true);
+ emit targetStateChanged();
+}
+
+void Debugger::Manager::setRegisterWatched(const Register::TypeData &data, bool watched)
+{
+ if (watched) {
+ if ( Register::list().isWatched(data) ) return;
+ Register::list().setWatched(data, true);
+ if ( programmer() && programmer()->state()==Programmer::Halted ) updateRegister(data);
+ } else Register::list().setWatched(data, false);
+}
+
+bool Debugger::Manager::readRegister(const Register::TypeData &data)
+{
+ Q_ASSERT( data.type()==Register::Regular || data.type()==Register::Special );
+ if ( _readRegisters.contains(data) ) return true;
+ BitValue value;
+ if ( !debugger()->readRegister(data, value) ) return false;
+ Register::list().setValue(data, value);
+ _readRegisters.append(data);
+ return true;
+}
+
+bool Debugger::Manager::writeRegister(const Register::TypeData &data, BitValue value)
+{
+ Q_ASSERT( data.type()==Register::Regular || data.type()==Register::Special );
+ if ( !debugger()->writeRegister(data, value) ) return false;
+ _readRegisters.clear();
+ if ( !updateRegister(data) ) return false;
+ emit statusChanged(debugger()->statusString());
+ return true;
+}
+
+bool Debugger::Manager::readAllRegisters()
+{
+ const Device::RegistersData *rdata = _data->registersData();
+ for (uint i=0; i<rdata->nbRegisters(); i++) {
+ Register::TypeData rtd(rdata->addressFromIndex(i), rdata->nbChars());
+ if ( !updateRegister(rtd) ) return false;
+ }
+ return true;
+}
+
+void Debugger::Manager::stopWatchAll()
+{
+ Register::list().clearWatched();
+}
+
+bool Debugger::Manager::prepareDebugging()
+{
+ if ( programmerGroup()->isSoftware() && programmerGroup()->isDebugger() ) {
+ PURL::Url curl = coffUrl();
+ if ( curl.isEmpty() ) {
+ log(Log::LineType::Error, i18n("Cannot start debugging session without input file (not specified)."));
+ return false;
+ }
+ PURL::Url first;
+ uint i = 0;
+ for (; i<Programmer::Nb_InputFileTypes; i++) {
+ PURL::FileType type = Programmer::INPUT_FILE_TYPE_DATA[i];
+ if ( !programmerGroup()->isInputFileTypeSupported(type) ) continue;
+ PURL::Url url = curl.toFileType(type);
+ if ( first.isEmpty() ) first = url;
+ if ( !url.exists() ) continue;
+ debugger()->setupInput(type, url.directory().path(), url.filename());
+ break;
+ }
+ if ( i==Programmer::Nb_InputFileTypes ) {
+ log(Log::LineType::Error, i18n("Cannot start debugging session without input file (%1).").arg(first.pretty()));
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/src/progs/manager/debug_manager.h b/src/progs/manager/debug_manager.h
new file mode 100644
index 0000000..90b8584
--- /dev/null
+++ b/src/progs/manager/debug_manager.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef DEBUG_MANAGER_H
+#define DEBUG_MANAGER_H
+
+#include <qtimer.h>
+
+#include "common/global/log.h"
+#include "common/global/purl.h"
+#include "common/common/storage.h"
+#include "devices/base/generic_device.h"
+#include "devices/base/register.h"
+#include "breakpoint.h"
+#include "prog_manager.h"
+#include "progs/base/generic_debug.h"
+namespace Coff { class TextObject; }
+namespace CDB { class Object; }
+
+namespace Debugger
+{
+class Manager : public QObject, public Log::Base, public GenericView
+{
+Q_OBJECT
+public:
+ Manager();
+ virtual ~Manager();
+ virtual PURL::Url coffUrl() const = 0;
+ virtual const Programmer::Group *programmerGroup() const = 0;
+ Programmer::Base *programmer() const { return Programmer::manager->programmer(); }
+ virtual const Device::Data *deviceData() const = 0;
+ Debugger::Base *debugger() const;
+ virtual void updateDevice();
+ bool prepareDebugging();
+ bool init();
+ const Coff::TextObject *coff() const { return _coff; }
+ virtual void clear();
+ Breakpoint::MarkType breakpointType(const Breakpoint::Data &data) const;
+ bool run();
+ bool halt();
+ bool reset();
+ bool step();
+ bool readRegister(const Register::TypeData &data);
+ bool writeRegister(const Register::TypeData &data, BitValue value);
+ BitValue pc() const;
+ bool isStepping() const;
+
+public slots:
+ void clearBreakpoints();
+ virtual bool update(bool gotoPC);
+ void setRegisterWatched(const Register::TypeData &data, bool watched);
+ bool readAllRegisters();
+ void stopWatchAll();
+
+signals:
+ void statusChanged(const QString &text);
+ void targetStateChanged();
+ void actionMessage(const QString &text);
+
+protected:
+ Coff::TextObject *_coff;
+ QMap<PURL::Url, uint> _currentSourceLines;
+
+ void freeActiveBreakpoint();
+ bool checkBreakpoint(const Breakpoint::Data &bdata, bool onlyWarn, Address &address);
+ bool updateRegisters();
+ virtual bool internalInit();
+ virtual bool checkState(bool &first);
+ virtual Log::View *compileView() = 0;
+ virtual bool isProjectSource(const PURL::Url &url) const = 0;
+ virtual bool checkIfContinueStepping(bool &continueStepping);
+
+private slots:
+ void slotRunTimeout();
+ bool doStep(bool first = false, bool continued = true);
+
+private:
+ const Device::Data *_data;
+ QTimer _runTimer, _stepTimer;
+ QValueList<Register::TypeData> _readRegisters;
+
+ void computeBreakpointAddresses();
+ QValueList<Address> activeBreakpointAddresses() const;
+ void updateBreakpointsDisplay();
+ virtual void updateView() { updateView(false); }
+ virtual void updateView(bool gotoPC) = 0;
+ bool updateRegister(const Register::TypeData &data);
+};
+
+extern Manager *manager;
+
+} // namespace
+
+#endif
diff --git a/src/progs/manager/manager.pro b/src/progs/manager/manager.pro
new file mode 100644
index 0000000..44b80d0
--- /dev/null
+++ b/src/progs/manager/manager.pro
@@ -0,0 +1,6 @@
+STOPDIR = ../../..
+include($${STOPDIR}/lib.pro)
+
+TARGET = progmanager
+HEADERS += breakpoint.h prog_manager.h debug_manager.h
+SOURCES += breakpoint.cpp prog_manager.cpp debug_manager.cpp
diff --git a/src/progs/manager/prog_manager.cpp b/src/progs/manager/prog_manager.cpp
new file mode 100644
index 0000000..bc824c9
--- /dev/null
+++ b/src/progs/manager/prog_manager.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
+ * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "prog_manager.h"
+
+#include "progs/base/generic_prog.h"
+#include "progs/base/prog_group.h"
+#include "progs/base/generic_debug.h"
+#include "progs/base/prog_config.h"
+#include "debug_manager.h"
+
+//----------------------------------------------------------------------------
+Programmer::Manager *Programmer::manager = 0;
+
+Programmer::Manager::Manager(QObject *parent)
+ : QObject(parent, "programmer_manager"), _programmer(0)
+{}
+
+Programmer::Manager::~Manager()
+{
+ delete _programmer;
+}
+
+void Programmer::Manager::clear()
+{
+ delete _programmer;
+ _programmer = 0;
+}
+
+void Programmer::Manager::createProgrammer(const Device::Data *data, const HardwareDescription &hd)
+{
+ if ( _programmer && _programmer->device()==data && !hasError() ) return;
+ delete _programmer;
+ _programmer = group().createProgrammer(isTargetSelfPowered(), data, hd);
+ _programmer->Log::Base::setParent(this);
+ connect(_programmer, SIGNAL(actionMessage(const QString &)), SIGNAL(actionMessage(const QString &)));
+ connect(&_programmer->progressMonitor(), SIGNAL(setLabel(const QString &)), SIGNAL(actionMessage(const QString &)));
+ connect(&_programmer->progressMonitor(), SIGNAL(setTotalProgress(uint)), SIGNAL(setTotalProgress(uint)));
+ connect(&_programmer->progressMonitor(), SIGNAL(setProgress(uint)), SIGNAL(setProgress(uint)));
+ connect(&_programmer->progressMonitor(), SIGNAL(showProgress(bool)), SIGNAL(showProgress(bool)));
+}
+
+bool Programmer::Manager::initProgramming(bool debugging)
+{
+ if ( !internalInitProgramming(debugging) ) return false;
+ setState(Programming);
+ return true;
+}
+
+bool Programmer::Manager::internalInitProgramming(bool)
+{
+ if ( device()==0 ) {
+ sorry(i18n("You need to specify the device for programming."));
+ return false;
+ }
+ if ( !group().isSupported(device()->name()) ) {
+ if ( group().isSoftware() && group().supportedDevices().isEmpty() )
+ sorry(i18n("Could not detect supported devices for \"%1\". Please check installation.").arg(group().label()));
+ else sorry(i18n("The current programmer \"%1\" does not support device \"%2\".").arg(group().label()).arg(device()->name()));
+ return false;
+ }
+ createProgrammer(device());
+ return true;
+}
+
+void Programmer::Manager::endProgramming()
+{
+ ::Debugger::manager->update(true);
+ setState(Idle);
+}
+
+bool Programmer::Manager::program(const Device::Memory &memory, const Device::MemoryRange &range)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = _programmer->program(memory, range);
+ endProgramming();
+ if ( ok && !group().isDebugger() && readConfigEntry(Config::RunAfterProgram).toBool() ) return run();
+ return ok;
+}
+
+bool Programmer::Manager::verify(const Device::Memory &memory, const Device::MemoryRange &range)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = _programmer->verify(memory, range);
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::read(Device::Memory &memory, const Device::MemoryRange &range)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = _programmer->read(memory, range);
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::erase(const Device::MemoryRange &range)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = _programmer->erase(range);
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::blankCheck(const Device::MemoryRange &range)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = _programmer->blankCheck(range);
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::connectDevice()
+{
+ if ( !initProgramming(false) ) return false;
+ _programmer->disconnectHardware();
+ bool ok = ::Debugger::manager->prepareDebugging();
+ if (ok) ok = _programmer->connectDevice();
+ if ( ok && group().isSoftware() && group().isDebugger() ) {
+ ok = _programmer->debugger()->init();
+ if (ok) ::Debugger::manager->update(true);
+ }
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::setDevicePower(bool on)
+{
+ if ( !initProgramming(false) ) return false;
+ bool ok = true;
+ if ( _programmer->isTargetSelfPowered() )
+ sorry(i18n("Cannot toggle target power since target is self-powered."), QString::null);
+ else {
+ emit actionMessage(i18n("Toggle Device Power..."));
+ ok = _programmer->setTargetPowerOn(on);
+ }
+ endProgramming();
+ return ok;
+}
+
+bool Programmer::Manager::disconnectDevice()
+{
+ ::Debugger::manager->clear();
+ emit actionMessage(i18n("Disconnecting..."));
+ bool debugger = group().isDebugger();
+ _programmer->setTargetPowerOn(false);
+ _programmer->disconnectHardware();
+ endProgramming();
+ if (debugger) log(Log::LineType::Information, i18n("Stopped."));
+ return true;
+}
+
+bool Programmer::Manager::run()
+{
+ bool debugger = group().isDebugger();
+ if ( !initProgramming(debugger) ) return false;
+ bool ok = (debugger ? ::Debugger::manager->run() : _programmer->run());
+ setState(Idle);
+ return ok;
+}
+
+bool Programmer::Manager::halt()
+{
+ bool debugger = group().isDebugger();
+ bool ok = (debugger ? ::Debugger::manager->halt() : _programmer->stop());
+ if (debugger) setState(Idle);
+ else {
+ endProgramming();
+ log(Log::LineType::Information, i18n("Stopped."));
+ }
+ return ok;
+}
+
+void Programmer::Manager::stop()
+{
+ if (_programmer) _programmer->disconnectHardware();
+}
+
+bool Programmer::Manager::restart()
+{
+ bool ok;
+ if (group().isDebugger()) {
+ if ( _programmer==0 || _programmer->state()==::Programmer::NotConnected
+ || _programmer->state()==::Programmer::Stopped ) return step();
+ if ( !initProgramming(true) ) return false;
+ ok = ::Debugger::manager->reset();
+ log(Log::LineType::Information, i18n("Reset.<Translators: please translate the past form of the verb>", "Reset."));
+ setState(Idle);
+ } else {
+ log(Log::LineType::Information, i18n("Restarting..."));
+ ok = _programmer->stop();
+ Port::msleep(200);
+ if (ok) ok = _programmer->run();
+ endProgramming();
+ }
+ return ok;
+}
+
+bool Programmer::Manager::step()
+{
+ if ( !initProgramming(true) ) return false;
+ bool ok = ::Debugger::manager->step();
+ setState(Idle);
+ return ok;
+}
+
+bool Programmer::Manager::isTargetSelfPowered() const
+{
+ if ( group().targetPowerMode()==TargetPowerModeFromConfig ) return readConfigEntry(Config::TargetSelfPowered).toBool();
+ return ( group().targetPowerMode()==TargetSelfPowered );
+}
diff --git a/src/progs/manager/prog_manager.h b/src/progs/manager/prog_manager.h
new file mode 100644
index 0000000..11f7401
--- /dev/null
+++ b/src/progs/manager/prog_manager.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
+ * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef PROG_MANAGER_H
+#define PROG_MANAGER_H
+
+#include <qobject.h>
+
+#include "common/global/log.h"
+namespace Device { class Data; class Memory; class MemoryRange; }
+namespace Port { class Description; }
+
+namespace Programmer
+{
+class Base;
+class Group;
+class HardwareDescription;
+
+class Manager : public QObject, public Log::Base
+{
+Q_OBJECT
+public:
+ Manager(QObject *parent);
+ virtual ~Manager();
+ ::Programmer::Base *programmer() { return _programmer; }
+ virtual void createProgrammer(const Device::Data *data) = 0;
+ bool initProgramming(bool debugging);
+ void endProgramming();
+ void clear();
+ void stop();
+ bool program(const Device::Memory &memory, const Device::MemoryRange &range);
+ bool verify(const Device::Memory &memory, const Device::MemoryRange &range);
+ bool read(Device::Memory &memory, const Device::MemoryRange &range);
+ bool erase(const Device::MemoryRange &range);
+ bool blankCheck(const Device::MemoryRange &range);
+ bool setDevicePower(bool on);
+ enum State { Idle, Programming };
+ virtual void setState(State state) = 0;
+
+public slots:
+ bool connectDevice();
+ bool disconnectDevice();
+ bool run();
+ bool halt();
+ bool restart();
+ bool step();
+
+signals:
+ void actionMessage(const QString &message);
+ void showProgress(bool show);
+ void setTotalProgress(uint steps);
+ void setProgress(uint steps);
+
+protected:
+ ::Programmer::Base *_programmer;
+
+ virtual const Group &group() const = 0;
+ virtual bool internalInitProgramming(bool debugging);
+ virtual const Device::Data *device() const = 0;
+ virtual bool isTargetSelfPowered() const;
+ virtual void createProgrammer(const Device::Data *data, const HardwareDescription &hd);
+};
+
+extern Manager *manager;
+
+} // namespace
+
+#endif