summaryrefslogtreecommitdiffstats
path: root/src/piklab-prog
diff options
context:
space:
mode:
Diffstat (limited to 'src/piklab-prog')
-rw-r--r--src/piklab-prog/Makefile.am31
-rw-r--r--src/piklab-prog/cli_debug_manager.cpp18
-rw-r--r--src/piklab-prog/cli_debug_manager.h34
-rw-r--r--src/piklab-prog/cli_interactive.cpp347
-rw-r--r--src/piklab-prog/cli_interactive.h53
-rw-r--r--src/piklab-prog/cli_prog_manager.cpp65
-rw-r--r--src/piklab-prog/cli_prog_manager.h38
-rw-r--r--src/piklab-prog/cli_purl.cpp29
-rw-r--r--src/piklab-prog/cmdline.cpp457
-rw-r--r--src/piklab-prog/cmdline.h59
-rw-r--r--src/piklab-prog/piklab-prog.pro32
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
+}