You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
14 KiB
440 lines
14 KiB
/***************************************************************************
|
|
* Copyright (C) 2003-2005 by David Saxton *
|
|
* david@bluehaze.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. *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#ifndef NO_GPSIM
|
|
|
|
#include "canvasitemparts.h"
|
|
#include "circuitdocument.h"
|
|
#include "docmanager.h"
|
|
#include "gpsimprocessor.h"
|
|
#include "libraryitem.h"
|
|
#include "logic.h"
|
|
#include "ktechlab.h"
|
|
#include "micropackage.h"
|
|
#include "picinfo.h"
|
|
#include "microlibrary.h"
|
|
#include "piccomponent.h"
|
|
#include "piccomponentpin.h"
|
|
#include "projectmanager.h"
|
|
|
|
#include <kdebug.h>
|
|
#include <kiconloader.h>
|
|
#include <tdelocale.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tqguardedptr.h>
|
|
#include <tqstringlist.h>
|
|
|
|
#include "gpsim/ioports.h"
|
|
#include "gpsim/pic-processor.h"
|
|
|
|
const TQString _def_PICComponent_fileName = i18n("<Enter location of PIC Program>");
|
|
|
|
|
|
Item* PICComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new PICComponent( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
|
|
LibraryItem* PICComponent::libraryItem()
|
|
{
|
|
TQStringList IDs;
|
|
IDs << "ec/pic" << "ec/picitem" << "ec/picitem_18pin";
|
|
|
|
return new LibraryItem(
|
|
IDs,
|
|
"PIC",
|
|
i18n("Integrated Circuits"),
|
|
"ic2.png",
|
|
LibraryItem::lit_component,
|
|
PICComponent::construct );
|
|
}
|
|
|
|
PICComponent::PICComponent( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Component( icnDocument, newItem, id ? id : "pic" )
|
|
{
|
|
m_name = i18n("PIC Micro");
|
|
m_desc = i18n("The PIC component allows the simulation of a PIC program.<br><br>"
|
|
"The loadable PIC program must be one of the following formats:"
|
|
"<ul><li>Assembly (.asm)</li>"
|
|
"<li>FlowCode (.flowcode)</li>"
|
|
"<li>Symbol file (.cod)</li>"
|
|
"<li>Microbe (.microbe, .basic)</li>"
|
|
"<li>C source (.c)</li></ul>"
|
|
"Doubleclick on the PIC component to open up the program source file.<br><br>"
|
|
"If the program source file is of type assembly, then the the opened text file will automatically be linked to the simulation. "
|
|
"You can control the program from the text document using the debug controls.<br><br>"
|
|
"Explanation of buttons:"
|
|
"<ul><li>Play - Run the PIC program from the point at which it was paused, or from the start otherwise.</li>"
|
|
"<li>Pause - Pause the simulation at the current execution point.</li>"
|
|
"<li>Stop - Reset all parts of the simulation.</li>"
|
|
"<li>Reload - Reread the PIC program from disk and restart gpsim.</li></ul>");
|
|
|
|
m_bCreatedInitialPackage = false;
|
|
m_bLoadingProgram = false;
|
|
m_pGpsim = 0L;
|
|
|
|
addButton( "run", TQRect(), TDEGlobal::iconLoader()->loadIcon( "media-playback-start", TDEIcon::Small ) );
|
|
addButton( "pause", TQRect(), TDEGlobal::iconLoader()->loadIcon( "media-playback-pause", TDEIcon::Small ) );
|
|
addButton( "reset", TQRect(), TDEGlobal::iconLoader()->loadIcon( "process-stop", TDEIcon::Small ) );
|
|
addButton( "reload", TQRect(), TDEGlobal::iconLoader()->loadIcon( "reload", TDEIcon::Small ) );
|
|
|
|
if ( icnDocument->ktechlab() )
|
|
connect( icnDocument->ktechlab(), TQT_SIGNAL(recentFileAdded(const KURL &)), this, TQT_SLOT(slotUpdateFileList()) );
|
|
|
|
connect( ProjectManager::self(), TQT_SIGNAL(projectOpened()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
connect( ProjectManager::self(), TQT_SIGNAL(projectClosed()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
connect( ProjectManager::self(), TQT_SIGNAL(projectCreated()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
connect( ProjectManager::self(), TQT_SIGNAL(subprojectCreated()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
connect( ProjectManager::self(), TQT_SIGNAL(filesAdded()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
connect( ProjectManager::self(), TQT_SIGNAL(filesRemoved()), this, TQT_SLOT(slotUpdateFileList()) );
|
|
|
|
createProperty( "program", Variant::Type::FileName );
|
|
property("program")->setCaption( i18n("Program") );
|
|
property("program")->setFilter("*.flowcode *.asm *.cod *.basic|All Supported Files\n*.flowcode|FlowCode (*.flowcode)\n*.cod|Symbol File (*.cod)\n*.asm|Assembly Code (*.asm)\n*.basic *.microbe|Microbe (*.basic, *.microbe)\n*.c|C (*.c)*|All Files");
|
|
|
|
// Used for restoring the pins on file loading before we have had a change
|
|
// to compile the PIC program
|
|
createProperty( "lastPackage", Variant::Type::String );
|
|
property("lastPackage")->setHidden( true );
|
|
|
|
// //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage"
|
|
// // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3
|
|
// // behaviour), but it will also load it if
|
|
|
|
// This to allow loading of the PIC component from pre-0.3 files (which didn't set a
|
|
// "lastPackage" property).
|
|
if ( !newItem )
|
|
property("lastPackage")->setValue("P16F84");
|
|
|
|
slotUpdateFileList();
|
|
slotUpdateBtns();
|
|
|
|
initPackage( 0 );
|
|
}
|
|
|
|
|
|
PICComponent::~PICComponent()
|
|
{
|
|
deletePICComponentPins();
|
|
delete m_pGpsim;
|
|
}
|
|
|
|
|
|
void PICComponent::dataChanged()
|
|
{
|
|
initPIC(false);
|
|
}
|
|
|
|
|
|
void PICComponent::initPIC( bool forceReload )
|
|
{
|
|
if ( !m_bCreatedInitialPackage )
|
|
{
|
|
// We are still being created, so other connectors will be expecting us to
|
|
// have grown pins soonish.
|
|
MicroInfo * microInfo = MicroLibrary::self()->microInfoWithID( dataString("lastPackage") );
|
|
if ( microInfo )
|
|
initPackage( microInfo );
|
|
}
|
|
|
|
TQString newProgram = KURL( dataString("program") ).path();
|
|
bool newFile = (m_picFile != newProgram);
|
|
if ( !newFile && !forceReload )
|
|
return;
|
|
|
|
delete m_pGpsim;
|
|
m_pGpsim = 0L;
|
|
|
|
switch ( GpsimProcessor::isValidProgramFile(newProgram) )
|
|
{
|
|
case GpsimProcessor::DoesntExist:
|
|
if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() )
|
|
break;
|
|
KMessageBox::sorry( 0l, i18n("The file \"%1\" does not exist.").arg( newProgram ) );
|
|
m_picFile = TQString();
|
|
break;
|
|
|
|
case GpsimProcessor::IncorrectType:
|
|
if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() )
|
|
break;
|
|
KMessageBox::sorry( 0L, i18n("\"%1\" is not a valid PIC program.\nThe file must exist, and the extension should be \".cod\", \".asm\", \".flowcode\", \".basic\", \".microbe\" or \".c\".\n\".hex\" is allowed, provided that there is a corresponding \".cod\" file.").arg(newProgram) );
|
|
m_picFile = TQString();
|
|
break;
|
|
|
|
case GpsimProcessor::Valid:
|
|
m_picFile = newProgram;
|
|
m_symbolFile = createSymbolFile();
|
|
break;
|
|
}
|
|
|
|
slotUpdateBtns();
|
|
}
|
|
|
|
|
|
void PICComponent::deletePICComponentPins()
|
|
{
|
|
const PICComponentPinMap::iterator picComponentMapEnd = m_picComponentPinMap.end();
|
|
for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != picComponentMapEnd; ++it )
|
|
delete it.data();
|
|
m_picComponentPinMap.clear();
|
|
}
|
|
|
|
|
|
void PICComponent::initPackage( MicroInfo * microInfo )
|
|
{
|
|
MicroPackage * microPackage = microInfo ? microInfo->package() : 0l;
|
|
|
|
if ( microPackage )
|
|
{
|
|
m_bCreatedInitialPackage = true;
|
|
|
|
//BEGIN Get pin IDs
|
|
TQStringList allPinIDs = microPackage->pinIDs();
|
|
TQStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
|
|
|
|
// Now, we make the unwanted pin ids blank, so a pin is not created for them
|
|
const TQStringList::iterator allPinIDsEnd = allPinIDs.end();
|
|
for ( TQStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it )
|
|
{
|
|
if ( !ioPinIDs.contains(*it) )
|
|
*it = "";
|
|
}
|
|
//END Get pin IDs
|
|
|
|
|
|
//BEGIN Remove old stuff
|
|
// Remove old text
|
|
TextMap textMapCopy = m_textMap;
|
|
const TextMap::iterator textMapEnd = textMapCopy.end();
|
|
for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it )
|
|
removeDisplayText(it.key());
|
|
|
|
// Remove the old pins
|
|
deletePICComponentPins();
|
|
|
|
// Remove old nodes
|
|
NodeMap nodeMapCopy = m_nodeMap;
|
|
const NodeMap::iterator nodeMapEnd = nodeMapCopy.end();
|
|
for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it )
|
|
{
|
|
if ( !ioPinIDs.contains(it.key()) )
|
|
removeNode( it.key() );
|
|
}
|
|
|
|
removeElements();
|
|
//END Remove old stuff
|
|
|
|
|
|
|
|
//BEGIN Create new stuff
|
|
initDIPSymbol( allPinIDs, 80 );
|
|
initDIP(allPinIDs);
|
|
|
|
PicPinMap picPinMap = microPackage->pins( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
|
|
const PicPinMap::iterator picPinMapEnd = picPinMap.end();
|
|
for ( PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it )
|
|
m_picComponentPinMap[it.key()] = new PICComponentPin( this, it.data() );
|
|
//END Create new stuff
|
|
|
|
|
|
removeDisplayText( "no_file" );
|
|
addDisplayText( "picid", TQRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() );
|
|
}
|
|
else
|
|
{
|
|
setSize( -48, -72, 96, 144 );
|
|
removeDisplayText( "picid" );
|
|
addDisplayText( "no_file", sizeRect(), i18n("(No\nprogram\nloaded)") );
|
|
}
|
|
|
|
|
|
//BEGIN Update button positions
|
|
int leftpos = (width()-88)/2+offsetX();
|
|
button("run")->setOriginalRect( TQRect( leftpos, height()+4+offsetY(), 20, 20 ) );
|
|
button("pause")->setOriginalRect( TQRect( leftpos+23, height()+4+offsetY(), 20, 20 ) );
|
|
button("reset")->setOriginalRect( TQRect( leftpos+46, height()+4+offsetY(), 20, 20 ) );
|
|
button("reload")->setOriginalRect( TQRect( leftpos+69, height()+4+offsetY(), 20, 20 ) );
|
|
updateAttachedPositioning();
|
|
//END Update button positions
|
|
}
|
|
|
|
|
|
void PICComponent::attachPICComponentPins()
|
|
{
|
|
if ( !m_pGpsim || !m_pGpsim->picProcessor() )
|
|
return;
|
|
|
|
pic_processor * picProcessor = m_pGpsim->picProcessor();
|
|
|
|
const PICComponentPinMap::iterator end = m_picComponentPinMap.end();
|
|
for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it )
|
|
it.data()->attach( picProcessor->get_pin( it.key() ) );
|
|
}
|
|
|
|
|
|
void PICComponent::slotUpdateFileList()
|
|
{
|
|
TQStringList preFileList;
|
|
if ( p_icnDocument && p_icnDocument->ktechlab() )
|
|
preFileList += p_icnDocument->ktechlab()->recentFiles();
|
|
|
|
TQStringList fileList;
|
|
|
|
if ( ProjectInfo * info = ProjectManager::self()->currentProject() )
|
|
{
|
|
const KURL::List urls = info->childOutputURLs( ProjectItem::AllTypes, ProjectItem::ProgramOutput );
|
|
KURL::List::const_iterator urlsEnd = urls.end();
|
|
for ( KURL::List::const_iterator it = urls.begin(); it != urlsEnd; ++it )
|
|
fileList << (*it).path();
|
|
}
|
|
|
|
const TQStringList::iterator end = preFileList.end();
|
|
for ( TQStringList::iterator it = preFileList.begin(); it != end; ++it )
|
|
{
|
|
TQString file = KURL(*it).path();
|
|
if ( (file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe") ) && !fileList.contains(file) ) {
|
|
fileList.append(file);
|
|
}
|
|
}
|
|
|
|
TQString fileName = dataString("program");
|
|
|
|
property("program")->setAllowed(fileList);
|
|
property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName );
|
|
}
|
|
|
|
|
|
void PICComponent::buttonStateChanged( const TQString &id, bool state )
|
|
{
|
|
if (!state)
|
|
return;
|
|
|
|
if ( id == "reload" )
|
|
{
|
|
programReload();
|
|
return;
|
|
}
|
|
|
|
if (!m_pGpsim)
|
|
return;
|
|
|
|
if ( id == "run" )
|
|
m_pGpsim->setRunning(true);
|
|
|
|
else if ( id == "pause" )
|
|
m_pGpsim->setRunning(false);
|
|
|
|
else if ( id == "reset" )
|
|
{
|
|
m_pGpsim->reset();
|
|
|
|
// Set all pin outputs to low
|
|
const PICComponentPinMap::iterator end = m_picComponentPinMap.end();
|
|
for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it )
|
|
it.data()->resetOutput();
|
|
}
|
|
|
|
slotUpdateBtns();
|
|
}
|
|
|
|
|
|
bool PICComponent::mouseDoubleClickEvent ( const EventInfo &eventInfo )
|
|
{
|
|
Q_UNUSED(eventInfo);
|
|
if ( m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName) )
|
|
return false;
|
|
|
|
(void) DocManager::self()->openURL(m_picFile);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
TQString PICComponent::createSymbolFile()
|
|
{
|
|
m_bLoadingProgram = true;
|
|
slotUpdateBtns();
|
|
|
|
return GpsimProcessor::generateSymbolFile( dataString("program"), this, TQT_SLOT(slotCODCreationSucceeded()), TQT_SLOT(slotCODCreationFailed()) );
|
|
}
|
|
|
|
|
|
void PICComponent::slotCODCreationSucceeded()
|
|
{
|
|
m_bLoadingProgram = false;
|
|
|
|
delete m_pGpsim;
|
|
m_pGpsim = new GpsimProcessor(m_symbolFile);
|
|
|
|
if ( m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess )
|
|
{
|
|
MicroInfo * microInfo = m_pGpsim->microInfo();
|
|
property("lastPackage")->setValue( microInfo->id() );
|
|
initPackage( microInfo );
|
|
|
|
connect( m_pGpsim, TQT_SIGNAL(runningStatusChanged(bool )), this, TQT_SLOT(slotUpdateBtns()) );
|
|
attachPICComponentPins();
|
|
}
|
|
|
|
else
|
|
{
|
|
m_pGpsim->displayCodLoadStatus();
|
|
delete m_pGpsim;
|
|
m_pGpsim = 0l;
|
|
}
|
|
|
|
slotUpdateBtns();
|
|
}
|
|
|
|
|
|
void PICComponent::slotCODCreationFailed()
|
|
{
|
|
m_bLoadingProgram = false;
|
|
slotUpdateBtns();
|
|
}
|
|
|
|
|
|
void PICComponent::programReload()
|
|
{
|
|
delete m_pGpsim;
|
|
m_pGpsim = 0L;
|
|
|
|
initPIC(true);
|
|
|
|
slotUpdateBtns();
|
|
}
|
|
|
|
|
|
void PICComponent::slotUpdateBtns()
|
|
{
|
|
// We can get called by the destruction of gpsim after our canvas has been set to NULL
|
|
if (!canvas())
|
|
return;
|
|
|
|
button("run")->setEnabled( m_pGpsim && !m_pGpsim->isRunning() );
|
|
button("pause")->setEnabled( m_pGpsim && m_pGpsim->isRunning() );
|
|
button("reset")->setEnabled( m_pGpsim );
|
|
button("reload")->setEnabled( !m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName) );
|
|
|
|
canvas()->setChanged( button("run")->boundingRect() );
|
|
canvas()->setChanged( button("pause")->boundingRect() );
|
|
canvas()->setChanged( button("reset")->boundingRect() );
|
|
canvas()->setChanged( button("reload")->boundingRect() );
|
|
}
|
|
|
|
|
|
#include "piccomponent.moc"
|
|
|
|
#endif
|