Skip to content

Commit

Permalink
Display the pin status immediately in FluidNC (#2349)
Browse files Browse the repository at this point in the history
* Display the pin status immediately in FluidNC
* Add Open door feature to FluidNC
  • Loading branch information
breiler authored Oct 21, 2023
1 parent 2eea204 commit 60b5931
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 129 deletions.
10 changes: 7 additions & 3 deletions ugs-core/src/com/willwinder/universalgcodesender/GrblUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ public static ControllerStatus getStatusFromStatusStringLegacy(String status, Un
*/
public static ControllerStatus getStatusFromStatusStringV1(ControllerStatus lastStatus, String status, Units reportingUnits) {
String stateString = "";
String subStateString = "";

Position MPos = null;
Position WPos = null;
Position WCO = null;
Expand All @@ -384,10 +386,12 @@ public static ControllerStatus getStatusFromStatusStringV1(ControllerStatus last
for (String part : status.substring(0, status.length()-1).split("\\|")) {
if (part.startsWith("<")) {
int idx = part.indexOf(':');
if (idx == -1)
if (idx == -1) {
stateString = part.substring(1);
else
} else {
stateString = part.substring(1, idx);
subStateString = part.substring(idx + 1);
}
}
else if (part.startsWith("MPos:")) {
MPos = GrblUtils.getPositionFromStatusString(status, machinePattern, reportingUnits);
Expand Down Expand Up @@ -454,7 +458,7 @@ else if (part.startsWith("A:")) {
}

ControllerState state = getControllerStateFromStateString(stateString);
return new ControllerStatus(state, MPos, WPos, feedSpeed, reportingUnits, spindleSpeed, overrides, WCO, pins, accessoryStates);
return new ControllerStatus(state, subStateString, MPos, WPos, feedSpeed, reportingUnits, spindleSpeed, overrides, WCO, pins, accessoryStates);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ This file is part of Universal Gcode Sender (UGS).
import com.willwinder.universalgcodesender.IFileService;
import com.willwinder.universalgcodesender.StatusPollTimer;
import com.willwinder.universalgcodesender.Utils;
import static com.willwinder.universalgcodesender.Utils.formatter;
import com.willwinder.universalgcodesender.communicator.GrblCommunicator;
import com.willwinder.universalgcodesender.communicator.ICommunicator;
import com.willwinder.universalgcodesender.communicator.ICommunicatorListener;
import com.willwinder.universalgcodesender.connection.ConnectionDriver;
import com.willwinder.universalgcodesender.connection.ConnectionException;
import com.willwinder.universalgcodesender.firmware.FirmwareSettingsException;
import com.willwinder.universalgcodesender.firmware.IFirmwareSettings;
import static com.willwinder.universalgcodesender.firmware.fluidnc.FluidNCUtils.DISABLE_ECHO_COMMAND;
import static com.willwinder.universalgcodesender.firmware.fluidnc.FluidNCUtils.GRBL_COMPABILITY_VERSION;
import com.willwinder.universalgcodesender.firmware.fluidnc.commands.FluidNCCommand;
import com.willwinder.universalgcodesender.firmware.fluidnc.commands.GetAlarmCodesCommand;
import com.willwinder.universalgcodesender.firmware.fluidnc.commands.GetErrorCodesCommand;
Expand All @@ -56,9 +59,12 @@ This file is part of Universal Gcode Sender (UGS).
import com.willwinder.universalgcodesender.model.PartialPosition;
import com.willwinder.universalgcodesender.model.Position;
import com.willwinder.universalgcodesender.model.UnitUtils;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.MM;
import static com.willwinder.universalgcodesender.model.UnitUtils.scaleUnits;
import com.willwinder.universalgcodesender.services.MessageService;
import com.willwinder.universalgcodesender.types.GcodeCommand;
import com.willwinder.universalgcodesender.utils.ControllerUtils;
import static com.willwinder.universalgcodesender.utils.ControllerUtils.sendAndWaitForCompletion;
import com.willwinder.universalgcodesender.utils.IGcodeStreamReader;
import com.willwinder.universalgcodesender.utils.SemanticVersion;
import com.willwinder.universalgcodesender.utils.ThreadHelper;
Expand All @@ -74,12 +80,6 @@ This file is part of Universal Gcode Sender (UGS).
import java.util.logging.Level;
import java.util.logging.Logger;

import static com.willwinder.universalgcodesender.Utils.formatter;
import static com.willwinder.universalgcodesender.firmware.fluidnc.FluidNCUtils.GRBL_COMPABILITY_VERSION;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.MM;
import static com.willwinder.universalgcodesender.model.UnitUtils.scaleUnits;
import static com.willwinder.universalgcodesender.utils.ControllerUtils.sendAndWaitForCompletion;

/**
* @author Joacim Breiler
*/
Expand Down Expand Up @@ -194,7 +194,10 @@ public void setWorkPosition(PartialPosition axisPosition) throws Exception {

@Override
public void openDoor() throws Exception {

if (isCommOpen()) {
pauseStreaming();
communicator.sendByteImmediately(GrblUtils.GRBL_DOOR_COMMAND);
}
}

@Override
Expand Down Expand Up @@ -541,6 +544,7 @@ private void initializeController() {
issueSoftReset();
return;
}
disableEcho();
queryFirmwareVersion();
queryControllerInformation();

Expand All @@ -563,6 +567,10 @@ private void initializeController() {
}
}

private void disableEcho() throws Exception {
communicator.sendByteImmediately(DISABLE_ECHO_COMMAND);
}

/**
* Attempts to get the current version of the controller. If the controller is not a FluidNC or if the version is
* too low this will throw an exception.
Expand Down Expand Up @@ -756,14 +764,7 @@ public void rawResponseListener(String response) {
}

ThreadHelper.invokeLater(this::initializeController);
}

if (FluidNCUtils.isProbeMessage(response)) {
Position p = FluidNCUtils.parseProbePosition(response, getFirmwareSettings().getReportingUnits());
listeners.forEach(l -> l.probeCoordinates(p));
}

if (FluidNCUtils.isMessageResponse(response)) {
} else if (FluidNCUtils.isMessageResponse(response)) {
MessageType messageType = MessageType.INFO;
if (controllerStatus.getState() == ControllerState.CONNECTING) {
messageType = MessageType.VERBOSE;
Expand All @@ -772,6 +773,11 @@ public void rawResponseListener(String response) {
} else {
messageService.dispatchMessage(MessageType.VERBOSE, "Other: " + response + "\n");
}

if (FluidNCUtils.isProbeMessage(response)) {
Position p = FluidNCUtils.parseProbePosition(response, getFirmwareSettings().getReportingUnits());
listeners.forEach(l -> l.probeCoordinates(p));
}
}

private void checkStreamFinished() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.willwinder.universalgcodesender.GrblUtils.getControllerStateFromStateString;
import static com.willwinder.universalgcodesender.utils.ControllerUtils.sendAndWaitForCompletion;
import static com.willwinder.universalgcodesender.utils.ControllerUtils.sendAndWaitForCompletionWithRetry;

public class FluidNCUtils {
public static final double GRBL_COMPABILITY_VERSION = 1.1d;
public static final SemanticVersion MINIMUM_VERSION = new SemanticVersion(3, 3, 0);
public static final byte DISABLE_ECHO_COMMAND = (byte)0x0c;

private static final String MESSAGE_REGEX = "\\[MSG:.*]";
private static final Pattern MESSAGE_PATTERN = Pattern.compile(MESSAGE_REGEX);
Expand Down Expand Up @@ -86,115 +86,8 @@ public static Optional<SemanticVersion> parseSemanticVersion(String response) {
return Optional.empty();
}

public static String getVersionNumber(String response) {
return response;
}

public static Optional<String> parseFirmwareVariant(String response) {
Matcher matcher = WELCOME_PATTERN.matcher(response);
if (matcher.find()) {
String versionString = matcher.group("fncvariant");
return Optional.ofNullable(versionString);
}

return Optional.empty();
}

public static ControllerStatus getStatusFromStatusResponse(ControllerStatus lastStatus, String status, UnitUtils.Units reportingUnits) {
String stateString = "";
String subStateString = "";
Position MPos = null;
Position WPos = null;
Position WCO = null;

ControllerStatus.OverridePercents overrides = null;
ControllerStatus.EnabledPins pins = null;
ControllerStatus.AccessoryStates accessoryStates = null;

double feedSpeed = 0;
double spindleSpeed = 0;
if (lastStatus != null) {
feedSpeed = lastStatus.getFeedSpeed();
spindleSpeed = lastStatus.getSpindleSpeed();
}
boolean isOverrideReport = false;

// Parse out the status messages.
for (String part : status.substring(0, status.length() - 1).split("\\|")) {
if (part.startsWith("<")) {
int idx = part.indexOf(':');
if (idx == -1) {
stateString = part.substring(1);
} else {
stateString = part.substring(1, idx);
subStateString = part.substring(idx + 1);
}
} else if (part.startsWith("MPos:")) {
MPos = GrblUtils.getPositionFromStatusString(status, MACHINE_PATTERN, reportingUnits);
} else if (part.startsWith("WPos:")) {
WPos = GrblUtils.getPositionFromStatusString(status, WORK_PATTERN, reportingUnits);
} else if (part.startsWith("WCO:")) {
WCO = GrblUtils.getPositionFromStatusString(status, WCO_PATTERN, reportingUnits);
} else if (part.startsWith("Ov:")) {
isOverrideReport = true;
String[] overrideParts = part.substring(3).trim().split(",");
if (overrideParts.length == 3) {
overrides = new ControllerStatus.OverridePercents(
Integer.parseInt(overrideParts[0]),
Integer.parseInt(overrideParts[1]),
Integer.parseInt(overrideParts[2]));
}
} else if (part.startsWith("F:")) {
feedSpeed = GrblUtils.parseFeedSpeed(part);
} else if (part.startsWith("FS:")) {
String[] parts = part.substring(3).split(",");
feedSpeed = Double.parseDouble(parts[0]);
spindleSpeed = Double.parseDouble(parts[1]);
} else if (part.startsWith("Pn:")) {
String value = part.substring(part.indexOf(':') + 1);
pins = new ControllerStatus.EnabledPins(value);
} else if (part.startsWith("A:")) {
String value = part.substring(part.indexOf(':') + 1);
accessoryStates = new ControllerStatus.AccessoryStates(value);
}
}

// Grab WCO from state information if necessary.
if (WCO == null) {
// Grab the work coordinate offset.
if (lastStatus != null && lastStatus.getWorkCoordinateOffset() != null) {
WCO = lastStatus.getWorkCoordinateOffset();
} else {
WCO = new Position(0, 0, 0, 0, 0, 0, reportingUnits);
}
}

// Calculate missing coordinate with WCO
if (WPos == null && MPos != null) {
WPos = new Position(MPos.x - WCO.x, MPos.y - WCO.y, MPos.z - WCO.z, MPos.a - WCO.a, MPos.b - WCO.b, MPos.c - WCO.c, reportingUnits);
} else if (MPos == null && WPos != null) {
MPos = new Position(WPos.x + WCO.x, WPos.y + WCO.y, WPos.z + WCO.z, WPos.a + WCO.a, WPos.b + WCO.b, WPos.c + WCO.c, reportingUnits);
}

if (!isOverrideReport && lastStatus != null) {
overrides = lastStatus.getOverrides();
pins = lastStatus.getEnabledPins();
accessoryStates = lastStatus.getAccessoryStates();
} else if (isOverrideReport) {
// If this is an override report and the 'Pn:' field wasn't sent
// set all pins to a disabled state.
if (pins == null) {
pins = new ControllerStatus.EnabledPins("");
}
// Likewise for accessory states.
if (accessoryStates == null) {
accessoryStates = new ControllerStatus.AccessoryStates("");
}
}

ControllerState state = getControllerStateFromStateString(stateString);

return new ControllerStatus(state, subStateString, MPos, WPos, feedSpeed, reportingUnits, spindleSpeed, overrides, WCO, pins, accessoryStates);
return GrblUtils.getStatusFromStatusStringV1(lastStatus, status, reportingUnits);
}

public static GetStatusCommand queryForStatusReport(IController controller, MessageService messageService) throws InterruptedException {
Expand All @@ -214,6 +107,7 @@ public static void addCapabilities(Capabilities capabilities, SemanticVersion ve
capabilities.addCapability(CapabilitiesConstants.HOMING);
capabilities.addCapability(CapabilitiesConstants.FIRMWARE_SETTINGS);
capabilities.addCapability(CapabilitiesConstants.OVERRIDES);
capabilities.addCapability(CapabilitiesConstants.OPEN_DOOR);

try {
if (firmwareSettings.isSoftLimitsEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,22 @@ public void getStatusFromStatusStringV1ShouldReturnState() {
assertEquals(ControllerState.TOOL, controllerStatus.getState());
}

@Test
public void getStatusFromStatusStringV1ShouldReturnSubState() {
Capabilities version = new Capabilities();
version.addCapability(GrblCapabilitiesConstants.REAL_TIME);

String status = "<Alarm:1|MPos:0.000,0.000,0.000|FS:0,0>";
ControllerStatus controllerStatus = GrblUtils.getStatusFromStatusStringV1(null, status, MM);
assertEquals(ControllerState.ALARM, controllerStatus.getState());
assertEquals("1", controllerStatus.getSubState());

status = "<Alarm:banana|MPos:0.000,0.000,0.000|FS:0,0>";
controllerStatus = GrblUtils.getStatusFromStatusStringV1(null, status, MM);
assertEquals(ControllerState.ALARM, controllerStatus.getState());
assertEquals("banana", controllerStatus.getSubState());
}

/**
* Test of getWorkPositionFromStatusString method, of class GrblUtils.
*/
Expand Down Expand Up @@ -539,9 +555,8 @@ public void getStatusFromStringVersion1WithoutMachineCoordinateStatusString() {
String status = "<Idle|WPos:4.0,5.0,6.0|WCO:7.0,8.0,9.0|Ov:1,2,3|F:12345.6|FS:12345.7,65432.1|Pn:XYZPDHRS|A:SFMC>";
Capabilities version = new Capabilities();
version.addCapability(GrblCapabilitiesConstants.V1_FORMAT);
UnitUtils.Units unit = MM;

ControllerStatus controllerStatus = GrblUtils.getStatusFromStatusString(null, status, version, unit);
ControllerStatus controllerStatus = GrblUtils.getStatusFromStatusString(null, status, version, MM);

assertEquals(new Position(11, 13, 15, MM), controllerStatus.getMachineCoord());
assertEquals(new Position(4, 5, 6, MM), controllerStatus.getWorkCoord());
Expand Down

0 comments on commit 60b5931

Please sign in to comment.