diff --git a/src/core/atcore.h b/src/core/atcore.h
--- a/src/core/atcore.h
+++ b/src/core/atcore.h
@@ -242,6 +242,12 @@
*/
bool isSdMounted() const;
+ /**
+ * @brief isSdWriting
+ * @return true if writing to sd card
+ */
+ bool isSdWriting() const;
+
signals:
/**
@@ -303,6 +309,18 @@
*/
void sdCardFileListChanged(const QStringList &fileList);
+ /**
+ * @brief WriteToSD precentage changed.
+ * @param newProgress.
+ */
+ void sdWriteProgressChanged(float newProgress);
+
+ /**
+ * @brief sdWriteChanged
+ * @param writing: true if writing to file.
+ */
+ void sdWriteChanged(bool writing);
+
public slots:
/**
@@ -473,6 +491,13 @@
*/
void sdCardPrintStatus();
+ /**
+ * @brief Write a file to the machines SdCard
+ * @param fileName: Local file to send to machine
+ * @return True if successful
+ */
+ bool toSd(const QString &fileName);
+
private slots:
/**
* @brief processQueue send commands from the queue.
diff --git a/src/core/atcore.cpp b/src/core/atcore.cpp
--- a/src/core/atcore.cpp
+++ b/src/core/atcore.cpp
@@ -66,6 +66,7 @@
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.
+ bool sdWriting = false; //!< @param sdWriting: True if writing to sd card.
QString sdCardFileName; //!< @param sdCardFileName: name of file being used from sd card.
QStringList sdCardFileList; //!< @param sdCardFileList: List of files on sd card.
};
@@ -765,6 +766,11 @@
return d->sdCardReadingFileList;
}
+bool AtCore::isSdWriting() const
+{
+ return d->sdWriting;
+}
+
void AtCore::setReadingSdCardList(bool readingList)
{
d->sdCardReadingFileList = readingList;
@@ -836,3 +842,85 @@
qCDebug(ATCORE_CORE) << "SerialError:" << errorString;
emit atcoreMessage(QStringLiteral("SerialError: %1").arg(errorString));
}
+
+bool AtCore::toSd(const QString &fileName)
+{
+ //Do a few sanity checks before attempting to write to SD.
+ //Can't write an empty fileName.
+ if (fileName.isEmpty()) {
+ qCDebug(ATCORE_CORE) << "Sd Write Failed: Empty fileName.";
+ return false;
+ }
+ //Can not write if plugin doesn't have Sd Support.
+ if (!d->firmwarePlugin->isSdSupported()) {
+ qCDebug(ATCORE_CORE) << "Sd Write Failed: Firmware plugin does not support Sd functions.";
+ return false;
+ }
+
+ //If the card is not mounted try to read the file list and mount it.
+ if (!d->sdCardMounted) {
+ getSDFileList();
+ if (!d->sdCardMounted) {
+ qCDebug(ATCORE_CORE) << "Sd Write Failed unable to mount Sd Card";
+ return false;
+ }
+ }
+ // Be sure the printer is IDLE
+ if (d->printerState == AtCore::DISCONNECTED) {
+ qCDebug(ATCORE_CORE) << "No Device Connected.";
+ return false;
+ } else if (d->printerState != AtCore::IDLE) {
+ qCDebug(ATCORE_CORE) << "Sd Write Failed: Device is Busy";
+ return false;
+ }
+
+ bool restoreTimer = d->tempTimer->isActive();
+ int timerTime = 0;
+ if (restoreTimer) {
+ timerTime = d->tempTimer->interval();
+ d->tempTimer->stop();
+ }
+
+ //Process without thread.
+ QString fname = QFileInfo(fileName).fileName();
+ QFile *file = new QFile(fileName);
+ file->open(QFile::ReadOnly);
+ QTextStream *txtStream = new QTextStream(file);
+ const qint64 filesize = file->size();
+ float progress = 0;
+ qint64 stillSize = filesize;
+ QString cline;
+
+ setState(AtCore::BUSY);
+ d->sdWriting = true;
+ emit sdWriteChanged(d->sdWriting);
+ pushCommand(GCode::toCommand(GCode::M28, fname));
+
+ while (!txtStream->atEnd()) {
+ if (state() == AtCore::STOP) {
+ txtStream->setString(new QString());
+ progress = 100;
+ } else {
+ cline = txtStream->readLine();
+ stillSize -= cline.size() + 1; //remove read chars
+ progress = float(filesize - stillSize) * 100 / float(filesize);
+ }
+ pushCommand(cline);
+ processQueue();
+ emit sdWriteProgressChanged(progress);
+ qDebug() << "Progress:" << progress << "Current Line:" << cline;
+ }
+
+ pushCommand(GCode::toCommand(GCode::M29, fname));
+
+ file->close();
+ setState(AtCore::IDLE);
+ getSDFileList();
+
+ d->sdWriting = false;
+ if (restoreTimer) {
+ d->tempTimer->start(timerTime);
+ }
+ emit sdWriteChanged(d->sdWriting);
+ return true;
+}
diff --git a/src/plugins/marlinplugin.h b/src/plugins/marlinplugin.h
--- a/src/plugins/marlinplugin.h
+++ b/src/plugins/marlinplugin.h
@@ -55,9 +55,26 @@
*/
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;
+
/**
* @brief validateCommand to filter commands from messages
* @param lastMessage: last Message from printer
*/
void validateCommand(const QString &lastMessage) override;
+
+private:
+ /**
+ * @brief Convert a filename to 8.3 Because Marlin will only accept those, Generates a 8.3 like Filename.
+ * This is Close to but not a 8.3 filename for instance we do not check the Filesystem so ~# will not be added if files with similar names are on the sd card
+ * Marlin will overwrite files with the samename.
+ * @param fileName: to convert to 8.3 format.
+ * @return Return a 8.3 Format name
+ */
+ QString shortName(const QString &fileName);
};
diff --git a/src/plugins/marlinplugin.cpp b/src/plugins/marlinplugin.cpp
--- a/src/plugins/marlinplugin.cpp
+++ b/src/plugins/marlinplugin.cpp
@@ -22,7 +22,9 @@
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 "marlinplugin.h"
@@ -45,6 +47,33 @@
qCDebug(MARLIN_PLUGIN) << name() << " plugin loaded!";
}
+QByteArray MarlinPlugin::translate(const QString &command)
+{
+ //Capture M28
+ static const auto marlin_M28RegEx = QRegularExpression(QStringLiteral("M28 \\S+"));
+ //Capture both M29 and M29 but not M290
+ static const auto marlin_M29RegEx = QRegularExpression(QStringLiteral("M29( \\S*)?[^0]"));
+
+ QString temp = command;
+ if (marlin_M28RegEx.match(command).hasMatch()) {
+ QString filename = temp.mid(4, temp.length());
+ filename = shortName(filename);
+ temp = QStringLiteral("M28 %1").arg(filename);
+
+ } else if (marlin_M29RegEx.match(command).hasMatch()) {
+ if (temp.length() > 3) {
+ //command contains file name
+ QString filename = temp.mid(4, temp.length());
+ filename = shortName(filename);
+ temp = QStringLiteral("M29 %1").arg(filename);
+ } else {
+ temp = QStringLiteral("M29");
+ }
+ }
+
+ return temp.toLocal8Bit();
+}
+
void MarlinPlugin::validateCommand(const QString &lastMessage)
{
if (lastMessage.contains(QStringLiteral("End file list"))) {
@@ -96,3 +125,20 @@
}
}
}
+
+QString MarlinPlugin::shortName(const QString &fileName)
+{
+ //Generate an 8.3 Like FileName.
+ QString newName;
+ QFileInfo info(fileName);
+ newName = info.baseName().toUpper();
+
+ if (newName.length() > 8) {
+ newName.resize(8);
+ }
+
+ newName.append(QStringLiteral("."));
+ newName.append(info.suffix().toUpper());
+ newName.replace(QStringLiteral(".GCODE"), QStringLiteral(".GCO"));
+ return newName;
+}
diff --git a/src/widgets/sdwidget.h b/src/widgets/sdwidget.h
--- a/src/widgets/sdwidget.h
+++ b/src/widgets/sdwidget.h
@@ -58,6 +58,11 @@
*/
void deleteSdFile(const QString &fileName);
+ /**
+ * @brief User has selected to write a file for the sd card.
+ */
+ void writeSdFile();
+
private:
QListWidget *listSdFiles = nullptr;
};
diff --git a/src/widgets/sdwidget.cpp b/src/widgets/sdwidget.cpp
--- a/src/widgets/sdwidget.cpp
+++ b/src/widgets/sdwidget.cpp
@@ -15,6 +15,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -42,6 +43,12 @@
}
});
+ newButton = new QPushButton(tr("Send File"));
+ hBoxLayout->addWidget(newButton);
+ connect(newButton, &QPushButton::clicked, this, [this] {
+ emit writeSdFile();
+ });
+
newButton = new QPushButton(tr("Delete Selected"));
hBoxLayout->addWidget(newButton);
connect(newButton, &QPushButton::clicked, this, [this] {
diff --git a/testclient/mainwindow.h b/testclient/mainwindow.h
--- a/testclient/mainwindow.h
+++ b/testclient/mainwindow.h
@@ -136,6 +136,11 @@
*/
void initWidgets();
+ /**
+ * @brief Handle WriteToSd
+ */
+ void writeToSd();
+
//Private GUI Items
//menuView is global to allow for docks to be added / removed.
QMenu *menuView = nullptr;
diff --git a/testclient/mainwindow.cpp b/testclient/mainwindow.cpp
--- a/testclient/mainwindow.cpp
+++ b/testclient/mainwindow.cpp
@@ -54,6 +54,7 @@
connect(core, &AtCore::stateChanged, this, &MainWindow::printerStateChanged);
connect(core, &AtCore::portsChanged, this, &MainWindow::locateSerialPort);
connect(core, &AtCore::sdCardFileListChanged, sdWidget, &SdWidget::updateFilelist);
+ connect(sdWidget, &SdWidget::writeSdFile, this, &MainWindow::writeToSd);
}
void MainWindow::initMenu()
@@ -584,3 +585,39 @@
statusWidget->showPrintArea(false);
}
}
+
+void MainWindow::writeToSd()
+{
+ static QString filter = tr("GCode Files(*.gco *.gcode)");
+ QString fileName = QFileDialog::getOpenFileName(
+ this
+ , tr("Write file to SD")
+ , QDir::homePath()
+ , tr("All Files(*.*);;GCode Files(*.gco *.gcode)")
+ , &filter
+ );
+
+ if (!fileName.isEmpty() && QFileInfo(fileName).isReadable()) {
+ QProgressDialog *dialog = new QProgressDialog(tr("Writing file to SD Card..."), tr("Cancel"), 0, 100, this);
+
+ connect(core, &AtCore::sdWriteChanged, this, [dialog](bool writing) {
+ if (writing) {
+ QApplication::processEvents();
+ dialog->open();
+ } else {
+ dialog->close();
+ }
+ });
+ connect(core, &AtCore::sdWriteProgressChanged, dialog, &QProgressDialog::setValue);
+
+ connect(dialog, &QProgressDialog::canceled, this, [this] {
+ core->setState(AtCore::STOP);
+ });
+
+ if (!core->toSd(fileName)) {
+ QMessageBox::warning(this, tr("Write to Sd"), tr("Writing FAILED"));
+ dialog->close();
+ core->setState(AtCore::IDLE);
+ }
+ }
+}