File indexing completed on 2024-05-05 05:46:08
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "config.h" 0012 #ifndef NO_GPSIM 0013 0014 #include "canvasitemparts.h" 0015 #include "circuitdocument.h" 0016 #include "docmanager.h" 0017 #include "gpsimprocessor.h" 0018 #include "ktechlab.h" 0019 #include "libraryitem.h" 0020 #include "logic.h" 0021 #include "microlibrary.h" 0022 #include "micropackage.h" 0023 #include "piccomponent.h" 0024 #include "piccomponentpin.h" 0025 #include "picinfo.h" 0026 #include "projectmanager.h" 0027 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 0031 #include <QIcon> 0032 #include <QPointer> 0033 #include <QStringList> 0034 0035 #include "gpsim/ioports.h" 0036 #include "gpsim/pic-processor.h" 0037 0038 #include <ktechlab_debug.h> 0039 0040 QString PICComponent::_def_PICComponent_fileName; 0041 0042 Item *PICComponent::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0043 { 0044 return new PICComponent(static_cast<ICNDocument *>(itemDocument), newItem, id); 0045 } 0046 0047 LibraryItem *PICComponent::libraryItem() 0048 { 0049 QStringList IDs; 0050 IDs << "ec/pic" 0051 << "ec/picitem" 0052 << "ec/picitem_18pin"; 0053 0054 return new LibraryItem(IDs, "PIC", i18n("Integrated Circuits"), "ic2.png", LibraryItem::lit_component, PICComponent::construct); 0055 } 0056 0057 PICComponent::PICComponent(ICNDocument *icnDocument, bool newItem, const char *id) 0058 : Component(icnDocument, newItem, id ? id : "pic") 0059 { 0060 m_name = i18n("PIC Micro"); 0061 0062 if (_def_PICComponent_fileName.isEmpty()) 0063 _def_PICComponent_fileName = i18n("<Enter location of PIC Program>"); 0064 0065 m_bCreatedInitialPackage = false; 0066 m_bLoadingProgram = false; 0067 m_pGpsim = nullptr; 0068 0069 addButton("run", QRect(), QIcon::fromTheme("media-playback-start")); 0070 addButton("pause", QRect(), QIcon::fromTheme("media-playback-pause")); 0071 addButton("reset", QRect(), QIcon::fromTheme("process-stop")); 0072 addButton("reload", QRect(), QIcon::fromTheme("view-refresh")); 0073 0074 connect(KTechlab::self(), &KTechlab::recentFileAdded, this, &PICComponent::slotUpdateFileList); 0075 0076 connect(ProjectManager::self(), &ProjectManager::projectOpened, this, &PICComponent::slotUpdateFileList); 0077 connect(ProjectManager::self(), &ProjectManager::projectClosed, this, &PICComponent::slotUpdateFileList); 0078 connect(ProjectManager::self(), &ProjectManager::projectCreated, this, &PICComponent::slotUpdateFileList); 0079 connect(ProjectManager::self(), &ProjectManager::subprojectCreated, this, &PICComponent::slotUpdateFileList); 0080 connect(ProjectManager::self(), &ProjectManager::filesAdded, this, &PICComponent::slotUpdateFileList); 0081 connect(ProjectManager::self(), &ProjectManager::filesRemoved, this, &PICComponent::slotUpdateFileList); 0082 0083 createProperty("program", Variant::Type::FileName); 0084 property("program")->setCaption(i18n("Program")); 0085 const FileFilters fileFilters({ 0086 {i18n("All Supported Files"), QStringLiteral("*.flowcode *.cod *.asm *.basic *.microbe *.c")}, 0087 {i18n("FlowCode") + QLatin1String(" (*.flowcode)"), QStringLiteral("*.flowcode")}, 0088 {i18n("Symbol File") + QLatin1String(" (*.cod)"), QStringLiteral("*.cod")}, 0089 {i18n("Assembly Code") + QLatin1String(" (*.asm)"), QStringLiteral("*.asm")}, 0090 {i18n("Microbe") + QLatin1String(" (*.basic, *.microbe)"), QStringLiteral("*.basic *.microbe")}, 0091 {i18n("C Code") + QLatin1String(" (*.c)"), QStringLiteral("*.c")}, 0092 {i18n("All Files"), QStringLiteral("*")}, 0093 }); 0094 property("program")->setFileFilters(fileFilters); 0095 0096 // Used for restoring the pins on file loading before we have had a change 0097 // to compile the PIC program 0098 createProperty("lastPackage", Variant::Type::String); 0099 property("lastPackage")->setHidden(true); 0100 0101 // //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage" 0102 // // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3 0103 // // behaviour), but it will also load it if 0104 0105 // This to allow loading of the PIC component from pre-0.3 files (which didn't set a 0106 // "lastPackage" property). 0107 if (!newItem) 0108 property("lastPackage")->setValue("P16F84"); 0109 0110 slotUpdateFileList(); 0111 slotUpdateBtns(); 0112 0113 initPackage(nullptr); 0114 } 0115 0116 PICComponent::~PICComponent() 0117 { 0118 deletePICComponentPins(); 0119 delete m_pGpsim; 0120 } 0121 0122 void PICComponent::dataChanged() 0123 { 0124 qCDebug(KTL_LOG); 0125 initPIC(false); 0126 } 0127 0128 void PICComponent::initPIC(bool forceReload) 0129 { 0130 if (!m_bCreatedInitialPackage) { 0131 qCDebug(KTL_LOG) << " creating initial package"; 0132 // We are still being created, so other connectors will be expecting us to 0133 // have grown pins soonish. 0134 MicroInfo *microInfo = MicroLibrary::self()->microInfoWithID(dataString("lastPackage")); 0135 if (microInfo) { 0136 initPackage(microInfo); 0137 } else { 0138 qCDebug(KTL_LOG) << " unknown last package: " << dataString("lastPackage"); 0139 } 0140 } 0141 0142 QString newProgram = dataString("program"); 0143 qCDebug(KTL_LOG) << "newProgram=" << newProgram; 0144 bool newFile = (m_picFile != newProgram); 0145 if (!newFile && !forceReload) { 0146 qCDebug(KTL_LOG) << "not new program, not force reload, exiting"; 0147 return; 0148 } 0149 0150 delete m_pGpsim; 0151 m_pGpsim = nullptr; 0152 0153 switch (GpsimProcessor::isValidProgramFile(newProgram)) { 0154 case GpsimProcessor::DoesntExist: 0155 if (newProgram == _def_PICComponent_fileName && !newProgram.isEmpty()) 0156 break; 0157 KMessageBox::error(nullptr, i18n("The file \"%1\" does not exist.", newProgram)); 0158 m_picFile = QString(); 0159 break; 0160 0161 case GpsimProcessor::IncorrectType: 0162 if (newProgram == _def_PICComponent_fileName && !newProgram.isEmpty()) 0163 break; 0164 KMessageBox::error(nullptr, 0165 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 " 0166 "corresponding \".cod\" file.", 0167 newProgram)); 0168 m_picFile = QString(); 0169 break; 0170 0171 case GpsimProcessor::Valid: 0172 m_picFile = newProgram; 0173 m_symbolFile = createSymbolFile(); 0174 break; 0175 } 0176 0177 slotUpdateBtns(); 0178 } 0179 0180 void PICComponent::deletePICComponentPins() 0181 { 0182 qDeleteAll(m_picComponentPinMap); 0183 m_picComponentPinMap.clear(); 0184 } 0185 0186 void PICComponent::initPackage(MicroInfo *microInfo) 0187 { 0188 MicroPackage *microPackage = microInfo ? microInfo->package() : nullptr; 0189 0190 if (microPackage) { 0191 m_bCreatedInitialPackage = true; 0192 0193 // BEGIN Get pin IDs 0194 QStringList allPinIDs = microPackage->pinIDs(); 0195 QStringList ioPinIDs = microPackage->pinIDs(PicPin::type_bidir | PicPin::type_input | PicPin::type_open); 0196 0197 // Now, we make the unwanted pin ids blank, so a pin is not created for them 0198 const QStringList::iterator allPinIDsEnd = allPinIDs.end(); 0199 for (QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it) { 0200 if (!ioPinIDs.contains(*it)) 0201 *it = ""; 0202 } 0203 // END Get pin IDs 0204 0205 // BEGIN Remove old stuff 0206 // Remove old text 0207 TextMap textMapCopy = m_textMap; 0208 const TextMap::iterator textMapEnd = textMapCopy.end(); 0209 for (TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it) 0210 removeDisplayText(it.key()); 0211 0212 // Remove the old pins 0213 deletePICComponentPins(); 0214 0215 // Remove old nodes 0216 NodeInfoMap nodeMapCopy = m_nodeMap; 0217 const NodeInfoMap::iterator nodeMapEnd = nodeMapCopy.end(); 0218 for (NodeInfoMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it) { 0219 if (!ioPinIDs.contains(it.key())) 0220 removeNode(it.key()); 0221 } 0222 0223 removeElements(); 0224 // END Remove old stuff 0225 0226 // BEGIN Create new stuff 0227 initDIPSymbol(allPinIDs, 80); 0228 initDIP(allPinIDs); 0229 0230 PicPinMap picPinMap = microPackage->pins(PicPin::type_bidir | PicPin::type_input | PicPin::type_open); 0231 const PicPinMap::iterator picPinMapEnd = picPinMap.end(); 0232 for (PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it) 0233 m_picComponentPinMap[it.key()] = new PICComponentPin(this, it.value()); 0234 // END Create new stuff 0235 0236 removeDisplayText("no_file"); 0237 addDisplayText("picid", QRect(offsetX(), offsetY() - 16, width(), 16), microInfo->id()); 0238 } else { 0239 setSize(-48, -72, 96, 144); 0240 removeDisplayText("picid"); 0241 addDisplayText("no_file", sizeRect(), i18n("(No\nprogram\nloaded)")); 0242 } 0243 0244 // BEGIN Update button positions 0245 int leftpos = (width() - 88) / 2 + offsetX(); 0246 button("run")->setOriginalRect(QRect(leftpos, height() + 4 + offsetY(), 20, 20)); 0247 button("pause")->setOriginalRect(QRect(leftpos + 23, height() + 4 + offsetY(), 20, 20)); 0248 button("reset")->setOriginalRect(QRect(leftpos + 46, height() + 4 + offsetY(), 20, 20)); 0249 button("reload")->setOriginalRect(QRect(leftpos + 69, height() + 4 + offsetY(), 20, 20)); 0250 updateAttachedPositioning(); 0251 // END Update button positions 0252 } 0253 0254 void PICComponent::attachPICComponentPins() 0255 { 0256 if (!m_pGpsim || !m_pGpsim->picProcessor()) 0257 return; 0258 0259 pic_processor *picProcessor = m_pGpsim->picProcessor(); 0260 0261 const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); 0262 for (PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it) 0263 it.value()->attach(picProcessor->get_pin(it.key())); 0264 } 0265 0266 void PICComponent::slotUpdateFileList() 0267 { 0268 QList<QUrl> preFileList = KTechlab::self()->recentFiles(); 0269 0270 QStringList fileList; 0271 0272 if (ProjectInfo *info = ProjectManager::self()->currentProject()) { 0273 const QList<QUrl> urls = info->childOutputURLs(ProjectItem::AllTypes, ProjectItem::ProgramOutput); 0274 for (const QUrl &url : urls) 0275 fileList << url.toLocalFile(); 0276 } 0277 0278 const QList<QUrl>::iterator end = preFileList.end(); 0279 for (QList<QUrl>::iterator it = preFileList.begin(); it != end; ++it) { 0280 const QUrl recentFile = *it; 0281 if (!recentFile.isLocalFile()) 0282 continue; 0283 const QString file = recentFile.toLocalFile(); 0284 if ((file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe")) && !fileList.contains(file)) { 0285 fileList.append(file); 0286 } 0287 } 0288 0289 QString fileName = dataString("program"); 0290 0291 property("program")->setAllowed(fileList); 0292 property("program")->setValue(fileName.isEmpty() ? _def_PICComponent_fileName : fileName); 0293 } 0294 0295 void PICComponent::buttonStateChanged(const QString &id, bool state) 0296 { 0297 if (!state) 0298 return; 0299 0300 if (id == "reload") { 0301 programReload(); 0302 return; 0303 } 0304 0305 if (!m_pGpsim) 0306 return; 0307 0308 if (id == "run") 0309 m_pGpsim->setRunning(true); 0310 0311 else if (id == "pause") 0312 m_pGpsim->setRunning(false); 0313 0314 else if (id == "reset") { 0315 m_pGpsim->reset(); 0316 0317 // Set all pin outputs to low 0318 const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); 0319 for (PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it) 0320 it.value()->resetOutput(); 0321 } 0322 0323 slotUpdateBtns(); 0324 } 0325 0326 bool PICComponent::mouseDoubleClickEvent(const EventInfo &eventInfo) 0327 { 0328 Q_UNUSED(eventInfo); 0329 if (m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName)) 0330 return false; 0331 0332 (void)DocManager::self()->openURL(QUrl::fromLocalFile(m_picFile)); 0333 0334 return true; 0335 } 0336 0337 QString PICComponent::createSymbolFile() 0338 { 0339 qCDebug(KTL_LOG); 0340 m_bLoadingProgram = true; 0341 slotUpdateBtns(); 0342 0343 return GpsimProcessor::generateSymbolFile(dataString("program"), this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed())); 0344 } 0345 0346 void PICComponent::slotCODCreationSucceeded() 0347 { 0348 qCDebug(KTL_LOG) << " m_symbolFile=" << m_symbolFile; 0349 m_bLoadingProgram = false; 0350 0351 delete m_pGpsim; 0352 m_pGpsim = new GpsimProcessor(m_symbolFile); 0353 0354 if (m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess) { 0355 MicroInfo *microInfo = m_pGpsim->microInfo(); 0356 if (!microInfo) { 0357 // FIXME we should be select somehow the type of the PIC. this is only a stability hack. 0358 qCWarning(KTL_LOG) << "cannot identify the PIC, defaulting to P16F84"; 0359 microInfo = MicroLibrary::self()->microInfoWithID("P16F84"); 0360 } 0361 property("lastPackage")->setValue(microInfo->id()); 0362 initPackage(microInfo); 0363 0364 connect(m_pGpsim, &GpsimProcessor::runningStatusChanged, this, &PICComponent::slotUpdateBtns); 0365 attachPICComponentPins(); 0366 } 0367 0368 else { 0369 m_pGpsim->displayCodLoadStatus(); 0370 delete m_pGpsim; 0371 m_pGpsim = nullptr; 0372 } 0373 0374 slotUpdateBtns(); 0375 } 0376 0377 void PICComponent::slotCODCreationFailed() 0378 { 0379 m_bLoadingProgram = false; 0380 slotUpdateBtns(); 0381 } 0382 0383 void PICComponent::programReload() 0384 { 0385 qCDebug(KTL_LOG); 0386 0387 delete m_pGpsim; 0388 m_pGpsim = nullptr; 0389 0390 initPIC(true); 0391 0392 slotUpdateBtns(); 0393 } 0394 0395 void PICComponent::slotUpdateBtns() 0396 { 0397 // We can get called by the destruction of gpsim after our canvas has been set to nullptr 0398 if (!canvas()) { 0399 qCDebug(KTL_LOG) << " no canvas, exiting"; 0400 return; 0401 } 0402 0403 button("run")->setEnabled(m_pGpsim && !m_pGpsim->isRunning()); 0404 button("pause")->setEnabled(m_pGpsim && m_pGpsim->isRunning()); 0405 button("reset")->setEnabled(m_pGpsim); 0406 button("reload")->setEnabled(!m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName)); 0407 0408 canvas()->setChanged(button("run")->boundingRect()); 0409 canvas()->setChanged(button("pause")->boundingRect()); 0410 canvas()->setChanged(button("reset")->boundingRect()); 0411 canvas()->setChanged(button("reload")->boundingRect()); 0412 } 0413 0414 #include "moc_piccomponent.cpp" 0415 0416 #endif