public void serialByteReceivedEvent(ByteFifo fifo) { readResponseLock.lock(); serialInUse.lock(); byte[] response = fifo.dequeueLine(); int responseLength = response.length; serialInUse.unlock(); // 0 is now an acceptable value; it merely means that we timed out // waiting for input if (responseLength < 0) { // This signifies EOF. FIXME: How do we handle this? Base.logger.severe("SerialPassthroughDriver.readResponse(): EOF occured"); readResponseLock.unlock(); return; } else if (responseLength != 0) { String line; try { // convert to string and remove any trailing \r or \n's line = new String(response, 0, responseLength, "US-ASCII").trim().toLowerCase(); } catch (UnsupportedEncodingException e) { Base.logger.severe("US-ASCII required. Terminating."); readResponseLock.unlock(); throw new RuntimeException(e); } // System.out.println("received: " + line); if (debugLevel > 1) Base.logger.info("<< " + line); if (line.length() == 0) Base.logger.fine("empty line received"); else if (line.startsWith("echo:")) { // if echo is turned on relay it to the user for debugging Base.logger.info(line); } else if (line.startsWith("ok t:") || line.startsWith("t:")) { Pattern r = Pattern.compile("t:([0-9\\.]+)"); Matcher m = r.matcher(line); if (m.find()) { String temp = m.group(1); machine.currentTool().setCurrentTemperature(Double.parseDouble(temp)); } r = Pattern.compile("^ok.*b:([0-9\\.]+)$"); m = r.matcher(line); if (m.find()) { String bedTemp = m.group(1); machine.currentTool().setPlatformCurrentTemperature(Double.parseDouble(bedTemp)); } } else if (line.startsWith("ok c:") || line.startsWith("c:")) { Pattern r = Pattern.compile("c: *x:?([-0-9\\.]+) *y:?([-0-9\\.]+) *z:?([-0-9\\.]+)"); Matcher m = r.matcher(line); if (m.find()) { double x = Double.parseDouble(m.group(1)); double y = Double.parseDouble(m.group(2)); double z = Double.parseDouble(m.group(3)); // super to avoid parroting back a G92 try { super.setCurrentPosition(new Point5d(x, y, z)); // Base.logger.fine("setting currentposition to:"+x+","+y+","+z+"."); } catch (RetryException e) { // do or do not, there is no retry } } } if (line.startsWith("ok")) { synchronized (okReceived) { okReceived.set(true); okReceived.notifyAll(); } bufferLock.lock(); // Notify the thread waitining in this gcode's sendCommand method that the gcode has been // received. if (buffer.isEmpty()) { Base.logger.severe("Received OK with nothing queued!"); } else { String notifier = buffer.removeLast(); if (debugLevel > 1) Base.logger.info("FW Accepted: " + notifier); synchronized (notifier) { notifier.notifyAll(); } } bufferLock.unlock(); synchronized (bufferLock) { /*let any sendCommand method waiting to send know that the buffer is now smaller and may be able to fit their command.*/ bufferLock.notifyAll(); } } // old arduino firmware sends "start" else if (line.contains("start")) { // Reset line number first in case gcode is sent below lineNumber.set(-1); boolean active = !buffer.isEmpty(); flushBuffer(); if (isInitialized()) { sendInitializationGcode(false); // If there were outstanding commands try to abort any print in progress. // This is a poor test: but do we know if we're printing at this level? // tried setInitialized(false); but that didn't work well if (active) { Base.logger.severe("Firmware reset with active commands!"); setError("Firmware reset with active commands!"); } } if (okAfterStart) { // firmware sends "ok" after start, put something here to consume it: bufferLock.lock(); buffer.addLast(";start-ok"); bufferLock.unlock(); } // todo: set version synchronized (startReceived) { startReceived.set(true); startReceived.notifyAll(); } // Wake up connect task to try again synchronized (okReceived) { okReceived.set(false); okReceived.notifyAll(); } } else if (line.startsWith("extruder fail")) { setError("Extruder failed: cannot extrude as this rate."); } else if (line.startsWith("resend:") || line.startsWith("rs ")) { // Bad checksum, resend requested Matcher badLineMatch = resendLinePattern.matcher(line); // Is it a Dud M or G code? String dudLetter = getRegexMatch("dud ([a-z]) code", line, 1); if (badLineMatch.find()) { int badLineNumber = Integer.parseInt(badLineMatch.group(1)); if (debugLevel > 1) Base.logger.warning("Received resend request for line " + badLineNumber); Queue<String> resend = new LinkedList<String>(); boolean found = false; // Search backwards for the bad line in our buffer. // Firmware flushed everything after this line, so // build a queue of lines to resend. bufferLock.lock(); lineSearch: while (!buffer.isEmpty()) { String bufferedLine = buffer.removeLast(); if (debugLevel > 1) Base.logger.info("Searching: " + bufferedLine); int bufferedLineNumber = Integer.parseInt( getRegexMatch(gcodeLineNumberPattern, bufferedLine.toLowerCase(), 1)); if (dudLetter != null && bufferedLineNumber == badLineNumber) { Base.logger.info("Dud " + dudLetter + " code: Dropping " + bufferedLine); synchronized (bufferedLine) { bufferedLine.notifyAll(); } found = true; break lineSearch; } resend.add(bufferedLine); if (bufferedLineNumber == badLineNumber) { found = true; break lineSearch; } } if (okAfterResend) { // firmware sends "ok" after resend, put something here to consume it: buffer.addLast(";resend-ok"); } bufferLock.unlock(); if (!found) { int restartLineNumber = Integer.parseInt( getRegexMatch(gcodeLineNumberPattern, resend.element().toLowerCase(), 1)); Base.logger.severe( "resend for line " + badLineNumber + " not in our buffer. Resuming from " + restartLineNumber); this.resendCommand(applyChecksum("N" + (restartLineNumber - 1) + " M110")); } // resend the lines while (!resend.isEmpty()) { String bufferedLine = resend.remove(); this.resendCommand(bufferedLine); } } else { // Malformed resend line request received. Resetting the line number Base.logger.warning( "malformed line resend request, " + "resetting line number. Malformed Data: \n" + line); this.resendCommand(applyChecksum("N" + (lineNumber.get() - 1) + " M110")); } } else if (line.startsWith("t:") || line.startsWith("c:")) { // temperature, position handled above } else { Base.logger.severe("Unknown: " + line); } } readResponseLock.unlock(); }