diff --git a/src/atcore.cpp b/src/atcore.cpp index 537dc51..cc60634 100644 --- a/src/atcore.cpp +++ b/src/atcore.cpp @@ -1,776 +1,776 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira - Lays Rodrigues + Patrick José Pereira + Lays Rodrigues This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include "atcore.h" #include "atcore_version.h" #include "seriallayer.h" #include "gcodecommands.h" #include "printthread.h" #include "atcore_default_folders.h" Q_LOGGING_CATEGORY(ATCORE_PLUGIN, "org.kde.atelier.core.plugin") Q_LOGGING_CATEGORY(ATCORE_CORE, "org.kde.atelier.core") /** * @brief The AtCorePrivate struct * Provides a private data set for atcore. */ struct AtCorePrivate { IFirmware *firmwarePlugin = nullptr;//!< @param firmwarePlugin: pointer to firmware plugin SerialLayer *serial = nullptr; //!< @param serial: pointer to the serial layer QPluginLoader pluginLoader; //!< @param pluginLoader: QPluginLoader QDir pluginsDir; //!< @param pluginsDir: Directory where plugins were found QMap plugins; //!< @param plugins: Map of plugins name / path QByteArray lastMessage; //!< @param lastMessage: lastMessage from the printer int extruderCount = 1; //!< @param extruderCount: extruder count Temperature temperature; //!< @param temperature: Temperature object QStringList commandQueue; //!< @param commandQueue: the list of commands to send to the printer bool ready = false; //!< @param ready: True if printer is ready for a command QTimer *tempTimer = nullptr; //!< @param tempTimer: timer connected to the checkTemperature function float percentage; //!< @param percentage: print job percent QByteArray posString; //!< @param posString: stored string from last M114 return AtCore::STATES printerState; //!< @param printerState: State of the Printer QStringList serialPorts; //!< @param seralPorts: Detected serial Ports QTimer *serialTimer = nullptr; //!< @param serialTimer: Timer connected to locateSerialPorts bool sdCardMounted = false; //!< @param sdCardMounted: True if Sd Card is mounted. bool sdCardReadingFileList = false; //!< @param sdCardReadingFileList: True while getting file names from sd card bool sdCardPrinting = false; //!< @param sdCardPrinting: True if currently printing from sd card. QString sdCardFileName; //!< @param sdCardFileName: name of file being used from sd card. QStringList sdCardFileList; //!< @param sdCardFileList: List of files on sd card. }; AtCore::AtCore(QObject *parent) : QObject(parent), d(new AtCorePrivate) { //Register MetaTypes qRegisterMetaType("AtCore::STATES"); setState(AtCore::DISCONNECTED); //Create and start the timer that checks for temperature. d->tempTimer = new QTimer(this); d->tempTimer->setInterval(5000); d->tempTimer->setSingleShot(false); //Attempt to find our plugins //For Windows and Mac we always look in plugins folder of the program using atcore. //On others we use AtCoreDirectories::pluginDir to hold a list of dirs to check #if defined(Q_OS_WIN) || defined(Q_OS_MAC) d->pluginsDir = qApp->applicationDirPath() + QStringLiteral("/plugins"); #else for (const auto &path : AtCoreDirectories::pluginDir) { qCDebug(ATCORE_PLUGIN) << "Lookin for plugins in " << path; if (QDir(path).exists()) { d->pluginsDir = QDir(path); qCDebug(ATCORE_PLUGIN) << "Valid path for plugins found !"; break; } } #endif if (!d->pluginsDir.exists()) { qCritical() << "No valid path for plugin !"; } qCDebug(ATCORE_PLUGIN) << d->pluginsDir; findFirmwarePlugins(); setState(AtCore::DISCONNECTED); } QString AtCore::version() const { QString versionString = QString::fromLatin1(ATCORE_VERSION_STRING); #if defined GIT_REVISION if (!QStringLiteral(GIT_REVISION).isEmpty()) { versionString.append(QString::fromLatin1("-%1").arg(QStringLiteral(GIT_REVISION))); } #endif return versionString; } SerialLayer *AtCore::serial() const { return d->serial; } IFirmware *AtCore::firmwarePlugin() const { return d->firmwarePlugin; } void AtCore::close() { exit(0); } Temperature &AtCore::temperature() const { return d->temperature; } void AtCore::findFirmware(const QByteArray &message) { if (state() == AtCore::DISCONNECTED) { qWarning() << "Cant find firwmware, serial not connected !"; return; } if (state() == AtCore::CONNECTING) { //Most Firmwares will return "start" on connect, some return their firmware name. if (message.contains("start")) { qCDebug(ATCORE_CORE) << "Waiting requestFirmware."; QTimer::singleShot(500, this, &AtCore::requestFirmware); return; } else if (message.contains("Grbl")) { loadFirmwarePlugin(QString::fromLatin1("grbl")); return; } else if (message.contains("Smoothie")) { loadFirmwarePlugin(QString::fromLatin1("smoothie")); return; } } qCDebug(ATCORE_CORE) << "Find Firmware Called" << message; if (!message.contains("FIRMWARE_NAME:")) { qCDebug(ATCORE_CORE) << "No firmware yet."; return; } qCDebug(ATCORE_CORE) << "Found firmware string, Looking for Firmware Name."; QString fwName = QString::fromLocal8Bit(message); fwName = fwName.split(QChar::fromLatin1(':')).at(1); if (fwName.indexOf(QChar::fromLatin1(' ')) == 0) { //remove leading space fwName.remove(0, 1); } if (fwName.contains(QChar::fromLatin1(' '))) { //check there is a space or dont' resize fwName.resize(fwName.indexOf(QChar::fromLatin1(' '))); } fwName = fwName.toLower().simplified(); if (fwName.contains(QChar::fromLatin1('_'))) { fwName.resize(fwName.indexOf(QChar::fromLatin1('_'))); } qCDebug(ATCORE_CORE) << "Firmware Name:" << fwName; if (message.contains("EXTRUDER_COUNT:")) { //this code is broken if more then 9 extruders are detected. since only one char is returned d->extruderCount = message.at(message.indexOf("EXTRUDER_COUNT:") + 15) - '0'; } qCDebug(ATCORE_CORE) << "Extruder Count:" << QString::number(extruderCount()); loadFirmwarePlugin(fwName); } void AtCore::loadFirmwarePlugin(const QString &fwName) { qCDebug(ATCORE_PLUGIN) << "Looking for Plugin:" << fwName; if (d->plugins.contains(fwName)) { d->pluginLoader.setFileName(d->plugins[fwName]); if (!d->pluginLoader.load()) { //Plugin was not loaded, Provide some debug info. qCDebug(ATCORE_PLUGIN) << "Plugin Loading: Failed."; qCDebug(ATCORE_PLUGIN) << d->pluginLoader.errorString(); setState(AtCore::CONNECTING); } else { //Plugin was loaded successfully. d->firmwarePlugin = qobject_cast(d->pluginLoader.instance()); firmwarePlugin()->init(this); qCDebug(ATCORE_PLUGIN) << "Plugin Loading: Successful"; disconnect(serial(), &SerialLayer::receivedCommand, this, &AtCore::findFirmware); connect(serial(), &SerialLayer::receivedCommand, this, &AtCore::newMessage); connect(firmwarePlugin(), &IFirmware::readyForCommand, this, &AtCore::processQueue); d->ready = true; // ready on new firmware load if (firmwarePlugin()->name() != QStringLiteral("Grbl")) { connect(d->tempTimer, &QTimer::timeout, this, &AtCore::checkTemperature); d->tempTimer->start(); } setState(IDLE); } } else { qCDebug(ATCORE_CORE) << "Plugin:" << fwName << ": Not found."; } } bool AtCore::initSerial(const QString &port, int baud) { d->serial = new SerialLayer(port, baud); if (serialInitialized() && d->serial->isWritable()) { setState(AtCore::CONNECTING); connect(serial(), &SerialLayer::receivedCommand, this, &AtCore::findFirmware); return true; } else { qCDebug(ATCORE_CORE) << "Failed to open device for Read / Write."; return false; } } bool AtCore::serialInitialized() const { if (!d->serial) { return false; } return d->serial->isOpen(); } QString AtCore::connectedPort() const { return serial()->portName(); } QStringList AtCore::serialPorts() const { QStringList ports; QList serialPortInfoList = QSerialPortInfo::availablePorts(); if (!serialPortInfoList.isEmpty()) { foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { #ifdef Q_OS_MAC //Mac OS has callout serial ports starting with cu these devices are read only. //It is necessary to filter them out to help prevent user error. if (!serialPortInfo.portName().startsWith(QStringLiteral("cu."), Qt::CaseInsensitive)) { ports.append(serialPortInfo.portName()); } #else ports.append(serialPortInfo.portName()); #endif } } return ports; } void AtCore::locateSerialPort() { QStringList ports = serialPorts(); if (d->serialPorts != ports) { d->serialPorts = ports; emit portsChanged(d->serialPorts); } } quint16 AtCore::serialTimerInterval() const { if (d->serialTimer != nullptr) { return d->serialTimer->interval(); } return 0; } void AtCore::setSerialTimerInterval(const quint16 &newTime) { if (!d->serialTimer) { //There is no timer. We need to create one. d->serialTimer = new QTimer(); connect(d->serialTimer, &QTimer::timeout, this, &AtCore::locateSerialPort); } //Start over with the new time. d->serialTimer->start(newTime); } void AtCore::newMessage(const QByteArray &message) { //Evaluate the messages coming from the printer. d->lastMessage = message; //Check if the message has current coordinates. if (message.startsWith(QString::fromLatin1("X:").toLocal8Bit())) { d->posString = message; d->posString.resize(d->posString.indexOf('E')); d->posString.replace(':', ""); } //Check if have temperature info and decode it if (d->lastMessage.contains("T:") || d->lastMessage.contains("B:")) { temperature().decodeTemp(message); } emit(receivedMessage(d->lastMessage)); } void AtCore::setRelativePosition() { pushCommand(GCode::toCommand(GCode::G91)); } void AtCore::setAbsolutePosition() { pushCommand(GCode::toCommand(GCode::G90)); } float AtCore::percentagePrinted() const { return d->percentage; } void AtCore::print(const QString &fileName, bool sdPrint) { if (state() == AtCore::CONNECTING) { qCDebug(ATCORE_CORE) << "Load a firmware plugin to print."; return; } //Start a print job. setState(AtCore::STARTPRINT); if (sdPrint) { //Printing from the sd card requires us to send some M commands. pushCommand(GCode::toCommand(GCode::M23, fileName)); d->sdCardFileName = fileName; pushCommand(GCode::toCommand(GCode::M24)); setState(AtCore::BUSY); d->sdCardPrinting = true; connect(d->tempTimer, &QTimer::timeout, this, &AtCore::sdCardPrintStatus); return; } //Process the gcode with a printThread. //The Thread processes the gcode without freezing the libary. //Only sends a command back when the printer is ready, avoiding buffer overflow in the printer. QThread *thread = new QThread(); PrintThread *printThread = new PrintThread(this, fileName); printThread->moveToThread(thread); connect(printThread, &PrintThread::printProgressChanged, this, &AtCore::printProgressChanged, Qt::QueuedConnection); connect(thread, &QThread::started, printThread, &PrintThread::start); connect(printThread, &PrintThread::finished, thread, &QThread::quit); connect(thread, &QThread::finished, printThread, &PrintThread::deleteLater); if (!thread->isRunning()) { thread->start(); } } void AtCore::pushCommand(const QString &comm) { //Append command to the commandQueue d->commandQueue.append(comm); if (d->ready) { //The printer is ready for a command now so push one. processQueue(); } } void AtCore::closeConnection() { if (serialInitialized()) { if (AtCore::state() == AtCore::BUSY && !d->sdCardPrinting) { //We have to clean up the print job if printing from the host. //However disconnecting while printing from sd card should not affect the print job. setState(AtCore::STOP); } if (firmwarePluginLoaded()) { disconnect(firmwarePlugin(), &IFirmware::readyForCommand, this, &AtCore::processQueue); disconnect(serial(), &SerialLayer::receivedCommand, this, &AtCore::newMessage); if (firmwarePlugin()->name() != QStringLiteral("Grbl")) { disconnect(d->tempTimer, &QTimer::timeout, this, &AtCore::checkTemperature); d->tempTimer->stop(); } //Attempt to unload the firmware plugin. QString name = firmwarePlugin()->name(); QString msg = d->pluginLoader.unload() ? QStringLiteral("success") : QStringLiteral("FAIL"); qCDebug(ATCORE_PLUGIN) << QStringLiteral("Firmware plugin %1 unload: %2").arg(name, msg); } serial()->close(); //Clear our copy of the sdcard filelist clearSdCardFileList(); setState(AtCore::DISCONNECTED); } } AtCore::STATES AtCore::state(void) { return d->printerState; } void AtCore::setState(AtCore::STATES state) { if (state != d->printerState) { qCDebug(ATCORE_CORE) << "Atcore state changed from [" \ << d->printerState << "] to [" << state << "]"; d->printerState = state; if (state == AtCore::FINISHEDPRINT && d->sdCardPrinting) { //Clean up the sd card print d->sdCardPrinting = false; disconnect(d->tempTimer, &QTimer::timeout, this, &AtCore::sdCardPrintStatus); } emit(stateChanged(d->printerState)); } } void AtCore::stop() { //Stop a print job setState(AtCore::STOP); d->commandQueue.clear(); if (d->sdCardPrinting) { stopSdPrint(); } setExtruderTemp(0, 0); setBedTemp(0); home(AtCore::X); } void AtCore::emergencyStop() { //Emergency Stop. Stops the machine //Clear the queue, and any print job //Before sending the command to ensure //Less chance of movement after the restart. d->commandQueue.clear(); if (AtCore::state() == AtCore::BUSY) { if (!d->sdCardPrinting) { //Stop our running print thread setState(AtCore::STOP); } } //push command through serial to bypass atcore's queue. serial()->pushCommand(GCode::toCommand(GCode::M112).toLocal8Bit()); } void AtCore::stopSdPrint() { //Stop an SdCard Print. pushCommand(GCode::toCommand(GCode::M25)); d->sdCardFileName = QString(); pushCommand(GCode::toCommand(GCode::M23, d->sdCardFileName)); AtCore::setState(AtCore::FINISHEDPRINT); AtCore::setState(AtCore::IDLE); } void AtCore::requestFirmware() { if (serialInitialized()) { qCDebug(ATCORE_CORE) << "Sending " << GCode::description(GCode::M115); serial()->pushCommand(GCode::toCommand(GCode::M115).toLocal8Bit()); } else { qCDebug(ATCORE_CORE) << "There is no open device to send commands"; } } bool AtCore::firmwarePluginLoaded() const { if (firmwarePlugin()) { return true; } else { return false; } } void AtCore::findFirmwarePlugins() { d->plugins.clear(); qCDebug(ATCORE_PLUGIN) << "plugin dir:" << d->pluginsDir; QStringList files = d->pluginsDir.entryList(QDir::Files); foreach (const QString &f, files) { QString file = f; #if defined(Q_OS_WIN) if (file.endsWith(QStringLiteral(".dll"))) #elif defined(Q_OS_MAC) if (file.endsWith(QStringLiteral(".dylib"))) #else if (file.endsWith(QStringLiteral(".so"))) #endif file = file.split(QChar::fromLatin1('.')).at(0); else { qCDebug(ATCORE_PLUGIN) << "File" << file << "not plugin."; continue; } qCDebug(ATCORE_CORE) << "Found plugin file" << f; if (file.startsWith(QStringLiteral("lib"))) { file = file.remove(QStringLiteral("lib")); } file = file.toLower().simplified(); QString pluginString; pluginString.append(d->pluginsDir.path()); pluginString.append(QChar::fromLatin1('/')); pluginString.append(f); d->plugins[file] = pluginString; qCDebug(ATCORE_CORE) << tr("plugins[%1]=%2").arg(file, pluginString); } } QStringList AtCore::availableFirmwarePlugins() const { return d->plugins.keys(); } void AtCore::pause(const QString &pauseActions) { if (d->sdCardPrinting) { pushCommand(GCode::toCommand(GCode::M25)); } //Push the command to request current coordinates. //This will be read by AtCore::newMessage and stored for use on resume. pushCommand(GCode::toCommand(GCode::M114)); if (!pauseActions.isEmpty()) { QStringList temp = pauseActions.split(QChar::fromLatin1(',')); for (int i = 0; i < temp.length(); i++) { pushCommand(temp.at(i)); } } setState(AtCore::PAUSE); } void AtCore::resume() { if (d->sdCardPrinting) { pushCommand(GCode::toCommand(GCode::M24)); } else { //Move back to previous coordinates. pushCommand(GCode::toCommand(GCode::G0, QString::fromLatin1(d->posString))); } setState(AtCore::BUSY); } /*~~~~~Control Slots ~~~~~~~~*/ void AtCore::home() { pushCommand(GCode::toCommand(GCode::G28)); } void AtCore::home(uchar axis) { QString args; if (axis & AtCore::X) { args.append(QStringLiteral("X0 ")); } if (axis & AtCore::Y) { args.append(QStringLiteral("Y0 ")); } if (axis & AtCore::Z) { args.append(QStringLiteral("Z0")); } pushCommand(GCode::toCommand(GCode::G28, args)); } void AtCore::setExtruderTemp(uint temp, uint extruder, bool andWait) { if (andWait) { pushCommand(GCode::toCommand(GCode::M109, QString::number(temp), QString::number(extruder))); } else { pushCommand(GCode::toCommand(GCode::M104, QString::number(extruder), QString::number(temp))); } } void AtCore::setBedTemp(uint temp, bool andWait) { if (andWait) { pushCommand(GCode::toCommand(GCode::M190, QString::number(temp))); } else { pushCommand(GCode::toCommand(GCode::M140, QString::number(temp))); } } void AtCore::setFanSpeed(uint speed, uint fanNumber) { pushCommand(GCode::toCommand(GCode::M106, QString::number(fanNumber), QString::number(speed))); } void AtCore::setPrinterSpeed(uint speed) { pushCommand(GCode::toCommand(GCode::M220, QString::number(speed))); } void AtCore::setFlowRate(uint speed) { pushCommand(GCode::toCommand(GCode::M221, QString::number(speed))); } void AtCore::move(AtCore::AXES axis, int arg) { static QLatin1Char a('?'); switch (axis) { case AtCore::X: a = QLatin1Char('X'); break; case AtCore::Y: a = QLatin1Char('Y'); break; case AtCore::Z: a = QLatin1Char('Z'); break; case AtCore::E: a = QLatin1Char('E'); break; default: break; }; move(a, arg); } void AtCore::move(QLatin1Char axis, int arg) { pushCommand(GCode::toCommand(GCode::G1, QStringLiteral("%1 %2").arg(axis).arg(QString::number(arg)))); } int AtCore::extruderCount() const { return d->extruderCount; } void AtCore::processQueue() { d->ready = true; if (d->commandQueue.isEmpty()) { return; } if (!serialInitialized()) { qCDebug(ATCORE_PLUGIN) << "Can't process queue ! Serial not initialized."; return; } QString text = d->commandQueue.takeAt(0); if (firmwarePluginLoaded()) { serial()->pushCommand(firmwarePlugin()->translate(text)); } else { serial()->pushCommand(text.toLocal8Bit()); } d->ready = false; } void AtCore::checkTemperature() { //One request for the temperature in the queue at a time. if (d->commandQueue.contains(GCode::toCommand(GCode::M105))) { return; } pushCommand(GCode::toCommand(GCode::M105)); } void AtCore::showMessage(const QString &message) { if (!message.isEmpty()) { pushCommand(GCode::toCommand((GCode::M117), message)); } } void AtCore::setUnits(AtCore::UNITS units) { switch (units) { case AtCore::METRIC: pushCommand(GCode::toCommand(GCode::G21)); break; case AtCore::IMPERIAL: pushCommand(GCode::toCommand(GCode::G20)); break; } } QStringList AtCore::portSpeeds() const { return serial()->validBaudRates(); } void AtCore::disableMotors(uint delay) { //Disables motors if (delay) { pushCommand(GCode::toCommand(GCode::M84, QString::number(delay))); } else { pushCommand(GCode::toCommand(GCode::M84)); } } //Most firmwares will not report if an sdcard is mounted on boot. bool AtCore::isSdMounted() const { return d->sdCardMounted; } void AtCore::setSdMounted(bool mounted) { if (mounted != isSdMounted()) { d->sdCardMounted = mounted; emit(sdMountChanged(d->sdCardMounted)); } } void AtCore::getSDFileList() { pushCommand(GCode::toCommand(GCode::M20)); } QStringList AtCore::sdFileList() { if (!d->sdCardReadingFileList) { getSDFileList(); } return d->sdCardFileList; } void AtCore::appendSdCardFileList(const QString &fileName) { d->sdCardFileList.append(fileName); emit(sdCardFileListChanged(d->sdCardFileList)); } void AtCore::clearSdCardFileList() { d->sdCardFileList.clear(); emit(sdCardFileListChanged(d->sdCardFileList)); } void AtCore::sdDelete(const QString &fileName) { if (d->sdCardFileList.contains(fileName)) { pushCommand(GCode::toCommand(GCode::M30, fileName)); getSDFileList(); } else { qCDebug(ATCORE_CORE) << "Delete failed file not found:" << fileName; } } void AtCore::mountSd(uint slot) { pushCommand(GCode::toCommand(GCode::M21, QString::number(slot))); } void AtCore::umountSd(uint slot) { pushCommand(GCode::toCommand(GCode::M22, QString::number(slot))); } bool AtCore::isReadingSdCardList() const { return d->sdCardReadingFileList; } void AtCore::setReadingSdCardList(bool readingList) { d->sdCardReadingFileList = readingList; } void AtCore::sdCardPrintStatus() { //One request for the Sd Job status in the queue at a time. if (d->commandQueue.contains(GCode::toCommand(GCode::M27))) { return; } pushCommand(GCode::toCommand(GCode::M27)); } diff --git a/src/atcore.h b/src/atcore.h index 03fb5ed..c157ad5 100644 --- a/src/atcore.h +++ b/src/atcore.h @@ -1,557 +1,557 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira - Lays Rodrigues + Patrick José Pereira + Lays Rodrigues This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include #include #include "ifirmware.h" #include "temperature.h" #include "atcore_export.h" class SerialLayer; class IFirmware; class QTime; struct AtCorePrivate; /** * @brief The AtCore class * aims to provides a high level interface for serial based gcode devices
* * #### General Workflow * - Connect to a serial port with initSerial() * - Firmware will be auto detected. Use loadFirmwarePLugin() to force load a firmware. * - Send commands to the device (pushCommand(),print(),...) * - AtCore::close() when you are all done. * #### How AtCore Finds Plugins. * - Windows and Mac Os will always look in appdir/plugins for plugins. * * Others Search: * 1. Build Dir/plugins (buildtime) * 2. ECM set KDE PLUGIN DIR (buildtime) * 3. Qt Plugin path/AtCore (runtime) * 4. plugins (runtime) */ class ATCORE_EXPORT AtCore : public QObject { Q_OBJECT Q_PROPERTY(QString version READ version) Q_PROPERTY(QStringList availableFirmwarePlugins READ availableFirmwarePlugins) Q_PROPERTY(int extruderCount READ extruderCount NOTIFY extruderCountChanged) Q_PROPERTY(quint16 serialTimerInterval READ serialTimerInterval WRITE setSerialTimerInterval NOTIFY serialTimerIntervalChanged) Q_PROPERTY(QStringList serialPorts READ serialPorts NOTIFY portsChanged) Q_PROPERTY(float percentagePrinted READ percentagePrinted NOTIFY printProgressChanged) Q_PROPERTY(QStringList portSpeeds READ portSpeeds) Q_PROPERTY(QString connectedPort READ connectedPort) Q_PROPERTY(AtCore::STATES state READ state WRITE setState NOTIFY stateChanged) Q_PROPERTY(bool sdMount READ isSdMounted WRITE setSdMounted NOTIFY sdMountChanged) Q_PROPERTY(QStringList sdFileList READ sdFileList NOTIFY sdCardFileListChanged) //Add friends as Sd Card support is extended to more plugins. friend class RepetierPlugin; friend class MarlinPlugin; //friend class SmoothiePlugin; //friend class TeacupPlugin; //friend class AprinterPlugin; //friend class SprinterPlugin; public: /** * @brief STATES enum Possible states the printer can be in */ enum STATES { DISCONNECTED, //!< Not Connected to a printer, initial state CONNECTING, //! * @param port: the port to initialize * @param baud: the baud of the port * @return True is connection was successful * @sa serialPorts(),serial(),closeConnection() */ Q_INVOKABLE bool initSerial(const QString &port, int baud); /** * @brief Returns a list of valid baud speeds */ QStringList portSpeeds() const; /** * @brief Main access to the serialLayer * @return Current serialLayer * @sa initSerial(),serialPorts(),closeConnection() */ SerialLayer *serial() const; /** * @brief Close the current serial connection * @sa initSerial(),serial(),serialPorts(),AtCore::close() */ Q_INVOKABLE void closeConnection(); /** * @brief Main access to the loaded firmware plugin * @return IFirmware * to currently loaded plugin * @sa availableFirmwarePlugins(),loadFirmwarePlugin() */ Q_INVOKABLE IFirmware *firmwarePlugin() const; /** * @brief List of available firmware plugins * @sa loadFirmwarePlugin(),firmwarePlugin() */ QStringList availableFirmwarePlugins() const; /** * @brief Load A firmware plugin * @param fwName : name of the firmware * @sa firmwarePlugin(),availableFirmwarePlugins() */ Q_INVOKABLE void loadFirmwarePlugin(const QString &fwName); /** * @brief Get Printer state * @return State of the printer * @sa setState(),stateChanged(),AtCore::STATES */ AtCore::STATES state(void); /** * @brief extruderCount * @return The number of detected Extruders Default is 1 */ int extruderCount() const; /** * @brief Return printed percentage * @sa printProgressChanged() */ float percentagePrinted() const; /** * @brief The temperature of the current hotend as told by the Firmware. */ Temperature &temperature() const; /** * @brief Return the amount of miliseconds the serialTimer is set to. 0 = Disabled */ quint16 serialTimerInterval() const; /** * @brief Attempt to Mount an sd card * @param slot: Sd card Slot on machine (0 is default) */ Q_INVOKABLE void mountSd(uint slot = 0); /** * @brief Attempt to Unmount an sd card * @param slot: Sd card Slot on machine (0 is default) */ Q_INVOKABLE void umountSd(uint slot = 0); /** * @brief sdFileList * @return List of files on the sd card. */ QStringList sdFileList(); /** * @brief Check if an sd card is mounted on the printer * @return True if card mounted */ bool isSdMounted() const; signals: /** * @brief New number of extruders * @sa extruderCount() */ void extruderCountChanged(); /** * @brief Print job's precentage changed. * @param newProgress : Message * @sa percentagePrinted() */ void printProgressChanged(const float &newProgress); /** * @brief New message was received from the printer * @param message: Message that was received */ void receivedMessage(const QByteArray &message); /** * @brief New interval between serial timer * @sa setSerialTimerInterval() */ void serialTimerIntervalChanged(); /** * @brief The Printer's State Changed * @param newState : the new state of the printer * @sa setState(),state(),AtCore::STATES */ void stateChanged(AtCore::STATES newState); /** * @brief Available serialports Changed */ void portsChanged(const QStringList &portList); /** * @brief Sd Card Mount Changed */ void sdMountChanged(bool newState); /** * @brief The files on the sd card have changed. */ void sdCardFileListChanged(const QStringList &fileList); public slots: /** * @brief Set the printers state * @param state : printer state. * @sa state(),stateChanged(),AtCore::STATES */ void setState(AtCore::STATES state); /** * @brief Push a command into the command queue * * @param comm : Command */ Q_INVOKABLE void pushCommand(const QString &comm); /** * @brief Public Interface for printing a file * @param fileName: the gcode file to print. * @param sdPrint: set true to print fileName from Sd card */ Q_INVOKABLE void print(const QString &fileName, bool sdPrint = false); /** * @brief Stop the Printer by empting the queue and aborting the print job (if running) * @sa emergencyStop(),pause(),resume() */ Q_INVOKABLE void stop(); /** * @brief stop the printer via the emergency stop Command (M112) * @sa stop(),pause(),resume() */ Q_INVOKABLE void emergencyStop(); /** * @brief pause an in process print job * * Sends M114 on pause to store the location where the head stoped. * This is known to cause problems on fake printers * @param pauseActions: Gcode to run after pausing commands are ',' separated * @sa resume(),stop(),emergencyStop() */ void pause(const QString &pauseActions); /** * @brief resume a paused print job. * After returning to location pause was triggered. * @sa pause(),stop(),emergencyStop() */ Q_INVOKABLE void resume(); /** * @brief Send home \p axis command * @param axis: the axis(es) to home (use X Y Z or any combo of) * @sa home(), move() */ Q_INVOKABLE void home(uchar axis); /** * @brief Send home all command * @sa home(uchar axis), move() */ Q_INVOKABLE void home(); /** * @brief Set extruder temperature * @param temp : new temperature * @param extruder : extruder number * @param andWait: True for heat and ignore commands until temperature is reached */ Q_INVOKABLE void setExtruderTemp(uint temp = 0, uint extruder = 0, bool andWait = false); /** * @brief move an axis of the printer * @param axis the axis to move AXES (X Y Z E ) * @param arg the distance to move the axis or the place to move to depending on printer mode * @sa home(), home(uchar axis), move(QLatin1Char axis, int arg) */ Q_INVOKABLE void move(AtCore::AXES axis, int arg); /** * @brief move an axis of the printer * @param axis the axis to move AXES (X Y Z E ) * @param arg the distance to move the axis or the place to move to depending on printer mode * @sa home(), home(uchar axis), move(AtCore::AXES, int arg) */ Q_INVOKABLE void move(QLatin1Char axis, int arg); /** * @brief Set the bed temperature * @param temp : new temperature * @param andWait: True for heat and ignore commands until temperature is reached * @sa setExtruderTemp() */ Q_INVOKABLE void setBedTemp(uint temp = 0, bool andWait = false); /** * @brief setFanSpeed set the fan speed * @param fanNumber: fan number * @param speed: new speed of the fan 0-100 */ Q_INVOKABLE void setFanSpeed(uint speed = 0, uint fanNumber = 0); /** * @brief Set printer to absolute position mode * @sa setRelativePosition() */ Q_INVOKABLE void setAbsolutePosition(); /** * @brief Set printer to relative position mode * @sa setAbsolutePosition() */ Q_INVOKABLE void setRelativePosition(); /** * @brief Disable motors after a delay * @param delay: Seconds until motors are disabled. 0= No delay */ Q_INVOKABLE void disableMotors(uint delay = 0); /** * @brief set the Printers speed * @param speed: speed in % (default is 100); */ Q_INVOKABLE void setPrinterSpeed(uint speed = 100); /** * @brief set extruder Flow rate * @param rate: flow rate in % (default is 100) */ Q_INVOKABLE void setFlowRate(uint rate = 100); /** * @brief close any open items. * You should call this on close events to force any stuck jobs to close * @sa closeConnection() */ Q_INVOKABLE void close(); /** * @brief showMessage push a message to the printers LCD * @param message: message to show on the LCD */ Q_INVOKABLE void showMessage(const QString &message); /** * @brief setUnits sets the measurement units do be used * @param units : the measurement units to use(METRIC / IMPERIAL) * @sa AtCore::UNITS */ Q_INVOKABLE void setUnits(AtCore::UNITS units); /** * @brief Set the time between checks for new serialPorts (0 is default) * @param newTime: Milliseconds between checks. 0 will Disable Checks. */ void setSerialTimerInterval(const quint16 &newTime); /** * @brief delete file from sd card */ Q_INVOKABLE void sdDelete(const QString &fileName); /** * @brief Queue the Printer for status of sd card print */ void sdCardPrintStatus(); private slots: /** * @brief processQueue send commands from the queue. */ void processQueue(); /** * @brief Send M105 to the printer if one is not in the Queue */ void checkTemperature(); /** * @brief Connect to SerialLayer::receivedCommand * @param message: new message. */ void newMessage(const QByteArray &message); /** * @brief Search for firmware string in message. * A Helper function for Firmware detection * @param message */ void findFirmware(const QByteArray &message); /** * @brief Search for new serial ports */ void locateSerialPort(); /** * @brief Send request to the printer for the sd card file list. */ void getSDFileList(); private: /** * @brief True if a firmware plugin is loaded */ bool firmwarePluginLoaded() const; /** * @brief True if a serial port is initialized */ bool serialInitialized() const; /** * @brief send firmware request to the printer */ void requestFirmware(); /** * @brief Search for atcore firmware plugins */ void findFirmwarePlugins(); /** * @brief returns AtCorePrivate::sdCardReadingFileList * @return True if printer is returning sd card file list */ bool isReadingSdCardList() const; /** * @brief stops print just for sd prints used internally * @sa stop(),emergencyStop() */ void stopSdPrint(); /** * @brief Hold private data of AtCore. */ AtCorePrivate *d; protected: /** * @brief Append a file to AtCorePrivate::sdCardFileList. * @param fileName: new FileName */ void appendSdCardFileList(const QString &fileName); /** * @brief Clear AtCorePrivate::sdCardFileList. */ void clearSdCardFileList(); /** * @brief Set if the sd card is mounted by the printer * @param mounted: True is mounted */ void setSdMounted(const bool mounted); /** * @brief set AtCorePrivate::sdCardReadingFileList * @param readingList set true if reading file list */ void setReadingSdCardList(bool readingList); }; diff --git a/src/atcore_default_folders.h.in b/src/atcore_default_folders.h.in index e08d26d..eac2a88 100644 --- a/src/atcore_default_folders.h.in +++ b/src/atcore_default_folders.h.in @@ -1,31 +1,31 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include namespace AtCoreDirectories { const QStringList pluginDir = \ QStringList(QStringLiteral("@CMAKE_CURRENT_BINARY_DIR@/plugins")) \ << QStringList(QStringLiteral("@KDE_INSTALL_PLUGINDIR@/AtCore")) \ << QStringList(QLibraryInfo::location(QLibraryInfo::PluginsPath) + QStringLiteral("/AtCore")) \ << QStringList(QStringLiteral("plugins")); }; diff --git a/src/gcodecommands.cpp b/src/gcodecommands.cpp index 1a9cd78..8c40ef3 100644 --- a/src/gcodecommands.cpp +++ b/src/gcodecommands.cpp @@ -1,564 +1,564 @@ /* AtCore Copyright (C) <2016> Authors: - Lays Rodrigues + Lays Rodrigues Tomaz Canabrava - Patrick José Pereira + Patrick José Pereira Chris Rizzitello This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "gcodecommands.h" const QString GCode::commandRequiresArgument = QObject::tr("%1%2: requires an argument"); const QString GCode::commandNotSupported = QObject::tr("Not implemented or not supported!"); QString GCode::description(GCommands gcode) { switch (gcode) { case G0://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G0: Rapid linear move"); case G1://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("G1: Linear move"); case G2://Sprinter - Marlin - Repetier - Smoothie return QObject::tr("G2: Controlled Arc Move clockwise"); case G3://Sprinter - Marlin - Repetier - Smoothie return QObject::tr("G3: Controlled Arc Move counterclockwise"); case G4://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G4: Dwell"); case G10://Marlin - Repetier > 0.92 - Smoothie return QObject::tr("G10: Retract"); case G11://Marlin - Repetier > 0.92 - Smoothie return QObject::tr("G11: Unretract"); case G20://Teacup - Sprinter - Repetier - Smoothie - RepRap Firmware return QObject::tr("G20: Set units to inches"); case G21://Teacup - Sprinter - Repetier - Smoothie - RepRap Firmware return QObject::tr("G21: Set units to millimeters"); case G28://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G28: Move to Origin Home"); case G29://Marlin - Repetier 0.91.7 return QObject::tr("G29: Detailed Z-Probe"); case G30:// Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("G30: Single Z-Probe"); case G31://Repetier 0.91.7 - Smoothie - RepRap Firmware - Marlin return QObject::tr("G31: Set or report current probe status / Dock Z Probe sled for Marlin"); case G32://Repetier 0.92.8 - Smoothie - RepRap Firmware - Marlin return QObject::tr("G32: Probe Z and calculate Z plane(Bed Leveling)/ UnDoc Z Probe sled for Marlin"); case G33://Repetier 0.92.8 return QObject::tr("G33: Measure/List/Adjust Distortion Matrix"); case G90://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G90: Set to absolute positioning"); case G91://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G91: Set to relative positioning"); case G92://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("G92: Set position"); case G100://Repetier 0.92 return QObject::tr("G100: Calibrate floor or rod radius"); case G130://MakerBot return QObject::tr("G130: Set digital potentiometer value"); case G131://Repetier 0.91 return QObject::tr("G131: Recase Move offset"); case G132://Repetier 0.91 return QObject::tr("G132: Calibrate endstops offsets"); case G133://Repetier 0.91 return QObject::tr("G133: Measure steps to top"); case G161://Teacup - MakerBot return QObject::tr("G161: Home axis to minimum"); case G162://Teacup - MakerBot return QObject::tr("G162: Home axis to maximum"); default: return commandNotSupported; } } QString GCode::toCommand(GCommands gcode, const QString &value1) { QString code = QStringLiteral("G%1").arg(QString::number(gcode)); switch (gcode) { case G90: case G91: return code; case G32: return code.append(QStringLiteral(" S1")); case G0: case G1: case G28: code = value1.isEmpty() ? code : code.append(QStringLiteral(" %1").arg(value1.toUpper())); return code; default: return commandNotSupported; } } QString GCode::description(MCommands gcode) { switch (gcode) { case M0://Marlin - Teacup - RepRap Firmware return QObject::tr("M0: Stop or unconditional stop"); case M1://Marlin - RepRap Firmware return QObject::tr("M1: Sleep or unconditional stop"); case M2://Teacup - Maker Bot return QObject::tr("M2: Program End"); case M6://Teacup return QObject::tr("M6: Tool Change"); case M17://Teacup - Marlin - Smoothie return QObject::tr("M17: Enable/power all steppers motors"); case M18://Teacup - Marlin(M84) - Smoothie -RepRap Firmware return QObject::tr("M18: Disable all steppers motors"); case M20://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M20: List SDCard"); case M21://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M21: Initialize SDCard"); case M22://Teacup - Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M22: Release SDCard"); case M23://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M23: Select SD file"); case M24://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M24: Start/resume SD print"); case M25://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M25: Pause SD print"); case M26://Sprinter - Marlin - Repetier - Smoothie(abort) - RepRap Firmware return QObject::tr("M26: Set SD position"); case M27://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M27: Report SD print status"); case M28://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M28: Begin write to SD card"); case M29:// Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M29: Stop writing to SD card"); case M30://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M30: Delete a file on the SD card"); case M31://Marlin return QObject::tr("M31: Output time since last M109 or SD card start to serial"); case M32://Marlin - Smoothie - RepRap Firmware return QObject::tr("M32: Select file and start SD print"); case M33://Marlin return QObject::tr("M33: Get the long name for an SD card file or folder"); case M34://Marlin return QObject::tr("M34: Set SD file sorting options"); case M36://RepRap Firmware return QObject::tr("M36: Return file information"); case M42://Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M42: Switch I/O pin"); case M48://Marlin return QObject::tr("M48: Measure Z-Probe repeatability"); case M70://MakerBot return QObject::tr("M70: Display message"); case M72://MakerBot return QObject::tr("M72: Play a tone or song"); case M73://MakerBot return QObject::tr("M73: Set build percentage"); case M80://Teacup(automatic) - Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M80: ATX Power On"); case M81://Teacup(automatic) - Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M81: ATX Power Off"); case M82://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M82: Set extruder to absolute mode"); case M83://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M83: Set extruder to relative mode"); case M84://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M84: Stop idle hold"); case M85://Sprinter - Marlin - Repetier return QObject::tr("M85: Set Inactivity shutdown timer"); case M92:// Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M92: Set axis steps per unit"); case M93:// Sprinter return QObject::tr("M93: Send axis steps per unit"); case M98: //RepRap Firmware return QObject::tr("M98: Call Macro/Subprogram"); case M99://RepRap Firmware return QObject::tr("M99: Return from Macro/Subprogram"); case M101://Teacup return QObject::tr("M101: Turn extruder 1 on Forward, Undo Retraction"); case M103://Teacup return QObject::tr("M103: Turn all extruders off - Extruder Retraction"); case M104://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("M104: Set Extruder Temperature"); case M105://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("M105: Get Extruder Temperature"); case M106://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M106: Fan On"); case M107:// Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M107: Fan Off"); case M108://Marlin return QObject::tr("M108: Cancel Heating"); case M109:// Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("M109: Set Extruder Temperature and Wait"); case M110:// Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M110: Set Current Line Number"); case M111://Teacup - Marlin - Repetier - RepRap Firmware return QObject::tr("M111: Set Debug Level"); case M112://Teacup - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M112: Emergency Stop"); case M114://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("M114: Get Current Position"); case M115://Teacup - Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M115: Get Firmware Version and Capabilities"); case M116://Teacup - Repetier - RepRap Firmware - MakerBot return QObject::tr("M116: Wait"); case M117:// Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M117: Display Message"); case M119://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M119: Get Endstop Status"); case M120://Marlin - Smoothie - RepRap Firmware return QObject::tr("M120: Push for Smoothie and RepRap Firmware / Enable Endstop detection for Marlin"); case M121://Marlin - Smoothie - RepRap Firmware return QObject::tr("M121: Pop for Smoothie and RepRap Firmware / Disable Endstop detection for Marlin"); case M122://RepRap Firmware return QObject::tr("M122: Diagnose"); case M126://Marlin - MakerBot return QObject::tr("M126: Open valve"); case M127://Marlin - MakerBot return QObject::tr("M127: Close valve"); case M130://Teacup return QObject::tr("M130: Set PID P value"); case M131://Teacup return QObject::tr("M131: Set PID I value"); case M132://Teacup - MakerBot return QObject::tr("M132: Set PID D value"); case M133://Teacup - MakerBot return QObject::tr("M133: Set PID I limit value"); case M134://Teacup - MakerBot return QObject::tr("M134: Write PID values to EEPROM"); case M135://RepRap Firmware - MakerBot return QObject::tr("M135: Set PID sample interval"); case M140://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware - MakerBot return QObject::tr("M140: Set Bed Temperature - Fast"); case M141://RepRap Firmware return QObject::tr("M141: Set Chamber Temperature - Fast"); case M143://RepRap Firmware return QObject::tr("M143: Maximum hot-end temperature"); case M144://RepRap Firmware return QObject::tr("M144: Stand by your bed"); case M150://Marlin return QObject::tr("M150: Set display color"); case M163://Repetier > 0.92 return QObject::tr("M163: Set weight of mixed material"); case M164://Repetier > 0.92 return QObject::tr("M164: Store weights"); case M190://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M190: Wait for bed temperature to reach target temp"); case M200://Marlin - Repetier - Smoothie return QObject::tr("M200: Set filament diameter"); case M201://Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M201: Set max printing acceleration"); case M202://Marlin - Repetier return QObject::tr("M202: Set max travel acceleration"); case M203://Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M203: Set maximum feedrate"); case M204://Sprinter - Marlin - Repetier - Smoothie return QObject::tr("M204: Set default acceleration"); case M205://Sprinter - Marlin - Repetier - Smoothie return QObject::tr("M205: Advanced settings"); case M206://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M206: Offset axes for Sprinter, Marlin, Smoothie, RepRap Firmware / Set eeprom value for Repetier"); case M207://Marlin - Smoothie return QObject::tr("M207: Set retract length"); case M208://Marlin - Smoothie return QObject::tr("M208: Set unretract length"); case M209://Marlin - Repetier return QObject::tr("M209: Enable automatic retract"); case M212://Marlin return QObject::tr("M212: Set Bed Level Sensor Offset"); case M218://Marlin return QObject::tr("M218: Set Hotend Offset"); case M220://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M220: Set speed factor override percentage"); case M221://Teacup - Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M221: Set extrude factor override percentage"); case M226://Marlin - Repetier return QObject::tr("M226: Wait for pin state"); case M231://Repetier return QObject::tr("M231: Set OPS parameter"); case M232://Repetier return QObject::tr("M232: Read and reset max. advance values"); case M240://Marlin return QObject::tr("M240: Trigger camera"); case M250://Marlin return QObject::tr("M250: Set LCD contrast"); case M251://Repetier return QObject::tr("M251: Measure Z steps from homing stop (Delta printers)"); case M280://Marlin return QObject::tr("M280: Set servo position"); case M300://Marlin - Repetier - RepRap Firmware - MakerBot return QObject::tr("M300: Play beep sound"); case M301://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M301: Set PID parameters"); case M302://Marlin - Repetier > 0.92 - RepRap Firmware return QObject::tr("M302: Allow cold extrudes "); case M303://Sprinter - Marlin - Repetier - Smoothie return QObject::tr("M303: Run PID tuning"); case M304://Marlin - RepRap Firmware return QObject::tr("M304: Set PID parameters - Bed"); case M305:// Smoothie - RepRap Firmware return QObject::tr("M305: Set thermistor and ADC parameters"); case M306:// Smoothie return QObject::tr("M306: set home offset calculated from toolhead position"); case M320://Repeier return QObject::tr("M320: Activate autolevel (Repetier)"); case M321://Repetier return QObject::tr("M321: Deactivate autolevel (Repetier)"); case M322://Repetier return QObject::tr("M322: Reset autolevel matrix (Repetier)"); case M323://Repetier return QObject::tr("M323: Distortion correction on/off (Repetier)"); case M340://Repetier return QObject::tr("M340: Control the servos"); case M350://Marlin - Repetier - RepRap Firmware return QObject::tr("M350: Set microstepping mode"); case M351://Marlin return QObject::tr("M351: Toggle MS1 MS2 pins directly"); case M355://Repetier > 0.92.2 return QObject::tr("M355: Turn case lights on/off"); case M360://Repetier > 9.92.2 return QObject::tr("M360: Report firmware configuration"); case M361://Smoothie return QObject::tr("M361: Move to Theta 90 degree position"); case M362://Smoothie return QObject::tr("M362: Move to Psi 0 degree position"); case M363://Smoothie return QObject::tr("M363: Move to Psi 90 degree position"); case M364://Smoothie return QObject::tr("M364: Move to Psi + Theta 90 degree position"); case M365://Smoothie return QObject::tr("M365: SCARA scaling factor"); case M366://Smoothie return QObject::tr("M366: SCARA convert trim"); case M370://Smoothie return QObject::tr("M370: Morgan manual bed level - clear map"); case M371://Smoothie return QObject::tr("M371: Move to next calibration position"); case M372://Smoothie return QObject::tr("M372: Record calibration value, and move to next position"); case M373://Smoothie return QObject::tr("M373: End bed level calibration mode"); case M374://Smoothie return QObject::tr("M374: Save calibration grid"); case M375://Smoothie return QObject::tr("M375: Display matrix / Load Matrix"); case M380://Marlin return QObject::tr("M380: Activate solenoid"); case M381://Marlin return QObject::tr("M381: Disable all solenoids"); case M400://Sprinter - Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M400: Wait for current moves to finish"); case M401://Marlin return QObject::tr("M401: Lower z-probe"); case M402://Marlin return QObject::tr("M402: Raise z-probe"); case M404://Marlin - RepRap Firmware return QObject::tr("M404: Filament width and nozzle diameter"); case M405://Marlin return QObject::tr("M405: Filament Sensor on"); case M406://Marlin return QObject::tr("M406: Filament Sensor off"); case M407://Marlin - RepRap Firmware return QObject::tr("M407: Display filament diameter"); case M408://RepRap Firmware return QObject::tr("M408: Report JSON-style response"); case M420: return QObject::tr("M420: Enable/Disable Mesh Leveling (Marlin)"); case M450://Repetier return QObject::tr("M450: Report Printer Mode"); case M451://Repetier return QObject::tr("M451: Select FFF Printer Mode"); case M452://Repetier return QObject::tr("M452: Select Laser Printer Mode"); case M453://Repetier return QObject::tr("M453: Select CNC Printer Mode"); case M460://Repetier return QObject::tr("M460: Define temperature range for thermistor controlled fan"); case M500://Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M500: Store parameters in EEPROM"); case M501://Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M501: Read parameters from EEPROM"); case M502://Sprinter - Marlin - Repetier - RepRap Firmware return QObject::tr("M502: Revert to the default 'factory settings'."); case M503://Sprinter - Marlin - RepRap Firmware return QObject::tr("M503: Print settings "); case M540://Marlin return QObject::tr("M540: Enable/Disable 'Stop SD Print on Endstop Hit'"); case M550://RepRap Firmware return QObject::tr("M550: Set Name"); case M551://RepRap Firmware return QObject::tr("M551: Set Password"); case M552://RepRap Firmware return QObject::tr("M552: Set IP address"); case M553://RepRap Firmware return QObject::tr("M553: Set Netmask"); case M554://RepRap Firmware return QObject::tr("M554: Set Gateway"); case M555://RepRap Firmware return QObject::tr("M555: Set compatibility"); case M556://RepRap Firmware return QObject::tr("M556: Axis compensation"); case M557://Smoothie - RepRap Firmware return QObject::tr("M557: Set Z probe point"); case M558://RepRap Firmware return QObject::tr("M558: Set Z probe type"); case M559://RepRap Firmware return QObject::tr("M559: Upload configuration file"); case M560://RepRap Firmware return QObject::tr("M560: Upload web page file"); case M561://Smoothie - RepRap Firmware return QObject::tr("M561: Set Identity Transform"); case M562://RepRap Firmware return QObject::tr("M562: Reset temperature fault"); case M563://RepRap Firmware return QObject::tr("M563: Define or remove a tool"); case M564://RepRap Firmware return QObject::tr("M564: Limit axes"); case M565://Smoothie return QObject::tr("M565: Set Z probe offset"); case M566://RepRap Firmware return QObject::tr("M566: Set allowable instantaneous speed change"); case M567://RepRap Firmware return QObject::tr("M567: Set tool mix ratio"); case M568://RepRap Firmware return QObject::tr("M568: Turn off/on tool mix ratio"); case M569://RepRap Firmware return QObject::tr("M569: Set axis direction and enable values"); case M570://RepRap Firmware return QObject::tr("M570: Set heater timeout"); case M571://RepRap Firmware return QObject::tr("M571: Set output on extrude"); case M573://RepRap Firmware return QObject::tr("M573: Report heater PWM"); case M574://RepRap Firmware return QObject::tr("M574: Set endstop configuration"); case M575://RepRap Firmware return QObject::tr("M575: Set serial comms parameters"); case M577://RepRap Firmware return QObject::tr("M577: Wait until endstop is triggered"); case M578://RepRap Firmware return QObject::tr("M578: Fire inkjet bits"); case M579://RepRap Firmware return QObject::tr("M579: Scale Cartesian axes"); case M580://RepRap Firmware return QObject::tr("M580: Select Roland"); case M600://Marlin return QObject::tr("M600: Filament change pause"); case M605://Marlin return QObject::tr("M605: Set dual x-carriage movement mode"); case M665://Marlin - Smoothie - RepRap Firmware return QObject::tr("M665: Set delta configuration"); case M666://Marlin - Repetier - Smoothie - RepRap Firmware return QObject::tr("M666: Set delta endstop adjustment"); case M667://RepRap Firmware return QObject::tr("M667: Select CoreXY mode"); case M851://Marlin return QObject::tr("M851: Set Z-Probe Offset"); case M906://RepRap Firmware return QObject::tr("M906: Set motor currents"); case M907://Marlin - Repetier - Smoothie return QObject::tr("M907: Set digital trimpot motor"); case M908://Marlin - Repetier > 0.92 return QObject::tr("M908: Control digital trimpot directly"); case M911://RepRap Firmware return QObject::tr("M911: Set power monitor threshold voltages"); case M912://RepRap Firmware return QObject::tr("M912: Set electronics temperature monitor adjustment"); case M913://RepRap Firmware return QObject::tr("M913: Set motor percentage of normal current"); case M928://Marlin return QObject::tr("M928: Start SD logging"); case M997://RepRap Firmware return QObject::tr("M997: Perform in-application firmware update"); case M998://RepRap Firmware return QObject::tr("M998: Request resend of line"); case M999://Marlin - Smoothie - RepRap Firmware return QObject::tr("M999: Restart after being stopped by error"); default: return commandNotSupported; } } QString GCode::toCommand(MCommands gcode, const QString &value1, const QString &value2) { QString code = QStringLiteral("M%1").arg(QString::number(gcode)); switch (gcode) { case M20: case M24: case M25: case M27: case M105: case M107: case M112: case M114: case M115: case M116: case M119: return code; case M21: case M22: code = value1.isEmpty() ? code : code.append(QStringLiteral(" P%1").arg(value1)); return code; case M23: case M28: case M29: case M30: case M117: code = value1.isEmpty() ? GCode::commandRequiresArgument.arg(QStringLiteral("M"), QString::number(gcode)) : code.append(QStringLiteral(" %1").arg(value1)); return code; case M109: case M140: case M190: case M220: case M221: code = value1.isEmpty() ? GCode::commandRequiresArgument.arg(QStringLiteral("M"), QString::number(gcode)) : code.append(QStringLiteral(" S%1").arg(value1)); return code; case M84: code = value1.isEmpty() ? code : code.append(QStringLiteral(" S%1").arg(value1)); return code; case M104: code = value2.isEmpty() ? code.append(QStringLiteral(" S%1").arg(value1)) : code.append(QStringLiteral(" P%1 S%2").arg(value1).arg(value2)); code = value1.isEmpty() ? GCode::commandRequiresArgument.arg(QStringLiteral("M"), QString::number(gcode)) : code ; return code; case M106: code = value2.isEmpty() ? code.append(QStringLiteral(" S%1").arg(value1)) : code.append(QStringLiteral(" P%1 S%2").arg(value1).arg(value2)); code = value1.isEmpty() ? QStringLiteral("M106") : code ; return code; /// For M26 values that end with %. AtCore will send the percentage verison of the command (optional in firmwares) /// For all values not ending in % it will start on that byte. This is the standard Sd resume supported by all reprap based firmware. case M26: { if (!value1.isEmpty()) { if (value1.endsWith(QStringLiteral("%"))) { QString temp = value1; temp.replace(QStringLiteral("%"), QStringLiteral("")); return code.append(QStringLiteral(" P%1").arg(temp.toDouble() / 100)); } return code.append(QStringLiteral(" S%1").arg(value1)); } return GCode::commandRequiresArgument.arg(QStringLiteral("M"), QString::number(gcode)); } default: return commandNotSupported; } } diff --git a/src/gcodecommands.h b/src/gcodecommands.h index dbe3015..e2e17f3 100644 --- a/src/gcodecommands.h +++ b/src/gcodecommands.h @@ -1,144 +1,144 @@ /* AtCore Copyright (C) <2016> Authors: - Lays Rodrigues + Lays Rodrigues Tomaz Canabrava - Patrick José Pereira + Patrick José Pereira Chris Rizzitello This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include #include "atcore_export.h" /** * @brief The GCode class * Provides Descriptions and Commands strings for G and M Commands */ class ATCORE_EXPORT GCode { Q_GADGET friend class GCodeTests; public: /** * @brief The GCommands enum */ enum GCommands { G0, G1, G2, G3, G4, G10 = 10, G11, G20 = 20, G21, G22, G23, G28 = 28, G29, G30, G31, G32, G33, G90 = 90, G91, G92, G100 = 100, G130 = 130, G131, G132, G133, G161 = 161, G162 }; Q_ENUM(GCommands); /** * @brief The MCommands enum */ enum MCommands { M0, M1, M2, M6 = 6, M17 = 17, M18, M20 = 20, M21, M22, M23, M24, M25, M26, M27, M28, M29, M30, M31, M32, M33, M34, M36 = 36, M37, M38, M40 = 40, M41, M42, M43, M48 = 48, M70 = 70, M72 = 72, M73, M80 = 80, M81, M82, M83, M84, M85, M92 = 92, M93, M98 = 98, M99, M101 = 101, M102, M103, M104, M105, M106, M107, M108, M109, M110, M111, M112, M113, M114, M115, M116, M117, M118, M119, M120, M121, M122, M123, M124, M126 = 126, M127, M128, M129, M130, M131, M132, M133, M134, M135, M136, M140 = 140, M141, M142, M143, M144, M146 = 146, M149 = 149, M150 = 150, M160 = 160, M163 = 163, M164 = 164, M190 = 190, M191, M200 = 200, M201, M202, M203, M204, M205, M206, M207, M208, M209, M210, M211, M212, M218 = 218, M220 = 220, M221, M222, M223, M224, M225, M226, M227, M228, M229, M230, M231, M232, M240 = 240, M241, M245 = 245, M246, M250 = 250, M251, M280 = 280, M300 = 300, M301, M302, M303, M304, M305, M306, M320 = 320, M321, M322, M323, M340 = 340, M350 = 350, M351, M355 = 355, M360 = 360, M361, M362, M363, M364, M365, M366, M370 = 370, M371, M372, M373, M374, M375, M380 = 380, M381, M400 = 400, M401, M402, M404 = 404, M405, M406, M407, M408, M420 = 420, M421, M450 = 450, M451, M452, M453, M460 = 460, M500 = 500, M501, M502, M503, M540 = 540, M550 = 550, M551, M552, M553, M554, M555, M556, M557, M558, M559, M560, M561, M562, M563, M564, M565, M566, M567, M568, M569, M570, M571, M572, M573, M574, M575, M577 = 577, M578, M579, M580 = 580, M581, M582, M583, M584, M600 = 600, M605 = 605, M665 = 665, M666 = 666, M667, M668, M700 = 700, M701, M702, M703, M710 = 710, M800 = 800, M801, M851 = 851, M906 = 906, M907, M908, M910 = 910, M911, M912, M913, M928 = 928, M997 = 997, M998, M999 }; Q_ENUM(MCommands); /** * @brief Return Description of command \p gcode * @param gcode: Command to describe * @return description of GCommand */ static QString description(GCommands gcode); /** * @brief Return Description of command \p gcode * @param gcode: Command to describe * @return description of MCommand */ static QString description(MCommands gcode); /** * @brief Convert GCode::GCommands to command * @param gcode: GCode::GCommands * @param value1: Value of argument * @return Command String to send to printer */ static QString toCommand(GCommands gcode, const QString &value1 = QString()); /** * @brief Convert GCode::MCommands to command * @param gcode: GCode::MCommands * @param value1: Value of argument 1 * @param value2: Value of argument 2 * @return Command String to send to printer */ static QString toCommand(MCommands gcode, const QString &value1 = QString(), const QString &value2 = QString()); protected: static const QString commandRequiresArgument; static const QString commandNotSupported; }; diff --git a/src/ifirmware.cpp b/src/ifirmware.cpp index bb353fa..17c4333 100644 --- a/src/ifirmware.cpp +++ b/src/ifirmware.cpp @@ -1,76 +1,76 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "ifirmware.h" #include "atcore.h" /** * @brief The IFirmwarePrivate struct * @param parent: parent of this object */ struct IFirmwarePrivate { AtCore *parent; /** * @brief command finished string */ static const QString _ok; }; const QString IFirmwarePrivate::_ok = QStringLiteral("ok"); IFirmware::IFirmware() : d(new IFirmwarePrivate) { } void IFirmware::init(AtCore *parent) { d->parent = parent; connect(d->parent, &AtCore::receivedMessage, this, &IFirmware::checkCommand); } AtCore *IFirmware::core() const { return d->parent; } IFirmware::~IFirmware() { } void IFirmware::checkCommand(const QByteArray &lastMessage) { validateCommand(QString::fromLatin1(lastMessage)); } void IFirmware::validateCommand(const QString &lastMessage) { if (lastMessage.contains(d->_ok)) { emit readyForCommand(); } } QByteArray IFirmware::translate(const QString &command) { return command.toLocal8Bit(); } diff --git a/src/ifirmware.h b/src/ifirmware.h index 34b560e..626929d 100644 --- a/src/ifirmware.h +++ b/src/ifirmware.h @@ -1,92 +1,92 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include #include "atcore_export.h" class Temperature; class AtCore; struct IFirmwarePrivate; /** * @brief The IFirmware class * Base Class for Firmware Plugins */ class ATCORE_EXPORT IFirmware : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name) public: IFirmware(); void init(AtCore *parent); ~IFirmware() override; /** * @brief Virtual name to be reimplemnted by Firmware plugin * * Return the name the firmware the plugin is for * @return Firmware Name */ virtual QString name() const = 0; /** * @brief Vitural validateCommand to filter commands from messages * @param lastMessage: last Message from printer */ virtual void validateCommand(const QString &lastMessage); /** * @brief Virtual translate to be reimplemnted by Firmwareplugin * * Translate common commands to firmware specific command. * @param command: Command command to translate * @return firmware specific translated command */ virtual QByteArray translate(const QString &command); /** * @brief AtCore Parent of the firmware plugin * @return */ AtCore *core() const; private: IFirmwarePrivate *d; public slots: /** * @brief call Validate Command * @param lastMessage: last message from printer */ void checkCommand(const QByteArray &lastMessage); signals: /** * @brief emit when firmware is ready for a command */ void readyForCommand(void); }; Q_DECLARE_INTERFACE(IFirmware, "org.kde.atelier.core.firmware") diff --git a/src/plugins/aprinterplugin.cpp b/src/plugins/aprinterplugin.cpp index b3c7169..8280059 100644 --- a/src/plugins/aprinterplugin.cpp +++ b/src/plugins/aprinterplugin.cpp @@ -1,41 +1,41 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "aprinterplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(APRINTER_PLUGIN, "org.kde.atelier.core.firmware.aprinter") QString AprinterPlugin::name() const { return QStringLiteral("Aprinter"); } AprinterPlugin::AprinterPlugin() { qCDebug(APRINTER_PLUGIN) << name() << " plugin loaded!"; } diff --git a/src/plugins/aprinterplugin.h b/src/plugins/aprinterplugin.h index 5466d11..a4fa07d 100644 --- a/src/plugins/aprinterplugin.h +++ b/src/plugins/aprinterplugin.h @@ -1,51 +1,51 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The AprinterPlugin class * Plugin for Aprinter */ class AprinterPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new AprinterPlugin */ AprinterPlugin(); /** * @brief Return Plugin name * @return Aprinter */ QString name() const override; }; diff --git a/src/plugins/grblplugin.cpp b/src/plugins/grblplugin.cpp index 255f64f..404ffce 100644 --- a/src/plugins/grblplugin.cpp +++ b/src/plugins/grblplugin.cpp @@ -1,43 +1,43 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include "grblplugin.h" QString GrblPlugin::name() const { return QStringLiteral("Grbl"); } GrblPlugin::GrblPlugin() { } void GrblPlugin::validateCommand(const QString &lastMessage) { Q_UNUSED(lastMessage); emit readyForCommand(); } diff --git a/src/plugins/grblplugin.h b/src/plugins/grblplugin.h index e751fb8..751ab6c 100644 --- a/src/plugins/grblplugin.h +++ b/src/plugins/grblplugin.h @@ -1,57 +1,57 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The GrblPlugin class * Plugin for Grbl */ class GrblPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new GrblPlugin */ GrblPlugin(); /** * @brief Return Plugin name * @return Grbl */ QString name() const override; /** * @brief Grbl does not return anything on command execution * @param lastMessage: last message from printer */ void validateCommand(const QString &lastMessage) override; }; diff --git a/src/plugins/marlinplugin.cpp b/src/plugins/marlinplugin.cpp index 09ce7f8..c86e56a 100644 --- a/src/plugins/marlinplugin.cpp +++ b/src/plugins/marlinplugin.cpp @@ -1,85 +1,85 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "marlinplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(MARLIN_PLUGIN, "org.kde.atelier.core.firmware.marlin") QString MarlinPlugin::name() const { return QStringLiteral("Marlin"); } MarlinPlugin::MarlinPlugin() { qCDebug(MARLIN_PLUGIN) << name() << " plugin loaded!"; } void MarlinPlugin::validateCommand(const QString &lastMessage) { if (lastMessage.contains(QStringLiteral("End file list"))) { core()->setReadingSdCardList(false); } else if (core()->isReadingSdCardList()) { // Below is to not add directories if (!lastMessage.endsWith(QChar::fromLatin1('/'))) { QString fileName = lastMessage; fileName.chop(fileName.length() - fileName.lastIndexOf(QChar::fromLatin1(' '))); core()->appendSdCardFileList(fileName); } } else { if (lastMessage.contains(QStringLiteral("SD card ok"))) { core()->setSdMounted(true); } else if (lastMessage.contains(QStringLiteral("SD init fail"))) { core()->setSdMounted(false); } else if (lastMessage.contains(QStringLiteral("Begin file list"))) { core()->setSdMounted(true); core()->clearSdCardFileList(); core()->setReadingSdCardList(true); } else if (lastMessage.contains(QStringLiteral("SD printing byte"))) { QString temp = lastMessage; temp.replace(QStringLiteral("SD printing byte"), QString()); qlonglong total = temp.mid(temp.lastIndexOf(QChar::fromLatin1('/')) + 1, temp.length() - temp.lastIndexOf(QChar::fromLatin1('/'))).toLongLong(); if (total) { temp.chop(temp.length() - temp.lastIndexOf(QChar::fromLatin1('/'))); qlonglong remaining = total - temp.toLongLong(); float progress = float(total - remaining) * 100 / float(total); core()->printProgressChanged(progress); if (progress >= 100) { core()->setState(AtCore::FINISHEDPRINT); core()->setState(AtCore::IDLE); } } else { core()->setState(AtCore::FINISHEDPRINT); core()->setState(AtCore::IDLE); } } if (lastMessage.contains(QStringLiteral("ok"))) { emit readyForCommand(); } } } diff --git a/src/plugins/marlinplugin.h b/src/plugins/marlinplugin.h index 053b3bc..3fa5306 100644 --- a/src/plugins/marlinplugin.h +++ b/src/plugins/marlinplugin.h @@ -1,57 +1,57 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The MarlinPlugin class * Plugin for Marlin */ class MarlinPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new MarlinPlugin */ MarlinPlugin(); /** * @brief Return Plugin name * @return Marlin */ QString name() const override; /** * @brief validateCommand to filter commands from messages * @param lastMessage: last Message from printer */ void validateCommand(const QString &lastMessage) override; }; diff --git a/src/plugins/repetierplugin.cpp b/src/plugins/repetierplugin.cpp index 5d1be27..40f28e8 100644 --- a/src/plugins/repetierplugin.cpp +++ b/src/plugins/repetierplugin.cpp @@ -1,87 +1,87 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "repetierplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(REPETIER_PLUGIN, "org.kde.atelier.core.firmware.repetier") QString RepetierPlugin::name() const { return QStringLiteral("Repetier"); } RepetierPlugin::RepetierPlugin() { qCDebug(REPETIER_PLUGIN) << name() << " plugin loaded!"; } void RepetierPlugin::validateCommand(const QString &lastMessage) { if (lastMessage.contains(QStringLiteral("End file list"))) { core()->setReadingSdCardList(false); } else if (core()->isReadingSdCardList()) { // Below is to not add directories if (!lastMessage.endsWith(QChar::fromLatin1('/'))) { QString fileName = lastMessage; fileName.chop(fileName.length() - fileName.lastIndexOf(QChar::fromLatin1(' '))); core()->appendSdCardFileList(fileName); } } else { if (lastMessage.contains(QStringLiteral("SD card"))) { if (lastMessage.contains(QStringLiteral("inserted"))) { core()->setSdMounted(true); } else if (lastMessage.contains(QStringLiteral("removed"))) { core()->setSdMounted(false); } } else if (lastMessage.contains(QStringLiteral("Begin file list"))) { core()->setSdMounted(true); core()->setReadingSdCardList(true); core()->clearSdCardFileList(); } else if (lastMessage.contains(QStringLiteral("SD printing byte"))) { QString temp = lastMessage; temp.replace(QStringLiteral("SD printing byte"), QString()); qlonglong total = temp.mid(temp.lastIndexOf(QChar::fromLatin1('/')) + 1, temp.length() - temp.lastIndexOf(QChar::fromLatin1('/'))).toLongLong(); if (total) { temp.chop(temp.length() - temp.lastIndexOf(QChar::fromLatin1('/'))); qlonglong remaining = total - temp.toLongLong(); float progress = float(total - remaining) * 100 / float(total); core()->printProgressChanged(progress); if (progress >= 100) { core()->setState(AtCore::FINISHEDPRINT); core()->setState(AtCore::IDLE); } } else { core()->setState(AtCore::FINISHEDPRINT); core()->setState(AtCore::IDLE); } } if (lastMessage.contains(QStringLiteral("ok"))) { emit readyForCommand(); } } } diff --git a/src/plugins/repetierplugin.h b/src/plugins/repetierplugin.h index 8778a3c..91239b7 100644 --- a/src/plugins/repetierplugin.h +++ b/src/plugins/repetierplugin.h @@ -1,57 +1,57 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The RepetierPlugin class * Plugin for Repetier */ class RepetierPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new RepetierPlugin */ RepetierPlugin(); /** * @brief Return Plugin name * @return Repetier */ QString name() const override; /** * @brief validateCommand to filter commands from messages * @param lastMessage: last Message from printer */ void validateCommand(const QString &lastMessage) override; }; diff --git a/src/plugins/smoothieplugin.cpp b/src/plugins/smoothieplugin.cpp index 001d011..3ea803e 100644 --- a/src/plugins/smoothieplugin.cpp +++ b/src/plugins/smoothieplugin.cpp @@ -1,41 +1,41 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "smoothieplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(SMOOTHIE_PLUGIN, "org.kde.atelier.core.firmware.smoothie") QString SmoothiePlugin::name() const { return QStringLiteral("Smoothie"); } SmoothiePlugin::SmoothiePlugin() { qCDebug(SMOOTHIE_PLUGIN) << name() << " plugin loaded!"; } diff --git a/src/plugins/smoothieplugin.h b/src/plugins/smoothieplugin.h index 7589d2b..a0d3355 100644 --- a/src/plugins/smoothieplugin.h +++ b/src/plugins/smoothieplugin.h @@ -1,51 +1,51 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The SmoothiePlugin class * Plugin for Smoothie */ class SmoothiePlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new SmoothiePlugin */ SmoothiePlugin(); /** * @brief Return Plugin name * @return Smoothie */ QString name() const override; }; diff --git a/src/plugins/sprinterplugin.cpp b/src/plugins/sprinterplugin.cpp index 01a232c..0d3dc66 100644 --- a/src/plugins/sprinterplugin.cpp +++ b/src/plugins/sprinterplugin.cpp @@ -1,41 +1,41 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "sprinterplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(SPRINTER_PLUGIN, "org.kde.atelier.core.firmware.sprinter") QString SprinterPlugin::name() const { return QStringLiteral("Sprinter"); } SprinterPlugin::SprinterPlugin() { qCDebug(SPRINTER_PLUGIN) << name() << " plugin loaded!"; } diff --git a/src/plugins/sprinterplugin.h b/src/plugins/sprinterplugin.h index 7b24b69..0edd93c 100644 --- a/src/plugins/sprinterplugin.h +++ b/src/plugins/sprinterplugin.h @@ -1,51 +1,51 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The SprinterPlugin class * Plugin for Sprinter */ class SprinterPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new SprinterPlugin */ SprinterPlugin(); /** * @brief Return Plugin name * @return Sprinter */ QString name() const override; }; diff --git a/src/plugins/teacupplugin.cpp b/src/plugins/teacupplugin.cpp index 1b40db2..86423f9 100644 --- a/src/plugins/teacupplugin.cpp +++ b/src/plugins/teacupplugin.cpp @@ -1,54 +1,54 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "teacupplugin.h" #include "atcore.h" Q_LOGGING_CATEGORY(TEACUP_PLUGIN, "org.kde.atelier.core.firmware.teacup") QString TeacupPlugin::name() const { return QStringLiteral("Teacup"); } TeacupPlugin::TeacupPlugin() { qCDebug(TEACUP_PLUGIN) << name() << " plugin loaded!"; } QByteArray TeacupPlugin::translate(const QString &command) { QString temp = command; if (command.contains(QStringLiteral("M109"))) { temp.replace(QStringLiteral("M109"), QStringLiteral("M104")); temp.append(QStringLiteral("\r\nM116")); } else if (command.contains(QStringLiteral("M190"))) { temp.replace(QStringLiteral("M190"), QStringLiteral("M140")); temp.append(QStringLiteral("\r\nM116")); } return temp.toLocal8Bit(); } diff --git a/src/plugins/teacupplugin.h b/src/plugins/teacupplugin.h index 3f62a9b..ef857db 100644 --- a/src/plugins/teacupplugin.h +++ b/src/plugins/teacupplugin.h @@ -1,58 +1,58 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "ifirmware.h" /** * @brief The TeacupPlugin class * Plugin for Teacup */ class TeacupPlugin : public IFirmware { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.atelier.core.firmware") Q_INTERFACES(IFirmware) public: /** * @brief Create new TeacupPlugin */ TeacupPlugin(); /** * @brief Return Plugin name * @return Teacup */ QString name() const override; /** * @brief Translate common commands to firmware specific command. * @param command: command to translate * @return firmware specific translated command */ QByteArray translate(const QString &command) override; }; diff --git a/src/seriallayer.cpp b/src/seriallayer.cpp index 78d55bf..a606742 100644 --- a/src/seriallayer.cpp +++ b/src/seriallayer.cpp @@ -1,151 +1,151 @@ /* AtCore Copyright (C) <2016> Authors: - Patrick José Pereira + Patrick José Pereira Chris Rizzitello Tomaz Canabrava This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include "seriallayer.h" Q_LOGGING_CATEGORY(SERIAL_LAYER, "org.kde.atelier.core.serialLayer") namespace { QByteArray _return = QByteArray("\r"); QByteArray _newLine = QByteArray("\n"); QByteArray _newLineReturn = QByteArray("\n\r"); QStringList _validBaudRates = { QStringLiteral("9600"), QStringLiteral("14400"), QStringLiteral("19200"), QStringLiteral("28800"), QStringLiteral("38400"), QStringLiteral("57600"), QStringLiteral("76800"), QStringLiteral("115200"), QStringLiteral("230400"), QStringLiteral("250000"), QStringLiteral("500000"), QStringLiteral("1000000") }; } /** * @brief The SerialLayerPrivate class */ class SerialLayerPrivate { public: bool _serialOpened; //!< @param _serialOpened: is serial port opened QByteArray _rawData; //!< @param _rawData: the raw serial data QVector _rByteCommands; //!< @param _rByteCommand: received Messages QVector _sByteCommands; //!< @param _sByteCommand: sent Messages }; SerialLayer::SerialLayer(const QString &port, uint baud, QObject *parent) : QSerialPort(parent), d(new SerialLayerPrivate()) { setPortName(port); setBaudRate(baud); if (open(QIODevice::ReadWrite)) { d->_serialOpened = true; connect(this, &QSerialPort::readyRead, this, &SerialLayer::readAllData); } }; void SerialLayer::readAllData() { d->_rawData.append(readAll()); /* * Check if \r exist and remove * Both \n\r and \n are used in string's end and some protocols */ if (d->_rawData.contains(_return)) { d->_rawData = d->_rawData.replace(_return, QByteArray()); } QByteArray tempArray; QList tempList = d->_rawData.split(_newLine.at(0)); for (auto i = tempList.begin(); i != tempList.end(); ++i) { // Get finished line to _byteCommands if (i < tempList.end() - 1) { d->_rByteCommands.append(*i); emit(receivedCommand(*i)); } else { d->_rawData.clear(); d->_rawData.append(*i); } } } void SerialLayer::pushCommand(const QByteArray &comm, const QByteArray &term) { if (!isOpen()) { qCDebug(SERIAL_LAYER) << "Serial not connected !"; return; } QByteArray tmp = comm + term; write(tmp); emit(pushedCommand(tmp)); } void SerialLayer::pushCommand(const QByteArray &comm) { pushCommand(comm, _newLineReturn); } void SerialLayer::add(const QByteArray &comm, const QByteArray &term) { QByteArray tmp = comm + term; d->_sByteCommands.append(tmp); } void SerialLayer::add(const QByteArray &comm) { add(comm, _newLineReturn); } void SerialLayer::push() { if (!isOpen()) { qCDebug(SERIAL_LAYER) << "Serial not connected !"; return; } foreach (const auto &comm, d->_sByteCommands) { write(comm); emit(pushedCommand(comm)); } d->_sByteCommands.clear(); } bool SerialLayer::commandAvailable() const { return !d->_rByteCommands.isEmpty(); } QStringList SerialLayer::validBaudRates() const { return _validBaudRates; } diff --git a/src/seriallayer.h b/src/seriallayer.h index 0670eb5..d699b87 100644 --- a/src/seriallayer.h +++ b/src/seriallayer.h @@ -1,124 +1,124 @@ /* AtCore Copyright (C) <2016> Authors: - Patrick José Pereira + Patrick José Pereira Chris Rizzitello Tomaz Canabrava This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include #include "atcore_export.h" class SerialLayerPrivate; /** * @brief The SerialLayer class. * Provide the low level serial operations */ class ATCORE_EXPORT SerialLayer : public QSerialPort { Q_OBJECT private: SerialLayerPrivate *d; /** * @brief Read all available serial data * */ void readAllData(); signals: /** * @brief Emit signal when command is pushed * * @param comm : Command */ void pushedCommand(const QByteArray &comm); /** * @brief Emit signal when command is received * * @param comm : Command */ void receivedCommand(const QByteArray &comm); public: /** * @brief SerialLayer Class to realize communication * * @param port : Port (/dev/ttyUSB ACM) * @param baud : Baud rate (115200) * @param parent : Parent */ SerialLayer(const QString &port, uint baud, QObject *parent = nullptr); /** * @brief Add command to be pushed * * @param comm : Command * @param term : Terminator */ void add(const QByteArray &comm, const QByteArray &term); /** * @brief Add command to be pushed * * @param comm : Command, default terminator will be used */ void add(const QByteArray &comm); /** * @brief Push command directly * * @param comm : Command * @param term : Terminator */ void pushCommand(const QByteArray &comm, const QByteArray &term); /** * @brief Push command directly * * @param comm : Command, default terminator will be used */ void pushCommand(const QByteArray &comm); /** * @brief Push all commands used in add to serial write * */ void push(); /** * @brief Check if is a command available * * @return bool */ bool commandAvailable() const; /** * @brief Return a QStringList of valids serial baud rates * * @return QStringList */ QStringList validBaudRates() const; }; diff --git a/src/temperature.cpp b/src/temperature.cpp index 73a0e87..f0a631c 100644 --- a/src/temperature.cpp +++ b/src/temperature.cpp @@ -1,137 +1,137 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava - Patrick José Pereira + Patrick José Pereira Chris Rizzitello This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "temperature.h" /** * @brief The TemperaturePrivate class * * Private Data of Temperature */ class TemperaturePrivate { public: float extruderTemp; //!< @param extruderTemp: Extruder current temperature float extruderTargetTemp; //!< @param extruderTargetTemp: Extruder target temperature float bedTemp; //!< @param bedTemp: Bed current temperature float bedTargetTemp; //!< @param bedTargetTemp: Bed target temperature }; Temperature::Temperature(QObject *parent) : QObject(parent) , d(new TemperaturePrivate) { } float Temperature::bedTargetTemperature() const { return d->bedTargetTemp; } float Temperature::bedTemperature() const { return d->bedTemp; } float Temperature::extruderTargetTemperature() const { return d->extruderTargetTemp; } float Temperature::extruderTemperature() const { return d->extruderTemp; } void Temperature::setBedTargetTemperature(float temp) { d->bedTargetTemp = temp; emit bedTargetTemperatureChanged(temp); } void Temperature::setBedTemperature(float temp) { d->bedTemp = temp; emit bedTemperatureChanged(temp); } void Temperature::setExtruderTargetTemperature(float temp) { d->extruderTargetTemp = temp; emit extruderTargetTemperatureChanged(temp); } void Temperature::setExtruderTemperature(float temp) { d->extruderTemp = temp; emit extruderTemperatureChanged(temp); } void Temperature::decodeTemp(const QByteArray &msg) { int bloc = msg.indexOf(QStringLiteral("B:")); float firstTargetTemperature = 0; float secondTargetTemperature = 0; QRegularExpression tempRegEx(QStringLiteral("(T:(?\\d+\\.?\\d*))")); QRegularExpression targetTempRegEx(QStringLiteral("(\\/)(?\\d*)(.+)")); QRegularExpressionMatch tempCheck = tempRegEx.match(QString::fromLatin1(msg)); QRegularExpressionMatch targetTempCheck = targetTempRegEx.match(QString::fromLatin1(msg)); if (tempCheck.hasMatch()) { setExtruderTemperature(tempCheck.captured(QStringLiteral("extruder")).toFloat()); } if (targetTempCheck.hasMatch()) { firstTargetTemperature = targetTempCheck.captured(QStringLiteral("extruderTarget")).toFloat(); } if (bloc != -1) { QRegularExpression bedRegEx(QStringLiteral("(B:(?\\d+\\.?\\d*))")); QRegularExpressionMatch bedCheck = bedRegEx.match(QString::fromLatin1(msg)); QRegularExpression targetBedRegEx(QStringLiteral("B:(.+)(\\/)(?\\d+)")); QRegularExpressionMatch targetBedCheck = targetBedRegEx.match(QString::fromLatin1(msg)); if (bedCheck.hasMatch()) { setBedTemperature(bedCheck.captured(QStringLiteral("bed")).toFloat()); } if (targetBedCheck.hasMatch()) { secondTargetTemperature = targetBedCheck.captured(QStringLiteral("bedTarget")).toFloat(); } } //Currently the first value after / is stored in firstTargetTemperature and the second / in secondTargetTemperature //Because of this we need to check what came first in the return and place the values //The regex for temperature needs to look at the whole T: or B: block to correctly decode targets if (bloc < msg.indexOf(QStringLiteral("T:")) && bloc != -1) { setExtruderTargetTemperature(secondTargetTemperature); setBedTargetTemperature(firstTargetTemperature); } else { setExtruderTargetTemperature(firstTargetTemperature); setBedTargetTemperature(secondTargetTemperature); } } diff --git a/src/temperature.h b/src/temperature.h index faff2aa..c37ad24 100644 --- a/src/temperature.h +++ b/src/temperature.h @@ -1,129 +1,129 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava - Patrick José Pereira + Patrick José Pereira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #pragma once #include #include "atcore_export.h" class TemperaturePrivate; /** * @brief The Temperature class * * Read and hold the Temperature info for the printer */ class ATCORE_EXPORT Temperature : public QObject { Q_OBJECT Q_PROPERTY(float bedTemperature READ bedTemperature WRITE setBedTemperature NOTIFY bedTemperatureChanged) Q_PROPERTY(float bedTargetTemperature READ bedTargetTemperature WRITE setBedTargetTemperature NOTIFY bedTargetTemperatureChanged) Q_PROPERTY(float extruderTemperature READ extruderTemperature WRITE setExtruderTemperature NOTIFY extruderTemperatureChanged) Q_PROPERTY(float extruderTargetTemperature READ extruderTargetTemperature WRITE setExtruderTargetTemperature NOTIFY extruderTargetTemperatureChanged) public: /** * @brief Create a new Temperature object * @param parent */ explicit Temperature(QObject *parent = nullptr); /** * @brief Get bed current temperature */ float bedTemperature() const; /** * @brief Get bed target temperature */ float bedTargetTemperature() const; /** * @brief Get extruder temperature */ float extruderTemperature() const; /** * @brief Get extruder target temperature */ float extruderTargetTemperature() const; /** * @brief decode Temp values from string \p msg * @param msg: string to read vaules from */ void decodeTemp(const QByteArray &msg); public slots: /** * @brief Set bed temperature * @param temp: bed temperature */ void setBedTemperature(float temp); /** * @brief Set bed target temperature * @param temp: bed target temperature */ void setBedTargetTemperature(float temp); /** * @brief Set exturder temperature * @param temp: bed temperature */ void setExtruderTemperature(float temp); /** * @brief Set extruder target temperature * @param temp: extruder target temperature */ void setExtruderTargetTemperature(float temp); signals: /** * @brief bed temperature has changed * @param temp : new bed temperature */ void bedTemperatureChanged(float temp); /** * @brief bed target temperature has changed * @param temp : new bed target temperature */ void bedTargetTemperatureChanged(float temp); /** * @brief extruder temperature has changed * @param temp : new extruder temperature */ void extruderTemperatureChanged(float temp); /** * @brief extruder target temperature has changed * @param temp : new extruder target temperature */ void extruderTargetTemperatureChanged(float temp); private: TemperaturePrivate *d; }; diff --git a/src/widgets/about.cpp b/src/widgets/about.cpp index 9608607..7226ef1 100644 --- a/src/widgets/about.cpp +++ b/src/widgets/about.cpp @@ -1,67 +1,72 @@ /* AtCore Test Client Copyright (C) <2017> Authors: Chris Rizzitello 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "about.h" About::About(QWidget *parent) : QDialog(parent) { setWindowTitle(QStringLiteral("About Atcore")); setWindowIcon(QIcon::fromTheme(QStringLiteral("help-about"), style()->standardIcon(QStyle::SP_MessageBoxInformation))); QLabel *lbl_version = new QLabel(QString::fromLatin1("Version: %1").arg(QCoreApplication::applicationVersion())); QLabel *lbl_qt_version = new QLabel(QString::fromLatin1("Using Qt: %1").arg(QString::fromLatin1(qVersion()))); - QLabel *lbl_authors = new QLabel(QStringLiteral("Authors:\n Chris Rizzitello \n Patrick José Pereira \n Lays Rodrigues \n Tomaz Canabrava ")); + QLabel *lbl_authors = new QLabel(QStringLiteral("Authors:\n" + " Chris Rizzitello \n" + " Patrick José Pereira \n" + " Lays Rodrigues \n" + " Tomaz Canabrava " + "")); QLabel *lbl_icon = new QLabel(); lbl_icon->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); lbl_icon->setScaledContents(true); lbl_icon->setPixmap(QPixmap(QStringLiteral(":/icon/atcore"))); QPushButton *btn_close = new QPushButton(QStringLiteral("&Close")); connect(btn_close, &QPushButton::clicked, this, &QDialog::close); QVBoxLayout *versionInfo = new QVBoxLayout; versionInfo->addWidget(lbl_version); versionInfo->addWidget(lbl_qt_version); QVBoxLayout *topLayout = new QVBoxLayout; topLayout->setContentsMargins(0, 0, 0, 0); topLayout->addWidget(lbl_icon); topLayout->addItem(versionInfo); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addItem(topLayout); mainLayout->addWidget(lbl_authors); mainLayout->addWidget(btn_close); setLayout(mainLayout); } About::~About() { } diff --git a/src/widgets/axiscontrol.cpp b/src/widgets/axiscontrol.cpp index 5b5616a..1ed202d 100644 --- a/src/widgets/axiscontrol.cpp +++ b/src/widgets/axiscontrol.cpp @@ -1,217 +1,217 @@ /* Atelier KDE Printer Host for 3D Printing Copyright (C) <2016> - Author: Lays Rodrigues - laysrodriguessilva@gmail.com + Author: Lays Rodrigues - lays.rodrigues@kde.org Chris Rizzitello - rizzitello@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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "axiscontrol.h" #include PieButton::PieButton(QLatin1Char& axis, int value, int size, int angle) : _axis(axis), _value(value) { const int delta = 16; // Qt Docs: angle is 16th of a degree. setBrush(_palette.button()); setStartAngle(angle * delta); setSpanAngle(90 * delta); setRect(QRect(QPoint(size * -1, size * -1), QPoint(size, size))); setZValue(size * -1); setAcceptHoverEvents(true); setToolTip(QStringLiteral("Move the hotend to the %1 by %2 units").arg(axis).arg(value)); } void PieButton::setPalette(QPalette palette) { _palette = palette; } void PieButton::mousePressEvent(QGraphicsSceneMouseEvent *) { emit clicked(_axis, _value); } void PieButton::hoverEnterEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.highlight()); } void PieButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.button()); } RectButton::RectButton(QLatin1Char& axis, int value, int size) : _axis(axis), _value(value) { setBrush(_palette.button()); setRect(QRect(QPoint(0, 0), QPoint(size, size))); setAcceptHoverEvents(true); setZValue(size * -1); if (axis != QLatin1Char('E')) { setToolTip(QStringLiteral("Move the hotend to the %1 by %2 units").arg(axis).arg(value)); } else { setToolTip(QStringLiteral("Extrude %1 Units").arg(value)); } } void RectButton::setPalette(QPalette palette) { _palette = palette; } void RectButton::mousePressEvent(QGraphicsSceneMouseEvent *) { emit clicked(_axis, _value); } void RectButton::hoverEnterEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.highlight()); } void RectButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.button()); } /* About the Magic Numbers I don't have experience programming with QGraphicsScene, Tomaz is helping me, but until we have a better solution, all the values that are dividing or multiplying the items is based only in tests and errors. Those values was chosen because it fit better on the alignment of the items in the scene. If you have a better solution, please share with us. Lays Rodrigues - Jan/2017 */ AxisControl::AxisControl(const QList &movementValues, QWidget* parent) : QGraphicsView(parent) { setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setScene(new QGraphicsScene()); const int listSize = movementValues.size(); int maxValue = *std::max_element(movementValues.begin(), movementValues.end()); QList lessList = movementValues; std::sort(lessList.begin(), lessList.end(), std::less()); QList greaterList = movementValues; std::sort(greaterList.begin(), greaterList.end(), std::greater()); auto createPie = [ this, maxValue ](QLatin1Char& axis, int value, int size, int angle) { auto pie = new PieButton(axis, value, size, angle); pie->setPalette(this->palette()); connect(pie, &PieButton::clicked, this, &AxisControl::clicked); if (abs(value) == maxValue) { setLabels(pie, axis, value); } scene()->addItem(pie); }; auto createRect = [ this, maxValue ](QLatin1Char& axis, int value, int size, int xPos, int yPos) { auto z = new RectButton(axis, value, size); z->setPalette(this->palette()); z->setPos(xPos, yPos); connect(z, &RectButton::clicked, this, &AxisControl::clicked); if (abs(value) == maxValue) { setLabels(z, axis, value); } scene()->addItem(z); }; int currPieSize = 25; auto xchar = QLatin1Char('X'); auto ychar = QLatin1Char('Y'); auto zchar = QLatin1Char('Z'); auto echar = QLatin1Char('E'); for(const int &value: lessList) { createPie(xchar, value, currPieSize, -45); // Left createPie(xchar, value * -1, currPieSize, 135); // Right createPie(ychar, value, currPieSize, 45); // Top createPie(ychar, value * -1, currPieSize, 225); // Bottom currPieSize += 25; } int currSize = 25; int xPos = sceneRect().width() - 50; int yPos = -(listSize * 25); //Align with the origin // Z+ for(const int &value: greaterList) { createRect(zchar, value, currSize, xPos, yPos); yPos += currSize; } // Z- for(const int &value: lessList){ createRect(zchar, -value, currSize, xPos, yPos); yPos += currSize; } currSize = 25; xPos = sceneRect().width() - 50; yPos = -(listSize * 25); //Align with the origin // E- for(const int &value: greaterList){ createRect(echar, -value, currSize, xPos, yPos); yPos += currSize; } // E+ for(const int &value: lessList){ createRect(echar, value, currSize, xPos, yPos); yPos += currSize; } setSceneRect(scene()->itemsBoundingRect()); } void AxisControl::resizeEvent(QResizeEvent *) { fitInView(sceneRect(), Qt::KeepAspectRatio); } void AxisControl::setLabels(QGraphicsItem *item, QLatin1Char& axis, int value) { auto *lb = new QGraphicsSimpleTextItem(); lb->setBrush(palette().buttonText()); if (this->logicalDpiX() <= 96) { lb->setText((value < 0) ? QStringLiteral(" -") + axis : QStringLiteral(" ") + axis); } else { lb->setText((value < 0) ? QStringLiteral("-") + axis : QStringLiteral(" ") + axis); } if (axis.toLatin1() == 'X') { lb->setY(item->y() - lb->boundingRect().width()); if (value < 0) { lb->setX(item->x() - item->boundingRect().width() / 1.2 - lb->boundingRect().width() / 2); } else { lb->setX(item->x() + item->boundingRect().width() / 1.2 - lb->boundingRect().width() / 2); } } else if (axis.toLatin1() == 'Y') { lb->setX(item->x() - lb->boundingRect().width() / 2); if (value < 0) { lb->setY(item->y() + item->boundingRect().height() / 1.5); } else { lb->setY(item->y() - item->boundingRect().height()); } } else { lb->setX(item->x() + lb->boundingRect().width() / fontMetrics().width(lb->text())); #ifndef Q_OS_WIN lb->setY(item->y() - lb->boundingRect().height() / fontMetrics().xHeight()); #else lb->setY(item->y() - lb->boundingRect().height() / fontMetrics().height()); #endif } scene()->addItem(lb); } diff --git a/src/widgets/axiscontrol.h b/src/widgets/axiscontrol.h index a8ddbb8..34eba38 100644 --- a/src/widgets/axiscontrol.h +++ b/src/widgets/axiscontrol.h @@ -1,86 +1,86 @@ /* Atelier KDE Printer Host for 3D Printing Copyright (C) <2016> - Author: Lays Rodrigues - laysrodriguessilva@gmail.com + Author: Lays Rodrigues - lays.rodrigues@kde.org Chris Rizzitello - rizzitello@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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include #include #include #include "atcorewidgets_export.h" /* Usage: * * Create a instance of PrinterHotendPositionVisualController and * connect the clicked signal, it will give you the axis and value * that was clicked. */ class ATCOREWIDGETS_EXPORT PieButton : public QObject, public QGraphicsEllipseItem { Q_OBJECT public: PieButton(QLatin1Char& axis, int value, int size, int angle); void setPalette(QPalette palette); protected: void mousePressEvent(QGraphicsSceneMouseEvent *); void hoverEnterEvent(QGraphicsSceneHoverEvent *); void hoverLeaveEvent(QGraphicsSceneHoverEvent *); signals: void clicked(QLatin1Char axis, int value); private: QLatin1Char _axis; int _value; QPalette _palette; }; class ATCOREWIDGETS_EXPORT RectButton : public QObject, public QGraphicsRectItem { Q_OBJECT public: RectButton(QLatin1Char& axis, int value, int size); void setPalette(QPalette palette); protected: void mousePressEvent(QGraphicsSceneMouseEvent *); void hoverEnterEvent(QGraphicsSceneHoverEvent *); void hoverLeaveEvent(QGraphicsSceneHoverEvent *); signals: void clicked(QLatin1Char axis, int value); private: QLatin1Char _axis; int _value; QPalette _palette; }; class ATCOREWIDGETS_EXPORT AxisControl : public QGraphicsView { Q_OBJECT public: explicit AxisControl(const QList &movementValues = {1, 10, 25}, QWidget *parent = nullptr); private: void setLabels(QGraphicsItem *item, QLatin1Char& axis, int value); protected: void resizeEvent(QResizeEvent *); signals: void clicked(QLatin1Char axis, int value); }; diff --git a/src/widgets/temperaturewidget.cpp b/src/widgets/temperaturewidget.cpp index 1cd60e2..b646b15 100644 --- a/src/widgets/temperaturewidget.cpp +++ b/src/widgets/temperaturewidget.cpp @@ -1,72 +1,72 @@ /* AtCore Test Client Copyright (C) <2018> Author: Chris Rizzitello - rizzitello@kde.org - Lays Rodrigues - lays.rodriguea@kde.org + Lays Rodrigues - lays.rodrigues@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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "temperaturewidget.h" #include #include #include #include TemperatureWidget::TemperatureWidget(QWidget *parent) : QWidget(parent) { auto *mainLayout = new QVBoxLayout; checkAndWait = new QCheckBox(tr("Wait Until Temperature Stabilizes")); mainLayout->addWidget(checkAndWait); auto label = new QLabel(tr("Bed Temp")); sbBedTemp = new QSpinBox; sbBedTemp->setRange(0, 120); sbBedTemp->setSuffix(QStringLiteral("°C")); auto *newButton = new QPushButton(tr("Set")); connect(newButton, &QPushButton::clicked, [this] { emit(bedTempChanged(sbBedTemp->value(), checkAndWait->isChecked())); }); auto *hboxLayout = new QHBoxLayout; hboxLayout->addWidget(label, 80); hboxLayout->addWidget(sbBedTemp); hboxLayout->addWidget(newButton); mainLayout->addItem(hboxLayout); comboExtruderSelect = new QComboBox; sbExtruderTemp = new QSpinBox; sbExtruderTemp->setRange(0, 275); sbExtruderTemp->setSuffix(QStringLiteral("°C")); newButton = new QPushButton(tr("Set")); connect(newButton, &QPushButton::clicked, [this] { emit(extTempChanged(sbExtruderTemp->value(), comboExtruderSelect->currentIndex(), checkAndWait->isChecked())); }); hboxLayout = new QHBoxLayout; hboxLayout->addWidget(comboExtruderSelect, 80); hboxLayout->addWidget(sbExtruderTemp); hboxLayout->addWidget(newButton); mainLayout->addItem(hboxLayout); setLayout(mainLayout); } void TemperatureWidget::updateExtruderCount(const int count) { for (int i = 0; i < count; i++) { comboExtruderSelect->insertItem(i, tr("Extruder %1").arg(i)); } } diff --git a/testclient/main.cpp b/testclient/main.cpp index ae8c999..1b907d0 100644 --- a/testclient/main.cpp +++ b/testclient/main.cpp @@ -1,39 +1,39 @@ /* AtCore Test Client Copyright (C) <2016> Authors: - Lays Rodrigues - Patrick José Pereira + Lays Rodrigues + Patrick José Pereira Chris Rizzitello Tomaz Canabrava 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QCoreApplication::setOrganizationName(QStringLiteral("KDE")); QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); QCoreApplication::setApplicationName(QStringLiteral("AtCore - KDE Print Service")); MainWindow window; window.show(); return app.exec(); } diff --git a/testclient/mainwindow.cpp b/testclient/mainwindow.cpp index f8545d7..f27534a 100644 --- a/testclient/mainwindow.cpp +++ b/testclient/mainwindow.cpp @@ -1,569 +1,569 @@ /* AtCore Test Client Copyright (C) <2016> Authors: - Patrick José Pereira - Lays Rodrigues + Patrick José Pereira + Lays Rodrigues Chris Rizzitello Tomaz Canabrava 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "mainwindow.h" #include "seriallayer.h" #include "gcodecommands.h" #include "about.h" Q_LOGGING_CATEGORY(TESTCLIENT_MAINWINDOW, "org.kde.atelier.core") int MainWindow::fanCount = 4; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), core(new AtCore(this)) { setWindowTitle(tr("AtCore - Test Client")); setWindowIcon(QIcon(QStringLiteral(":/icon/windowIcon"))); QCoreApplication::setApplicationVersion(core->version()); initMenu(); initStatusBar(); initWidgets(); logWidget->appendLog(tr("Attempting to locate Serial Ports")); core->setSerialTimerInterval(1000); connect(core, &AtCore::stateChanged, this, &MainWindow::printerStateChanged); connect(core, &AtCore::portsChanged, this, &MainWindow::locateSerialPort); connect(core, &AtCore::sdCardFileListChanged, sdWidget, &SdWidget::updateFilelist); connect(&core->temperature(), &Temperature::bedTemperatureChanged, [ this ](float temp) { checkTemperature(0x00, 0, temp); plotWidget->appendPoint(tr("Actual Bed"), temp); plotWidget->update(); }); connect(&core->temperature(), &Temperature::bedTargetTemperatureChanged, [ this ](float temp) { checkTemperature(0x01, 0, temp); plotWidget->appendPoint(tr("Target Bed"), temp); plotWidget->update(); }); connect(&core->temperature(), &Temperature::extruderTemperatureChanged, [ this ](float temp) { checkTemperature(0x02, 0, temp); plotWidget->appendPoint(tr("Actual Ext.1"), temp); plotWidget->update(); }); connect(&core->temperature(), &Temperature::extruderTargetTemperatureChanged, [ this ](float temp) { checkTemperature(0x03, 0, temp); plotWidget->appendPoint(tr("Target Ext.1"), temp); plotWidget->update(); }); } void MainWindow::initMenu() { QMenu *menuFile = new QMenu(tr("File")); QAction *actionQuit = new QAction(style()->standardIcon(QStyle::SP_DialogCloseButton), tr("Quit")); connect(actionQuit, &QAction::triggered, this, &MainWindow::close); menuFile->addAction(actionQuit); menuView = new QMenu(tr("View")); QAction *actionShowDockTitles = new QAction(tr("Show Dock Titles")); actionShowDockTitles->setCheckable(true); actionShowDockTitles->setChecked(true); connect(actionShowDockTitles, &QAction::toggled, this, &MainWindow::toggleDockTitles); menuView->addAction(actionShowDockTitles); QMenu *menuHelp = new QMenu(tr("Help")); QAction *actionAbout = new QAction(tr("About")); actionAbout->setShortcut(QKeySequence(Qt::Key_F1)); connect(actionAbout, &QAction::triggered, [] { auto *dialog = new About; dialog->exec(); }); menuHelp->addAction(actionAbout); menuBar()->addMenu(menuFile); menuBar()->addMenu(menuView); menuBar()->addMenu(menuHelp); } void MainWindow::initStatusBar() { statusWidget = new StatusWidget; connect(statusWidget, &StatusWidget::stopPressed, core, &AtCore::stop); connect(core, &AtCore::printProgressChanged, statusWidget, &StatusWidget::updatePrintProgress); connect(core, &AtCore::sdMountChanged, statusWidget, &StatusWidget::setSD); statusBar()->addPermanentWidget(statusWidget, 100); } void MainWindow::initWidgets() { //Make the Docks makeCommandDock(); makePrintDock(); makeTempTimelineDock(); makeLogDock(); makeConnectDock(); makeMoveDock(); makeTempControlsDock(); makeSdDock(); setDangeriousDocksDisabled(true); setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North); setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North); tabifyDockWidget(moveDock, tempControlsDock); tabifyDockWidget(moveDock, sdDock); moveDock->raise(); tabifyDockWidget(connectDock, printDock); tabifyDockWidget(connectDock, commandDock); connectDock->raise(); setCentralWidget(nullptr); //More Gui stuff //hide the printing progress bar. statusWidget->showPrintArea(false); } void MainWindow::makeCommandDock() { commandWidget = new CommandWidget; //Connect the commandPressed signal connect(commandWidget, &CommandWidget::commandPressed, [this](const QString & command) { core->pushCommand(command.toUpper()); }); //Connect the messagePressed signal connect(commandWidget, &CommandWidget::messagePressed, [this](const QString & message) { core->showMessage(message); }); //Create the dock, and set the Widget. commandDock = new QDockWidget(tr("Commands"), this); commandDock->setWidget(commandWidget); //Push the toggle view action into our view menu menuView->insertAction(nullptr, commandDock->toggleViewAction()); //Place the Dock into a DockWidget Area. //Failure todo this will create some odd side effects at runtime addDockWidget(Qt::LeftDockWidgetArea, commandDock); } void MainWindow::makePrintDock() { printWidget = new PrintWidget; connect(printWidget, &PrintWidget::printPressed, this, &MainWindow::printPBClicked); connect(printWidget, &PrintWidget::emergencyStopPressed, core, &AtCore::emergencyStop); connect(printWidget, &PrintWidget::fanSpeedChanged, core, &AtCore::setFanSpeed); connect(printWidget, &PrintWidget::printSpeedChanged, [this](const int speed) { core->setPrinterSpeed(speed); }); connect(printWidget, &PrintWidget::flowRateChanged, [this](const int rate) { core->setFlowRate(rate); }); printDock = new QDockWidget(tr("Print"), this); printDock->setWidget(printWidget); menuView->insertAction(nullptr, printDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, printDock); } void MainWindow::makeTempTimelineDock() { plotWidget = new PlotWidget; tempTimelineDock = new QDockWidget(tr("Temperature Timeline"), this); tempTimelineDock->setWidget(plotWidget); menuView->insertAction(nullptr, tempTimelineDock->toggleViewAction()); addDockWidget(Qt::RightDockWidgetArea, tempTimelineDock); } void MainWindow::makeLogDock() { logWidget = new LogWidget(new QTemporaryFile(QDir::tempPath() + QStringLiteral("/AtCore_"))); logDock = new QDockWidget(tr("Session Log"), this); logDock->setWidget(logWidget); menuView->insertAction(nullptr, logDock->toggleViewAction()); addDockWidget(Qt::RightDockWidgetArea, logDock); } void MainWindow::makeConnectDock() { auto *mainLayout = new QVBoxLayout; auto *newLabel = new QLabel(tr("Port:")); comboPort = new QComboBox; comboPort->setEditable(true); auto *hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(comboPort, 75); mainLayout->addLayout(hBoxLayout); newLabel = new QLabel(tr("Baud Rate:")); comboBAUD = new QComboBox; comboBAUD->addItems(core->portSpeeds()); comboBAUD->setCurrentIndex(9); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(comboBAUD, 75); mainLayout->addLayout(hBoxLayout); newLabel = new QLabel(tr("Use Plugin:")); comboPlugin = new QComboBox; comboPlugin->addItem(tr("Autodetect")); comboPlugin->addItems(core->availableFirmwarePlugins()); connect(comboPlugin, &QComboBox::currentTextChanged, this, &MainWindow::pluginCBChanged); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(comboPlugin, 75); mainLayout->addLayout(hBoxLayout); buttonConnect = new QPushButton(tr("Connect")); connect(buttonConnect, &QPushButton::clicked, this, &MainWindow::connectPBClicked); mainLayout->addWidget(buttonConnect); auto *dockContents = new QWidget; dockContents->setLayout(mainLayout); connectDock = new QDockWidget(tr("Connect"), this); connectDock->setWidget(dockContents); menuView->insertAction(nullptr, connectDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, connectDock); } void MainWindow::makeMoveDock() { movementWidget = new MovementWidget; connect(movementWidget, &MovementWidget::homeAllPressed, [this] { logWidget->appendLog(tr("Home All")); core->home(); }); connect(movementWidget, &MovementWidget::homeXPressed, [this] { logWidget->appendLog(tr("Home X")); core->home(AtCore::X); }); connect(movementWidget, &MovementWidget::homeYPressed, [this] { logWidget->appendLog(tr("Home Y")); core->home(AtCore::Y); }); connect(movementWidget, &MovementWidget::homeZPressed, [this] { logWidget->appendLog(tr("Home Z")); core->home(AtCore::Z); }); connect(movementWidget, &MovementWidget::absoluteMove, [this](const QLatin1Char & axis, const double & value) { logWidget->appendLog(GCode::description(GCode::G1)); core->move(axis, value); }); connect(movementWidget, &MovementWidget::disableMotorsPressed, [this] { core->disableMotors(0); }); connect(movementWidget, &MovementWidget::relativeMove, [this](const QLatin1Char & axis, const double & value) { core->setRelativePosition(); core->move(axis, value); core->setAbsolutePosition(); }); moveDock = new QDockWidget(tr("Movement"), this); moveDock->setWidget(movementWidget); menuView->insertAction(nullptr, moveDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, moveDock); } void MainWindow::makeTempControlsDock() { temperatureWidget = new TemperatureWidget; connect(temperatureWidget, &TemperatureWidget::bedTempChanged, core, &AtCore::setBedTemp); connect(temperatureWidget, &TemperatureWidget::extTempChanged, core, &AtCore::setExtruderTemp); tempControlsDock = new QDockWidget(tr("Temperatures"), this); tempControlsDock->setWidget(temperatureWidget); menuView->insertAction(nullptr, tempControlsDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, tempControlsDock); } void MainWindow::makeSdDock() { sdWidget = new SdWidget; connect(sdWidget, &SdWidget::requestSdList, core, &AtCore::sdFileList); connect(sdWidget, &SdWidget::printSdFile, [this](const QString & fileName) { if (fileName.isEmpty()) { QMessageBox::information(this, tr("Print Error"), tr("You must Select a file from the list")); } else { core->print(fileName, true); } }); connect(sdWidget, &SdWidget::deleteSdFile, [this](const QString & fileName) { if (fileName.isEmpty()) { QMessageBox::information(this, tr("Delete Error"), tr("You must Select a file from the list")); } else { core->sdDelete(fileName); } }); sdDock = new QDockWidget(tr("Sd Card"), this); sdDock->setWidget(sdWidget); menuView->insertAction(nullptr, sdDock->toggleViewAction()); addDockWidget(Qt::LeftDockWidgetArea, sdDock); } void MainWindow::closeEvent(QCloseEvent *event) { core->close(); event->accept(); } MainWindow::~MainWindow() { } void MainWindow::checkTemperature(uint sensorType, uint number, uint temp) { QString msg; switch (sensorType) { case 0x00: // bed msg = QString::fromLatin1("Bed Temperature "); break; case 0x01: // bed target msg = QString::fromLatin1("Bed Target Temperature "); break; case 0x02: // extruder msg = QString::fromLatin1("Extruder Temperature "); break; case 0x03: // extruder target msg = QString::fromLatin1("Extruder Target Temperature "); break; case 0x04: // enclosure msg = QString::fromLatin1("Enclosure Temperature "); break; case 0x05: // enclosure target msg = QString::fromLatin1("Enclosure Target Temperature "); break; } msg.append(QString::fromLatin1("[%1] : %2")); msg = msg.arg(QString::number(number)) .arg(QString::number(temp)); logWidget->appendLog(msg); } /** * @brief MainWindow::locateSerialPort * Locate all active serial ports on the computer and add to the list * of serial ports */ void MainWindow::locateSerialPort(const QStringList &ports) { comboPort->clear(); if (!ports.isEmpty()) { comboPort->addItems(ports); logWidget->appendLog(tr("Found %1 Ports").arg(QString::number(ports.count()))); } else { QString portError(tr("No available ports! Please connect a serial device to continue!")); if (! logWidget->endsWith(portError)) { logWidget->appendLog(portError); } } } void MainWindow::connectPBClicked() { if (core->state() == AtCore::DISCONNECTED) { if (core->initSerial(comboPort->currentText(), comboBAUD->currentText().toInt())) { connect(core, &AtCore::receivedMessage, logWidget, &LogWidget::appendRLog); connect(core->serial(), &SerialLayer::pushedCommand, logWidget, &LogWidget::appendSLog); buttonConnect->setText(tr("Disconnect")); logWidget->appendLog(tr("Serial connected")); if (comboPlugin->currentText().contains(tr("Autodetect"))) { logWidget->appendLog(tr("No plugin loaded !")); logWidget->appendLog(tr("Requesting Firmware...")); } else { core->loadFirmwarePlugin(comboPlugin->currentText()); } } else { logWidget->appendLog(tr("Failed to open serial in r/w mode")); } } else { disconnect(core, &AtCore::receivedMessage, logWidget, &LogWidget::appendRLog); disconnect(core->serial(), &SerialLayer::pushedCommand, logWidget, &LogWidget::appendSLog); core->closeConnection(); core->setState(AtCore::DISCONNECTED); logWidget->appendLog(tr("Disconnected")); buttonConnect->setText(tr("Connect")); } } void MainWindow::printPBClicked() { QString fileName; switch (core->state()) { case AtCore::DISCONNECTED: QMessageBox::information(this, tr("Error"), tr("Not Connected To a Printer")); break; case AtCore::CONNECTING: QMessageBox::information(this, tr("Error"), tr(" A Firmware Plugin was not loaded!\n Please send the command M115 and let us know what your firmware returns, so we can improve our firmware detection. We have loaded the most common plugin \"repetier\" for you. You may try to print again after this message")); comboPlugin->setCurrentText(QStringLiteral("repetier")); break; case AtCore::IDLE: fileName = QFileDialog::getOpenFileName(this, tr("Select a file to print"), QDir::homePath(), tr("*.gcode")); if (fileName.isNull()) { logWidget->appendLog(tr("No File Selected")); } else { logWidget->appendLog(tr("Print: %1").arg(fileName)); core->print(fileName); } break; case AtCore::BUSY: core->pause(printWidget->postPauseCommand()); break; case AtCore::PAUSE: core->resume(); break; default: qCDebug(TESTCLIENT_MAINWINDOW) << "ERROR / STOP unhandled."; } } void MainWindow::pluginCBChanged(QString currentText) { if (core->state() != AtCore::DISCONNECTED) { if (!currentText.contains(tr("Autodetect"))) { core->loadFirmwarePlugin(currentText); } } } void MainWindow::printerStateChanged(AtCore::STATES state) { QString stateString; switch (state) { case AtCore::IDLE: printWidget->setPrintText(tr("Print File")); stateString = tr("Connected to ") + core->connectedPort(); break; case AtCore::STARTPRINT: stateString = tr("START PRINT"); printWidget->setPrintText(tr("Pause Print")); statusWidget->showPrintArea(true); break; case AtCore::FINISHEDPRINT: stateString = tr("Finished Print"); printWidget->setPrintText(tr("Print File")); statusWidget->showPrintArea(false); break; case AtCore::PAUSE: stateString = tr("Paused"); printWidget->setPrintText(tr("Resume Print")); break; case AtCore::BUSY: stateString = tr("Printing"); printWidget->setPrintText(tr("Pause Print")); break; case AtCore::DISCONNECTED: stateString = QStringLiteral("Not Connected"); setDangeriousDocksDisabled(true); break; case AtCore::CONNECTING: stateString = QStringLiteral("Connecting"); setDangeriousDocksDisabled(false); break; case AtCore::STOP: stateString = tr("Stopping Print"); break; case AtCore::ERRORSTATE: stateString = tr("Command ERROR"); break; } statusWidget->setState(stateString); } void MainWindow::toggleDockTitles(bool checked) { if (checked) { delete connectDock->titleBarWidget(); delete logDock->titleBarWidget(); delete tempTimelineDock->titleBarWidget(); delete commandDock->titleBarWidget(); delete moveDock->titleBarWidget(); delete tempControlsDock->titleBarWidget(); delete printDock->titleBarWidget(); delete sdDock->titleBarWidget(); } else { connectDock->setTitleBarWidget(new QWidget()); logDock->setTitleBarWidget(new QWidget()); tempTimelineDock->setTitleBarWidget(new QWidget()); commandDock->setTitleBarWidget(new QWidget()); moveDock->setTitleBarWidget(new QWidget()); tempControlsDock->setTitleBarWidget(new QWidget()); printDock->setTitleBarWidget(new QWidget()); sdDock->setTitleBarWidget(new QWidget()); } } void MainWindow::setDangeriousDocksDisabled(bool disabled) { commandDock->widget()->setDisabled(disabled); moveDock->widget()->setDisabled(disabled); tempControlsDock->widget()->setDisabled(disabled); printDock->widget()->setDisabled(disabled); sdDock->widget()->setDisabled(disabled); if (!disabled) { temperatureWidget->updateExtruderCount(core->extruderCount()); printWidget->updateFanCount(fanCount); } } diff --git a/testclient/mainwindow.h b/testclient/mainwindow.h index d195ef5..f23ef9b 100644 --- a/testclient/mainwindow.h +++ b/testclient/mainwindow.h @@ -1,179 +1,179 @@ /* AtCore Test Client Copyright (C) <2016> Authors: - Patrick José Pereira - Lays Rodrigues + Patrick José Pereira + Lays Rodrigues Chris Rizzitello Tomaz Canabrava 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include #include #include "atcore.h" #include "commandwidget.h" #include "logwidget.h" #include "movementwidget.h" #include "plotwidget.h" #include "printwidget.h" #include "sdwidget.h" #include "statuswidget.h" #include "temperaturewidget.h" class SerialLayer; class MainWindow: public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow() override; public slots: /** * @brief Check temperature * * @param sensorType : type of sensor * @param number : index of sensor * @param temp : temperature */ void checkTemperature(uint sensorType, uint number, uint temp); private slots: //ButtonEvents /** * @brief Connect Button Clicked will connect or disconnect based on printer state */ void connectPBClicked(); /** * @brief Print Button Clicked, can also pause /resue print based on printer state */ void printPBClicked(); /** * @brief printerStateChanged Catch and proccess printer state commands * @param state: new printer state */ void printerStateChanged(AtCore::STATES state); /** * @brief show/hide dock titlebars * @param checked: True if shown */ void toggleDockTitles(bool checked); /** * @brief Toggle disable state of dangerous docks * Command, Sd Card, Movement, Temperature Controls and Printing docks * @param disabled: True if items are disabled. */ void setDangeriousDocksDisabled(bool disabled); private: AtCore *core; // Define max number of fans static int fanCount; void closeEvent(QCloseEvent *event) override; /** * @brief Locate serial port * */ void locateSerialPort(const QStringList &ports); /** * @brief pluginCB index changed */ void pluginCBChanged(QString currentText); /** * @brief setupActions for KXMLGui */ void setupActions(); /** * @brief Populate comboboxes */ void populateCBs(); /** * @brief Gui Changes for when sd card mount status has changed. */ void sdChanged(bool mounted); //UI Functions /** * @brief Create The Menubar */ void initMenu(); /** * @brief Create StatusBar */ void initStatusBar(); /** * @brief Create Main Widgets. */ void initWidgets(); //Private GUI Items //menuView is global to allow for docks to be added / removed. QMenu *menuView = nullptr; //Status Bar Items StatusWidget *statusWidget = nullptr; //Docks void makeLogDock(); QDockWidget *logDock = nullptr; LogWidget *logWidget = nullptr; void makeTempTimelineDock(); QDockWidget *tempTimelineDock = nullptr; PlotWidget *plotWidget = nullptr; void makeCommandDock(); QDockWidget *commandDock = nullptr; CommandWidget *commandWidget = nullptr; void makePrintDock(); QDockWidget *printDock = nullptr; PrintWidget *printWidget = nullptr; void makeConnectDock(); QDockWidget *connectDock = nullptr; QComboBox *comboPort = nullptr; QComboBox *comboBAUD = nullptr; QComboBox *comboPlugin = nullptr; QPushButton *buttonConnect = nullptr; void makeMoveDock(); QDockWidget *moveDock = nullptr; MovementWidget *movementWidget = nullptr; void makeTempControlsDock(); QDockWidget *tempControlsDock = nullptr; TemperatureWidget *temperatureWidget = nullptr; void makeSdDock(); QDockWidget *sdDock = nullptr; SdWidget *sdWidget = nullptr; };