/*
*
* Goko
* Copyright (C) 2013 PsyKo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.goko.controller.tinyg.commons;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.goko.core.common.exception.GkException;
import org.goko.core.common.measure.SIPrefix;
import org.goko.core.common.measure.Units;
import org.goko.core.common.measure.quantity.Angle;
import org.goko.core.common.measure.quantity.Length;
import org.goko.core.common.measure.quantity.Speed;
import org.goko.core.common.measure.units.Unit;
import org.goko.core.controller.bean.DefaultControllerValues;
import org.goko.core.controller.bean.MachineState;
import org.goko.core.controller.bean.MachineValue;
import org.goko.core.controller.bean.MachineValueStore;
import org.goko.core.gcode.element.ICoordinateSystem;
import org.goko.core.gcode.rs274ngcv3.context.CoordinateSystem;
import org.goko.core.gcode.rs274ngcv3.context.EnumDistanceMode;
import org.goko.core.gcode.rs274ngcv3.context.EnumMotionMode;
import org.goko.core.gcode.rs274ngcv3.context.EnumPlane;
import org.goko.core.gcode.rs274ngcv3.context.EnumUnit;
import org.goko.core.gcode.rs274ngcv3.context.GCodeContext;
import org.goko.core.math.Tuple6b;
/**
* Storage of the internal state of the TinyG board
*
* @author PsyKo
*/
public abstract class AbstractTinyGState extends MachineValueStore{
/** The current GCode context */
private GCodeContext gcodeContext;
/** The position stored locally for speed reasons... */
private Tuple6b position;
/** The offsets */
private Map<ICoordinateSystem, Tuple6b> offsets;
/** Unit in use by TinyG*/
private Unit<Length> currentUnit;
/**
* Constructor
* @throws GkException GkException
*/
public AbstractTinyGState() throws GkException {
super();
initializeDefaultValue();
initializeDefaultContext();
}
/**
* Initialize the default GCodeContext
* @throws GkException GkException
*/
protected void initializeDefaultContext() throws GkException {
gcodeContext = new GCodeContext();
gcodeContext.setPosition(new Tuple6b());
gcodeContext.setMachinePosition(new Tuple6b());
gcodeContext.setOriginOffset(new Tuple6b());
gcodeContext.setCoordinateSystem(CoordinateSystem.G54);
gcodeContext.setSelectedToolNumber(0);
gcodeContext.setActiveToolNumber(0);
gcodeContext.setUnit(EnumUnit.MILLIMETERS);
gcodeContext.setMotionMode(EnumMotionMode.RAPID);
gcodeContext.setFeedrate(Speed.ZERO);
gcodeContext.setDistanceMode(EnumDistanceMode.ABSOLUTE);
gcodeContext.setPlane(EnumPlane.XY_PLANE);
}
/**
* Initialize the defaults values
* @throws GkException GkException
*/
protected void initializeDefaultValue() throws GkException{
position = new Tuple6b().setZero();
currentUnit = SIPrefix.MILLI(Units.METRE);
storeValue(DefaultControllerValues.STATE, "State", "The state of TinyG controller board", MachineState.UNDEFINED);
storeValue(DefaultControllerValues.POSITION_X, "X", "The X work position", Length.ZERO);
storeValue(DefaultControllerValues.POSITION_Y, "Y", "The Y work position", Length.ZERO);
storeValue(DefaultControllerValues.POSITION_Z, "Z", "The Z work position", Length.ZERO);
storeValue(DefaultControllerValues.POSITION_A, "A", "The A work position", Angle.ZERO);
storeValue(DefaultControllerValues.MACHINE_POSITION_X, "Machine X", "The X machine position in absolute coord system", Length.ZERO);
storeValue(DefaultControllerValues.MACHINE_POSITION_Y, "Machine Y", "The Y machine position in absolute coord system", Length.ZERO);
storeValue(DefaultControllerValues.MACHINE_POSITION_Z, "Machine Z", "The Z machine position in absolute coord system", Length.ZERO);
storeValue(DefaultControllerValues.MACHINE_POSITION_A, "Machine A", "The A machine position in absolute coord system", Angle.ZERO);
storeValue(DefaultControllerValues.VELOCITY , "Velocity", "The current velocity of the machine", Speed.ZERO);
storeValue(DefaultControllerValues.SPINDLE_STATE , "Spindle", "The current state of the spindle", "false");
storeValue(DefaultControllerValues.CONTEXT_UNIT , "Units", "The units in use", StringUtils.EMPTY);
storeValue(DefaultControllerValues.CONTEXT_COORD_SYSTEM , "Coordinates", "The coordinate system",StringUtils.EMPTY);
storeValue(DefaultControllerValues.CONTEXT_DISTANCE_MODE, "Distance mode", "The distance motion setting", StringUtils.EMPTY);
storeValue(DefaultControllerValues.CONTEXT_PLANE, "Plane", "The current working plane", StringUtils.EMPTY);
storeValue(DefaultControllerValues.CONTEXT_FEEDRATE, "Feedrate", "The current context feedrate", Speed.ZERO);
offsets = new HashMap<ICoordinateSystem, Tuple6b>();
offsets.put(CoordinateSystem.G53, new Tuple6b());
offsets.put(CoordinateSystem.G54, new Tuple6b());
offsets.put(CoordinateSystem.G55, new Tuple6b());
offsets.put(CoordinateSystem.G56, new Tuple6b());
offsets.put(CoordinateSystem.G57, new Tuple6b());
}
/**
* @return the state
* @throws GkException
*/
public MachineState getState() throws GkException {
MachineState state = MachineState.UNDEFINED;
MachineValue<MachineState> storedState = getValue(DefaultControllerValues.STATE, MachineState.class);
if(storedState != null && storedState.getValue() != null){
state = storedState.getValue();
}
return state;
}
/**
* @param state the state to set
* @throws GkException
*/
public void setState(MachineState state) throws GkException {
updateValue(DefaultControllerValues.STATE, state);
}
/**
* Determine if the spindle is ON
* @return <code>true</code> if the spindle is ON, <code>false</code> otherwise
* @throws GkException GkException
*/
public boolean isSpindleOn() throws GkException{
return StringUtils.equals(getValue(DefaultControllerValues.SPINDLE_STATE, String.class).getValue(), TinyG.ON);
}
/**
* Determine if the spindle is OFF
* @return <code>true</code> if the spindle is OFF, <code>false</code> otherwise
* @throws GkException GkException
*/
public boolean isSpindleOff() throws GkException{
return StringUtils.equals(getValue(DefaultControllerValues.SPINDLE_STATE, String.class).getValue(), TinyG.OFF);
}
/**
* @return the gcodeContext
*/
public GCodeContext getGCodeContext() {
return new GCodeContext(gcodeContext);
}
/**
* @param gcodeContext the gcodeContext to set
* @throws GkException GkException
*/
public void setGCodeContext(GCodeContext gcodeContext) throws GkException {
this.gcodeContext = gcodeContext;
updateValue(DefaultControllerValues.CONTEXT_UNIT, String.valueOf(gcodeContext.getUnit()));
setCurrentUnit( gcodeContext.getUnit().getUnit());
setWorkPosition(gcodeContext.getPosition());
setMachinePosition(gcodeContext.getMachinePosition());
if(gcodeContext.getCoordinateSystem() != null){
updateValue(DefaultControllerValues.CONTEXT_COORD_SYSTEM, gcodeContext.getCoordinateSystem().getCode());
}
updateValue(DefaultControllerValues.CONTEXT_DISTANCE_MODE, String.valueOf(gcodeContext.getDistanceMode()));
updateValue(DefaultControllerValues.CONTEXT_PLANE, String.valueOf(gcodeContext.getPlane()));
updateValue(DefaultControllerValues.CONTEXT_FEEDRATE, gcodeContext.getFeedrate());
}
/**
* @return the velocity
* @throws GkException
*/
public Speed getVelocity() throws GkException {
return getValue(DefaultControllerValues.VELOCITY, Speed.class).getValue();
}
/**
* @param velocity the velocity to set
* @throws GkException
*/
public void setVelocity(Speed velocity) throws GkException {
updateValue(DefaultControllerValues.VELOCITY, velocity);
}
/**
* @return the position
* @throws GkException
*/
public Tuple6b getWorkPosition() throws GkException {
return new Tuple6b(this.position);
}
/**
* Access the X position
* @return {@link BigDecimalQuantity} the X position
* @throws GkException GkException
*/
protected Length getX() throws GkException{
return position.getX();
}
/**
* Access the Y position
* @return {@link BigDecimalQuantity} the Y position
* @throws GkException GkException
*/
protected Length getY() throws GkException{
return position.getY();
}
/**
* Access the Z position
* @return {@link BigDecimalQuantity} the Z position
* @throws GkException GkException
*/
protected Length getZ() throws GkException{
return position.getZ();
}
/**
* Access the A position
* @return {@link BigDecimalQuantity} the A position
* @throws GkException GkException
*/
protected Angle getA() throws GkException{
return position.getA();
}
/**
* Sets the work position
* @param position the position to set
* @throws GkException GkException
*/
public void setWorkPosition(Tuple6b position) throws GkException {
this.position = new Tuple6b(position);
updateValue(DefaultControllerValues.POSITION_X, position.getX());
updateValue(DefaultControllerValues.POSITION_Y, position.getY());
updateValue(DefaultControllerValues.POSITION_Z, position.getZ());
updateValue(DefaultControllerValues.POSITION_A, position.getA());
}
/**
* Sets the machine position
* @param position the position to set
* @throws GkException GkException
*/
public void setMachinePosition(Tuple6b position) throws GkException {
updateValue(DefaultControllerValues.MACHINE_POSITION_X, position.getX());
updateValue(DefaultControllerValues.MACHINE_POSITION_Y, position.getY());
updateValue(DefaultControllerValues.MACHINE_POSITION_Z, position.getZ());
updateValue(DefaultControllerValues.MACHINE_POSITION_A, position.getA());
}
public Tuple6b getCoordinateSystemOffset(ICoordinateSystem cs) throws GkException {
return offsets.get(cs);
}
public void setCoordinateSystemOffset(ICoordinateSystem cs, Tuple6b offset) throws GkException {
offsets.put(cs, offset);
if(gcodeContext != null){
gcodeContext.setCoordinateSystemData(cs, offset);
}
}
/**
* @return the currentUnit
*/
protected Unit<Length> getCurrentUnit() {
return currentUnit;
}
/**
* @param currentUnit the currentUnit to set
*/
protected void setCurrentUnit(Unit<Length> currentUnit) {
this.currentUnit = currentUnit;
}
}