From 87fb687277c819ef2dc05f5d27845297cf84ed9b Mon Sep 17 00:00:00 2001 From: Adam Carmichael Date: Tue, 30 Apr 2019 02:32:59 +1000 Subject: [PATCH 1/3] fixes #69 --- .../AbstractCommunicator.java | 2 + .../AbstractController.java | 15 ++++++ .../BufferedCommunicator.java | 49 +++++++++++++++++++ .../universalgcodesender/IController.java | 2 + .../model/GUIBackend.java | 1 + .../panels/ConnectionSettingsPanel.java | 7 +++ .../utils/GcodeStreamReader.java | 25 ++++++++++ .../universalgcodesender/utils/Settings.java | 12 +++++ .../utils/SettingsFactory.java | 1 + .../resources/MessagesBundle_en_US.properties | 2 + .../BufferedCommunicatorTest.java | 10 ++++ .../core/windows/DiagnosticsTopComponent.java | 1 + 12 files changed, 127 insertions(+) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java b/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java index 895fc0a04d..8894696220 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java @@ -74,6 +74,8 @@ public AbstractCommunicator() { /*********************/ abstract public void setSingleStepMode(boolean enable); abstract public boolean getSingleStepMode(); + abstract public void setSingleBlockMode(boolean enable); + abstract public boolean getSingleBlockMode(); abstract public void queueStringForComm(final String input); abstract public void queueStreamForComm(final GcodeStreamReader input); abstract public void sendByteImmediately(byte b) throws Exception; diff --git a/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java b/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java index 486b390513..089df38a0a 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java @@ -347,6 +347,21 @@ public boolean getSingleStepMode() { } return false; } + + @Override + public void setSingleBlockMode(boolean enabled) { + if (this.comm != null) { + this.comm.setSingleBlockMode(enabled); + } + } + + @Override + public boolean getSingleBlockMode() { + if (this.comm != null) { + return this.comm.getSingleBlockMode(); + } + return false; + } @Override public void setStatusUpdatesEnabled(boolean enabled) { diff --git a/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java b/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java index 427c329036..0b09489c87 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java @@ -47,6 +47,7 @@ public abstract class BufferedCommunicator extends AbstractCommunicator { private int sentBufferSize = 0; private Boolean singleStepModeEnabled = false; + private Boolean singleBlockModeEnabled = false; abstract public int getBufferSize(); @@ -69,6 +70,16 @@ public void setSingleStepMode(boolean enable) { public boolean getSingleStepMode() { return this.singleStepModeEnabled; } + + @Override + public void setSingleBlockMode(boolean enable) { + this.singleBlockModeEnabled = enable; + } + + @Override + public boolean getSingleBlockMode() { + return this.singleBlockModeEnabled; + } /** * Add command to the command queue outside file mode. This is the only way @@ -187,6 +198,32 @@ else if (!this.commandBuffer.isEmpty()) { } return null; } + + private GcodeCommand peekNextCommand() { + GcodeCommand nc = null; + + if (nextCommand != null) { + nc = nextCommand; + } + else if (!this.commandBuffer.isEmpty()) { + nc = new GcodeCommand(commandBuffer.peek()); + } + else + try { + if (commandStream != null && commandStream.ready()) + { + nc = commandStream.peekNextCommand(); + } + } catch (IOException ignored) { + // Fall through to null handling. + } + + if (nc != null && nc.getCommandString().endsWith("\n")) { + nc.setCommand(nextCommand.getCommandString().trim()); + } + + return nc; + } /** * Streams anything in the command buffer to the comm port. @@ -235,6 +272,18 @@ && allowMoreCommands()) { e.printStackTrace(); System.exit(-1); } + + // Single block mode: pause after this command is sent + // iff the next command is from the commandStream + // (ie do not pause for commandBuffer commands) + if( this.getSingleBlockMode() && + commandBuffer.isEmpty() && + peekNextCommand() != null && + !peekNextCommand().getCommandString().isEmpty() ) { + + logger.log(Level.INFO, "singleBlockMode: pausing"); + pauseSend(); + } } } diff --git a/ugs-core/src/com/willwinder/universalgcodesender/IController.java b/ugs-core/src/com/willwinder/universalgcodesender/IController.java index c17d30be09..3bc8f54d33 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/IController.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/IController.java @@ -126,6 +126,8 @@ void jogMachine(int dirX, int dirY, int dirZ, */ void setSingleStepMode(boolean enabled); boolean getSingleStepMode(); + void setSingleBlockMode(boolean enabled); + boolean getSingleBlockMode(); void setStatusUpdatesEnabled(boolean enabled); boolean getStatusUpdatesEnabled(); diff --git a/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java b/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java index d2725b1613..c3690fa21a 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java @@ -771,6 +771,7 @@ public void applySettingsToController(Settings settings, IController controller) try { controller.setSingleStepMode(settings.isSingleStepMode()); + controller.setSingleBlockMode(settings.isSingleStepMode()); controller.setStatusUpdatesEnabled(settings.isStatusUpdatesEnabled()); controller.setStatusUpdateRate(settings.getStatusUpdateRate()); } catch (Exception ex) { diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/ConnectionSettingsPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/ConnectionSettingsPanel.java index bcc2c8248e..d55c7dbd88 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/ConnectionSettingsPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/ConnectionSettingsPanel.java @@ -46,6 +46,8 @@ public class ConnectionSettingsPanel extends AbstractUGSSettings { Localization.getString("sender.step.separateZ")); private final Checkbox singleStepMode = new Checkbox( Localization.getString("sender.singlestep")); + private final Checkbox singleBlockMode = new Checkbox( + Localization.getString("sender.singleblock")); private final Checkbox statusPollingEnabled = new Checkbox( Localization.getString("sender.status")); private final Spinner statusPollRate = new Spinner( @@ -77,6 +79,7 @@ public ConnectionSettingsPanel(Settings settings) { public String getHelpMessage() { return Localization.getString("sender.help.verbose.console") + "\n\n" + Localization.getString("sender.help.singlestep") + "\n\n" + + Localization.getString("sender.help.singleblock") + "\n\n" + Localization.getString("sender.help.status") + "\n\n" + Localization.getString("sender.help.status.rate") + "\n\n" + Localization.getString("sender.help.state") + "\n\n"; @@ -87,6 +90,7 @@ public void save() { settings.setVerboseOutputEnabled(verboseConsoleOutput.getValue()); settings.setUseZStepSize(useZStepSize.getValue()); settings.setSingleStepMode(singleStepMode.getValue()); + settings.setSingleBlockMode(singleBlockMode.getValue()); settings.setStatusUpdatesEnabled(statusPollingEnabled.getValue()); settings.setStatusUpdateRate((int)statusPollRate.getValue()); //settings.setAutoConnectEnabled(autoConnect.getValue()); @@ -125,6 +129,9 @@ protected void updateComponentsInternal(Settings s) { singleStepMode.setSelected(s.isSingleStepMode()); add(singleStepMode, "spanx, wrap"); + singleBlockMode.setSelected(s.isSingleBlockMode()); + add(singleBlockMode, "spanx, wrap"); + statusPollingEnabled.setSelected(s.isStatusUpdatesEnabled()); add(statusPollingEnabled, "spanx, wrap"); diff --git a/ugs-core/src/com/willwinder/universalgcodesender/utils/GcodeStreamReader.java b/ugs-core/src/com/willwinder/universalgcodesender/utils/GcodeStreamReader.java index bcf76ddaf8..c9b8ea03b7 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/utils/GcodeStreamReader.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/utils/GcodeStreamReader.java @@ -98,6 +98,31 @@ public GcodeCommand getNextCommand() throws IOException { Integer.parseInt(nextLine[COL_COMMAND_NUMBER])); } + /** + * Peek at the next command without moving the pointers + * NOTE: this calls mark() and reset() so reset() calls outside of + * peekNextCommand() may be interfered with by this. + * @return GcodeCommand containing next line + * @throws IOException + */ + public GcodeCommand peekNextCommand() throws IOException { + if (numRowsRemaining == 0) return null; + + reader.mark(NUM_COLUMNS); // bookmark for rollback + String line = reader.readLine(); + reader.reset(); // rollback to mark + + String nextLine[] = parseLine(line); + if (nextLine.length != NUM_COLUMNS) { + throw new IOException("Corrupt data found while processing gcode stream: " + line); + } + return new GcodeCommand( + nextLine[COL_PROCESSED_COMMAND], + nextLine[COL_ORIGINAL_COMMAND], + nextLine[COL_COMMENT], + Integer.parseInt(nextLine[COL_COMMAND_NUMBER])); + } + @Override public void close() throws IOException { reader.close(); diff --git a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java index 141a3d26f9..183d15304b 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java @@ -37,6 +37,7 @@ This file is part of Universal Gcode Sender (UGS). import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.logging.Level; import java.util.logging.Logger; public class Settings { @@ -64,6 +65,7 @@ public class Settings { private WindowSettings mainWindowSettings = new WindowSettings(0,0,640,520); private WindowSettings visualizerWindowSettings = new WindowSettings(0,0,640,480); private boolean singleStepMode = false; + private boolean singleBlockMode = false; private boolean statusUpdatesEnabled = true; private int statusUpdateRate = 200; private Units preferredUnits = Units.MM; @@ -313,6 +315,16 @@ public void setSingleStepMode(boolean singleStepMode) { changed(); } + public boolean isSingleBlockMode() { + return singleBlockMode; + } + + public void setSingleBlockMode(boolean singleBlockMode) { + logger.log(Level.INFO, "Setting singleBlockMode to ".concat((singleBlockMode)?"true":"false")); + this.singleBlockMode = singleBlockMode; + changed(); + } + public boolean isStatusUpdatesEnabled() { return statusUpdatesEnabled; } diff --git a/ugs-core/src/com/willwinder/universalgcodesender/utils/SettingsFactory.java b/ugs-core/src/com/willwinder/universalgcodesender/utils/SettingsFactory.java index 49a97e2794..04b62941c1 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/utils/SettingsFactory.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/utils/SettingsFactory.java @@ -136,6 +136,7 @@ private static void migrateOldSettings() { out.setVerboseOutputEnabled(Boolean.valueOf(properties.getProperty("verboseOutput.enabled", FALSE))); out.setFirmwareVersion(properties.getProperty("firmwareVersion", "GRBL")); out.setSingleStepMode(Boolean.valueOf(properties.getProperty("singleStepMode", FALSE))); + out.setSingleBlockMode(Boolean.valueOf(properties.getProperty("singleBlockMode", FALSE))); out.setStatusUpdatesEnabled(Boolean.valueOf(properties.getProperty("statusUpdatesEnabled", "true"))); out.setStatusUpdateRate(Integer.valueOf(properties.getProperty("statusUpdateRate", "200"))); out.updateMacro(1, null, null, properties.getProperty("customGcode1", "G0 X0 Y0;")); diff --git a/ugs-core/src/resources/MessagesBundle_en_US.properties b/ugs-core/src/resources/MessagesBundle_en_US.properties index fc7999e32c..097f66a673 100644 --- a/ugs-core/src/resources/MessagesBundle_en_US.properties +++ b/ugs-core/src/resources/MessagesBundle_en_US.properties @@ -163,6 +163,7 @@ sender.speed.percent = Speed override percent sender.command.length = Max command length sender.truncate = Truncate decimal digits sender.singlestep = Enable single step mode +sender.singleblock = Enable single block mode sender.whitespace = Remove all whitespace in commands sender.status = Enable status polling sender.status.rate = Status poll rate (ms) @@ -180,6 +181,7 @@ sender.help.speed.percent = Speed override percent\: Factor that speeds will be sender.help.command.length = Max command length\: Maximum length of a command before an error is triggered. sender.help.truncate = Truncate decimal digits\: Number of fractional digits that will be sent to firmware. sender.help.singlestep = Enable single step mode\: Turns on single step mode, this is very slow. +sender.help.singleblock = Enable single block mode\: Pause sender after every block, useful for testing programs though extremely slow. sender.help.whitespace = Remove all whitespace\: Removes the usually unnecessary whitespace in gcode commands. sender.help.status = Enable status polling\: Turns on status polling for firmware if supported. sender.help.status.rate = Status poll rate\: The rate in milliseconds that status requests are sent at. diff --git a/ugs-core/test/com/willwinder/universalgcodesender/BufferedCommunicatorTest.java b/ugs-core/test/com/willwinder/universalgcodesender/BufferedCommunicatorTest.java index cdeca8bff7..0034cc9497 100644 --- a/ugs-core/test/com/willwinder/universalgcodesender/BufferedCommunicatorTest.java +++ b/ugs-core/test/com/willwinder/universalgcodesender/BufferedCommunicatorTest.java @@ -101,6 +101,16 @@ public void testSingleStepMode() { fail("Not implemented yet."); } + /** + * Test of setSingleBlockMode method of class BufferedCommunicator. + */ + @Test + @Ignore + public void testSingleBlockMode() { + System.out.println("testSingleBlockMode"); + fail("Not implemented yet."); + } + /** * Test of getBufferSize method, of class BufferedCommunicator. */ diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/windows/DiagnosticsTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/windows/DiagnosticsTopComponent.java index 8dba760590..d3ecdf3ffb 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/windows/DiagnosticsTopComponent.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/windows/DiagnosticsTopComponent.java @@ -95,6 +95,7 @@ private void initComponents() { this.labels.put("communicator:numActiveCommands", new JLabel("-----")); this.labels.put("communicator:isPaused", new JLabel("-----")); this.labels.put("communicator:getSingleStepMode", new JLabel("-----")); + this.labels.put("communicator:getSingleBlockMode", new JLabel("-----")); this.labels.put("settings:isHomingEnabled", new JLabel("-----")); this.labels.put("settings:getReportingUnits", new JLabel("-----")); From f3cdcf99ed992ef4bace5ac9ecaa74db3cc68974 Mon Sep 17 00:00:00 2001 From: Adam Carmichael Date: Tue, 30 Apr 2019 04:36:00 +1000 Subject: [PATCH 2/3] incorporate javadoc and style suggestions from @breiler --- .../AbstractCommunicator.java | 13 +++++++++++++ .../universalgcodesender/AbstractController.java | 11 +++++++++++ .../BufferedCommunicator.java | 7 +++++++ .../universalgcodesender/IController.java | 13 +++++++++++++ .../universalgcodesender/utils/Settings.java | 15 ++++++++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java b/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java index 8894696220..c9e81e3bce 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/AbstractCommunicator.java @@ -74,8 +74,21 @@ public AbstractCommunicator() { /*********************/ abstract public void setSingleStepMode(boolean enable); abstract public boolean getSingleStepMode(); + + /** + * Enable singleBlockMode, pausing the commandStream after every + * block sent to the controller. + * @param boolean enable true if enabled + */ abstract public void setSingleBlockMode(boolean enable); + + /** + * Get the state of singleBlockMode, which pauses the commandStream + * after every block sent to the controller. + * @return boolean true if enabled + */ abstract public boolean getSingleBlockMode(); + abstract public void queueStringForComm(final String input); abstract public void queueStreamForComm(final GcodeStreamReader input); abstract public void sendByteImmediately(byte b) throws Exception; diff --git a/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java b/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java index 089df38a0a..1ce60d5ef6 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/AbstractController.java @@ -348,6 +348,11 @@ public boolean getSingleStepMode() { return false; } + /** + * Wrapper to set singleBlockMode in the communicator + * @see AbstractCommunicator.setSingleBlockMode() + * @param boolean true to enable + */ @Override public void setSingleBlockMode(boolean enabled) { if (this.comm != null) { @@ -355,6 +360,12 @@ public void setSingleBlockMode(boolean enabled) { } } + /** + * Wrapper to get the singleBlockMode in the communicator. + * getSingleBlockMode wrapper for AbstractCommunicator + * @see AbstractCommunicator.getSingleBlockMode() + * @return boolean true if enabled else false + */ @Override public boolean getSingleBlockMode() { if (this.comm != null) { diff --git a/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java b/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java index 0b09489c87..7f96c3d3e3 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/BufferedCommunicator.java @@ -199,6 +199,13 @@ else if (!this.commandBuffer.isEmpty()) { return null; } + /** + * See the next command to be sent out without popping from the + * commandBuffer or commandStream. + * @see BufferedCommunicator.getNextCommand() + * @see GcodeStreamReader.peekNextCommand() + * @return GcodeCommand the next command to be sent to the controller + */ private GcodeCommand peekNextCommand() { GcodeCommand nc = null; diff --git a/ugs-core/src/com/willwinder/universalgcodesender/IController.java b/ugs-core/src/com/willwinder/universalgcodesender/IController.java index 3bc8f54d33..c7fc283429 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/IController.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/IController.java @@ -126,7 +126,20 @@ void jogMachine(int dirX, int dirY, int dirZ, */ void setSingleStepMode(boolean enabled); boolean getSingleStepMode(); + + /** + * Wrapper to set singleBlockMode in the communicator + * @see AbstractCommunicator.setSingleBlockMode() + * @param boolean true to enable + */ void setSingleBlockMode(boolean enabled); + + /** + * Wrapper to get the singleBlockMode in the communicator. + * getSingleBlockMode wrapper for AbstractCommunicator + * @see AbstractCommunicator.getSingleBlockMode() + * @return boolean true if enabled else false + */ boolean getSingleBlockMode(); void setStatusUpdatesEnabled(boolean enabled); diff --git a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java index 183d15304b..f3af143d84 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java @@ -315,12 +315,25 @@ public void setSingleStepMode(boolean singleStepMode) { changed(); } + /** + * Retrieve the setting to determine if communicator should pause + * streaming after each command in the communicator commandStream. + * @see AbstractCommunicator.getSingleBlockMode() + * @return true if singleBlockMode is enabled + */ public boolean isSingleBlockMode() { return singleBlockMode; } + /** + * Enable / disable the pausing of streaming after each command in + * the commandStream of the communicator. Also requires + * singleStepMode to be enabled + * @see AbstractCommunicator.setSingleBlockMode() + * @param boolean singleBlockMode true if enabled + */ public void setSingleBlockMode(boolean singleBlockMode) { - logger.log(Level.INFO, "Setting singleBlockMode to ".concat((singleBlockMode)?"true":"false")); + logger.log(Level.INFO, "Setting singleBlockMode to ".concat( ((Boolean)singleBlockMode).toString() )); this.singleBlockMode = singleBlockMode; changed(); } From 22d7ede73bcd815340e8f7725273ca43d1b6e8b7 Mon Sep 17 00:00:00 2001 From: Adam Carmichael Date: Wed, 1 May 2019 01:07:29 +1000 Subject: [PATCH 3/3] fix silly typo --- .../com/willwinder/universalgcodesender/model/GUIBackend.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java b/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java index c3690fa21a..5ebe8bf9f2 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/model/GUIBackend.java @@ -771,7 +771,7 @@ public void applySettingsToController(Settings settings, IController controller) try { controller.setSingleStepMode(settings.isSingleStepMode()); - controller.setSingleBlockMode(settings.isSingleStepMode()); + controller.setSingleBlockMode(settings.isSingleBlockMode()); controller.setStatusUpdatesEnabled(settings.isStatusUpdatesEnabled()); controller.setStatusUpdateRate(settings.getStatusUpdateRate()); } catch (Exception ex) {