/** * */ package org.goko.controller.tinyg.commons.jog; import org.goko.controller.tinyg.commons.AbstractTinyGCommunicator; import org.goko.controller.tinyg.commons.ITinyGControllerService; import org.goko.controller.tinyg.commons.bean.EnumTinyGAxis; import org.goko.controller.tinyg.commons.configuration.AbstractTinyGConfiguration; import org.goko.core.common.exception.GkException; import org.goko.core.common.measure.quantity.Length; import org.goko.core.common.measure.quantity.QuantityUtils; import org.goko.core.common.measure.quantity.Speed; import org.goko.core.common.measure.quantity.Time; import org.goko.core.common.measure.quantity.TimeUnit; import org.goko.core.common.measure.units.Unit; import org.goko.core.config.GokoPreference; import org.goko.core.controller.bean.DefaultControllerValues; import org.goko.core.controller.bean.EnumControllerAxis; import org.goko.core.controller.bean.MachineState; import org.goko.core.gcode.rs274ngcv3.context.EnumDistanceMode; import org.goko.core.gcode.rs274ngcv3.context.EnumUnit; import org.goko.core.gcode.rs274ngcv3.context.GCodeContext; import org.goko.core.log.GkLog; /** * TinyG Jogging utility * @author PsyKo */ public abstract class AbstractTinyGJogger<F extends AbstractTinyGConfiguration<F>, S extends ITinyGControllerService<F>, C extends AbstractTinyGCommunicator<F, S>> { /** Log */ private static final GkLog LOG = GkLog.getLogger(AbstractTinyGJogger.class); /** The target TinyG service */ private S controllerService; /** The target communicator */ private C communicator; /** The estimated jog interval */ private long period = 100; // 100ms aka 10Hz /** The active distance mode before jog */ private EnumDistanceMode previousDistanceMode; /** Stop requested flag - when complete effective stop before jogging again*/ private boolean stopRequested; /** * Constructor */ public AbstractTinyGJogger(S controllerService, C communicator) { this.controllerService = controllerService; this.communicator = communicator; this.stopRequested = false; } public void jog(EnumControllerAxis axis, Length step, Speed feedrate) throws GkException { Length localStep = step; EnumTinyGAxis tinygAxis = EnumTinyGAxis.getEnum(axis.getCode()); if(!stopRequested && isReadyToJog()){ if(axis != null){ GCodeContext context = controllerService.getGCodeContext(); if(previousDistanceMode == null){ previousDistanceMode = context.getDistanceMode(); } stopRequested = false; EnumUnit contextUnit = context.getUnit(); String command = "G91G1"; if(feedrate != null){ command += "F"+ QuantityUtils.format(feedrate, 0, true, false, contextUnit.getFeedUnit()); } if(step == null){ localStep = feedrate.multiply(Time.valueOf(period, TimeUnit.MILLISECOND).multiply(2)); } command = getRelativeJogCommand(command, tinygAxis, localStep); communicator.send(command, true); } } } /** * Determine if TinyG is ready to jog * @return <code>true</code> if TinyG is ready to receive another jog order, <code>false</code> otherwise * @throws GkException GkException */ abstract protected boolean isReadyToJog() throws GkException; /** * Stops jogging * @throws GkException GkException */ public void stopJog() throws GkException{ if(previousDistanceMode != null){ stopRequested = true; controllerService.stopMotion(); // Restore previous distance mode controllerService.schedule().execute(getRestoreDistanceModeRunnable(previousDistanceMode)).whenState(MachineState.PROGRAM_STOP).timeout(5, TimeUnit.SECOND).begin(); if(previousDistanceMode != null){ controllerService.schedule().execute(new Runnable() { @Override public void run() { previousDistanceMode = null; stopRequested = false; } }).when(DefaultControllerValues.CONTEXT_DISTANCE_MODE, previousDistanceMode.name()).timeout(5, TimeUnit.SECOND).begin(); } } } /** * Creates the runnable that will restore the previous distance mode * @param pPreviousDistanceMode the previous distance mode * @return Runnable */ protected Runnable getRestoreDistanceModeRunnable(EnumDistanceMode pPreviousDistanceMode){ return new Runnable() { @Override public void run() { try { if(EnumDistanceMode.ABSOLUTE == pPreviousDistanceMode){ communicator.send("G90", true); }else{ communicator.send("G91", true); } } catch (GkException e) { LOG.error(e); } } }; } /** * Generates jogging command when Grbl is in relative distance mode * @param command the base command * @return a String * @throws GkException GkException */ public String getRelativeJogCommand(String command, EnumTinyGAxis axis, Length step) throws GkException{ command += axis.getAxisCode(); Unit<Length> currentUnit = controllerService.getGCodeContext().getUnit().getUnit(); if(axis.isNegative()){ command+="-"; } command += GokoPreference.getInstance().format(step, true, false, currentUnit); return command; } /** * @return the controllerService */ public S getControllerService() { return controllerService; } /** * @return the communicator */ public C getCommunicator() { return communicator; } }