/*************************************************************************** * 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 #include #include #include #include #include #include "gpsim/ioports.h" #include "gpsim/pic-processor.h" const TQString _def_PICComponent_fileName = i18n(""); 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.

" "The loadable PIC program must be one of the following formats:" "
  • Assembly (.asm)
  • " "
  • FlowCode (.flowcode)
  • " "
  • Symbol file (.cod)
  • " "
  • Microbe (.microbe, .basic)
  • " "
  • C source (.c)
" "Doubleclick on the PIC component to open up the program source file.

" "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.

" "Explanation of buttons:" "
  • Play - Run the PIC program from the point at which it was paused, or from the start otherwise.
  • " "
  • Pause - Pause the simulation at the current execution point.
  • " "
  • Stop - Reset all parts of the simulation.
  • " "
  • Reload - Reread the PIC program from disk and restart gpsim.
"); m_bCreatedInitialPackage = false; m_bLoadingProgram = false; m_pGpsim = 0L; addButton( "run", TQRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) ); addButton( "pause", TQRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) ); addButton( "reset", TQRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) ); addButton( "reload", TQRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::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.").tqarg( 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.").tqarg(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->codLoadtqStatus() == 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->displayCodLoadtqStatus(); 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