Skip to content

Commit 0c51a21

Browse files
committed
Implement character-counting protocol for Grbl. Closes t-oster#74
1 parent 904b520 commit 0c51a21

File tree

2 files changed

+131
-14
lines changed

2 files changed

+131
-14
lines changed

src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,17 @@ else if (this.port != null)
791791

792792
}
793793

794+
795+
/* sendJobPrepare() and sendJobFinish() can be overrided in children to
796+
* perform device-specific setup before and after sending job over serial
797+
* line
798+
*/
799+
protected void sendJobPrepare() throws IOException {
800+
}
801+
802+
protected void sendJobFinish() throws IOException {
803+
}
804+
794805
@Override
795806
public void sendJob(LaserJob job, ProgressListener pl, List<String> warnings) throws IllegalJobException, Exception {
796807
pl.progressChanged(this, 0);
@@ -805,6 +816,7 @@ public void sendJob(LaserJob job, ProgressListener pl, List<String> warnings) th
805816
connect(pl);
806817
pl.taskChanged(this, "sending");
807818
try {
819+
sendJobPrepare();
808820
writeInitializationCode();
809821
pl.progressChanged(this, 20);
810822
int i = 0;
@@ -825,6 +837,7 @@ public void sendJob(LaserJob job, ProgressListener pl, List<String> warnings) th
825837
pl.progressChanged(this, 20 + (int) (i*(double) 60/max));
826838
}
827839
writeShutdownCode();
840+
sendJobFinish();
828841
disconnect(job.getName()+".gcode");
829842
}
830843
catch (IOException e) {

src/com/t_oster/liblasercut/drivers/Grbl.java

Lines changed: 118 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Arrays;
2626
import java.util.LinkedList;
2727
import java.util.List;
28+
import java.util.ArrayDeque;
2829

2930
/**
3031
* This class implements a driver for Grbl based firmwares.
@@ -33,8 +34,11 @@
3334
*/
3435
public class Grbl extends GenericGcodeDriver
3536
{
37+
protected ArrayDeque<Integer> commandLenQueue;
38+
3639
public Grbl()
3740
{
41+
commandLenQueue = new ArrayDeque<Integer>();
3842
//set some grbl-specific defaults
3943
setLineend("CR");
4044
setIdentificationLine("Grbl");
@@ -105,20 +109,109 @@ public void setAutoHome(boolean auto_home)
105109
this.autoHome = auto_home;
106110
}
107111

112+
protected boolean simpleStreamMode = true;
113+
114+
public boolean isSimpleStreamMode()
115+
{
116+
return simpleStreamMode;
117+
}
118+
119+
public void setSimpleStreamMode(boolean mode) throws IOException
120+
{
121+
if (mode != simpleStreamMode) {
122+
if (!simpleStreamMode)
123+
waitForCommandsCompletion();
124+
else
125+
commandLenQueue.clear();
126+
127+
simpleStreamMode = mode;
128+
}
129+
}
108130

109131
@Override
110132
public String getModelName()
111133
{
112134
return "Grbl Gcode Driver";
113135
}
114-
136+
115137
protected void sendLineWithoutWait(String text, Object... parameters) throws IOException
116138
{
117139
boolean wasSetWaitingForOk = isWaitForOKafterEachLine();
118140
setWaitForOKafterEachLine(false);
119141
sendLine(text, parameters);
120142
setWaitForOKafterEachLine(wasSetWaitingForOk);
121143
}
144+
145+
@Override
146+
protected String waitForLine() throws IOException
147+
{
148+
String line = "";
149+
while ("".equals(line))
150+
{//skip empty lines
151+
line = in.readLine();
152+
}
153+
154+
//TODO: remove
155+
if (isSimpleStreamMode() || !"ok".equals(line))
156+
System.out.println("< "+line);
157+
else {
158+
int len = commandLenQueue.peek();
159+
// Debug: print counted chars still remains in the buffer AFTER receiving this 'ok' response
160+
System.out.println(String.format(FORMAT_LOCALE, "%d< %s", getBufferedCommandsLen() - len, line));
161+
}
162+
163+
return line;
164+
}
165+
166+
protected static final int GRBL_BUF_LEN = 128;
167+
168+
protected Integer getBufferedCommandsLen()
169+
{
170+
Integer len = 0;
171+
for (Integer c : commandLenQueue)
172+
len += c;
173+
return len;
174+
}
175+
176+
protected void sendLineSimple(String text, Object... parameters) throws IOException
177+
{
178+
super.sendLine(text, parameters);
179+
}
180+
181+
protected void sendLineCC(String text, Object... parameters) throws IOException
182+
{
183+
String outStr = String.format(FORMAT_LOCALE, text+LINEEND(), parameters);
184+
int len = outStr.length();
185+
186+
// Read all received responses from grbl or wait for needed free space in the serial buffer
187+
while (in.ready() || (getBufferedCommandsLen() + len > GRBL_BUF_LEN)) {
188+
String line = waitForLine();
189+
if (!"ok".equals(line))
190+
{
191+
throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead.");
192+
}
193+
commandLenQueue.remove();
194+
}
195+
196+
commandLenQueue.add(len);
197+
out.print(outStr);
198+
//TODO: Remove
199+
System.out.println(String.format(FORMAT_LOCALE, "%d> %s", getBufferedCommandsLen(), outStr));
200+
out.flush();
201+
}
202+
203+
protected void waitForCommandsCompletion() throws IOException
204+
{
205+
while (!commandLenQueue.isEmpty()) {
206+
String line = waitForLine();
207+
if (!"ok".equals(line))
208+
{
209+
throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead.");
210+
}
211+
commandLenQueue.remove();
212+
}
213+
}
214+
122215

123216
/**
124217
* Initializes Grbl, handling issuing of soft-reset and initial homing
@@ -186,28 +279,39 @@ protected void move(PrintStream out, double x, double y, double resolution) thro
186279
sendLine("G0 X%f Y%f", x, y);
187280
}
188281
}
189-
282+
190283
/**
191284
* Send a line of gcode to the cutter, stripping out any whitespace in the process
192285
* @param text
193286
* @param parameters
194287
* @throws IOException
195288
*/
196289
@Override
290+
197291
protected void sendLine(String text, Object... parameters) throws IOException
198292
{
199-
out.format(FORMAT_LOCALE, text.replace(" ", "")+LINEEND(), parameters);
200-
//TODO: Remove
201-
System.out.println(String.format(FORMAT_LOCALE, "> "+text+LINEEND(), parameters));
202-
out.flush();
203-
if (isWaitForOKafterEachLine())
204-
{
205-
String line = waitForLine();
206-
if (!"ok".equals(line))
207-
{
208-
throw new IOException("Lasercutter did not respond 'ok', but '"+line+"'instead.");
209-
}
210-
}
293+
if (isSimpleStreamMode())
294+
sendLineSimple(text, parameters);
295+
else
296+
sendLineCC(text, parameters);
297+
}
298+
299+
@Override
300+
protected void sendJobPrepare() throws IOException {
301+
setSimpleStreamMode(false);
302+
}
303+
304+
@Override
305+
protected void sendJobFinish() throws IOException {
306+
setSimpleStreamMode(true);
307+
}
308+
309+
@Override
310+
protected void setKeysMissingFromDeserialization()
311+
{
312+
super.setKeysMissingFromDeserialization();
313+
commandLenQueue = new ArrayDeque<Integer>();
314+
simpleStreamMode = true;
211315
}
212316

213317
@Override

0 commit comments

Comments
 (0)