/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package tgfx.ui.gcode;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Date;
import java.util.ResourceBundle;
import java.util.logging.Level;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.util.Duration;
import jfxtras.labs.scene.control.gauge.Lcd;
import org.apache.log4j.Logger;
import tgfx.Main;
import tgfx.render.CNCMachine;
import tgfx.render.Draw2d;
import tgfx.tinyg.CommandManager;
import tgfx.tinyg.TinygDriver;
import tgfx.ui.tgfxsettings.TgfxSettingsController;
/**
* FXML Controller class
*
* @author rileyporter
*/
public class GcodeTabController implements Initializable {
private byte[] BAD_BYTES = {(byte) 0x21, (byte) 0x18, (byte) 0x7e};
private double scaleAmount;
private int buildNumber;
private String buildDate;
private boolean taskActive = false;
static final Logger logger = Logger.getLogger(GcodeTabController.class);
public ObservableList data; //List to store the gcode file
public static StackPane gcodePane = new StackPane(); //Holds CNCMachine This needs to be before CNCMachine()
private static CNCMachine cncMachine = new CNCMachine();
private final EventHandler keyPress;
private final EventHandler keyRelease;
private String _axis = new String();
public static SimpleBooleanProperty isSendingFile = new SimpleBooleanProperty(false); //This tracks to see if we are sending a file to tinyg. This allows us to NOT try to jog while sending files
private boolean isKeyPressed = false;
private double jogDial = 0;
private double FEED_RATE_PERCENTAGE = .05; //%5
private double TRAVERSE_FEED_RATE = 1; //%100
private double NUDGE_FEED_RATE = .05; //%5
private static int totalGcodeLines = 0;
private static Date timeStartDt;
/* ######################## FXML ELEMENTS ############################*/
@FXML
private static Text timeElapsedTxt;
@FXML
private static Text timeLeftTxt;
@FXML
private Lcd xLcd, yLcd, zLcd, aLcd, velLcd; //DRO Lcds
@FXML
StackPane machineWorkspace;
@FXML
private Pane previewPane;
@FXML
private TableColumn<GcodeLine, String> gcodeCol;
@FXML
private static TableView gcodeView;
@FXML
private Text xAxisLocation, yAxisLocation;
@FXML
private static Text gcodeStatusMessage; //Cursor location on the cncMachine Canvas
@FXML
private static TextArea console;
@FXML
private Button Run, Connect, gcodeZero, btnClearScreen, pauseResume, btnTest, btnHandleInhibitAllAxis;
@FXML
private GridPane coordLocationGridPane;
private float zScale = 0.1f;
String cmd;
@FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
@FXML // fx:id="zMoveScale"
private ChoiceBox<?> zMoveScale; // Value injected by FXMLLoader
@FXML
private HBox gcodeTabControllerHBox;
/**
* Initializes the controller class.
*/
public GcodeTabController() {
logger.setLevel(org.apache.log4j.Level.ERROR);
logger.info("Gcode Controller Loaded");
cncMachine.setOnMouseMoved(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent me) {
yAxisLocation.setText(cncMachine.getNormalizedYasString(me.getY()));
xAxisLocation.setText(cncMachine.getNormalizedXasString(me.getX()));
}
});
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
//JOGGING NEEDS TO BE BROKEN INTO A NEW CLASS
keyPress = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent keyEvent) {
if (isSendingFile.get() == false) { //If we are sending a file.. Do NOT jog right now
// Main.postConsoleMessage("KEY PRESSED: " + keyEvent.getCode().toString());
//Do the jogging.
_axis = " "; // Initialize to no valid axis set
if (!isKeyPressed) { //If this event has already sent a jog in need to pass this over.
KeyCode _kc = keyEvent.getCode();
if (_kc.equals(KeyCode.SHIFT)) {
return; //This is going to toss out our initial SHIFT press for the z axis key combination.
}
if (keyEvent.isShiftDown()) {
//Alt is down so we make this into a Z movement
FEED_RATE_PERCENTAGE = TRAVERSE_FEED_RATE;
} else {
FEED_RATE_PERCENTAGE = NUDGE_FEED_RATE;
}
//Y Axis Jogging Movement
if (_kc.equals(KeyCode.UP) || _kc.equals(KeyCode.DOWN)) {
//This is and Y Axis Jog action
_axis = "Y"; //Set the axis for this jog movment
if (keyEvent.getCode().equals(KeyCode.UP)) {
jogDial = TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis);
} else if (keyEvent.getCode().equals(KeyCode.DOWN)) {
jogDial = (-1 * TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis)); //Invert this value by multiplying by -1
}
//X Axis Jogging Movement
} else if (_kc.equals(KeyCode.RIGHT) || _kc.equals(KeyCode.LEFT)) {
//This is a X Axis Jog Action
_axis = "X"; //Set the axis for this jog movment
if (keyEvent.getCode().equals(KeyCode.LEFT)) {
jogDial = (-1 * TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis));
} else if (keyEvent.getCode().equals(KeyCode.RIGHT)) {
jogDial = TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis); //Invert this value by multiplying by -1
}
//Z Axis Jogging Movement
} else if (_kc.equals(KeyCode.MINUS) || (_kc.equals(KeyCode.EQUALS))) {
_axis = "Z";
if (keyEvent.getCode().equals(KeyCode.MINUS)) {
jogDial = (-1 * TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis));
} else if (keyEvent.getCode().equals(KeyCode.EQUALS)) {
jogDial = TinygDriver.getInstance().machine.getJoggingIncrementByAxis(_axis); //Invert this value by multiplying by -1
}
}
try {
if (_axis.equals("X") || _axis.equals("Y") || _axis.equals("Z")) {
// valid key pressed
CommandManager.setIncrementalMovementMode();
TinygDriver.getInstance().write("{\"GC\":\"G1F" + (TinygDriver.getInstance().machine.getAxisByName(_axis).getFeed_rate_maximum() * FEED_RATE_PERCENTAGE) + _axis + jogDial + "\"}\n");
// TinygDriver.getInstance().write("{\"GC\":\"G0" + _axis + jogDial + "\"}\n");
isKeyPressed = true;
}
} catch (Exception ex) {
java.util.logging.Logger.getLogger(CNCMachine.class.getName()).log(Level.SEVERE, null, ex);
}
}
} //end if isSendingFile
else {
//We are sending a file... We need to post a messages
setGcodeTextTemp("Jogging Disabled... Sending File.");
}
}
};
keyRelease = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent keyEvent) {
// Main.postConsoleMessage("Stopping Jog Action: " + keyEvent.getCode().toString());
if (isSendingFile.get() == false) {
try {
setGcodeText("");
if (isKeyPressed) { //We should find out of TinyG's distance mode is set to G90 before just firing this off.
CommandManager.stopJogMovement();
if (TinygDriver.getInstance().machine.getGcode_distance_mode().equals(TinygDriver.getInstance().machine.gcode_distance_mode.INCREMENTAL)) {
//We are in incremental mode we now will enter ABSOLUTE mode
CommandManager.setAbsoluteMovementMode();
} //re-enable absolute mode
isKeyPressed = false; //reset the press flag
}
} catch (Exception ex) {
java.util.logging.Logger.getLogger(CNCMachine.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
cncMachine.setOnKeyPressed(keyPress);
cncMachine.setOnKeyReleased(keyRelease);
}
public static void setGcodeTextTemp(String _text) {
gcodeStatusMessage.setText(_text);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000), gcodeStatusMessage);
fadeTransition.setFromValue(1.0);
fadeTransition.setToValue(0.0);
fadeTransition.play();
// gcodeStatusMessage.setText(""); //clear it out
}
public static void setGcodeText(String _text) {
gcodeStatusMessage.setText(_text);
gcodeStatusMessage.setVisible(true);
// FadeTransition fadeTransition = new FadeTransition(Duration.millis(1000), gcodeStatusMessage);
// fadeTransition.setFromValue(0.0);
// fadeTransition.setToValue(1.0);
// fadeTransition.play();
}
public static void hideGcodeText() {
// gcodeStatusMessage.setVisible(false);
// FadeTransition fadeTransition = new FadeTransition(Duration.millis(500), gcodeStatusMessage);
// fadeTransition.setFromValue(1.0);
// fadeTransition.setToValue(0.0);
// fadeTransition.play();
}
public static void drawCanvasUpdate() {
if (TgfxSettingsController.isDrawPreview()) {
cncMachine.drawLine(TinygDriver.getInstance().machine.getMotionMode().get(), TinygDriver.getInstance().machine.getVelocity());
}
}
private void drawTable() {
//TODO We need to make this a message to subscribe to.
if (!gcodePane.getChildren().contains(cncMachine)) {
gcodePane.getChildren().add(cncMachine); // Add the cnc machine to the gcode pane
}
}
@FXML
private void handleHomeXYZ(ActionEvent evt) {
if (TinygDriver.getInstance().isConnected().get()) {
try {
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_SYSTEM_HOME_XYZ_AXES);
} catch (Exception ex) {
logger.error("Erroring HomingXYZ Command");
}
}
}
@FXML
private void handleHomeAxisClick(ActionEvent evt) {
MenuItem m = (MenuItem) evt.getSource();
String _axis = String.valueOf(m.getId().charAt(0));
if (TinygDriver.getInstance().isConnected().get()) {
try {
switch (_axis) {
case "x":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_HOME_X_AXIS);
break;
case "y":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_HOME_Y_AXIS);
break;
case "z":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_HOME_Z_AXIS);
break;
case "a":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_HOME_A_AXIS);
break;
}
} catch (Exception ex) {
logger.error("Exception in handleHomeAxisClick for Axis: " + _axis + " " + ex.getMessage());
}
}
tgfx.Main.postConsoleMessage("[+]Homing " + _axis.toUpperCase() + " Axis...\n");
}
@FXML
private void handleZeroAxisClick(ActionEvent evt) {
MenuItem m = (MenuItem) evt.getSource();
String _axis = String.valueOf(m.getId().charAt(0));
if (TinygDriver.getInstance().isConnected().get()) {
Draw2d.setFirstDraw(true); //We set this so we do not draw lines for the previous position to the new zero.
try {
switch (_axis) {
case "x":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_ZERO_X_AXIS);
break;
case "y":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_ZERO_Y_AXIS);
break;
case "z":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_ZERO_Z_AXIS);
break;
case "a":
TinygDriver.getInstance().write(CommandManager.CMD_APPLY_ZERO_A_AXIS);
break;
}
} catch (Exception ex) {
logger.error("Exception in handleZeroAxisClick for Axis: " + _axis + " " + ex.getMessage());
}
}
tgfx.Main.postConsoleMessage("[+]Zeroed " + _axis.toUpperCase() + " Axis...\n");
}
@FXML
private void handleDroMouseClick(MouseEvent me) {
if (me.isSecondaryButtonDown()) { //Check to see if its a Right Click
String t;
String _axis;
Lcd l;
l = (Lcd) me.getSource();
t = String.valueOf(l.idProperty().get().charAt(0));
}
}
public static void setCNCMachineVisible(boolean t) {
cncMachine.setVisible(t);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
/* add support for zmove
*
*/
// assert zMoveScale != null : "fx:id=\"zMoveScale\" was not injected: check your FXML file 'Position.fxml'.";
//
// // Set up ChoiceBox selection handler
// zMoveScale.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
// @Override
// public void changed(ObservableValue<? extends Number> observableValue, Number number, Number result) {
// switch ((int) result) {
// case 0:
// zScale = 10.0f;
// break;
// case 1:
// zScale = 1.0f;
// break;
// case 2:
// zScale = 0.1f;
// break;
// }
// }
// });
timeStartDt = new Date();
setCNCMachineVisible(false); //We default to NOT display the CNC machine pane. Once the serial port is connected we will show this.
//This adds our CNC Machine (2d preview) to our display window
if (!gcodePane.getChildren().contains(cncMachine)) {
gcodePane.getChildren().add(cncMachine); // Add the cnc machine to the gcode pane
}
coordLocationGridPane.visibleProperty().bind(cncMachine.visibleProperty()); //This shows the coords when the cncMachine is visible.
xLcd.valueProperty().bind(TinygDriver.getInstance().machine.getAxisByName("x").getMachinePositionSimple().subtract(TinygDriver.getInstance().machine.getAxisByName("x").getOffset()).divide(TinygDriver.getInstance().machine.gcodeUnitDivision));
yLcd.valueProperty().bind(TinygDriver.getInstance().machine.getAxisByName("y").getMachinePositionSimple().subtract(TinygDriver.getInstance().machine.getAxisByName("y").getOffset()).divide(TinygDriver.getInstance().machine.gcodeUnitDivision));
zLcd.valueProperty().bind(TinygDriver.getInstance().machine.getAxisByName("z").getMachinePositionSimple().subtract(TinygDriver.getInstance().machine.getAxisByName("z").getOffset()).divide(TinygDriver.getInstance().machine.gcodeUnitDivision));
aLcd.valueProperty().bind(TinygDriver.getInstance().machine.getAxisByName("a").getMachinePositionSimple().subtract(TinygDriver.getInstance().machine.getAxisByName("a").getOffset()));
velLcd.valueProperty().bind(TinygDriver.getInstance().machine.velocity);
/*######################################
* BINDINGS CODE
######################################*/
gcodeTabControllerHBox.disableProperty().bind(TinygDriver.getInstance().connectionStatus.not());
/*######################################
* CHANGE LISTENERS
######################################*/
xLcd.valueProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue) {
double tmp = TinygDriver.getInstance().machine.getAxisByName("y").getWorkPosition().doubleValue() + 5;
}
});
yLcd.valueProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue) {
double tmp = TinygDriver.getInstance().machine.getAxisByName("y").getWorkPosition().doubleValue() + 5;
}
});
TinygDriver.getInstance().machine.getGcodeUnitMode().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue) {
String tmp = TinygDriver.getInstance().machine.getGcodeUnitMode().get();
// gcodeUnitMode.getSelectionModel().select(TinygDriver.getInstance().m.getGcodeUnitModeAsInt());
if (TinygDriver.getInstance().machine.getGcodeUnitModeAsInt() == 0) {
//A bug in the jfxtras does not allow for units to be updated.. we hide them if they are not mm
xLcd.lcdUnitVisibleProperty().setValue(false);
yLcd.lcdUnitVisibleProperty().setValue(false);
zLcd.lcdUnitVisibleProperty().setValue(false);
aLcd.lcdUnitVisibleProperty().setValue(false);
velLcd.lcdUnitVisibleProperty().setValue(false);
} else {
xLcd.lcdUnitVisibleProperty().setValue(true);
yLcd.lcdUnitVisibleProperty().setValue(true);
zLcd.lcdUnitVisibleProperty().setValue(true);
aLcd.lcdUnitVisibleProperty().setValue(true);
velLcd.lcdUnitVisibleProperty().setValue(true);
}
tgfx.Main.postConsoleMessage("[+]Gcode Unit Mode Changed to: " + tmp + "\n");
try {
TinygDriver.getInstance().serialWriter.setThrottled(true);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_MOTOR_1_SETTINGS);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_MOTOR_2_SETTINGS);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_MOTOR_3_SETTINGS);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_MOTOR_4_SETTINGS);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_X);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_Y);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_Z);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_A);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_B);
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_QUERY_AXIS_C);
Thread.sleep(400);
TinygDriver.getInstance().serialWriter.setThrottled(false);
} catch (Exception ex) {
logger.error("Error querying tg model state on gcode unit change. Main.java binding section.");
}
}
});
cncMachine.heightProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue o, Object oldVal,
Object newVal) {
logger.info("cncHeightChanged: " + cncMachine.getHeight());
// Main.print(cncHeightString
}
});
cncMachine.maxWidthProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue) {
handleMaxWithChange();
}
});
cncMachine.maxHeightProperty()
.addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue) {
handleMaxHeightChange();
}
});
/*######################################
* GCODE FILE CODE
######################################*/
data = FXCollections.observableArrayList();
gcodeCol.setCellValueFactory(
new PropertyValueFactory<GcodeLine, String>("codeLine"));
GcodeLine n = new GcodeLine("Click open to load..", 0);
gcodeView.getItems()
.setAll(data);
data.add(n);
gcodeView.setItems(data);
gcodeView.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent me) {
if (me.getButton().equals(me.getButton().PRIMARY)) {
if (me.getClickCount() == 2) {
GcodeLine gcl = (GcodeLine) gcodeView.getSelectionModel().getSelectedItem();
if (TinygDriver.getInstance().isConnected().get()) {
logger.info("Double Clicked gcodeView " + gcl.getCodeLine());
try {
TinygDriver.getInstance().write(gcl.getGcodeLineJsonified());
tgfx.Main.postConsoleMessage(gcl.getGcodeLineJsonified());
} catch (Exception ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
} else {
logger.info("TinyG Not Connected not sending: " + gcl.getGcodeLineJsonified());
tgfx.Main.postConsoleMessage("TinyG Not Connected not sending: " + gcl.getGcodeLineJsonified());
}
}
}
}
});
}
private Lcd getLcdByAxisName(String _axis) {
switch (_axis) {
case ("x"):
return (xLcd);
case ("y"):
return (yLcd);
case ("z"):
return (zLcd);
case ("a"):
return (aLcd);
case ("vel"):
return (velLcd);
}
return (null);
}
@FXML
private void handleZeroSystem(ActionEvent evt) {
cncMachine.zeroSystem();
}
@FXML
private void handlePauseResumeAct(ActionEvent evt) throws Exception {
if ("Pause".equals(pauseResume.getText())) {
pauseResume.setText("Resume");
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_APPLY_PAUSE);
} else {
pauseResume.setText("Pause");
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_APPLY_RESUME);
}
}
@FXML
private void handleClearScreen(ActionEvent evt) {
tgfx.Main.postConsoleMessage("[+]Clearing Screen...\n");
cncMachine.clearScreen();
Draw2d.setFirstDraw(true); //clear this so our first line added draws correctly
}
@FXML
private void handleReset(ActionEvent evt) throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
TinygDriver.getInstance().serialWriter.clearQueueBuffer();
TinygDriver.getInstance().priorityWrite(CommandManager.CMD_APPLY_RESET); //This sends the 0x18 byte
//We disable everything while waiting for theboard to reset
// topAnchorPane.setDisable(true);
// topTabPane.setDisable(true);
// Thread.sleep(8000);
// onConnectActions();
tgfx.Main.postConsoleMessage("[!]Resetting TinyG....\n.");
TinygDriver.getInstance().serialWriter.notifyAck();
TinygDriver.getInstance().serialWriter.clearQueueBuffer();
cncMachine.clearScreen();
isSendingFile.set(false); //We set this to false to allow us to jog again
} catch (Exception ex) {
logger.error("handleReset " + ex.getMessage());
}
}
});
}
@FXML
private void handleStop(ActionEvent evt) throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
logger.info("[!]Stopping Job Clearing Serial Queue...\n");
CommandManager.stopTinyGMovement();
isSendingFile.set(false); //We set this to false to allow us to jog again
} catch (Exception ex) {
logger.error("handleStop " + ex.getMessage());
}
}
});
}
static int test = 1;
@FXML
static void handleTestButton(ActionEvent evt) throws Exception {
//logger.info("Test Button....");
updateProgress(test);
test += 5;
//tgfx.Main.postConsoleMessage("Test!");
//timeElapsedTxt.setText("hello");
// Iterator ii = null;
// Line l;
// cncMachine.getChildren().iterator();
// while(ii.hasNext()){
// l = (Line) ii.next();
//
// }
}
public Task fileSenderTask() {
return new Task() {
@Override
protected Object call() throws Exception {
StringBuilder line = new StringBuilder();
int gcodeCharLength = data.size();
String tmp;
for (int i = 0; i < gcodeCharLength; i++) {
GcodeLine _gcl = (GcodeLine) data.get(i);
if (isTaskActive() == false) {
//Cancel Button was pushed
tgfx.Main.postConsoleMessage("[!]File Sending Task Killed....\n");
break;
} else {
if (_gcl.getCodeLine().equals("")) {
//Blank Line.. Passing..
continue;
}
if (_gcl.getCodeLine().toLowerCase().contains("(")) {
TinygDriver.getInstance().write("**COMMENT**" + _gcl.getCodeLine());
// tgfx.Main.postConsoleMessage("GCODE COMMENT:" + _gcl.getCodeLine());
continue;
}
line.setLength(0);
line.append("{\"gc\":\"").append(_gcl.getCodeLine()).append("\"}\n");
TinygDriver.getInstance().write(line.toString());
}
}
TinygDriver.getInstance().write("**FILEDONE**");
return true;
}
};
}
public static void setIsFileSending(boolean flag) {
isSendingFile.set(flag);
}
@FXML
private void handleRunFile(ActionEvent evt) {
if (!isSendingFile.get()) {
isSendingFile.set(true); //disables jogging while file is running
taskActive = true; //Set the thread condition to start
Task fileSend = fileSenderTask();
Thread fsThread = new Thread(fileSend);
fsThread.setName("FileSender");
timeStartDt = new Date();
// updateProgress(1);
fsThread.start();
}
}
public synchronized boolean isTaskActive() {
return taskActive;
}
public synchronized void setTaskActive(boolean boolTask) {
taskActive = boolTask;
}
@FXML
private void handleOpenFile(ActionEvent event) {
Platform.runLater(new Runnable() {
@Override
public void run() {
// logger.debug("handleOpenFile");
try {
tgfx.Main.postConsoleMessage("[+]Loading a gcode file.....\n");
FileChooser fc = new FileChooser();
fc.setTitle("Open GCode File");
String HOME_DIR = System.getenv("HOME"); //Get Home DIR in OSX
if (HOME_DIR == null) {
HOME_DIR = System.getProperty("user.home"); //Get Home DIR in Windows
}
fc.setInitialDirectory(new File(HOME_DIR)); //This will find osx users home dir
File f = fc.showOpenDialog(null);
FileInputStream fstream = new FileInputStream(f);
DataInputStream in = new DataInputStream((fstream));
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
data.removeAll(data);
//Clear the list if there was a previous file loaded
int _linenumber = 0;
while ((strLine = br.readLine()) != null) {
if (!strLine.equals("")) {
//Do not add empty lines to the list
//gcodesList.appendText(strLine + "\n");
if (!strLine.toUpperCase().startsWith("N")) {
strLine = "N" + String.valueOf(_linenumber) + " " + strLine;
}
if (normalizeGcodeLine(strLine)) {
data.add(new GcodeLine(strLine, _linenumber));
_linenumber++;
} else {
Main.postConsoleMessage("ERROR: Your gcode file contains an invalid character.. Either !,% or ~. Remove this character and try again.");
Main.postConsoleMessage(" Line " + _linenumber);
data.clear(); //Remove all other previous entered lines
break;
}
}
}
totalGcodeLines = _linenumber;
// logger.info("File Loading Complete");
} catch (FileNotFoundException ex) {
logger.error("File Not Found.");
} catch (Exception ex) {
logger.error(ex.getMessage());
}
}
});
}
private boolean normalizeGcodeLine(String gcl) {
byte[] tmpLine = gcl.getBytes();
//0x21 = !
//0x18 = Ctrl-X
//0x7e = ~
//0x25 = %
//These are considered bad bytes in gcode files. These will trigger tinyg to throw interrupts
for (int i = 0; i < tmpLine.length; i++) {
}
for (int i = 0; i < BAD_BYTES.length; i++) {
for (int j = 0; j < gcl.length(); j++) {
if (gcl.charAt(j) == BAD_BYTES[i]) {
//Bad Byte Found
logger.error("Bad Byte Char Detected: " + BAD_BYTES[i]);
return false;
}
}
}
return true;
}
/*######################################
* EVENT LISTENERS CODE
######################################*/
public void handleMaxHeightChange() {
if (gcodePane.getWidth() - TinygDriver.getInstance().machine.getAxisByName("x").getTravelMaxSimple().get() < gcodePane.getHeight() - TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get()) {
//X is longer use this code
if (TinygDriver.getInstance().machine.getGcodeUnitModeAsInt() == 0) { //INCHES
scaleAmount = ((gcodePane.heightProperty().get() / (TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get() * 25.4))) * .80; //%80 of the scale;
} else { //MM
scaleAmount = ((gcodePane.heightProperty().get() / TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get())) * .80; //%80 of the scale;
}
} else {
//Y is longer use this code
if (TinygDriver.getInstance().machine.getGcodeUnitModeAsInt() == 0) { //INCHES
scaleAmount = ((gcodePane.heightProperty().get() / (TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get() * 25.4))) * .80; //%80 of the scale;
} else { //MM
scaleAmount = ((gcodePane.heightProperty().get() / TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get())) * .80; //%80 of the scale;
}
// scaleAmount = ((gcodePane.heightProperty().get() / TinygDriver.getInstance().m.getAxisByName("y").getTravelMaxSimple().get())) * .80; //%80 of the scale;
}
cncMachine.autoScaleWorkTravelSpace(scaleAmount);
// widthSize.textProperty().bind( Bindings.format("%s", cncMachine.widthProperty().divide(TinygDriver.getInstance().m.gcodeUnitDivision).asString().concat(TinygDriver.getInstance().m.getGcodeUnitMode()) )); //.asString().concat(TinygDriver.getInstance().m.getGcodeUnitMode().get()));
// heightSize.setText(decimalFormat.format(TinygDriver.getInstance().m.getAxisByName("y").getTravel_maximum()) + " " + TinygDriver.getInstance().m.getGcodeUnitMode().getValue());
}
public void handleMaxWithChange() {
//This is for the change listener to call for Max Width Change on the CNC Machine
if (gcodePane.getWidth() - TinygDriver.getInstance().machine.getAxisByName("x").getTravelMaxSimple().get() < gcodePane.getHeight() - TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get()) {
//X is longer use this code
if (TinygDriver.getInstance().machine.getGcodeUnitModeAsInt() == 0) { //INCHES
scaleAmount = ((gcodePane.heightProperty().get() / (TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get() * 25.4))) * .80; //%80 of the scale;
} else { //MM
scaleAmount = ((gcodePane.heightProperty().get() / TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get())) * .80; //%80 of the scale;
}
} else {
//Y is longer use this code
if (TinygDriver.getInstance().machine.getGcodeUnitModeAsInt() == 0) { //INCHES
scaleAmount = ((gcodePane.heightProperty().get() / (TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get() * 25.4))) * .80; //%80 of the scale;
} else { //MM
scaleAmount = ((gcodePane.heightProperty().get() / TinygDriver.getInstance().machine.getAxisByName("y").getTravelMaxSimple().get())) * .80; //%80 of the scale;
}
}
cncMachine.autoScaleWorkTravelSpace(scaleAmount);
// widthSize.setText(decimalFormat.format(TinygDriver.getInstance().m.getAxisByName("x").getTravel_maximum()) + " " + TinygDriver.getInstance().m.getGcodeUnitMode().getValue());
}
// Scroll Gcode table view to specified line, show elapsed and remaining time
public static void updateProgress(int lineNum) {
if (isSendingFile.get() && lineNum > 0) {
// gcodeView.scrollTo(lineNum);
// Show elapsed and remaining time
Date currentTimeDt = new Date(); // Get current time
long elapsed = (currentTimeDt.getTime() - timeStartDt.getTime());
float rate = elapsed / lineNum;
long remain = (long) ((totalGcodeLines - lineNum) * rate); // remaining lines * secs per line
timeElapsedTxt.setText(String.format("%02d:%02d", elapsed / 60000, (elapsed / 1000) % 60));
timeLeftTxt.setText(String.format("%02d:%02d", remain / 60000, (remain / 1000) % 60));
}
}
}