From 05777da05008289cce24f033de33009c990cd458 Mon Sep 17 00:00:00 2001 From: Yauhen Kharuzhy Date: Sat, 7 Jan 2017 15:09:43 +0300 Subject: [PATCH] Implement character-counting protocol for Grbl. Closes #74 --- .../drivers/.GenericGcodeDriver.java.swp | Bin 0 -> 16384 bytes .../liblasercut/drivers/.Grbl.java.swp | Bin 0 -> 24576 bytes .../drivers/GenericGcodeDriver.java | 19 ++- src/com/t_oster/liblasercut/drivers/Grbl.java | 132 ++++++++++++++++-- 4 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 src/com/t_oster/liblasercut/drivers/.GenericGcodeDriver.java.swp create mode 100644 src/com/t_oster/liblasercut/drivers/.Grbl.java.swp diff --git a/src/com/t_oster/liblasercut/drivers/.GenericGcodeDriver.java.swp b/src/com/t_oster/liblasercut/drivers/.GenericGcodeDriver.java.swp new file mode 100644 index 0000000000000000000000000000000000000000..c21c07fd8ada27f7f698137d1bfd967a4aac4e75 GIT binary patch literal 16384 zcmeHOON<;x8SW4WU@!zYAOVN6L!?=2-Ltk4viykLJJYkF#t_?|2;AKY>=k+BGpC>i#wWpq2fBlcO$DTf?X*by|nflNV%0;nY4=wjq z6s%9<^j3XLhqqXoC3MK@A0 z@@LiRLCUuvtG>b_mh$1sFb-H#rRg{67JaByRe_3u_W=XB7@aP#2Oq3oCRbk-0~G@m0~G@m0~G@m0~G@m z0~G@m0~G@m1OJx{&_L5Z4$Ex05yt)hZ2$l6CpGO2;6>oOfDPRLgr@xr_%`rOzy^*1 zuN_Aj;9EcwxDSEv0DlF35Bv`JG4MQa1Nbs<0+5RT^f68QHSi-~8+aDD0GtGl1AjiI zX@3A-0lo)}flXitd>(lHqnh>t@Eza=unwFAP5^IyMALo<+yFic-1{(W1RUUT;3rQ& z7VtUXrytU^uK@S4um1sX9=L~1e++yIcp2vj4)7LudI6ApU6Y*c`4Ez%cn2{QEFhVn zf)B}vM>Hg!NO`nLJk$5B&Pu=M*j=O9Z=3#Vw@EIOlf5L2X+S1SjN{57lzuA*k!+ytVdQwFzPKT`IB_54PkgJwiSt65oi)C}Dfp`nl_*UEO z_IxS3&BKsqY#2vDCf%4)E>v5jEKA}jo5u;OWBL82X&W0-vUiBkK}^$tKr|Di=7D}1 zF3e&6ngIo^uG{ZklN#1$w&Eupp*0Dk!!ZeY#7K=tNT6tKG|L2yF^?XrX?A?8Wi<@h zm-?PR>qg7Uek)*+;3Gc7Xo;iQK&fH$q#|46Vmyy7*Yvt}PwG)^?d3_?g_@2JuK#Lk@z^u7)w3u%2*qH zk43Pm;V#;(#fEFQ<}u6Y`CVr=eq?tdvbl=Bz3Tf8DT3}CLq^t`#qOSK%Wkko5JA!$ z!dkZF^wr>Qg*+h}#JJ7p2|ud7iu$Vl`n>g*&E~3Ut*olZWy^PV1N49~1#|n`T70kH?BKcs{R@Q+0q`p*iOCl=$O#LNn5p z6D7HXB>d9VTgEHtRE$qkL|Yc=0ec3uWJNiLGksGhV$6s)iDNP5tcaNugF>b%g&ECL zQapjwWj#xfY#irdKrjypiV;o25KDk8!;?uy;zY*Tj7S+gBQmlFXm`w31Ez##d4kuN z(pM?XAEQv=IiDmUn;=@Fa;Z=mNy%pM@RF>!%XS$Lm1)JBPF<^?I;Cl-j@BR%6M8n% zhjAL|Va+e4;U*{Qm>%)vx2#@khKFx`UGBF_i{%*)w>MM4^F>PP6}vEGZod@)^_5mr1{ zO&wj>!Jd*d*1cxNk|1o!9?$&VRuv>RT>Si;W_awy2;S<50_ZJ6vq1c zlp39~htn{|%6y8I2HErASSQwq;7#)))(ebWl0Ef8y*`~z_01^P<8%`*kcSLQx~%?; z8g?6TJ{xyqxq8Lom|?jTV5|(|WShhzHM&+hJz}G4APA^Pg2l5_gcrMz2a}{#4=tyL z-Xu;L2^dCsm?9cHmc>M}b;NE)s?&-K{{*&6=PjdJ*JEgJA^fprDin4U=qE@ZoKM zfUYKoYz+4X+lTl+lICTlc^9NpWJn|Qj$LA;1&GFVv=!FYd?dw4Ney(HRL;g&04_IDmizy+*oVI&_v6_A z&+fN>i~asfKmZuP6Tm&W*9U$BybAmRhye~f3)Fxw0&n6B;3Z%a7y<*}I@GmCrxJM@;jk)> za6lnb)SozNO17O8o6b~lmep{KmMs+dhn(f9DmVj-*z}O2zM867o(CRPyS5-t|Hzdt zwyG%)@V}yG7V;5M>h&z)Q4lhDR(|O+S<;slu>0iM-t^1ljJ{NuS+A>o`EBf^ao&S% zG#9w*;ddC0?}R+Lg8(wc>7o3It=@#=tPf`zqcon7^|lTDgg^)lU42N zanTh>NhcGox|wv~I%L+`RE%{x$ZEA_j8hl3psq_7%IPAAGUjfJAA;nR-7;!>flE^=#y_@WgLk^aCn@S_O#cKXeZ2gQx=(H`u% JAwFEgzX4=Rz5M_H literal 0 HcmV?d00001 diff --git a/src/com/t_oster/liblasercut/drivers/.Grbl.java.swp b/src/com/t_oster/liblasercut/drivers/.Grbl.java.swp new file mode 100644 index 0000000000000000000000000000000000000000..c04cbc2bd7d2c29b178f18d8b8281e5eeac07c48 GIT binary patch literal 24576 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 literal 0 HcmV?d00001 diff --git a/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java b/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java index cfb2e009..baf5d7fb 100644 --- a/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java +++ b/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java @@ -495,7 +495,7 @@ protected void line(PrintStream out, double x, double y, double resolution) thro sendLine("G1 X%f Y%f"+append, x, y); } - private void writeInitializationCode() throws IOException { + protected void writeInitializationCode() throws IOException { if (preJobGcode != null) { for (String line : preJobGcode.split(",")) @@ -506,7 +506,7 @@ private void writeInitializationCode() throws IOException { } - private void writeShutdownCode() throws IOException { + protected void writeShutdownCode() throws IOException { if (postJobGcode != null) { for (String line : postJobGcode.split(",")) @@ -671,7 +671,7 @@ protected String connect_serial(CommPortIdentifier i, ProgressListener pl) throw * Used to buffer the file before uploading via http */ private ByteArrayOutputStream outputBuffer; - private String jobName; + protected String jobName; protected void connect(ProgressListener pl) throws IOException, PortInUseException, NoSuchPortException, UnsupportedCommOperationException { outputBuffer = null; @@ -791,6 +791,17 @@ else if (this.port != null) } + + /* sendJobPrepare() and sendJobFinish() can be overrided in children to + * perform device-specific setup before and after sending job over serial + * line + */ + protected void sendJobPrepare() throws IOException { + } + + protected void sendJobFinish() throws IOException { + } + @Override public void sendJob(LaserJob job, ProgressListener pl, List warnings) throws IllegalJobException, Exception { pl.progressChanged(this, 0); @@ -805,6 +816,7 @@ public void sendJob(LaserJob job, ProgressListener pl, List warnings) th connect(pl); pl.taskChanged(this, "sending"); try { + sendJobPrepare(); writeInitializationCode(); pl.progressChanged(this, 20); int i = 0; @@ -825,6 +837,7 @@ public void sendJob(LaserJob job, ProgressListener pl, List warnings) th pl.progressChanged(this, 20 + (int) (i*(double) 60/max)); } writeShutdownCode(); + sendJobFinish(); disconnect(job.getName()+".gcode"); } catch (IOException e) { diff --git a/src/com/t_oster/liblasercut/drivers/Grbl.java b/src/com/t_oster/liblasercut/drivers/Grbl.java index 68beb9bc..be605c82 100644 --- a/src/com/t_oster/liblasercut/drivers/Grbl.java +++ b/src/com/t_oster/liblasercut/drivers/Grbl.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.ArrayDeque; /** * This class implements a driver for Grbl based firmwares. @@ -33,8 +34,11 @@ */ public class Grbl extends GenericGcodeDriver { + protected ArrayDeque commandLenQueue; + public Grbl() { + commandLenQueue = new ArrayDeque(); //set some grbl-specific defaults setLineend("CR"); setIdentificationLine("Grbl"); @@ -105,13 +109,31 @@ public void setAutoHome(boolean auto_home) this.autoHome = auto_home; } + protected boolean simpleStreamMode = true; + + public boolean isSimpleStreamMode() + { + return simpleStreamMode; + } + + public void setSimpleStreamMode(boolean mode) throws IOException + { + if (mode != simpleStreamMode) { + if (!simpleStreamMode) + waitForCommandsCompletion(); + else + commandLenQueue.clear(); + + simpleStreamMode = mode; + } + } @Override public String getModelName() { return "Grbl Gcode Driver"; } - + protected void sendLineWithoutWait(String text, Object... parameters) throws IOException { boolean wasSetWaitingForOk = isWaitForOKafterEachLine(); @@ -119,6 +141,77 @@ protected void sendLineWithoutWait(String text, Object... parameters) throws IOE sendLine(text, parameters); setWaitForOKafterEachLine(wasSetWaitingForOk); } + + @Override + protected String waitForLine() throws IOException + { + String line = ""; + while ("".equals(line)) + {//skip empty lines + line = in.readLine(); + } + + //TODO: remove + if (isSimpleStreamMode() || !"ok".equals(line)) + System.out.println("< "+line); + else { + int len = commandLenQueue.peek(); + // Debug: print counted chars still remains in the buffer AFTER receiving this 'ok' response + System.out.println(String.format(FORMAT_LOCALE, "%d< %s", getBufferedCommandsLen() - len, line)); + } + + return line; + } + + protected static final int GRBL_BUF_LEN = 128; + + protected Integer getBufferedCommandsLen() + { + Integer len = 0; + for (Integer c : commandLenQueue) + len += c; + return len; + } + + protected void sendLineSimple(String text, Object... parameters) throws IOException + { + super.sendLine(text, parameters); + } + + protected void sendLineCC(String text, Object... parameters) throws IOException + { + String outStr = String.format(FORMAT_LOCALE, text+LINEEND(), parameters); + int len = outStr.length(); + + // Read all received responses from grbl or wait for needed free space in the serial buffer + while (in.ready() || (getBufferedCommandsLen() + len > GRBL_BUF_LEN)) { + String line = waitForLine(); + if (!"ok".equals(line)) + { + throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead."); + } + commandLenQueue.remove(); + } + + commandLenQueue.add(len); + out.print(outStr); + //TODO: Remove + System.out.println(String.format(FORMAT_LOCALE, "%d> %s", getBufferedCommandsLen(), outStr)); + out.flush(); + } + + protected void waitForCommandsCompletion() throws IOException + { + while (!commandLenQueue.isEmpty()) { + String line = waitForLine(); + if (!"ok".equals(line)) + { + throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead."); + } + commandLenQueue.remove(); + } + } + /** * Initializes Grbl, handling issuing of soft-reset and initial homing @@ -186,7 +279,7 @@ protected void move(PrintStream out, double x, double y, double resolution) thro sendLine("G0 X%f Y%f", x, y); } } - + /** * Send a line of gcode to the cutter, stripping out any whitespace in the process * @param text @@ -194,20 +287,31 @@ protected void move(PrintStream out, double x, double y, double resolution) thro * @throws IOException */ @Override + protected void sendLine(String text, Object... parameters) throws IOException { - out.format(FORMAT_LOCALE, text.replace(" ", "")+LINEEND(), parameters); - //TODO: Remove - System.out.println(String.format(FORMAT_LOCALE, "> "+text+LINEEND(), parameters)); - out.flush(); - if (isWaitForOKafterEachLine()) - { - String line = waitForLine(); - if (!"ok".equals(line)) - { - throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead."); - } - } + if (isSimpleStreamMode()) + sendLineSimple(text, parameters); + else + sendLineCC(text, parameters); + } + + @Override + protected void sendJobPrepare() throws IOException { + setSimpleStreamMode(false); + } + + @Override + protected void sendJobFinish() throws IOException { + setSimpleStreamMode(true); + } + + @Override + protected void setKeysMissingFromDeserialization() + { + super.setKeysMissingFromDeserialization(); + commandLenQueue = new ArrayDeque(); + simpleStreamMode = true; } @Override