/*************************************************************************** * Copyright (C) 2005-2006 Nicolas Hadacek * * Copyright (C) 2002-2003 Stephen Landamore * * * * 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 "icd2.h" #include "common/global/global.h" #include "common/common/misc.h" #include "common/port/port_base.h" #include "icd2_data.h" #include "icd2_usb.h" //----------------------------------------------------------------------------- const uchar Icd2::TARGET_MODE_VALUES[Pic::Nb_TargetModes] = { 0x00, // stopped 0x01, // running 0x02 // in programming }; const char * const Icd2::RESET_MODE_VALUES[Pic::Nb_ResetModes] = { "00", // reset held "01" // reset released }; //----------------------------------------------------------------------------- const Icd2::Hardware::VoltageTypeData Icd2::Hardware::VOLTAGE_TYPE_DATA[Pic::Nb_VoltageTypes] = { { "37", 0.07988 }, // icd Vpp { "34", 0.03908 }, // target Vdd { "35", 0.07988 }, // target Vpp }; const char * const Icd2::Hardware::WRITE_MODE_VALUES[Pic::Nb_WriteModes] = { "00", // write only "01" // erase then write }; const int Icd2::TestData::RESULT_TYPE_VALUES[::Programmer::Nb_ResultTypes+1] = { 0x00, // pass 0x01, // low 0x80, // high -2, // not used -1 }; const char * const Icd2::TestData::VOLTAGE_LABELS[Nb_VoltageTypes] = { I18N_NOOP("Target Vdd"), I18N_NOOP("Module Vpp"), I18N_NOOP("MCLR ground"), I18N_NOOP("MCLR Vdd"), I18N_NOOP("MCLR Vpp") }; Icd2::TestData::TestData() { for (uint k=0; ksend("$7F00\x0D", 6); QString s; if ( !_port->receive(2, s) ) return false; if ( s!="02" ) { log(Log::LineType::Error, i18n("Unexpected answer ($7F00) from ICD2 (%1).").arg(s)); return false; } // ?? if ( !command("08", 2) ) return false; if ( _rx.mid(5, 2)!="00" ) { log(Log::LineType::Error, i18n("Unexpected answer (08) from ICD2 (%1).").arg(_rx)); return false; } return !hasError(); } bool Icd2::Hardware::sendCommand(const QString &s) { //format: QString cs = s.upper(); QString tx = "<"; tx += toHex(cs.length() + 6, 2); tx += cs; uchar chk = tx[1].latin1() + tx[2].latin1(); for (uint i=0; isend(a.data(), a.count()); } bool Icd2::Hardware::receiveResponse(const QString &command, uint responseSize, bool poll) { // format: [LLXX...CC] uint size = responseSize + 8; if ( poll && _port->type()==PortType::USB ) { if ( !static_cast(_port)->poll(size, _rx) ) return false; } else if ( !_port->receive(size, _rx, 180000) ) return false; // is 3 minutes enough ?? (we should really have an abort button here...) log(Log::DebugLevel::Extra, QString("received answer: '%1'").arg(_rx)); if ( size!=fromHex(_rx.mid(1, 2), 0) ) { log(Log::LineType::Error, i18n("Received length too short.")); return false; } if ( uint(_rx.length())!=size ) { log(Log::LineType::Error, i18n("Received string too short.")); return false; } if ( _rx[0]!='[' || _rx[size-1]!=']' ) { log(Log::LineType::Error, i18n("Malformed string received \"%1\"").arg(_rx)); return false; } if ( command.mid(0, 2)!=_rx.mid(3, 2) ) { log(Log::LineType::Error, i18n("Wrong return value (\"%1\"; was expecting \"%2\")") .arg(_rx.mid(3, 2)).arg(command.mid(0, 2))); return false; } // verify the checksum uchar chk = 0; for (uint i=1; itype()==PortType::Serial ? 2*nbBytesWord : 0x100); uint size = QMIN(maxSize, length-i); QString tmp; if ( _port->type()==PortType::USB ) { if ( !static_cast(_port)->dataReceive(size, tmp) ) return false; } else if ( !_port->receive(size, tmp) ) return false; s += tmp; i += size; } // treat data if ( s[0]!='{' || s[s.length()-1]!='}' ) { log(Log::LineType::Error, i18n("Invalid begin or end character for read block.")); return false; } log(Log::DebugLevel::Max, "received: " + s); data.resize(nbWords); Q_UINT8 chk = 0; for (uint i=0; i=0; k--) { data[i] = data[i] << 8; data[i] |= fromHex(ts.mid(2*k, 2), 0); chk += ts[2*k].latin1() + ts[2*k+1].latin1(); } } QString cs = s.mid(s.length()-3, 2); if ( chk!=fromHex(cs, 0) ) { log(Log::LineType::Error, i18n("Bad checksum for read block: %1 (%2 expected).").arg(cs).arg(toHex(chk, 2))); return false; } return true; } bool Icd2::Hardware::readMemory(Pic::MemoryRangeType type, uint wordOffset, Device::Array &data, const ::Programmer::VerifyData *vdata) { const char *r = readCommand(type); if ( r==0 ) return false; uint nbBytesWord = device().nbBytesWord(type); uint div = 2; if ( type==Pic::MemoryRangeType::Eeprom || nbBytesWord>=2 ) div = 1; uint inc = device().addressIncrement(type); Address start = device().range(type).start; // address uint todo = inc * data.count(); // address uint offset = inc * wordOffset; // address //qDebug("read size=%s div=%i nbBytes=%i", toHex(size, 8).data(), div, nbBytesWord); data.resize(0); do { uint size = QMIN(todo, uint(0x1000)); // addresses uint nb = size / inc; // word //qDebug("read %s start=%s size=%s", Pic::MEMORY_RANGE_TYPE_DATA[type].label, toHex(start+offset, 8).data(), toHex(nb, 8).data()); QString cmd = r + toHex(start+offset, 8) + toHex(nb/div, 8); if ( !command(cmd, 0) ) return false; Device::Array pdata; if ( !readBlock(nbBytesWord, nb, pdata) ) return false; if ( !receiveResponse(cmd, 0, false) ) return false; if (vdata) { for (uint i=0; i=0; k--) { //if ( i<10 || i>=nbWords-10 ) qDebug("send: %i-%i %s", i, k, ts.mid(2*k, 2).data()); s += ts.mid(2*k, 2); chk += ts[2*k].latin1() + ts[2*k+1].latin1(); } } s += toHex(chk, 2); s += "}"; log(Log::DebugLevel::Max, "send: " + s); // send data uint i = 0; while ( idescription().type==PortType::Serial ? 2*nbBytesWord : 0x100); if ( _port->description().type==PortType::Serial && i==0 ) maxSize = 1; uint size = QMIN(maxSize, s.length()-i); QByteArray a = toAscii(s); if ( _port->type()==PortType::USB ) { if ( !static_cast(_port)->dataSend(a.data()+i, size) ) return false; } else if ( !_port->send(a.data()+i, size) ) return false; i += size; } //qDebug("done sending %i words (chk=%s)", nbWords, toHex(chk, 2).data()); return true; } bool Icd2::Hardware::writeMemory(Pic::MemoryRangeType type, uint wordOffset, const Device::Array &data) { //qDebug("write memory: offset:%s nbWords:%s (size: %s)", toHex(wordOffset, 4).data(), toHex(nbWords, 4).data(), toHex(data.size(), 4).data()); const char *w = writeCommand(type); if ( w==0 ) return true; uint nbBytesWord = device().nbBytesWord(type); uint div = 2; if ( type==Pic::MemoryRangeType::Eeprom || nbBytesWord>=2 ) div = 1; uint inc = device().addressIncrement(type); Address start = device().range(type).start; // address uint todo = inc * data.count(); // address uint offset = inc * wordOffset; // address uint index = 0; //qDebug("write todo=%s div=%i nbBytes=%i dataSize=%i", toHex(todo, 8).data(), div, nbBytesWord, data.size()); do { uint size = QMIN(todo, uint(0x1000)); // address uint nb = size / inc; // word //qDebug("write %s start=%s nbWords=%s", Pic::MEMORY_RANGE_TYPE_DATA[type].label, toHex(start+offset, 8).data(), toHex(nb, 8).data()); QString cmd = w + toHex(start+offset+index, 8) + toHex(nb/div, 8); if ( !command(cmd, 0) ) return false; if ( !writeBlock(nbBytesWord, data, index/inc, nb) ) return false; if ( !receiveResponse(cmd, 0, false) ) return false; index += size; todo -= size; if ( type==Pic::MemoryRangeType::Code || type==Pic::MemoryRangeType::Eeprom ) _base.progressMonitor().addTaskProgress(nb); } while ( todo!=0 ); return true; } bool Icd2::Hardware::eraseAll() { setTargetReset(Pic::ResetHeld); if ( hasError() ) return false; if ( !sendCommand("29") ) return false; if ( !receiveResponse("29", 0, true) ) return false; // poll return true; } bool Icd2::Hardware::haltRun() { return command("2E", 0); } bool Icd2::Hardware::step() { return command("2F", 0); } bool Icd2::Hardware::resumeRun() { return command("30", 0); } bool Icd2::Hardware::setWriteMode(Pic::WriteMode mode) { return command(QString("4B") + WRITE_MODE_VALUES[mode], 0); } bool Icd2::Hardware::writeRegister(Address address, BitValue value, uint nbBytes) { QString cmd = "1B" + toHex(address, 8) + toHex(nbBytes, 8); if ( !command(cmd, 0) ) return false; Device::Array data(nbBytes); for (uint i=0; i