|
|
|
/***************************************************************************
|
|
|
|
* 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 "generic_prog.h"
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
|
|
|
|
#include "common/global/global.h"
|
|
|
|
#include "prog_group.h"
|
|
|
|
#include "prog_config.h"
|
|
|
|
#include "devices/base/device_group.h"
|
|
|
|
#include "generic_debug.h"
|
|
|
|
#include "hardware_config.h"
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
const double Programmer::UNKNOWN_VOLTAGE = -1.0;
|
|
|
|
|
|
|
|
const char * const Programmer::RESULT_TYPE_LABELS[Nb_ResultTypes+1] = {
|
|
|
|
I18N_NOOP("Pass"),
|
|
|
|
I18N_NOOP("Low"),
|
|
|
|
I18N_NOOP("High"),
|
|
|
|
I18N_NOOP("Fail"),
|
|
|
|
I18N_NOOP("---")
|
|
|
|
};
|
|
|
|
|
|
|
|
const Programmer::Task::Data Programmer::Task::DATA[Nb_Types] = {
|
|
|
|
{ 0, I18N_NOOP("Reading...") },
|
|
|
|
{ 0, I18N_NOOP("Programming...") },
|
|
|
|
{ 0, I18N_NOOP("Verifying...") },
|
|
|
|
{ 0, I18N_NOOP("Erasing...") },
|
|
|
|
{ 0, I18N_NOOP("Blank Checking...") }
|
|
|
|
};
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Programmer::Base::Base(const Group &group, const Device::Data *device, const char *)
|
|
|
|
: _hardware(0), _specific(0), _device(device), _debugger(group.createDebugger(*this)),
|
|
|
|
_state(NotConnected), _targetPowerOn(false), _group(group)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void Programmer::Base::init(bool targetSelfPowered, Hardware *hardware, DeviceSpecific *ds)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
_targetSelfPowered = targetSelfPowered;
|
|
|
|
_hardware = hardware;
|
|
|
|
_specific = ds;
|
|
|
|
}
|
|
|
|
|
|
|
|
Programmer::Base::~Base()
|
|
|
|
{
|
|
|
|
delete _debugger;
|
|
|
|
delete _specific;
|
|
|
|
delete _hardware;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::clear()
|
|
|
|
{
|
|
|
|
_firmwareVersion.clear();
|
|
|
|
_mode = NormalMode;
|
|
|
|
resetError();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::simpleConnectHardware()
|
|
|
|
{
|
|
|
|
Q_ASSERT(_hardware);
|
|
|
|
disconnectHardware();
|
|
|
|
clear();
|
|
|
|
if (_device) {
|
|
|
|
TQString label = _group.label();
|
|
|
|
if ( group().isSoftware() )
|
|
|
|
log(Log::LineType::Information, i18n("Connecting %1 with device %2...").tqarg(label).tqarg(_device->name()));
|
|
|
|
else {
|
|
|
|
if ( !_hardware->name().isEmpty() ) label += "[" + _hardware->name() + "]";
|
|
|
|
Port::Description pd = _hardware->portDescription();
|
|
|
|
TQString s = pd.type.label();
|
|
|
|
if (pd.type.data().withDevice) s += " (" + pd.device + ")";
|
|
|
|
log(Log::LineType::Information, i18n("Connecting %1 on %2 with device %3...").tqarg(label).tqarg(s).tqarg(_device->name()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _hardware->connectHardware();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::connectHardware()
|
|
|
|
{
|
|
|
|
_progressMonitor.insertTask(i18n("Connecting..."), 2);
|
|
|
|
log(Log::DebugLevel::Extra, "connect hardware");
|
|
|
|
if ( !simpleConnectHardware() ) return false;
|
|
|
|
_progressMonitor.addTaskProgress(1);
|
|
|
|
if ( !group().isSoftware() ) {
|
|
|
|
if ( !readFirmwareVersion() ) return false;
|
|
|
|
if ( _specific==0 ) return true;
|
|
|
|
if ( _mode==BootloadMode ) return true;
|
|
|
|
if ( !setupFirmware() ) return false;
|
|
|
|
if ( !checkFirmwareVersion() ) return false;
|
|
|
|
if ( !setTargetPowerOn(false) ) return false;
|
|
|
|
if ( !setTarget() ) return false;
|
|
|
|
log(Log::LineType::Information, i18n(" Set target self powered: %1").tqarg(_targetSelfPowered ? "true" : "false"));
|
|
|
|
if ( !setTargetPowerOn(!_targetSelfPowered) ) return false;
|
|
|
|
if ( !internalSetupHardware() ) return false;
|
|
|
|
if ( !readVoltages() ) return false;
|
|
|
|
if ( !selfTest(true) ) return false;
|
|
|
|
}
|
|
|
|
if ( hasError() ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Connected."));
|
|
|
|
_state = Stopped;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::disconnectHardware()
|
|
|
|
{
|
|
|
|
_state = NotConnected;
|
|
|
|
log(Log::DebugLevel::Extra, "disconnect hardware");
|
|
|
|
clear();
|
|
|
|
_hardware->disconnectHardware();
|
|
|
|
}
|
|
|
|
|
|
|
|
PURL::Directory Programmer::Base::firmwareDirectory()
|
|
|
|
{
|
|
|
|
if ( _firmwareDirectory.isEmpty() ) _firmwareDirectory = GroupConfig::firmwareDirectory(group());
|
|
|
|
PURL::Directory dir(_firmwareDirectory);
|
|
|
|
if ( !dir.exists() ) {
|
|
|
|
log(Log::LineType::Error, i18n("Firmware directory is not configured or does not exist."));
|
|
|
|
return PURL::Directory();
|
|
|
|
}
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::checkFirmwareVersion()
|
|
|
|
{
|
|
|
|
if ( _mode==BootloadMode ) log(Log::LineType::Information, i18n("Programmer is in bootload mode."));
|
|
|
|
if ( !_firmwareVersion.isValid() ) return true;
|
|
|
|
log(Log::LineType::Information, i18n("Firmware version is %1").tqarg(_firmwareVersion.pretty()));
|
|
|
|
VersionData vd = _firmwareVersion.toWithoutDot();
|
|
|
|
VersionData tmp = firmwareVersion(FirmwareVersionType::Max);
|
|
|
|
if ( tmp.isValid() && tmp.toWithoutDot()<vd ) {
|
|
|
|
VersionData mplab = mplabVersion(FirmwareVersionType::Max);
|
|
|
|
TQString s = (mplab.isValid() ? " " + i18n("MPLAB %1").tqarg(mplab.prettyWithoutDot()) : TQString());
|
|
|
|
log(Log::LineType::Warning, i18n("The firmware version (%1) is higher than the version tested with piklab (%2%3).\n"
|
|
|
|
"You may experience problems.").tqarg(_firmwareVersion.pretty()).tqarg(tmp.pretty()).tqarg(s));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
tmp = firmwareVersion(FirmwareVersionType::Min);
|
|
|
|
if ( tmp.isValid() && vd<tmp.toWithoutDot() ) {
|
|
|
|
VersionData mplab = mplabVersion(FirmwareVersionType::Min);
|
|
|
|
TQString s = (mplab.isValid() ? " " + i18n("MPLAB %1").tqarg(mplab.prettyWithoutDot()) : TQString());
|
|
|
|
log(Log::LineType::Warning, i18n("The firmware version (%1) is lower than the version tested with piklab (%2%3).\n"
|
|
|
|
"You may experience problems.").tqarg(_firmwareVersion.pretty()).tqarg(tmp.pretty()).tqarg(s));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
tmp = firmwareVersion(FirmwareVersionType::Recommended);
|
|
|
|
if ( tmp.isValid() && vd<tmp.toWithoutDot() ) {
|
|
|
|
VersionData mplab = mplabVersion(FirmwareVersionType::Recommended);
|
|
|
|
TQString s = (mplab.isValid() ? " " + i18n("MPLAB %1").tqarg(mplab.prettyWithoutDot()) : TQString());
|
|
|
|
log(Log::LineType::Warning, i18n("The firmware version (%1) is lower than the recommended version (%2%3).\n"
|
|
|
|
"It is recommended to upgrade the firmware.").tqarg(_firmwareVersion.pretty()).tqarg(tmp.pretty()).tqarg(s));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::enterMode(Mode mode)
|
|
|
|
{
|
|
|
|
log(Log::DebugLevel::Normal, mode==BootloadMode ? " Enter bootload mode" : " Enter normal mode");
|
|
|
|
if ( _mode==mode ) {
|
|
|
|
log(Log::DebugLevel::Normal, " Already in requested mode.");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if ( !internalEnterMode(mode) ) return false;
|
|
|
|
return ( _mode==mode );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::log(Log::LineType type, const TQString &message)
|
|
|
|
{
|
|
|
|
if ( type==Log::LineType::Error ) _state = NotConnected;
|
|
|
|
Log::Base::log(type, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::log(Log::DebugLevel level, const TQString &message)
|
|
|
|
{
|
|
|
|
Log::Base::log(level, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::setTargetPowerOn(bool on)
|
|
|
|
{
|
|
|
|
_targetPowerOn = on;
|
|
|
|
return _specific->setTargetPowerOn(on);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::appendTask(Task task, const Device::MemoryRange *range)
|
|
|
|
{
|
|
|
|
_progressMonitor.appendTask(task.label(), nbSteps(task, range));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::connectDevice()
|
|
|
|
{
|
|
|
|
_progressMonitor.clear();
|
|
|
|
bool ok = doConnectDevice();
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doConnectDevice()
|
|
|
|
{
|
|
|
|
if ( _state==NotConnected ) {
|
|
|
|
if ( !connectHardware() ) return false;
|
|
|
|
if ( !enterMode(NormalMode) ) return false;
|
|
|
|
if ( !verifyDeviceId() ) return false;
|
|
|
|
} else {
|
|
|
|
setTargetPowerOn(!_targetSelfPowered);
|
|
|
|
}
|
|
|
|
_state = Stopped;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::run()
|
|
|
|
{
|
|
|
|
emit actionMessage(i18n("Running..."));
|
|
|
|
_progressMonitor.clear();
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Run..."));
|
|
|
|
internalRun();
|
|
|
|
return !hasError();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::stop()
|
|
|
|
{
|
|
|
|
emit actionMessage(i18n("Breaking..."));
|
|
|
|
return internalStop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Programmer::Base::endProgramming()
|
|
|
|
{
|
|
|
|
if ( _state==Stopped && readConfigEntry(Config::PowerDownAfterProgramming).toBool() )
|
|
|
|
setTargetPowerOn(false);
|
|
|
|
if ( !(group().properties() & HasConnectedState) ) disconnectHardware();
|
|
|
|
_progressMonitor.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::uploadFirmware(const PURL::Url &url)
|
|
|
|
{
|
|
|
|
_progressMonitor.clear();
|
|
|
|
log(Log::DebugLevel::Normal, TQString(" Firmware file: %1").tqarg(url.pretty()));
|
|
|
|
Log::StringView sview;
|
|
|
|
PURL::File file(url, sview);
|
|
|
|
if ( !file.openForRead() ) {
|
|
|
|
log(Log::LineType::Error, i18n("Could not open firmware file \"%1\".").tqarg(url.pretty()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool ok = doUploadFirmware(file);
|
|
|
|
_firmwareVersion.clear();
|
|
|
|
if (ok) ok = readFirmwareVersion();
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doUploadFirmware(PURL::File &file)
|
|
|
|
{
|
|
|
|
emit actionMessage(i18n("Uploading firmware..."));
|
|
|
|
return internalUploadFirmware(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Programmer::Base::erase(const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
_progressMonitor.clear();
|
|
|
|
appendTask(Task::Erase, &range);
|
|
|
|
if ( readConfigEntry(Config::BlankCheckAfterErase).toBool() ) appendTask(Task::BlankCheck);
|
|
|
|
bool ok = doErase(range);
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doErase(const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkErase() ) return false;
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Erasing..."));
|
|
|
|
if ( !internalErase(range) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Erasing done"));
|
|
|
|
if ( readConfigEntry(Config::BlankCheckAfterErase).toBool() ) {
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Blank checking..."));
|
|
|
|
if ( !doVerify(BlankCheckVerify, range, 0) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Blank checking done."));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Programmer::Base::checkCanRead()
|
|
|
|
{
|
|
|
|
if ( !(group().properties() & CanReadMemory) ) {
|
|
|
|
log(Log::LineType::Error, i18n("The selected programmer cannot read device memory."));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::read(Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkCanRead() ) return false;
|
|
|
|
_progressMonitor.clear();
|
|
|
|
appendTask(Task::Read, &range);
|
|
|
|
bool ok = doRead(memory, range);
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doRead(Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkRead() ) return false;
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Reading device memory..."));
|
|
|
|
memory.clear();
|
|
|
|
if ( !internalRead(&memory, range, 0) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Reading done."));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Programmer::Base::program(const Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
_progressMonitor.clear();
|
|
|
|
appendTask(Task::Write, &range);
|
|
|
|
bool ok = doProgram(memory, range);
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doProgram(const Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkProgram(memory) ) return false;
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Programming device memory..."));
|
|
|
|
if ( !internalProgram(memory, range) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Programming successful."));
|
|
|
|
if ( group().isDebugger() && !_debugger->init() ) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Programmer::Base::verify(const Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkCanRead() ) return false;
|
|
|
|
_progressMonitor.clear();
|
|
|
|
appendTask(Task::Verify, &range);
|
|
|
|
bool ok = doVerify(memory, range);
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doVerify(VerifyAction action, const Device::MemoryRange &range, const Device::Memory *memory)
|
|
|
|
{
|
|
|
|
const Device::Memory *vmemory = memory;
|
|
|
|
if ( memory==0 ) {
|
|
|
|
Q_ASSERT( action & BlankCheckVerify );
|
|
|
|
vmemory = _device->group().createMemory(*_device);
|
|
|
|
}
|
|
|
|
VerifyData vdata(action, *vmemory);
|
|
|
|
bool ok = internalRead(0, range, &vdata);
|
|
|
|
if ( memory==0 ) delete vmemory;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doVerify(const Device::Memory &memory, const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkRead() ) return false;
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Verifying..."));
|
|
|
|
if ( !doVerify(NormalVerify, range, &memory) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Verifying successful."));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::blankCheck(const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkCanRead() ) return false;
|
|
|
|
_progressMonitor.clear();
|
|
|
|
appendTask(Task::BlankCheck, &range);
|
|
|
|
bool ok = doBlankCheck(range);
|
|
|
|
endProgramming();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Programmer::Base::doBlankCheck(const Device::MemoryRange &range)
|
|
|
|
{
|
|
|
|
if ( !checkRead() ) return false;
|
|
|
|
if ( !doConnectDevice() ) return false;
|
|
|
|
_progressMonitor.startNextTask();
|
|
|
|
log(Log::LineType::Information, i18n("Blank checking..."));
|
|
|
|
if ( !doVerify(BlankCheckVerify, range, 0) ) return false;
|
|
|
|
log(Log::LineType::Information, i18n("Blank checking successful."));
|
|
|
|
return true;
|
|
|
|
}
|