diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
commit | f508189682b6fba62e08feeb1596f682bad5fff9 (patch) | |
tree | 28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/piklab-prog | |
download | piklab-f508189682b6fba62e08feeb1596f682bad5fff9.tar.gz piklab-f508189682b6fba62e08feeb1596f682bad5fff9.zip |
Added KDE3 version of PikLab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/piklab-prog')
-rw-r--r-- | src/piklab-prog/Makefile.am | 31 | ||||
-rw-r--r-- | src/piklab-prog/cli_debug_manager.cpp | 18 | ||||
-rw-r--r-- | src/piklab-prog/cli_debug_manager.h | 34 | ||||
-rw-r--r-- | src/piklab-prog/cli_interactive.cpp | 347 | ||||
-rw-r--r-- | src/piklab-prog/cli_interactive.h | 53 | ||||
-rw-r--r-- | src/piklab-prog/cli_prog_manager.cpp | 65 | ||||
-rw-r--r-- | src/piklab-prog/cli_prog_manager.h | 38 | ||||
-rw-r--r-- | src/piklab-prog/cli_purl.cpp | 29 | ||||
-rw-r--r-- | src/piklab-prog/cmdline.cpp | 457 | ||||
-rw-r--r-- | src/piklab-prog/cmdline.h | 59 | ||||
-rw-r--r-- | src/piklab-prog/piklab-prog.pro | 32 |
11 files changed, 1163 insertions, 0 deletions
diff --git a/src/piklab-prog/Makefile.am b/src/piklab-prog/Makefile.am new file mode 100644 index 0000000..fd53ef0 --- /dev/null +++ b/src/piklab-prog/Makefile.am @@ -0,0 +1,31 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +bin_PROGRAMS = piklab-prog +OBJ = $(top_builddir)/src/progs/list/libproglistnoui.la \ + $(top_builddir)/src/progs/picdem_bootloader/base/libpicdembootloader.la \ + $(top_builddir)/src/progs/pickit2_bootloader/base/libpickit2bootloader.la \ + $(top_builddir)/src/progs/tbl_bootloader/base/libtblbootloader.la \ + $(top_builddir)/src/progs/bootloader/base/libbootloader.la \ + $(top_builddir)/src/progs/gpsim/base/libgpsim.la $(top_builddir)/src/progs/psp/base/libpsp.la \ + $(top_builddir)/src/progs/pickit1/base/libpickit1.la \ + $(top_builddir)/src/progs/pickit2v2/base/libpickit2v2.la $(top_builddir)/src/progs/pickit2/base/libpickit2.la \ + $(top_builddir)/src/progs/icd1/base/libicd1.la $(top_builddir)/src/progs/icd2/base/libicd2.la \ + $(top_builddir)/src/progs/icd2/icd2_data/libicd2data.la $(top_builddir)/src/progs/direct/base/libdirectprog.la \ + $(top_builddir)/src/devices/mem24/prog/libmem24prog.la $(top_builddir)/src/devices/pic/prog/libpicprog.la \ + $(top_builddir)/src/progs/manager/libprogmanager.la $(top_builddir)/src/progs/base/libprogbase.la \ + \ + $(top_builddir)/src/coff/base/libcoff.la $(top_builddir)/src/common/port/libport.la \ + $(top_builddir)/src/common/cli/libcli.la $(top_builddir)/src/common/global/libglobal.la \ + \ + $(top_builddir)/src/devices/list/libdevicelistnoui.la \ + $(top_builddir)/src/devices/pic/pic/libpic.la $(top_builddir)/src/devices/pic/base/libpicbase.la \ + $(top_builddir)/src/devices/pic/xml_data/libpicxml.la \ + $(top_builddir)/src/devices/mem24/mem24/libmem24.la $(top_builddir)/src/devices/mem24/base/libmem24base.la \ + $(top_builddir)/src/devices/mem24/xml_data/libmem24xml.la \ + $(top_builddir)/src/devices/base/libdevicebase.la \ + $(top_builddir)/src/common/common/libcommon.la +piklab_prog_DEPENDENCIES = $(OBJ) +piklab_prog_LDADD = $(OBJ) $(LIB_KIO) $(LIBUSB_LIBS) $(LIBREADLINE_LIBS) +piklab_prog_LDFLAGS = $(all_libraries) $(KDE_RPATH) +piklab_prog_SOURCES = cmdline.cpp cli_prog_manager.cpp cli_debug_manager.cpp cli_interactive.cpp diff --git a/src/piklab-prog/cli_debug_manager.cpp b/src/piklab-prog/cli_debug_manager.cpp new file mode 100644 index 0000000..418bc06 --- /dev/null +++ b/src/piklab-prog/cli_debug_manager.cpp @@ -0,0 +1,18 @@ +/*************************************************************************** + * 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 "cli_debug_manager.h" + +#include "progs/base/generic_prog.h" +#include "progs/base/generic_debug.h" + +void Debugger::CliManager::updateView(bool) +{ + if ( Programmer::manager->programmer() && debugger() ) log(Log::LineType::Normal, debugger()->statusString()); + // ### TODO: show current and next PC lines +} diff --git a/src/piklab-prog/cli_debug_manager.h b/src/piklab-prog/cli_debug_manager.h new file mode 100644 index 0000000..8da14fa --- /dev/null +++ b/src/piklab-prog/cli_debug_manager.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * 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 CLI_DEBUG_MANAGER_H +#define CLI_DEBUG_MANAGER_H + +#include "progs/manager/debug_manager.h" +#include "cmdline.h" + +namespace Debugger +{ +class CliManager : public Manager +{ +Q_OBJECT +public: + CliManager() {} + virtual PURL::Url coffUrl() const { return CLI::_coffUrl; } + +private: + virtual const Programmer::Group *programmerGroup() const { return CLI::_progGroup; } + virtual const Device::Data *deviceData() const { return CLI::_device; } + virtual Log::View *compileView() { return view(); } + virtual void updateView(bool gotoPC); + virtual bool isProjectSource(const PURL::Url &) const { return true; } +}; + +} // namespace + +#endif diff --git a/src/piklab-prog/cli_interactive.cpp b/src/piklab-prog/cli_interactive.cpp new file mode 100644 index 0000000..148ba62 --- /dev/null +++ b/src/piklab-prog/cli_interactive.cpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * 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 "cli_interactive.h" + +#if defined(HAVE_READLINE) +# include <readline/readline.h> +# include <readline/history.h> +#else +# include <stdio.h> +#endif +#include <signal.h> +#include <qtimer.h> +#include <stdlib.h> + +#include "progs/base/generic_prog.h" +#include "cmdline.h" +#include "cli_prog_manager.h" +#include "common/cli/cli_log.h" +#include "devices/base/device_group.h" +#include "devices/pic/base/pic_register.h" +#include "devices/pic/prog/pic_prog.h" +#include "coff/base/text_coff.h" +#include "devices/pic/prog/pic_debug.h" + +//----------------------------------------------------------------------------- +const CLI::CommandData CLI::INTERACTIVE_COMMAND_DATA[] = { + { "property-list", NoCommandProperty, I18N_NOOP("Display the list of available properties.") }, + { "register-list", NoCommandProperty, I18N_NOOP("Display the list of registers.") }, + { "variable-list", NoCommandProperty, I18N_NOOP("Display the list of variables.") }, + { "range-list", NoCommandProperty, I18N_NOOP("Display the list of memory ranges.") }, + { "help", NoCommandProperty, I18N_NOOP("Display help.") }, + { "quit", NoCommandProperty, I18N_NOOP("Quit.") }, + { "set", NoCommandProperty, I18N_NOOP("Set property value: \"set <property> <value>\" or \"<property> <value>\".") }, + { "unset", NoCommandProperty, I18N_NOOP("Unset property value: \"unset <property>\".") }, + { "get", NoCommandProperty, I18N_NOOP("Get property value: \"get <property>\" or \"<property>\".") }, + { "disconnect", NeedProgrammer, I18N_NOOP("Disconnect programmer.") }, + { "start", NeedDevice | NeedProgrammer, I18N_NOOP("Start or restart debugging session.") }, + { "step", NeedDevice | NeedProgrammer, I18N_NOOP("Step one instruction.") }, + { "x", NeedDevice | NeedProgrammer, I18N_NOOP("Read or set a register or variable: \"x PORTB\" or \"x W 0x1A\".") }, + { "break", NeedDevice | NeedProgrammer, I18N_NOOP("Set a breakpoint \"break e 0x04\" or list all breakpoints \"break\".") }, + { "clear", NeedDevice | NeedProgrammer, I18N_NOOP("Clear a breakpoint \"clear 0\", \"clear e 0x04\", or clear all breakpoints \"clear all\".") }, + { "raw-com", NeedDevice | NeedProgrammer, I18N_NOOP("Write and read raw commands to port from given file.") }, + { 0, NoCommandProperty, 0 } +}; + +const CLI::PropertyData CLI::PROPERTY_DATA[] = { + { "programmer", "programmer <name>", "p", I18N_NOOP("Programmer to use."), "programmer-list", I18N_NOOP("Return the list of supported programmers.") }, + { "hardware", "hardware <name>", "h", I18N_NOOP("Programmer hardware configuration to use (for direct programmer)."), "hardware-list", I18N_NOOP("Return the list of supported programmer hardware configurations.") }, + { "device", "device <name>", "d", I18N_NOOP("Target device."), "device-list", I18N_NOOP("Return the list of supported devices.") }, + { "format", "format <name>", "f", I18N_NOOP("Hex output file format."), "format-list", I18N_NOOP("Return the list of supported hex file formats.") }, + { "port", "port <name>", "t", I18N_NOOP("Programmer port (\"usb\" or device such as \"/dev/ttyS0\")"), "port-list", I18N_NOOP("Return the list of detected ports.") }, + { "firmware-dir", "firmware-dir <dir>", 0, I18N_NOOP("Firmware directory."), 0, 0 }, + { "target-self-powered", "target-self-powered <true|false>", 0, I18N_NOOP("Set if target device is self-powered."), 0, 0 }, + { "hex", 0, 0, I18N_NOOP("Hex file to be used for programming."), 0, 0 }, + { "coff", 0, 0, I18N_NOOP("COFF file to be used for debugging."), 0, 0 }, + { "processor", 0, 0, I18N_NOOP("Same as \"device\"."), 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +//----------------------------------------------------------------------------- +void CLI::Interactive::signalHandler(int n) +{ + if ( n!=SIGINT ) return; + fprintf(stdout, "<CTRL C> Break\n"); + fflush(stdout); + Programmer::Base *prog = Programmer::manager->programmer(); + if ( prog && prog->state()==Programmer::Running ) Programmer::manager->halt(); + _interactive->redisplayPrompt(); +} + +CLI::Interactive::Interactive(QObject *parent) + : QObject(parent, "interactive") +{ + setView(_view); + ::signal(SIGINT, signalHandler); +#if defined(HAVE_READLINE) + using_history(); +#else + _stdin.open(IO_ReadOnly, stdin); +#endif + QTimer::singleShot(0, this, SLOT(displayPrompt())); +} + +void CLI::Interactive::redisplayPrompt() +{ +#if defined(HAVE_READLINE) + rl_forced_update_display(); +#else + fprintf(stdout, "> "); + fflush(stdout); +#endif +} + +void CLI::Interactive::displayPrompt() +{ +#if defined(HAVE_READLINE) + char *line = readline("> "); + _input = QString(line); + if ( !_input.isEmpty() ) add_history(line); + free(line); +#else + fprintf(stdout, "> "); + fflush(stdout); + char buffer[1000]; + _stdin.readLine(buffer, 1000); + _input = QString(buffer); +#endif + lineRead(); +} + +CLI::ExitCode CLI::Interactive::processLine(const QString &s) +{ + QStringList words = QStringList::split(" ", s); + if ( words.count()==0 ) return ARG_ERROR; + if ( words[0]=="command-list" || words[0]=="property-list" || words[0]=="range-list" + || isPropertyList(words[0]) ) return static_cast<Main *>(_main)->list(words[0]); + if ( words[0]=="register-list" ) return registerList(); + if ( words[0]=="variable-list" ) return variableList(); + if ( isProperty(words[0]) ) { + if ( words.count()==1 ) words.prepend("get"); + else if ( words.count()==2 ) words.prepend("set"); + else return errorExit(i18n("This command takes no or one argument"), ARG_ERROR); + } + if ( findCommand(words[0])!=OK ) return ARG_ERROR; + const CommandData *data = findCommandData(words[0]); + if ( words[0]=="quit" ) return EXITING; + if ( words[0]=="set" ) { + if ( words.count()==2 ) return static_cast<Main *>(_main)->executeSetCommand(words[1], QString::null); + if ( words.count()!=3 ) return errorExit(i18n("This command takes two arguments."), ARG_ERROR); + return static_cast<Main *>(_main)->executeSetCommand(words[1], words[2]); + } + if ( words[0]=="unset" ) { + if ( words.count()!=2 ) return errorExit(i18n("This command takes one argument."), ARG_ERROR); + return static_cast<Main *>(_main)->executeSetCommand(words[1], QString::null); + } + if ( words[0]=="get" ) { + if ( words.count()!=2 ) return errorExit(i18n("This command takes one argument."), ARG_ERROR); + QString s = static_cast<Main *>(_main)->executeGetCommand(words[1]); + if ( !s.isEmpty() ) log(Log::LineType::Normal, words[1] + ": " + s); + return OK; + } + if ( words[0]=="help" ) return static_cast<Main *>(_main)->list("command-list"); + if ( words[0]=="x" ) { + if ( words.count()!=2 && words.count()!=3 ) return errorExit(i18n("This command takes one or two argument."), ARG_ERROR); + return executeRegister(words[1], words.count()==3 ? words[2] : QString::null); + } + if ( words[0]=="break" ) { + if ( words.count()==3 ) { + if ( words[1]=="e" ) { + bool ok; + ulong address = fromAnyLabel(words[2], &ok); + if ( !ok ) return errorExit(i18n("Number format not recognized."), ARG_ERROR); + PURL::Url dummy; + Breakpoint::Data data(dummy, address); + if ( Breakpoint::list().contains(data) ) return okExit(i18n("Breakpoint already set at %1.").arg(toHexLabel(address, nbChars(NumberBase::Hex, address)))); + Breakpoint::list().append(data); + Breakpoint::list().setAddress(data, address); + Breakpoint::list().setState(data, Breakpoint::Active); + return okExit(i18n("Breakpoint set at %1.").arg(toHexLabel(address, nbChars(NumberBase::Hex, address)))); + } + return errorExit(i18n("The first argument should be \"e\"."), ARG_ERROR); + } + if ( words.count()==1 ) { + uint nb = Breakpoint::list().count(); + if ( nb==0 ) return okExit(i18n("No breakpoint set.")); + log(Log::LineType::Normal, i18n("Breakpoints:")); + uint nbc = 0; + if (_device) nbc = _device->nbCharsAddress(); + else for (uint i=0; i<nb; i++) { + Address address = Breakpoint::list().address(Breakpoint::list().data(i)); + nbc = QMAX(nbc, nbChars(NumberBase::Hex, address.toUInt())); + } + for (uint i=0; i<nb; i++) { + Address address = Breakpoint::list().address(Breakpoint::list().data(i)); + log(Log::LineType::Normal, QString(" #%1: %2").arg(i).arg(toHexLabel(address, nbc))); + } + return OK; + } + if ( words.count()!=1 && words.count()!=3 ) return errorExit(i18n("This command takes no or two argument."), ARG_ERROR); + return errorExit(i18n("Arguments not recognized."), ARG_ERROR); + } + if ( words[0]=="clear" ) { + if ( words.count()!=2 ) return errorExit(i18n("This command takes one argument."), ARG_ERROR); + if ( words[1]=="all" ) { + Breakpoint::list().clear(); + return okExit(i18n("All breakpoints removed.")); + } + bool ok; + uint i = words[1].toUInt(&ok); + if ( !ok ) return errorExit(i18n("Argument should be breakpoint index."), ARG_ERROR); + if ( i>=Breakpoint::list().count() ) return errorExit(i18n("Breakpoint index too large."), ARG_ERROR); + Breakpoint::Data data = Breakpoint::list().data(i); + Address address = Breakpoint::list().address(data); + Breakpoint::list().remove(data); + return okExit(i18n("Breakpoint at %1 removed.").arg(toHexLabelAbs(address))); + } + if ( words[0]=="raw-com" ) { + if ( words.count()!=2 ) return errorExit(i18n("This command needs a commands filename."), ARG_ERROR); + } else if ( words[0]=="program" || words[0]=="read" || words[0]=="verify" || words[0]=="erase" || words[0]=="blank_check" ) { + uint hexi = 1; + if ( words.count()>=2 && words[1]=="-r" ) { + hexi = 3; + if ( words.count()==2 ) return errorExit(i18n("You need to specify the range."), ARG_ERROR); + ExitCode code = static_cast<Main *>(_main)->extractRange(words[2]); + if ( code!=OK ) return code; + } + if ( data->properties & (InputHex|OutputHex) ) { + if ( uint(words.count())>(hexi+1) ) return errorExit(i18n("Too many arguments."), ARG_ERROR); + if ( uint(words.count())==(hexi+1) )_hexUrl = PURL::Url(runDirectory(), words[hexi]); + if ( _hexUrl.isEmpty() ) return errorExit(i18n("This command needs an hex filename."), ARG_ERROR); + } else if ( uint(words.count())>hexi ) return errorExit(i18n("Too many arguments."), ARG_ERROR); + } else if ( words.count()!=1 ) return errorExit(i18n("This command takes no argument."), ARG_ERROR); + + ExitCode code = static_cast<Main *>(_main)->prepareCommand(words[0]); + if ( code!=OK ) return code; + if ( words[0]=="raw-com" ) return executeRawCommands(words[1]); + return static_cast<Main *>(_main)->executeCommand(words[0]); +} + +void CLI::Interactive::lineRead() +{ + QString s = _input.stripWhiteSpace(); + _input = QString::null; + if ( processLine(s)==EXITING ) { +#if QT_VERSION<0x040000 + qApp->exit(OK); +#else + QCoreApplication::exit(OK); +#endif + return; + } + QTimer::singleShot(0, this, SLOT(displayPrompt())); +} + +CLI::ExitCode CLI::Interactive::registerList() +{ + if ( _device==0 ) return errorExit(i18n("No device specified."), NOT_SUPPORTED_ERROR); + if ( _device->group().name()!="pic" ) return errorExit(i18n("No register."), NOT_SUPPORTED_ERROR); + const Pic::Data &data = static_cast<const Pic::Data &>(*_device); + const Coff::Object *coff = Debugger::manager->coff(); + const Pic::RegistersData &rdata = data.registersData(); + log(Log::LineType::Normal, i18n("Special Function Registers:")); + QValueVector<Pic::RegisterNameData> list = Pic::sfrList(data); + for (uint i=0; i<uint(list.count()); i++) log(Log::LineType::Normal, QString(" %1: %2").arg(toHexLabel(list[i].data().address(), rdata.nbCharsAddress())).arg(list[i].label())); + log(Log::LineType::Normal, i18n("General Purpose Registers:")); + list = Pic::gprList(data, coff); + for (uint i=0; i<uint(list.count()); i++) log(Log::LineType::Normal, QString(" %1: %2").arg(toHexLabel(list[i].data().address(), rdata.nbCharsAddress())).arg(list[i].label())); + return OK; +} + +CLI::ExitCode CLI::Interactive::variableList() +{ + if ( _device==0 ) return errorExit(i18n("No device specified."), NOT_SUPPORTED_ERROR); + const Coff::Object *coff = Debugger::manager->coff(); + if ( coff==0 ) return errorExit(i18n("No COFF file specified."), NOT_SUPPORTED_ERROR); + if ( _device->group().name()!="pic" ) return errorExit(i18n("No register."), NOT_SUPPORTED_ERROR); + const Pic::Data &data = static_cast<const Pic::Data &>(*_device); + const Pic::RegistersData &rdata = data.registersData(); + QValueVector<Pic::RegisterNameData> list = Pic::variableList(data, *coff); + if ( list.count()==0 ) log(Log::LineType::Normal, i18n("No variable.")); + for (uint i=0; i<uint(list.count()); i++) log(Log::LineType::Normal, QString(" %1: %2").arg(toHexLabel(list[i].data().address(), rdata.nbCharsAddress())).arg(list[i].label())); + return OK; +} + +Address CLI::Interactive::findRegisterAddress(const QString &name) +{ + const Pic::Data &data = static_cast<const Pic::Data &>(*_device); + const Coff::Object *coff = Debugger::manager->coff(); + const Pic::RegistersData &rdata = data.registersData(); + bool ok; + Address address = fromAnyLabel(name, &ok); + if (ok) { + if ( address>rdata.addressFromIndex(rdata.nbRegisters()-1) ) return Address(); + return address; + } + QValueVector<Pic::RegisterNameData> sfrs = Pic::sfrList(data); + for (uint i=0; i<uint(sfrs.count()); i++) if ( name.lower()==sfrs[i].label().lower() ) return sfrs[i].data().address(); + if ( coff==0 ) return Address(); + QMap<QString, Address> variables = coff->variables(); + if ( variables.contains(name) ) return variables[name]; + return Address(); +} + +CLI::ExitCode CLI::Interactive::executeRegister(const QString &name, const QString &value) +{ + if ( Debugger::manager->debugger()==0 ) return errorExit(i18n("You need to start the debugging session first (with \"start\")."), ARG_ERROR); + const Pic::Data &data = static_cast<const Pic::Data &>(*_device); + const Pic::RegistersData &rdata = data.registersData(); + uint nbChars = rdata.nbChars(); + bool ok; + ulong v = fromAnyLabel(value, &ok); + if ( !ok ) return errorExit(i18n("Number format not recognized."), ARG_ERROR); + if ( v>maxValue(NumberBase::Hex, nbChars) ) return errorExit(i18n("The given value is too large (max: %1).").arg(toHexLabel(maxValue(NumberBase::Hex, nbChars), nbChars)), ARG_ERROR); + Register::TypeData rtd; + if ( name.lower()=="w" || name.lower()=="wreg" ) + rtd = static_cast<Debugger::PicBase *>(Debugger::manager->debugger())->deviceSpecific()->wregTypeData(); + else if ( name.lower()=="pc" ) + rtd = Debugger::manager->debugger()->pcTypeData(); + else { + Address address = findRegisterAddress(name); + if ( !address.isValid() ) return errorExit(i18n("Unknown register or variable name."), ARG_ERROR); + rtd = Register::TypeData(address, rdata.nbChars()); + } + if ( value.isEmpty() ) { + if ( !Debugger::manager->readRegister(rtd) ) return ARG_ERROR; + return okExit(i18n("%1 = %2").arg(name.upper()).arg(toHexLabel(Register::list().value(rtd), nbChars))); + } + return (Debugger::manager->writeRegister(rtd, v) ? OK : EXEC_ERROR); +} + +CLI::ExitCode CLI::Interactive::executeRawCommands(const QString &filename) +{ + QFile file(filename); + if ( !file.open(IO_ReadOnly) ) return errorExit(i18n("Could not open filename \"%1\".").arg(filename), ARG_ERROR); + if ( Programmer::manager->programmer()==0 ) { + Programmer::manager->createProgrammer(_device); + if ( !Programmer::manager->programmer()->simpleConnectHardware() ) return EXEC_ERROR; + } + Programmer::Base *programmer = Programmer::manager->programmer(); + for (;;) { + QString s; +#if QT_VERSION<0x040000 + if ( file.readLine(s, 1000)==-1 ) break; +#else + char buffer[1000]; + if ( file.readLine(buffer, 1000)==-1 ) break; + s += buffer; +#endif + bool write = !s.startsWith(" "); + s = s.stripWhiteSpace(); + if ( s.isEmpty() ) continue; + if (write) { + if ( !programmer->hardware()->rawWrite(s) ) return EXEC_ERROR; + } else { + QString rs; + if ( !programmer->hardware()->rawRead(s.length(), rs) ) return EXEC_ERROR; + if ( rs!=s ) log(Log::LineType::Warning, i18n("Read string is different than expected: %1 (%2).").arg(rs).arg(s)); + } + } + return okExit(i18n("End of command file reached.")); +} diff --git a/src/piklab-prog/cli_interactive.h b/src/piklab-prog/cli_interactive.h new file mode 100644 index 0000000..fad6e9d --- /dev/null +++ b/src/piklab-prog/cli_interactive.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * 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 CLI_INTERACTIVE_H +#define CLI_INTERACTIVE_H + +#include <qfile.h> +#include "common/global/global.h" +#include "common/cli/cli_global.h" +#include "common/global/log.h" +#include "common/common/bitvalue.h" + +namespace CLI +{ +//---------------------------------------------------------------------------- +enum CommandProperty { NoCommandProperty = 0, NeedProgrammer = 1, InputHex = 2, + OutputHex = 4, NeedDevice = 8 }; +Q_DECLARE_FLAGS(CommandProperties, CommandProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(CommandProperties) + +//---------------------------------------------------------------------------- +class Interactive : public QObject, public Log::Base +{ +Q_OBJECT +public: + Interactive(QObject *parent); + void redisplayPrompt(); + +private slots: + void displayPrompt(); + +private: + QFile _stdin; + QString _input; + void lineRead(); + ExitCode processLine(const QString &s); + ExitCode executeRegister(const QString &name, const QString &value); + ExitCode registerList(); + ExitCode variableList(); + ExitCode executeRawCommands(const QString &filename); + Address findRegisterAddress(const QString &name); + ExitCode start(); + static void signalHandler(int n); +}; + +} // namespace + +#endif diff --git a/src/piklab-prog/cli_prog_manager.cpp b/src/piklab-prog/cli_prog_manager.cpp new file mode 100644 index 0000000..472757a --- /dev/null +++ b/src/piklab-prog/cli_prog_manager.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + * 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 "cli_prog_manager.h" + +#include "progs/base/generic_prog.h" +#include "progs/base/prog_group.h" +#include "progs/base/prog_config.h" +#include "progs/base/hardware_config.h" +#include "progs/base/generic_debug.h" + +//---------------------------------------------------------------------------- +Port::Description Programmer::CliManager::portDescription() const +{ + Log::Base *log = const_cast<Log::Base *>(static_cast<const Log::Base *>(this)); + if ( CLI::_port.isEmpty() ) { + log->log(Log::LineType::Information, i18n("Using port from configuration file.")); + return Programmer::GroupConfig::portDescription(group()); + } + if ( CLI::_port=="usb" ) return Port::Description(PortType::USB, QString::null); + PortType type = Port::findType(CLI::_port); + if ( type==PortType::Nb_Types ) { + log->log(Log::LineType::Warning, i18n("Could not find device \"%1\" as serial or parallel port. Will try to open as serial port.").arg(CLI::_port)); + type = PortType::Serial; + } + return Port::Description(type, CLI::_port); +} + +bool Programmer::CliManager::isTargetSelfPowered() const +{ + bool targetSelfPowered = ::Programmer::Manager::isTargetSelfPowered(); + if ( !CLI::_targetSelfPowered.isEmpty() ) targetSelfPowered = ( CLI::_targetSelfPowered=="true" ); + return targetSelfPowered; +} + +void Programmer::CliManager::createProgrammer(const Device::Data *data) +{ + HardwareDescription hd; + hd.port = portDescription(); + ::Hardware::Config *config = CLI::_progGroup->hardwareConfig(); + if (config) { + if ( CLI::_hardware.isEmpty() ) hd.name = config->currentHardware(hd.port.type); + else hd.name = CLI::_hardware; + } + delete config; + Manager::createProgrammer(data, hd); + if ( !CLI::_firmwareDir.isEmpty() ) _programmer->setFirmwareDirectory(CLI::_firmwareDir.path()); +} + +bool Programmer::CliManager::internalInitProgramming(bool debugging) +{ + if ( !Manager::internalInitProgramming(debugging) ) return false; + if ( _programmer->isActive() ) { + if ( !halt() ) return false; + } else if (debugging) { + if ( ::Debugger::manager->coff()==0 && !::Debugger::manager->init() ) log(Log::LineType::Warning, i18n("Starting debug session without COFF file (no source file information).")); + if ( !group().isSoftware() ) log(Log::LineType::Warning, i18n("Starting debugging session with device memory in an unknown state. You may want to reprogram the device.")); + } + return true; +} diff --git a/src/piklab-prog/cli_prog_manager.h b/src/piklab-prog/cli_prog_manager.h new file mode 100644 index 0000000..27775a4 --- /dev/null +++ b/src/piklab-prog/cli_prog_manager.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * 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 CLI_PROG_MANAGER_H +#define CLI_PROG_MANAGER_H + +#include "progs/manager/prog_manager.h" +#include "cli_debug_manager.h" +#include "cmdline.h" + +namespace Programmer +{ +class CliManager : public Manager +{ +Q_OBJECT +public: + CliManager(QObject *parent) : Manager(parent), _state(Idle) {} + Port::Description portDescription() const; + virtual void createProgrammer(const Device::Data *data); + +private: + State _state; + + virtual const Group &group() const { return *CLI::_progGroup; } + virtual void setState(State state) { _state = state; } + virtual const Device::Data *device() const { return CLI::_device; } + virtual bool internalInitProgramming(bool debugging); + virtual bool isTargetSelfPowered() const; +}; + +} // namespace + +#endif diff --git a/src/piklab-prog/cli_purl.cpp b/src/piklab-prog/cli_purl.cpp new file mode 100644 index 0000000..2cd38a5 --- /dev/null +++ b/src/piklab-prog/cli_purl.cpp @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2005-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 "common/global/purl.h" + +#include <qfileinfo.h> +#include <qdatetime.h> + +bool PURL::Base::probablyExists() const +{ + QFileInfo fi(_url.path()); + return fi.exists(); +} + +bool PURL::Url::isDestinationUpToDate(FileType type) const +{ + if ( !(data().properties & Source) ) return true; + Url dest = toFileType(type); + QFileInfo sfi(_url.path()); + if ( !sfi.exists() ) return true; // source does not exists + QFileInfo dfi(dest._url.path()); + if ( !dfi.exists() ) return false; // destination does not exists + return sfi.lastModified()<dfi.lastModified(); +} diff --git a/src/piklab-prog/cmdline.cpp b/src/piklab-prog/cmdline.cpp new file mode 100644 index 0000000..2ec4530 --- /dev/null +++ b/src/piklab-prog/cmdline.cpp @@ -0,0 +1,457 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 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 "cmdline.h" + +#if defined(HAVE_READLINE) +# include <readline/readline.h> +# include <readline/history.h> +#else +# include <stdio.h> +#endif +#include <signal.h> +#include <qtimer.h> + +#include "devices/list/device_list.h" +#include "devices/base/device_group.h" +#include "common/global/about.h" +#include "progs/base/prog_config.h" +#include "progs/base/hardware_config.h" +#include "devices/pic/pic/pic_memory.h" +#include "devices/pic/prog/pic_prog.h" +#include "progs/list/prog_list.h" +#include "common/cli/cli_log.h" +#include "cli_prog_manager.h" +#include "cli_debug_manager.h" + +//----------------------------------------------------------------------------- +const CLI::CommandData CLI::NORMAL_COMMAND_DATA[] = { + { "connect", NeedProgrammer | NeedDevice, + I18N_NOOP("Connect programmer.") }, + { "run", NeedProgrammer | NeedDevice, + I18N_NOOP("Run device (release reset).") }, + { "stop", NeedProgrammer | NeedDevice, + I18N_NOOP("Stop device (hold reset).") }, + { "program", NeedProgrammer | InputHex | NeedDevice, + I18N_NOOP("Program device memory: \"program <hexfilename>\".") }, + { "verify", NeedProgrammer | InputHex | NeedDevice, + I18N_NOOP("Verify device memory: \"verify <hexfilename>\".") }, + { "read", NeedProgrammer | OutputHex | NeedDevice, + I18N_NOOP("Read device memory: \"read <hexfilename>\".") }, + { "erase", NeedProgrammer | NeedDevice, + I18N_NOOP("Erase device memory.") }, + { "blank_check", NeedProgrammer | NeedDevice, + I18N_NOOP("Blank check device memory.") }, + { "upload_firmware", NeedProgrammer | InputHex, + I18N_NOOP("Upload firmware to programmer: \"upload_firmware <hexfilename>\".") }, + { 0, NoCommandProperty, 0 } +}; + +const KCmdLineOptions CLI::OPTIONS[] = { + { "r", 0, 0 }, + { "range <name>", I18N_NOOP("Memory range to operate on."), 0 }, + { "range-list", I18N_NOOP("Return the list of memory ranges."), 0 }, + KCmdLineLastOption +}; + +//----------------------------------------------------------------------------- +const Programmer::Group *CLI::_progGroup = 0; +const Device::Data *CLI::_device = 0; +HexBuffer::Format CLI::_format = HexBuffer::IHX32; +QString CLI::_port, CLI::_targetSelfPowered, CLI::_hardware; +PURL::Directory CLI::_firmwareDir; +PURL::Url CLI::_hexUrl, CLI::_coffUrl; +Device::Memory *CLI::_memory = 0; +CLI::Interactive *CLI::_interactive = 0; + +//----------------------------------------------------------------------------- +CLI::ExitCode CLI::Main::formatList() +{ + log(Log::LineType::Normal, i18n("Supported hex file formats:")); + for (uint i=0; i<HexBuffer::Nb_Formats; i++) + log(Log::LineType::Normal, QString(" ") + HexBuffer::FORMATS[i]); + return OK; +} + +CLI::ExitCode CLI::Main::programmerList() +{ + log(Log::LineType::Normal, i18n("Supported programmers:")); + Programmer::Lister::ConstIterator it; + for (it=Programmer::lister().begin(); it!=Programmer::lister().end(); it++) + log(Log::LineType::Normal, " " + QString(it.data()->name())); + return OK; +} + +CLI::ExitCode CLI::Main::hardwareList() +{ + log(Log::LineType::Normal, i18n("Supported hardware configuration for programmers:")); + Programmer::Lister::ConstIterator it; + for (it=Programmer::lister().begin(); it!=Programmer::lister().end(); it++) { + ::Hardware::Config *config = it.data()->hardwareConfig(); + if ( config==0 ) continue; + FOR_EACH(PortType, type) { + if ( !it.data()->isPortSupported(type) ) continue; + log(Log::LineType::Normal, "-" + QString(it.data()->name()) + " [" + type.label() + "]:"); + QStringList list = config->hardwareNames(type); + for (uint k=0; k<uint(list.count()); k++) log(Log::LineType::Normal, " " + list[k]); + } + delete config; + } + return OK; +} + +CLI::ExitCode CLI::Main::deviceList() +{ + QValueVector<QString> devices; + if ( _progGroup==0 ) { + log(Log::LineType::Normal, i18n("Supported devices:")); + devices = Programmer::lister().supportedDevices(); + } else { + log(Log::LineType::Normal, i18n("Supported devices for \"%1\":").arg(_progGroup->label())); + devices = _progGroup->supportedDevices(); + } + qHeapSort(devices); + QString s; + for (uint i=0; i<uint(devices.count()); i++) s += " " + devices[i]; + log(Log::LineType::Normal, s + "\n"); + return OK; +} + +CLI::ExitCode CLI::Main::portList() +{ + if (_progGroup) log(Log::LineType::Normal, i18n("Detected ports supported by \"%1\":").arg(_progGroup->label())); + else log(Log::LineType::Normal, i18n("Detected ports:")); + FOR_EACH(PortType, type) { + if ( _progGroup && !_progGroup->isPortSupported(type) ) continue; + QString s = "- " + type.label() + ":"; + if ( !Port::isAvailable(type) ) { + log(Log::LineType::Normal, s + i18n(" support disabled.")); + continue; + } + QStringList list = Port::probedDeviceList(type); + if ( list.count()==0 ) log(Log::LineType::Normal, s + i18n(" no port detected.")); + else { + log(Log::LineType::Normal, s); + for (uint k=0; k<uint(list.count()); k++) log(Log::LineType::Normal, " " + list[k]); + } + } + return OK; +} + +CLI::ExitCode CLI::Main::rangeList() +{ + log(Log::LineType::Normal, i18n("Memory ranges for PIC/dsPIC devices:")); + FOR_EACH(Pic::MemoryRangeType, type) log(Log::LineType::Normal, QString(" %1").arg(type.key())); + return OK; +} + +CLI::ExitCode CLI::Main::prepareCommand(const QString &command) +{ + const CommandData *data = findCommandData(command); + CommandProperties properties = static_cast<CommandProperties>(data->properties); + if ( _device==0 && (properties & NeedDevice) ) return errorExit(i18n("Device not specified."), ARG_ERROR); + if ( _progGroup==0 && (properties & NeedProgrammer) ) return errorExit(i18n("Programmer not specified."), ARG_ERROR); + + if ( (properties & InputHex) || (properties & OutputHex) ) { + if ( _hexUrl.isEmpty() ) return errorExit(i18n("Hex filename not specified."), ARG_ERROR); + //if ( !_filename.isLocalFile() ) return errorExit(i18n("Only local files are supported."), ARG_ERROR); + PURL::File file(_hexUrl, *_view); + delete _memory; + _memory = 0; + if ( properties & NeedDevice ) _memory = _device->group().createMemory(*_device); + if ( properties & InputHex ) { + if (_memory) { + if ( !file.openForRead() ) return FILE_ERROR; + QStringList errors, warnings; + Device::Memory::WarningTypes warningTypes; + if ( !_memory->load(file.stream(), errors, warningTypes, warnings) ) + return errorExit(i18n("Could not load hex file \"%1\".").arg(errors[0]), FILE_ERROR); + if ( warningTypes!=Device::Memory::NoWarning ) + log(Log::LineType::Warning, i18n("Hex file seems incompatible with device \"%1\".").arg(warnings.join(" "))); + } + } else if ( properties & OutputHex ) { + if ( !_force && _hexUrl.exists() ) return errorExit(i18n("Output hex filename already exists."), FILE_ERROR); + } + } + + return OK; +} + +CLI::Main::Main() + : MainBase(HasForce | HasInteractiveMode) +{ + _range = new Device::MemoryRange; + Programmer::manager = new Programmer::CliManager(this); + Programmer::manager->setView(_view); + Debugger::manager = new Debugger::CliManager; +} + +CLI::Main::~Main() +{ + delete _range; +} + +CLI::ExitCode CLI::Main::list(const QString &command) +{ + if ( MainBase::list(command)==OK ) return OK; + if ( command=="format-list" ) return formatList(); + if ( command=="programmer-list" ) return programmerList(); + if ( command=="hardware-list" ) return hardwareList(); + if ( command=="port-list" ) return portList(); + if ( command=="device-list" ) return deviceList(); + if ( command=="range-list" ) return rangeList(); + Q_ASSERT(false); + return OK; +} + +CLI::ExitCode CLI::Main::prepareRun(bool &interactive) +{ + // argument + if ( _args->count()>1 ) return errorExit(i18n("Too many arguments."), ARG_ERROR); + if ( _args->count()==1 ) { + PURL::Url url(_args->url(0)); + ExitCode code = OK; + if ( url.fileType()==PURL::Hex ) code = executeSetCommand("hex", url.filepath()); + else if ( url.fileType()==PURL::Coff ) code = executeSetCommand("coff", url.filepath()); + else return errorExit(i18n("Argument file type not recognized."), ARG_ERROR); + if ( code!=OK ) return code; + } + + interactive = _args->isSet("cli"); + if (interactive) { + _interactive = new Interactive(this); + log(Log::LineType::Normal, i18n("Interactive mode: type help for help")); + log(Log::LineType::Normal, QString::null); +#if QT_VERSION<0x040000 + return ExitCode(qApp->exec()); +#else + return ExitCode(QCoreApplication::exec()); +#endif + } + + // range + if ( _args->isSet("range-list") ) return list("range-list"); + ExitCode code = extractRange(_args->getOption("range")); + if ( code!=OK ) return code; + + return OK; +} + +CLI::ExitCode CLI::Main::extractRange(const QString &range) +{ + delete _range; + _range = 0; + if ( !range.isEmpty() ) { + if ( _device==0 ) return errorExit(i18n("Cannot specify range without specifying device."), ARG_ERROR); + if ( _device->group().name()=="pic" ) { + FOR_EACH(Pic::MemoryRangeType, type) { + if ( range!=type.key() ) continue; + if ( !static_cast<const Pic::Data *>(_device)->isReadable(type) ) return errorExit(i18n("Memory range not present on this device."), ARG_ERROR); + _range = new Pic::MemoryRange(type); + break; + } + if ( _range==0 ) return errorExit(i18n("Memory range not recognized."), ARG_ERROR); + } else return errorExit(i18n("Memory ranges are not supported for the specified device."), ARG_ERROR); + } else _range = new Device::MemoryRange; + return OK; +} + +CLI::ExitCode CLI::Main::executeCommand(const QString &command) +{ + Programmer::Base *programmer = Programmer::manager->programmer(); + if ( command=="connect" ) return (Programmer::manager->connectDevice() ? OK : EXEC_ERROR); + if ( command=="disconnect" ) { + if ( programmer==0 || programmer->state()==Programmer::NotConnected ) + return okExit(i18n("Programmer is already disconnected.")); + return (Programmer::manager->disconnectDevice() ? OK : EXEC_ERROR); + } + if ( command=="run" ) { + if ( programmer && programmer->state()==Programmer::Running ) return okExit(i18n("Programmer is already running.")); + return (Programmer::manager->run() ? OK : EXEC_ERROR); + } + if ( command=="stop" ) { + if ( programmer && programmer->state()!=Programmer::Running ) return okExit(i18n("Programmer is already stopped.")); + return (Programmer::manager->halt() ? OK : EXEC_ERROR); + } + if ( command=="step" ) { + if ( !_progGroup->isDebugger() ) return errorExit(i18n("Debugging is not supported for specified programmer."), NOT_SUPPORTED_ERROR); + if ( programmer && programmer->state()==Programmer::Running ) return (Programmer::manager->halt() ? OK : EXEC_ERROR); + return (Programmer::manager->step() ? OK : EXEC_ERROR); + } + if ( command=="start" ) { + if ( !_progGroup->isDebugger() ) return errorExit(i18n("Debugging is not supported for specified programmer."), NOT_SUPPORTED_ERROR); + return (Programmer::manager->restart() ? OK : EXEC_ERROR); + } + if ( command=="program" ) { + if ( _progGroup->isSoftware() ) return errorExit(i18n("Reading device memory not supported for specified programmer."), NOT_SUPPORTED_ERROR); + return (Programmer::manager->program(*_memory, *_range) ? OK : EXEC_ERROR); + } + if ( command=="verify" ) { + if ( _progGroup->isSoftware() ) + return errorExit(i18n("Reading device memory not supported for specified programmer."), NOT_SUPPORTED_ERROR); + return (Programmer::manager->verify(*_memory, *_range) ? OK : EXEC_ERROR); + } + if ( command=="read" ) { + if ( _progGroup->isSoftware() ) + return errorExit(i18n("Reading device memory not supported for specified programmer."), NOT_SUPPORTED_ERROR); + if ( !Programmer::manager->read(*_memory, *_range) ) return EXEC_ERROR; + PURL::File file(_hexUrl, *_view); + if ( !file.openForWrite() ) return FILE_ERROR; + if ( !_memory->save(file.stream(), _format) ) + return errorExit(i18n("Error while writing file \"%1\".").arg(_hexUrl.pretty()), FILE_ERROR); + return OK; + } + if ( command=="erase" ) { + if ( _progGroup->isSoftware() ) + return errorExit(i18n("Erasing device memory not supported for specified programmer."), NOT_SUPPORTED_ERROR); + return (Programmer::manager->erase(*_range) ? OK : EXEC_ERROR); + } + if ( command=="blank_check" ) { + if ( _progGroup->isSoftware() ) + return errorExit(i18n("Blank-checking device memory not supported for specified programmer."), NOT_SUPPORTED_ERROR); + return (Programmer::manager->blankCheck(*_range) ? OK : EXEC_ERROR); + } + if ( command=="upload_firmware" ) { + if ( !(_progGroup->properties() & ::Programmer::CanUploadFirmware) ) + return errorExit(i18n("Uploading firmware is not supported for the specified programmer."), NOT_SUPPORTED_ERROR); + if ( Programmer::manager->programmer()==0 ) Programmer::manager->createProgrammer(0); // no device specified + return (Programmer::manager->programmer()->uploadFirmware(_hexUrl) ? OK : EXEC_ERROR); + } + Q_ASSERT(false); + return EXEC_ERROR; +} + +CLI::ExitCode CLI::Main::checkProgrammer() +{ + if ( _progGroup==0 ) return OK; + if ( _progGroup->isSoftware() && _progGroup->supportedDevices().isEmpty() ) + return errorExit(i18n("Please check installation of selected software debugger."), NOT_SUPPORTED_ERROR); + if ( _device && !_progGroup->isSupported(_device->name()) ) + return errorExit(i18n("The selected device \"%1\" is not supported by the selected programmer.").arg(_device->name()), NOT_SUPPORTED_ERROR); + if ( !_hardware.isEmpty() ) { + ::Hardware::Config *config = _progGroup->hardwareConfig(); + Port::Description pd = static_cast<Programmer::CliManager *>(Programmer::manager)->portDescription(); + bool ok = (config==0 || config->hardwareNames(pd.type).contains(_hardware)); + delete config; + if ( !ok ) return errorExit(i18n("The selected programmer does not supported the specified hardware configuration (\"%1\").").arg(_hardware), NOT_SUPPORTED_ERROR); + } + return OK; +} + +CLI::ExitCode CLI::Main::executeSetCommand(const QString &property, const QString &value) +{ + if ( property=="programmer" ) { + _progGroup = 0; + if ( value.isEmpty() ) return OK; + _progGroup = Programmer::lister().group(value.lower()); + if (_progGroup) return checkProgrammer(); + return errorExit(i18n("Unknown programmer \"%1\".").arg(value.lower()), ARG_ERROR); + } + if ( property=="hardware" ) { _hardware = value; return OK; } + if ( property=="device" || property=="processor" ) { + if ( value.isEmpty() ) { + _device = 0; + return OK; + } + QString s = value.upper(); + _device = Device::lister().data(s); + Debugger::manager->updateDevice(); + if ( _device==0 ) return errorExit(i18n("Unknown device \"%1\".").arg(s), ARG_ERROR); + Debugger::manager->init(); + return checkProgrammer(); + } + if ( property=="format" ) { + if ( value.isEmpty() ) { + _format = HexBuffer::IHX32; + return OK; + } + QString s = value.lower(); + for (uint i=0; i<HexBuffer::Nb_Formats; i++) + if ( s==HexBuffer::FORMATS[i] ) { + _format = HexBuffer::Format(i); + return OK; + } + return errorExit(i18n("Unknown hex file format \"%1\".").arg(s), ARG_ERROR); + } + if ( property=="port" ) { _port = value; return OK; } + if ( property=="firmware-dir" ) { _firmwareDir = value; return OK; } + if ( property=="target-self-powered" ) { _targetSelfPowered = value.lower(); return OK; } + if ( property=="hex" ) { + PURL::Url url = PURL::Url::fromPathOrUrl(value); + if ( url.isRelative() ) _hexUrl = PURL::Url(runDirectory(), value); + else _hexUrl = url; + return OK; + } + if ( property=="coff" ) { + PURL::Url url = PURL::Url::fromPathOrUrl(value); + if ( url.isRelative() ) _coffUrl = PURL::Url(runDirectory(), value); + else _coffUrl = url; + if ( _device && !Debugger::manager->init() ) return ARG_ERROR; + return OK; + } + return errorExit(i18n("Unknown property \"%1\"").arg(property), ARG_ERROR); +} + +QString CLI::Main::executeGetCommand(const QString &property) +{ + if ( property=="programmer" ) { + if ( _progGroup==0 ) return i18n("<not set>"); + return _progGroup->name(); + } + if ( property=="hardware" ) { + if ( !_hardware.isEmpty() ) return _hardware; + if ( _progGroup==0 ) return i18n("<not set>"); + Port::Description pd = static_cast<Programmer::CliManager *>(Programmer::manager)->portDescription(); + ::Hardware::Config *config = _progGroup->hardwareConfig(); + if (config) return config->currentHardware(pd.type) + " " + i18n("<from config>"); + delete config; + return i18n("<not set>"); + } + if ( property=="device" || property=="processor" ) { + if ( _device==0 ) return i18n("<not set>"); + return _device->name(); + } + if ( property=="format" ) return HexBuffer::FORMATS[_format]; + if ( property=="port" ) { + if ( !_port.isEmpty() ) return _port; + if ( _progGroup==0 ) return i18n("<not set>"); + Port::Description pd = Programmer::GroupConfig::portDescription(*_progGroup); + QString s = pd.type.key(); + if (pd.type.data().withDevice) s += " (" + pd.device + ")"; + return s + " " + i18n("<from config>"); + } + if ( property=="firmware-dir" ) { + if ( !_firmwareDir.isEmpty() ) return _firmwareDir.pretty(); + if ( _progGroup==0 ) return i18n("<not set>"); + return Programmer::GroupConfig::firmwareDirectory(*_progGroup) + " " + i18n("<from config>"); + } + if ( property=="target-self-powered" ) { + if ( !_targetSelfPowered.isEmpty() ) return _targetSelfPowered; + return QString(readConfigEntry(Programmer::Config::TargetSelfPowered).toBool() ? "true" : "false") + " " + i18n("<from config>"); + } + if ( property=="hex" ) { + if ( !_hexUrl.isEmpty() ) return _hexUrl.pretty(); + return i18n("<not set>"); + } + if ( property=="coff" ) { + if ( !_coffUrl.isEmpty() ) return _coffUrl.pretty(); + return i18n("<not set>"); + } + log(Log::LineType::SoftError, i18n("Unknown property \"%1\"").arg(property)); + return QString::null; +} + +//----------------------------------------------------------------------------- +int main(int argc, char **argv) +{ + CLI::Main main; + Piklab::AboutData *about = new Piklab::AboutData("piklab-prog", I18N_NOOP("Piklab Programmer Utility"), I18N_NOOP("Command-line programmer/debugger.")); + CLI::OptionList list = main.optionList(I18N_NOOP("Hex filename for programming.")); + Piklab::init(about, argc, argv, false, list.ptr()); + return main.doRun(); +} diff --git a/src/piklab-prog/cmdline.h b/src/piklab-prog/cmdline.h new file mode 100644 index 0000000..03d4091 --- /dev/null +++ b/src/piklab-prog/cmdline.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 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 CMDLINE_H +#define CMDLINE_H + +#include "common/cli/cli_main.h" +#include "cli_interactive.h" +#include "common/global/purl.h" +#include "devices/base/hex_buffer.h" +namespace Device { class Data; class Memory; class MemoryRange; } +namespace Programmer { class Base; class Group; } + +namespace CLI +{ +class Main : public MainBase +{ +Q_OBJECT +public: + Main(); + virtual ~Main(); + virtual ExitCode prepareRun(bool &interactive); + virtual ExitCode prepareCommand(const QString &command); + virtual ExitCode executeCommand(const QString &command); + virtual ExitCode executeSetCommand(const QString &property, const QString &value); + virtual QString executeGetCommand(const QString &property); + virtual ExitCode list(const QString &command); + ExitCode extractRange(const QString &range); + +private: + Device::MemoryRange *_range; + + ExitCode formatList(); + ExitCode programmerList(); + ExitCode hardwareList(); + ExitCode deviceList(); + ExitCode portList(); + ExitCode rangeList(); + ExitCode checkProgrammer(); +}; + +extern const Programmer::Group *_progGroup; +extern QString _hardware; +extern const Device::Data *_device; +extern HexBuffer::Format _format; +extern QString _port, _targetSelfPowered; +extern PURL::Directory _firmwareDir; +extern PURL::Url _hexUrl, _coffUrl; +extern Device::Memory *_memory; +extern Interactive *_interactive; + +} // namespace + +#endif diff --git a/src/piklab-prog/piklab-prog.pro b/src/piklab-prog/piklab-prog.pro new file mode 100644 index 0000000..bd70cb2 --- /dev/null +++ b/src/piklab-prog/piklab-prog.pro @@ -0,0 +1,32 @@ +STOPDIR = ../.. +include($${STOPDIR}/app.pro) + +TARGET = piklab-prog +HEADERS += cli_prog_manager.h cli_debug_manager.h cli_interactive.h cmdline.h +SOURCES += cli_prog_manager.cpp cli_debug_manager.cpp cli_interactive.cpp cmdline.cpp +LIBS += ../progs/manager/libprogmanager.a ../progs/list/libprogslist.a \ + ../progs/picdem_bootloader/base/libpicdem_bootloader.a ../progs/pickit2_bootloader/base/libpickit2_bootloader.a \ + ../progs/tbl_bootloader/base/libtbl_bootloader.a ../progs/bootloader/base/libbootloader.a \ + ../progs/pickit2v2/base/libpickit2v2.a \ + ../progs/gpsim/base/libgpsim.a \ + ../progs/psp/base/libpsp.a ../progs/pickit1/base/libpickit1.a \ + ../progs/pickit2/base/libpickit2.a ../progs/icd1/base/libicd1.a \ + ../progs/icd2/base/libicd2.a \ + ../progs/icd2/icd2_data/libicd2data.a ../progs/direct/base/libdirectprog.a \ + ../devices/pic/prog/libpicprog.a ../devices/mem24/prog/libmem24prog.a \ + ../progs/base/libprogbase.a ../common/port/libport.a ../coff/base/libcoff.a \ + ../devices/list/libdevicelist.a \ + ../devices/mem24/mem24/libmem24.a ../devices/mem24/xml_data/libmem24xml.a \ + ../devices/mem24/base/libmem24base.a \ + ../devices/pic/pic/libpic.a ../devices/pic/xml_data/libpicxml.a \ + ../devices/pic/base/libpicbase.a \ + ../devices/base/libdevicebase.a \ + ../common/cli/libcli.a ../common/global/libglobal.a \ + ../common/nokde/libnokde.a ../common/common/libcommon.a +contains(DEFINES, HAVE_USB) { + unix:LIBS += -lusb + win32:LIBS += $${LIBUSB_PATH}\lib\gcc\libusb.a +} +contains(DEFINES, HAVE_READLINE) { + unix:LIBS += -lhistory -lreadline -lcurses +} |