/*
* TinyG Control layer, coordinates all aspects of control.
*/
/*
Copywrite 2013-2016 Will Winder
This file is part of Universal Gcode Sender (UGS).
UGS 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.
UGS 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 UGS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.willwinder.universalgcodesender;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.willwinder.universalgcodesender.gcode.TinyGGcodeCommandCreator;
import com.willwinder.universalgcodesender.i18n.Localization;
import com.willwinder.universalgcodesender.listeners.ControllerStatus;
import com.willwinder.universalgcodesender.model.Overrides;
import com.willwinder.universalgcodesender.model.Position;
import com.willwinder.universalgcodesender.model.UnitUtils.Units;
import com.willwinder.universalgcodesender.types.TinyGGcodeCommand;
import java.io.File;
import java.io.IOException;
import javax.vecmath.Point3d;
/**
*
* @author wwinder
*/
public class TinyGController extends AbstractController {
private static final String NOT_SUPPORTED_YET = "Not supported yet.";
private boolean isReady = false;
private Units units;
private String state = "";
private Position machineLocation = new Position();
private Position workLocation = new Position();
protected TinyGController(TinyGCommunicator comm) {
super(comm);
this.commandCreator = new TinyGGcodeCommandCreator();
//this.positionPollTimer = createPositionPollTimer();
}
public TinyGController() {
this(new TinyGCommunicator()); //f4grx: connection created at opencomm() time
}
@Override
public Boolean handlesAllStateChangeEvents() {
return false;
}
@Override
public long getJobLengthEstimate(File gcodeFile) {
return 0;
}
@Override
protected void closeCommBeforeEvent() {
//throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void closeCommAfterEvent() {
//throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void openCommAfterEvent() throws Exception {
byte b = 0x18;
this.comm.sendByteImmediately(b);
}
@Override
protected void cancelSendBeforeEvent() {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void cancelSendAfterEvent() {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void pauseStreamingEvent() throws IOException {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void resumeStreamingEvent() throws IOException {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected Boolean isIdleEvent() {
// Let abstract controller decide
return true;
}
@Override
protected void rawResponseHandler(String response) {
JsonObject jo;
try {
jo = TinyGUtils.jsonToObject(response);
} catch (Exception e) {
// Some TinyG responses aren't JSON, those will end up here.
//this.messageForConsole(response + "\n");
return;
}
if (TinyGUtils.isRestartingResponse(jo)) {
this.messageForConsole("[restarting] " + response + "\n");
this.isReady = false;
}
else if (TinyGUtils.isReadyResponse(jo)) {
//this.messageForConsole("Got version: " + TinyGUtils.getVersion(jo) + "\n");
this.messageForConsole("[ready] " + response + "\n");
this.isReady = true;
}
else if (TinyGUtils.isStatusResponse(jo)) {
TinyGUtils.StatusResult result = TinyGUtils.updateStatus(jo);
state = result.state;
machineLocation.set(result.machine);
workLocation.set(result.work);
ControllerStatus cs = new ControllerStatus(state, machineLocation, workLocation);
dispatchStatusString(cs);
}
else if (TinyGGcodeCommand.isOkErrorResponse(response)) {
try {
this.commandComplete(response);
} catch (Exception e) {
this.errorMessageForConsole(Localization.getString("controller.error.response")
+ " <" + response + ">: " + e.getMessage());
}
this.messageForConsole(response + "\n");
}
else {
// Display any unhandled messages
this.messageForConsole("[unhandled message] " + response + "\n");
}
}
@Override
public void performHomingCycle() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void resetCoordinatesToZero() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void returnToHome() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void killAlarmLock() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void toggleCheckMode() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void viewParserState() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void softReset() throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void isReadyToStreamCommandsEvent() throws Exception {
//throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void isReadyToSendCommandsEvent() throws Exception {
//throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void statusUpdatesEnabledValueChanged(boolean enabled) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
protected void statusUpdatesRateValueChanged(int rate) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
@Override
public void sendOverrideCommand(Overrides command) throws Exception {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
static class TinyGUtils {
private static JsonParser parser = new JsonParser();
private static JsonObject jsonToObject(String response) {
return parser.parse(response).getAsJsonObject();
}
private static boolean isTinyGVersion(JsonObject response) {
if (response.has("r")) {
JsonObject jo = response.getAsJsonObject("r");
if (jo.has("fv")) {
return true;
}
}
return false;
}
private static String getVersion(JsonObject response) {
if (response.has("r")) {
JsonObject jo = response.getAsJsonObject("r");
if (jo.has("fv")) {
return jo.get("fv").getAsString();
}
}
return "";
}
private static boolean isRestartingResponse(JsonObject response) {
if (response.has("r")) {
JsonObject jo = response.getAsJsonObject("r");
if (jo.has("msg")) {
String msg = jo.get("msg").getAsString();
return msg.equals("Loading configs from EEPROM");
}
}
return false;
}
private static boolean isReadyResponse(JsonObject response) {
if (response.has("r")) {
JsonObject jo = response.getAsJsonObject("r");
if (jo.has("msg")) {
String msg = jo.get("msg").getAsString();
return msg.equals("SYSTEM READY");
}
}
return false;
}
private static boolean isStatusResponse(JsonObject response) {
return response.has("sr");
}
private static class StatusResult {
private Point3d machine = new Point3d();
private Point3d work = new Point3d();
private String state;
}
private static StatusResult updateStatus(JsonObject response) {
StatusResult result = new StatusResult();
if (response.has("sr")) {
JsonObject jo = response.getAsJsonObject("sr");
if (jo.has("posx")) {
result.machine.x = jo.get("posx").getAsDouble();
}
if (jo.has("posy")) {
result.machine.y = jo.get("posy").getAsDouble();
}
if (jo.has("posz")) {
result.machine.z = jo.get("posz").getAsDouble();
}
if (jo.has("stat")) {
result.state = getStateAsString(jo.get("stat").getAsInt());
}
result.work.set(result.machine);
}
return result;
}
private static String getStateAsString(int state) {
switch (state) {
case 0:
return "initializing";
case 1:
return "ready";
case 2:
return "shutdown";
case 3:
return "stop";
case 4:
return "end";
case 5:
return "run";
case 6:
return "hold";
case 9:
return "homing";
default:
return "unknown("+state+")";
}
}
}
}