diff options
Diffstat (limited to 'src/progs/manager')
-rw-r--r-- | src/progs/manager/Makefile.am | 5 | ||||
-rw-r--r-- | src/progs/manager/breakpoint.cpp | 74 | ||||
-rw-r--r-- | src/progs/manager/breakpoint.h | 70 | ||||
-rw-r--r-- | src/progs/manager/debug_manager.cpp | 392 | ||||
-rw-r--r-- | src/progs/manager/debug_manager.h | 99 | ||||
-rw-r--r-- | src/progs/manager/manager.pro | 6 | ||||
-rw-r--r-- | src/progs/manager/prog_manager.cpp | 217 | ||||
-rw-r--r-- | src/progs/manager/prog_manager.h | 74 |
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 |