diff options
Diffstat (limited to 'src/electronics/components/piccomponent.cpp')
-rw-r--r-- | src/electronics/components/piccomponent.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/src/electronics/components/piccomponent.cpp b/src/electronics/components/piccomponent.cpp new file mode 100644 index 0000000..47320bb --- /dev/null +++ b/src/electronics/components/piccomponent.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#include "config.h" +#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 <klocale.h> +#include <kmessagebox.h> +#include <qguardedptr.h> +#include <qstringlist.h> + +#include "gpsim/ioports.h" +#include "gpsim/pic-processor.h" + +const QString _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() +{ + QStringList 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", QRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) ); + addButton( "pause", QRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) ); + addButton( "reset", QRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) ); + addButton( "reload", QRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::Small ) ); + + if ( icnDocument->ktechlab() ) + connect( icnDocument->ktechlab(), SIGNAL(recentFileAdded(const KURL &)), this, SLOT(slotUpdateFileList()) ); + + connect( ProjectManager::self(), SIGNAL(projectOpened()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectClosed()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(subprojectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesAdded()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesRemoved()), this, 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 ); + } + + QString 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 = QString::null; + 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 = QString::null; + 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 + QStringList allPinIDs = microPackage->pinIDs(); + QStringList 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 QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::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", QRect(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( QRect( leftpos, height()+4+offsetY(), 20, 20 ) ); + button("pause")->setOriginalRect( QRect( leftpos+23, height()+4+offsetY(), 20, 20 ) ); + button("reset")->setOriginalRect( QRect( leftpos+46, height()+4+offsetY(), 20, 20 ) ); + button("reload")->setOriginalRect( QRect( 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() +{ + QStringList preFileList; + if ( p_icnDocument && p_icnDocument->ktechlab() ) + preFileList += p_icnDocument->ktechlab()->recentFiles(); + + QStringList 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 QStringList::iterator end = preFileList.end(); + for ( QStringList::iterator it = preFileList.begin(); it != end; ++it ) + { + QString 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); + } + } + + QString fileName = dataString("program"); + + property("program")->setAllowed(fileList); + property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName ); +} + + +void PICComponent::buttonStateChanged( const QString &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; +} + + +QString PICComponent::createSymbolFile() +{ + m_bLoadingProgram = true; + slotUpdateBtns(); + + return GpsimProcessor::generateSymbolFile( dataString("program"), this, SLOT(slotCODCreationSucceeded()), 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, SIGNAL(runningStatusChanged(bool )), this, 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 |