/***************************************************************************
* Copyright ( C ) 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 "pickit2v2.h"
# include "progs/base/prog_config.h"
# include "progs/icd2/base/microchip.h"
# include "pickit2v2_data.h"
//-----------------------------------------------------------------------------
const Pickit2V2 : : FamilyData * Pickit2V2 : : familyData ( const Pic : : Data & device )
{
for ( uint i = 0 ; FAMILY_DATA [ i ] . architecture ! = Pic : : Architecture : : Nb_Types ; i + + )
if ( FAMILY_DATA [ i ] . architecture = = device . architecture ( ) ) return & FAMILY_DATA [ i ] ;
Q_ASSERT ( false ) ;
return 0 ;
}
//-----------------------------------------------------------------------------
Pickit2V2 : : Hardware : : Hardware ( : : Programmer : : Base & base )
: : : Programmer : : PicHardware ( base , new USBPort ( base ) , TQString ( ) ) ,
_scriptBufferChecksum ( 0 ) , _deviceSet ( false )
{ }
bool Pickit2V2 : : Hardware : : internalConnectHardware ( )
{
return port ( ) . open ( ) ;
}
bool Pickit2V2 : : Hardware : : setTarget ( )
{
//setIcspSpeed(0); // #### ??
_fastProgramming = true ; // #### ??
uint checksum ;
if ( ! getScriptBufferChecksum ( checksum ) ) return false ;
if ( ! _deviceSet | | _scriptBufferChecksum ! = checksum ) {
if ( ! downloadScripts ( ) ) return false ;
}
_deviceSet = true ;
return true ;
}
bool Pickit2V2 : : Hardware : : readtqStatus ( ushort & status )
{
if ( ! port ( ) . command ( ReadtqStatus ) ) return false ;
Array a ;
if ( ! port ( ) . receive ( a ) ) return false ;
status = ( a [ 1 ] < < 8 ) + a [ 0 ] ;
return true ;
}
bool Pickit2V2 : : Hardware : : sendScript ( const ushort * script , uint length )
{
Array cmd ;
cmd [ 0 ] = ClearUploadBuffer ;
cmd [ 1 ] = ExecuteScript ;
cmd [ 2 ] = length ;
for ( uint i = 0 ; i < length ; i + + ) cmd [ 3 + i ] = script [ i ] ;
return port ( ) . command ( cmd ) ;
}
bool Pickit2V2 : : Hardware : : executeScript ( uint i )
{
Q_ASSERT ( i ! = 0 ) ;
const ScriptData & sdata = SCRIPT_DATA [ i - 1 ] ;
log ( Log : : DebugLevel : : Extra , TQString ( " execute script #%1: %2 " ) . tqarg ( i ) . tqarg ( sdata . name ) ) ;
return sendScript ( sdata . data , sdata . length ) ;
}
bool Pickit2V2 : : Hardware : : getScriptBufferChecksum ( uint & checksum )
{
if ( ! port ( ) . command ( ScriptBufferChecksum ) ) return false ;
Array array ;
if ( ! port ( ) . receive ( array ) ) return false ;
checksum = ( array [ 0 ] < < 24 ) + ( array [ 1 ] < < 16 ) + ( array [ 2 ] < < 8 ) + array [ 3 ] ;
log ( Log : : DebugLevel : : Extra , TQString ( " get script buffer checksum: %1 " ) . tqarg ( toHexLabel ( checksum , 8 ) ) ) ;
return true ;
}
bool Pickit2V2 : : Hardware : : downloadScript ( ScriptType type , uint i )
{
if ( i = = 0 ) return true ; // empty script
const ScriptData & sdata = SCRIPT_DATA [ i - 1 ] ;
log ( Log : : DebugLevel : : Max , TQString ( " download script #%1 ( \" %2 \" ) at position #%3 " )
. tqarg ( i - 1 ) . tqarg ( sdata . name ) . tqarg ( toHexLabel ( type , 2 ) ) ) ;
Array cmd ;
cmd [ 0 ] = DownloadScript ;
cmd [ 1 ] = type ;
cmd [ 2 ] = sdata . length ;
for ( uint k = 0 ; k < sdata . length ; k + + ) {
if ( ! _fastProgramming & & sdata . data [ k ] = = 0xAAE7 ) {
ushort next = sdata . data [ k + 1 ] ;
if ( ( next & 0xFF ) < 170 & & next ! = 0 ) {
cmd [ 3 + k ] = sdata . data [ k ] ;
cmd [ 3 + k + 1 ] = next + next / 2 ;
} else {
cmd [ 3 + k ] = DelayLong ;
cmd [ 3 + k + 1 ] = 2 ;
}
k + + ;
} else if ( ! _fastProgramming & & sdata . data [ k ] = = 0xAAE8 ) {
ushort next = sdata . data [ k + 1 ] ;
if ( ( next & 0xFF ) < 171 & & next ! = 0 ) {
cmd [ 3 + k ] = sdata . data [ k ] ;
cmd [ 3 + k + 1 ] = next + next / 2 ;
} else {
cmd [ 3 + k ] = DelayLong ;
cmd [ 3 + k + 1 ] = 0 ;
}
k + + ;
} else cmd [ 3 + k ] = sdata . data [ k ] ;
}
return port ( ) . command ( cmd ) ;
}
bool Pickit2V2 : : Hardware : : downloadScripts ( )
{
if ( ! port ( ) . command ( ClearDownloadBuffer ) ) return false ;
log ( Log : : DebugLevel : : Extra , " clear scripts buffer " ) ;
if ( ! port ( ) . command ( ClearScriptBuffer ) ) return false ;
log ( Log : : DebugLevel : : Extra , " download scripts " ) ;
const Data & d = data ( device ( ) . name ( ) ) ;
for ( uint i = 0 ; i < Nb_ScriptTypes ; i + + ) {
if ( i = = TestMemoryRead | | i = = ConfigErase ) continue ; // ### to get same checksum as pk2cmd
if ( ! downloadScript ( ScriptType ( i ) , d . scriptIndexes [ i ] ) ) return false ;
}
return getScriptBufferChecksum ( _scriptBufferChecksum ) ;
}
bool Pickit2V2 : : Hardware : : setTargetReset ( Pic : : ResetMode mode )
{
ushort script [ 1 ] ;
switch ( mode ) {
case Pic : : ResetHeld : script [ 0 ] = MclrGroundOn ; break ;
case Pic : : ResetReleased : script [ 0 ] = MclrGroundOff ; break ;
case Pic : : Nb_ResetModes : Q_ASSERT ( false ) ; return false ;
}
return sendScript ( script , 1 ) ;
}
bool Pickit2V2 : : Hardware : : setVddVoltage ( double value , double threshold )
{
ushort v = ushort ( tqRound ( 32.0 * value + 10.5 ) ) < < 6 ;
uchar vfault = uchar ( tqRound ( 256.0 * ( threshold * value ) / 5.0 ) ) ;
if ( vfault > 210 ) vfault = 210 ;
Array cmd ;
cmd [ 0 ] = SetVdd ;
cmd [ 1 ] = v & 0xFF ;
cmd [ 2 ] = v > > 8 ;
cmd [ 3 ] = vfault ;
return port ( ) . command ( cmd ) ;
}
bool Pickit2V2 : : Hardware : : setVppVoltage ( double value , double threshold )
{
Array cmd ;
cmd [ 0 ] = SetVpp ;
cmd [ 1 ] = 0x40 ;
cmd [ 2 ] = uchar ( tqRound ( 18.61 * value ) ) ;
cmd [ 3 ] = uchar ( tqRound ( 18.61 * value * threshold ) ) ;
return port ( ) . command ( cmd ) ;
}
bool Pickit2V2 : : Hardware : : setVddOn ( bool on )
{
log ( Log : : DebugLevel : : Extra , TQString ( " Vdd set to %1, self powered is %2 " ) . tqarg ( on ) . tqarg ( _base . isTargetSelfPowered ( ) ) ) ;
ushort script [ 2 ] ;
script [ 0 ] = ( on ? VddGroundOff : VddOff ) ;
if ( _base . isTargetSelfPowered ( ) ) script [ 1 ] = ( on ? VddOff : VddGroundOff ) ;
else script [ 1 ] = ( on ? VddOn : VddGroundOn ) ;
return sendScript ( script , 2 ) ;
}
bool Pickit2V2 : : Hardware : : setIcspSpeed ( uchar speed )
{
ushort script [ 2 ] ;
script [ 0 ] = SetIcspSpeed ;
script [ 1 ] = speed ;
return sendScript ( script , 2 ) ;
}
bool Pickit2V2 : : Hardware : : getMode ( VersionData & version , : : Programmer : : Mode & mode )
{
if ( ! port ( ) . command ( FirmwareVersion ) ) return false ;
Array data ;
if ( ! port ( ) . receive ( data ) ) return false ;
if ( data [ 0 ] = = ' B ' ) {
mode = : : Programmer : : BootloadMode ;
version = VersionData ( ) ;
} else {
mode = : : Programmer : : NormalMode ;
version = VersionData ( data [ 0 ] , data [ 1 ] , data [ 2 ] ) ;
}
return true ;
}
bool Pickit2V2 : : Hardware : : readVoltages ( VoltagesData & voltagesData )
{
if ( ! port ( ) . command ( ReadVoltages ) ) return false ;
Array array ;
if ( ! port ( ) . receive ( array ) ) return false ;
double vadc = 256 * array [ 1 ] + array [ 0 ] ;
voltagesData [ Pic : : TargetVdd ] . value = 5.0 * ( vadc / 65536 ) ;
voltagesData [ Pic : : TargetVdd ] . error = false ;
vadc = 256 * array [ 3 ] + array [ 2 ] ;
voltagesData [ Pic : : TargetVpp ] . value = 13.7 * ( vadc / 65536 ) ;
voltagesData [ Pic : : TargetVpp ] . error = false ;
return true ;
}
bool Pickit2V2 : : Hardware : : downloadAddress ( Address address )
{
log ( Log : : DebugLevel : : Max , TQString ( " download address %1 " ) . tqarg ( toHexLabel ( address , 6 ) ) ) ;
Array cmd ;
cmd [ 0 ] = ClearDownloadBuffer ;
cmd [ 1 ] = DownloadData ;
cmd [ 2 ] = 3 ;
cmd [ 3 ] = address . toUInt ( ) & 0xFF ;
cmd [ 4 ] = ( address . toUInt ( ) > > 8 ) & 0xFF ;
cmd [ 5 ] = ( address . toUInt ( ) > > 16 ) & 0xFF ;
return port ( ) . command ( cmd ) ;
}
bool Pickit2V2 : : Hardware : : runScript ( ScriptType stype , uint repetitions , uint nbNoLens )
{
log ( Log : : DebugLevel : : Max , TQString ( " run script %1: repetitions=%2 nbNoLen=%3 " )
. tqarg ( toHexLabel ( stype , 2 ) ) . tqarg ( repetitions ) . tqarg ( nbNoLens ) ) ;
#if 0 // ALTERNATE METHOD
const Data & d = data ( device ( ) . name ( ) ) ;
for ( uint i = 0 ; i < repetitions ; i + + )
if ( ! executeScript ( d . scriptIndexes [ stype ] ) ) return false ;
if ( nbNoLens ) {
Array cmd ;
for ( uint i = 0 ; i < nbNoLens ; i + + ) cmd [ i ] = UploadDataNoLen ;
if ( ! port ( ) . command ( cmd ) ) return false ;
}
# else
Array cmd ;
cmd [ 0 ] = ClearUploadBuffer ;
cmd [ 1 ] = RunScript ;
cmd [ 2 ] = stype ;
cmd [ 3 ] = repetitions ;
for ( uint i = 0 ; i < nbNoLens ; i + + ) cmd [ 4 + i ] = UploadDataNoLen ;
if ( ! port ( ) . command ( cmd ) ) return false ;
# endif
if ( stype = = ProgExit & & ! setTargetReset ( Pic : : ResetReleased ) ) return false ;
return true ;
}
bool Pickit2V2 : : Hardware : : prepareRead ( Pic : : MemoryRangeType type , uint wordIndex )
{
ScriptType stype = prepareReadScript ( type ) ;
if ( type ! = Pic : : MemoryRangeType : : Cal & & ( stype = = Nb_ScriptTypes | | data ( device ( ) . name ( ) ) . scriptIndexes [ stype ] = = 0 ) ) return true ;
switch ( type . type ( ) ) {
case Pic : : MemoryRangeType : : Code :
if ( ! device ( ) . architecture ( ) . data ( ) . hasAddressAccess ) return true ;
if ( ! downloadAddress ( 0x10000 * ( wordIndex / 0x8000 ) ) ) return false ;
break ;
case Pic : : MemoryRangeType : : Eeprom :
if ( device ( ) . nbBytesWord ( Pic : : MemoryRangeType : : Eeprom ) = = 4 ) {
if ( ! downloadAddress ( device ( ) . range ( Pic : : MemoryRangeType : : Eeprom ) . start . toUInt ( ) ) ) return false ; // #### correct ?
} else if ( ! downloadAddress ( 0x0 ) ) return false ;
break ;
case Pic : : MemoryRangeType : : Config : return true ; // ConfigPrepareRead unused (?)
case Pic : : MemoryRangeType : : UserId : break ;
case Pic : : MemoryRangeType : : Cal : {
Address start = device ( ) . range ( Pic : : MemoryRangeType : : Cal ) . start ;
Q_ASSERT ( start = = device ( ) . range ( Pic : : MemoryRangeType : : Code ) . end + 1 ) ;
return downloadAddress ( start . toUInt ( ) ) ;
}
default : return true ;
case Pic : : MemoryRangeType : : Nb_Types : Q_ASSERT ( false ) ; return false ;
}
return runScript ( stype ) ;
}
bool Pickit2V2 : : Hardware : : readMemory ( Pic : : MemoryRangeType otype , Device : : Array & data , const : : Programmer : : VerifyData * vdata )
{
uint nbWords = device ( ) . nbWords ( otype ) ;
data . resize ( nbWords ) ;
log ( Log : : DebugLevel : : Max , TQString ( " read %1 nbWords=%2 " ) . tqarg ( otype . label ( ) ) . tqarg ( nbWords ) ) ;
uint nbBytesWord = device ( ) . nbBytesWord ( otype ) ;
// EEPROM is read like regular program memory in midrange
if ( ! device ( ) . is18Family ( ) & & ! device ( ) . is16bitFamily ( ) & & otype = = Pic : : MemoryRangeType : : Eeprom ) nbBytesWord = 2 ;
uint wordOffset = 0 ;
Pic : : MemoryRangeType type = otype ;
if ( otype = = Pic : : MemoryRangeType : : Config & & device ( ) . range ( Pic : : MemoryRangeType : : Config ) . start = = device ( ) . range ( Pic : : MemoryRangeType : : Code ) . end + 1 ) { // config in code memory
wordOffset = device ( ) . range ( Pic : : MemoryRangeType : : Config ) . start . toUInt ( ) ;
type = Pic : : MemoryRangeType : : Code ;
}
bool setAddress = true ;
ScriptType stype = readScript ( type ) ;
Q_ASSERT ( stype ! = Nb_ScriptTypes ) ;
const FamilyData * fdata = familyData ( device ( ) ) ;
uint nbRunWords = TQMIN ( UploadBufferNbBytes / nbBytesWord , nbWords ) ;
uint nbRuns = 1 ;
uint nbReceive = ( nbRunWords * nbBytesWord + 63 ) / 64 ;
switch ( type . type ( ) ) {
case Pic : : MemoryRangeType : : Code : nbRuns = nbRunWords / Pickit2V2 : : data ( device ( ) . name ( ) ) . codeMemoryNbReadWords ; break ;
case Pic : : MemoryRangeType : : Eeprom : nbRuns = nbRunWords / Pickit2V2 : : data ( device ( ) . name ( ) ) . eepromMemoryNbReadWords ; break ;
default : break ;
}
if ( ! runScript ( ProgEntry ) ) return false ;
for ( uint i = 0 ; i < nbWords ; ) {
if ( setAddress ) {
setAddress = false ;
if ( ! prepareRead ( type , wordOffset + i ) ) return false ;
}
TQValueVector < uint > words ;
if ( type = = Pic : : MemoryRangeType : : Config | | type = = Pic : : MemoryRangeType : : Cal ) {
if ( ! runScript ( stype , 1 , 0 ) ) return false ;
if ( ! port ( ) . command ( UploadData ) ) return false ;
// config memory return includes a length byte that we need to ignore
if ( ! port ( ) . receiveWords ( nbBytesWord , nbReceive , words , 1 ) ) return false ;
} else {
if ( ! runScript ( stype , nbRuns , nbReceive ) ) return false ;
if ( ! port ( ) . receiveWords ( nbBytesWord , nbReceive , words ) ) return false ;
}
log ( Log : : DebugLevel : : Max , TQString ( " nbRunWords=%1 readNbWords=%2 index=%3/%4 " ) . tqarg ( nbRunWords ) . tqarg ( words . count ( ) ) . tqarg ( i ) . tqarg ( nbWords ) ) ;
for ( uint k = 0 ; k < words . count ( ) ; k + + ) {
if ( i > = nbWords ) break ;
data [ i ] = words [ k ] ;
if ( fdata - > progMemShift ) data [ i ] > > = 1 ;
data [ i ] = data [ i ] . maskWith ( device ( ) . mask ( type ) ) ; // ### correct ?
if ( vdata & & ! verifyWord ( i , data [ i ] , type , * vdata ) ) return false ;
if ( type = = Pic : : MemoryRangeType : : Code & & i ! = 0x0 & & i % 0x8000 = = 0 ) setAddress = true ;
i + + ;
}
}
if ( ! runScript ( ProgExit ) ) return false ;
return true ;
}
bool Pickit2V2 : : Hardware : : eraseAll ( )
{
const Data & d = data ( device ( ) . name ( ) ) ;
if ( d . scriptIndexes [ ConfigErase ] ! = 0 ) {
if ( ! runScript ( ProgEntry ) ) return false ;
if ( d . scriptIndexes [ ConfigWritePrepare ] ! = 0 ) {
if ( ! downloadAddress ( 0 ) ) return false ;
if ( ! runScript ( ConfigWritePrepare ) ) return false ;
}
if ( ! runScript ( ConfigErase ) ) return false ;
if ( ! runScript ( ProgExit ) ) return false ;
}
if ( ! runScript ( ProgEntry ) ) return false ;
if ( d . scriptIndexes [ EraseChipPrepare ] ! = 0 & & ! runScript ( EraseChipPrepare ) ) return false ;
if ( ! runScript ( ChipErase ) ) return false ;
if ( ! runScript ( ProgExit ) ) return false ;
return true ;
}
bool Pickit2V2 : : Hardware : : eraseRange ( Pic : : MemoryRangeType type )
{
if ( type = = Pic : : MemoryRangeType : : Code ) {
if ( ! runScript ( ProgEntry ) ) return false ;
if ( ! runScript ( ProgMemoryErase ) ) return false ;
if ( ! runScript ( ProgExit ) ) return false ;
return true ;
}
if ( type = = Pic : : MemoryRangeType : : Eeprom ) {
if ( ! runScript ( ProgEntry ) ) return false ;
if ( ! runScript ( EepromErase ) ) return false ;
if ( ! runScript ( ProgExit ) ) return false ;
return true ;
}
Q_ASSERT ( false ) ;
return false ;
}
bool Pickit2V2 : : Hardware : : prepareWrite ( Pic : : MemoryRangeType type , uint wordIndex )
{
ScriptType stype = prepareWriteScript ( type ) ;
if ( stype = = Nb_ScriptTypes | | data ( device ( ) . name ( ) ) . scriptIndexes [ stype ] = = 0 ) return true ;
switch ( type . type ( ) ) {
case Pic : : MemoryRangeType : : Code :
case Pic : : MemoryRangeType : : Config :
if ( ! device ( ) . architecture ( ) . data ( ) . hasAddressAccess ) return true ;
if ( ! downloadAddress ( 0x10000 * ( wordIndex / 0x8000 ) ) ) return false ;
break ;
case Pic : : MemoryRangeType : : Eeprom : {
Address address = ( device ( ) . nbBytesWord ( Pic : : MemoryRangeType : : Eeprom ) = = 4 ? device ( ) . range ( Pic : : MemoryRangeType : : Eeprom ) . start : 0x000000 ) ;
if ( ! downloadAddress ( address ) ) return false ;
break ;
}
case Pic : : MemoryRangeType : : UserId : break ;
default : return true ;
case Pic : : MemoryRangeType : : Nb_Types : Q_ASSERT ( false ) ; return false ;
}
return runScript ( stype ) ;
}
bool Pickit2V2 : : Hardware : : writeMemory ( Pic : : MemoryRangeType otype , const Device : : Array & data , bool force )
{
Q_UNUSED ( force ) ;
return false ; // ### TODO
}
//-----------------------------------------------------------------------------
bool Pickit2V2 : : DeviceSpecific : : canEraseRange ( Pic : : MemoryRangeType type ) const
{
const Data & d = data ( device ( ) . name ( ) ) ;
if ( type = = Pic : : MemoryRangeType : : Code ) return d . scriptIndexes [ ProgMemoryErase ] ;
if ( type = = Pic : : MemoryRangeType : : Eeprom ) return d . scriptIndexes [ EepromErase ] ;
return false ;
}
bool Pickit2V2 : : DeviceSpecific : : canReadRange ( Pic : : MemoryRangeType type ) const
{
const Data & d = data ( device ( ) . name ( ) ) ;
if ( type = = Pic : : MemoryRangeType : : Cal ) return d . scriptIndexes [ OsccalRead ] ;
return true ;
}
bool Pickit2V2 : : DeviceSpecific : : canWriteRange ( Pic : : MemoryRangeType type ) const
{
const Data & d = data ( device ( ) . name ( ) ) ;
if ( type = = Pic : : MemoryRangeType : : Cal ) return d . scriptIndexes [ OsccalWrite ] ;
return true ;
}
bool Pickit2V2 : : DeviceSpecific : : doWrite ( Pic : : MemoryRangeType type , const Device : : Array & data , bool force )
{
Q_ASSERT ( data . size ( ) = = device ( ) . nbWords ( type ) ) ;
return hardware ( ) . writeMemory ( type , data , force ) ;
}