Frontend to the famous GRBL.

outputdevicegrbl.cpp 8.4KB

    /* Part of x2grbl * * Copyright Johann Wilhelm <johann.wilhelm@9mal6.de> 2015 * * see Readme.md for detailed license and usage information! */ #include "outputdevicegrbl.h" #include <QDebug> #include <QTimer> #include <QThread> #include <QtTest/QTest> #include <QRegExp> #include "gcodeparser.h" OutputDeviceGrbl::OutputDeviceGrbl(QObject *parent) : GCodeOutputDevice(parent) { connect(&SerialPort, SIGNAL(readyRead()), this, SLOT(dataAvailable())); isSending=false; isConnecting=false; sentCmds=0; emitFinishedFlag=false; statusUpdateTimer.setInterval(1000); connect(&statusUpdateTimer, SIGNAL(timeout()), this, SLOT(requestStatusUpdate())); statusUpdateTimer.start(); } bool OutputDeviceGrbl::supported(GCode &Cmd) { if (Cmd.Code==CodeType_RAW) { return true; } else if (Cmd.Code==CodeType_MCode) { switch(Cmd.Cmd) { case 0: case 2: case 3: case 4: case 5: case 8: case 9: case 30: return true; break; default: return false; } } if (Cmd.Code==CodeType_GCode) { switch(Cmd.Cmd) { case 0: case 1: case 2: case 3: case 4: case 17: case 18: case 19: case 20: case 21: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 80: case 90: case 91: case 93: case 94: return true; break; case 28: case 30: case 92: if (Cmd.SubCmd==-1 || Cmd.SubCmd==1) { return true;} return false; case 10: if (Cmd.Parameters[QString("L")]==QString("2") || Cmd.Parameters[QString("L")]==QString("20")) return true; return false; case 38: if (Cmd.SubCmd==2) return true; return false; default: return false; } } return false; } void OutputDeviceGrbl::tryConnect(QString PortName) { SerialPort.close(); isConnecting=true; isSending=false; SendQueue.clear(); SerialPort.setPortName(PortName); SerialPort.setBaudRate(BAUD115200); SerialPort.setDataBits(DATA_8); SerialPort.setParity(PAR_NONE); SerialPort.setStopBits(STOP_1); SerialPort.setFlowControl(FLOW_OFF); VersionString.clear(); if (!SerialPort.open(QIODevice::ReadWrite)) { emit Failed(); } else { emit Connecting(); //Get Grbl-Version... SerialPort.write("\r\n\r\n"); } sentCmds=0; } void OutputDeviceGrbl::Disconnect() { SerialPort.close(); VersionString.clear(); emit Disconnected(); } QString OutputDeviceGrbl::name() { return QString("Grbl"); } bool OutputDeviceGrbl::isConnected() { if (!VersionString.length()) return false; return SerialPort.isOpen(); } void OutputDeviceGrbl::dataAvailable() { Buffer+=SerialPort.readAll(); int Start=0; for (int i=0;i<Buffer.length();i++) { if (Buffer[i]=='\r' || Buffer[i]=='\n') { if (i>0) { QString Response=QString::fromLatin1(Buffer.mid(Start,i-Start)); if (Response.length()) { parseResponse(Response); } } Start=i+1; } } if (Start<Buffer.length()) { Buffer=Buffer.mid(Start); } else Buffer.clear(); } void OutputDeviceGrbl::parseResponse(QString Response) { QRegExp isError(QString("error: (..*)$")); QRegExp isVersionString(QString("Grbl2.5d ([0-9]+\\.[0-9]+[a-z]*) \\['\\$' for help\\]")); QRegExp isStatus("<(\\w+),MPos:([-\\d\\.]+),([-\\d\\.]+),([-\\d\\.]+),WPos:([-\\d\\.]+),([-\\d\\.]+),([-\\d\\.]+)>"); QRegExp isProbingResult("\\[PRB:([-\\d\\.]+),([-\\d\\.]+),([-\\d\\.]+),WPos:([-\\d\\.]+),([-\\d\\.]+),([-\\d\\.]+)\\]"); // qDebug()<<"Grbl Response:"<<Response<<"\n"; if (Response=="ok") { // qDebug()<<"Cmd Executed\n"; if (!SendQueue.isEmpty()) { sentCmds++; GCode Cmd=SendQueue.dequeue(); // qDebug()<<"Cmds in Queue:"<<SendQueue.count()<<"\n"; emit ProgressUpdate((float)sentCmds/(float)(sentCmds+SendQueue.count())); QString Command=Cmd.serialize()+QString("\n"); // qDebug()<<"Sending Cmd:"<<Command; SerialPort.write(Command.toLatin1()); //todo: handle errors during sending... } else { isSending=false; // qDebug()<<"Queue empty!\n"; } } else if (isVersionString.exactMatch(Response)) { isVersionString.indexIn(Response); QStringList Matches=isVersionString.capturedTexts(); if (Matches.count()==2) { VersionString=Matches[1]; // qDebug()<<"Grbl-Version:"<<VersionString<<"\n"; if (isConnecting) { isConnecting=false; emit Connected(); } } } else if (isStatus.exactMatch(Response)) { isStatus.indexIn(Response); QStringList Matches=isStatus.capturedTexts(); if (Matches.count()==8) { QString Status; double Mx,My,Mz; double Wx,Wy,Wz; Status=Matches[1]; Mx=Matches[2].toDouble(); My=Matches[3].toDouble(); Mz=Matches[4].toDouble(); Wx=Matches[5].toDouble(); Wy=Matches[6].toDouble(); Wz=Matches[7].toDouble(); // qDebug()<<"Grbl-Status:"<<Status<<"\n"; // qDebug()<<"Machine Coordinates:"<<Mx<<", "<<My<<", "<<Mz<<"\n"; // qDebug()<<"World Coordinates:"<<Wx<<", "<<Wy<<", "<<Wz<<"\n"; if (emitFinishedFlag && SendQueue.isEmpty()) { if (Status.compare("Idle")==0) { emitFinished(false); emit ExecutionFinished(); } } if (isConnecting) emit Connected(); } } else if (isError.exactMatch(Response)) { isError.indexIn(Response); QStringList Matches=isError.capturedTexts(); if (Matches.count()==2) { sentCmds=0; isSending=false; SendQueue.clear(); QString ErrorString=Matches[1]; qDebug()<<"Reported Error:"<<ErrorString<<"\n"; emit Error(ErrorString); } } else if (isProbingResult.exactMatch(Response)) { isProbingResult.indexIn(Response); QStringList Matches=isProbingResult.capturedTexts(); if (Matches.count()==7) { double x=Matches[1].toDouble(); double y=Matches[2].toDouble(); double z=Matches[3].toDouble(); double Wx=Matches[4].toDouble(); double Wy=Matches[5].toDouble(); double Wz=Matches[6].toDouble(); qDebug()<<"Probing Result:"<<x<<","<<y<<","<<z<<" WCS:"<<Wx<<","<<Wy<<","<<Wz<<"\n"; probingData.append(QVector3D(Wx,Wy,Wz)); } } else { qDebug()<<"Unhandeled response:"<<Response<<"\n"; } } //device does not support sync processing... bool OutputDeviceGrbl::Run(GCode &Cmd) { if (!supported(Cmd)) return false; sendCommand(Cmd); return true; } void OutputDeviceGrbl::sendCommand(GCode Cmd) { if (!SerialPort.isOpen()) return; if (isConnecting) return; // qDebug()<<Cmd.serialize()<<"\n"; SendQueue.enqueue(Cmd); if (!isSending) { isSending=true; GCode Cmd=SendQueue.dequeue(); QString Command=Cmd.serialize()+QString("\n"); // qDebug()<<Command; // qDebug()<<"Sending Cmd:"<<Command; SerialPort.write(Command.toLatin1()); //todo: handle errors during sending... } } void OutputDeviceGrbl::requestStatusUpdate() { GCode Cmd; Cmd.Code=CodeType_RAW; Cmd.Raw="?"; if (SendQueue.isEmpty()) sendCommand(Cmd); } void OutputDeviceGrbl::Reset() { sentCmds=0; } void OutputDeviceGrbl::goHome() { GCode Cmd; Cmd.Code=CodeType_RAW; Cmd.Raw="$H"; sendCommand(Cmd); }