public static void main(String[] args) { if (args.length != 1) { System.out.println("usage java TestSer port"); System.exit(-1); } TestSer ts = new TestSer(args[0]); byte[] buf = new byte[256]; ts.start(); start = System.currentTimeMillis(); new Thread() { public void run() { for (; ; ) { try { Thread.sleep(1000); } catch (Exception e) { } long i = cntRcv; long t = System.currentTimeMillis() - start; if (t != 0) { System.out.print( (cntSend / 1024) + " KB sent " + (i / 1024) + " KB received " + (cntSend / 1024 * 1000 / t) + " KB/s " + (i / 1024 * 1000 / t) + " KB/s \r"); } } } }.start(); for (; ; ) { try { os.write(buf); } catch (Exception e) { System.out.println(e); } cntSend += buf.length; } }
Server() throws IOException { if (useSerial) { ServerThread.initSerial(); ServerThread.writeSerial(true); try { Thread.sleep(200); } catch (InterruptedException e1) { } ServerThread.writeSerial(true); try { Thread.sleep(200); } catch (InterruptedException e1) { } ServerThread.writeSerial(true); } int port = 10055; ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(port); System.out.println("Soccer robots server active on port " + port + "."); } catch (IOException e) { System.err.println("Could not listen on port: " + port + "."); System.exit(-1); } while (true) { ServerThread tmp = new ServerThread(serverSocket.accept()); threads.add(tmp); } }
public boolean avrdude(Collection params) throws RunnerException { List commandDownloader = new ArrayList(); commandDownloader.add("avrdude"); // Point avrdude at its config file since it's in a non-standard location. if (Base.isMacOS()) { commandDownloader.add("-C" + "hardware/tools/avr/etc/avrdude.conf"); } else if (Base.isWindows()) { String userdir = System.getProperty("user.dir") + File.separator; commandDownloader.add("-C" + userdir + "hardware/tools/avr/etc/avrdude.conf"); } else { // ???: is it better to have Linux users install avrdude themselves, in // a way that it can find its own configuration file? commandDownloader.add("-C" + "hardware/tools/avrdude.conf"); } if (Preferences.getBoolean("upload.verbose")) { commandDownloader.add("-v"); commandDownloader.add("-v"); commandDownloader.add("-v"); commandDownloader.add("-v"); } else { commandDownloader.add("-q"); commandDownloader.add("-q"); } // XXX: quick hack to chop the "atmega" off of "atmega8" and "atmega168", // then shove an "m" at the beginning. won't work for attiny's, etc. commandDownloader.add( "-pm" + Preferences.get("boards." + Preferences.get("board") + ".build.mcu").substring(6)); commandDownloader.addAll(params); return executeUploadCommand(commandDownloader); }
public TestSer(String port) { try { portId = CommPortIdentifier.getPortIdentifier(port); serialPort = (SerialPort) portId.open("TestSer", 2000); is = serialPort.getInputStream(); os = serialPort.getOutputStream(); /* serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); */ serialPort.setSerialPortParams( 115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); serialPort.setFlowControlMode( SerialPort.FLOWCONTROL_RTSCTS_OUT | SerialPort.FLOWCONTROL_RTSCTS_IN); serialPort.enableReceiveTimeout(TIMEOUT); // serialPort.enableReceiveThreshold(4); } catch (Exception e) { System.out.println(e.getMessage()); System.exit(-1); } }
public static Serial open(String defaultPort) { boolean portFound = false; final int mComPortIdentifier = CommPortIdentifier.PORT_SERIAL; final Enumeration portList = CommPortIdentifier.getPortIdentifiers(); final int BAUD = 115200; while (portList.hasMoreElements()) { final CommPortIdentifier portId = (CommPortIdentifier) portList.nextElement(); System.out.println("Found port id: " + portId); if (portId.getPortType() == mComPortIdentifier) { System.out.println("Found CommPortIdentifier."); if (portId.getName().equals(defaultPort)) { System.out.println("Found port " + defaultPort); SerialPort serialPort; OutputStream outputStream = null; try { serialPort = (SerialPort) portId.open("SimpleWrite", 2000); } catch (PortInUseException e) { System.out.println("Port in use."); continue; } try { outputStream = serialPort.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } try { serialPort.setSerialPortParams( BAUD, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); } try { serialPort.notifyOnOutputEmpty(true); } catch (Exception e) { System.out.println("Error setting event notification"); System.out.println(e.toString()); System.exit(-1); } return new Serial(serialPort, outputStream); } } } if (!portFound) { System.out.println("port " + defaultPort + " not found."); } return null; }
private void sendData(byte[] data) throws SerialConnectionException { try { int size = data.length; int sent = 0; _sent = 0; long starttime = System.currentTimeMillis(); while (sent < size) { int tosend; if (!_keepRunning) return; if ((sent + _chunkSize) > size) { tosend = size - sent; } else { tosend = _chunkSize; } _os.write(data, sent, tosend); sent += tosend; _sent = sent; // update GUI _results.updateBytesSent(sent); } } catch (IOException e) { throw new SerialConnectionException("Error writing to i/o streams"); } }
class ServerThread extends Thread implements constants { static Team[] teams = new Team[2]; DataInputStream in; ServerThread(Socket socket) { try { in = new DataInputStream(socket.getInputStream()); } catch (IOException e) { e.printStackTrace(); } teams[0] = new KairusTeam(0); teams[1] = new EmptyTeam(1); this.start(); new gameRunner(new Team[] {teams[0], teams[1]}).start(); } long lastTime = System.currentTimeMillis(); double[][][] robotVelocitys = new double[2][5][3]; double[][][] robotPositions = new double[2][5][3]; double[] ballPosition = new double[2]; double[] ballVelocity = new double[2]; public double toBigEndian(double d) { ByteBuffer bb = ByteBuffer.wrap(new byte[8]); bb.putDouble(d); bb.order(ByteOrder.LITTLE_ENDIAN); bb.position(0); return bb.getDouble(); } public double toRadians(double d) { return (d * Math.PI) / 180; } static DataOutputStream comOS = null; public static void initSerial() { Enumeration portList = CommPortIdentifier.getPortIdentifiers(); CommPortIdentifier portId = null; boolean portFound = false; while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (portId.getName().equals("COM3")) { portFound = true; } } } if (!portFound) { System.out.println("port COM3 not found."); return; } SerialPort port; try { port = (SerialPort) portId.open("COM3", 2000); port.setSerialPortParams( 115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); comOS = new DataOutputStream(port.getOutputStream()); } catch (PortInUseException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (UnsupportedCommOperationException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static int[] inputs = new int[10]; public static void writeSerial(boolean stop) { byte[] toSend = new byte[48]; toSend[0] = (byte) 0xff; toSend[1] = (byte) 0xff; toSend[2] = (byte) 0x01; int MAX_SPEED = 8196; // 8196 int accelerationJump = 30; if (!stop) { for (int i = 0; i < 5; i++) { // if (i == 0) // System.out.println("speed: "+teams[0].robot[i].GetSpeedInput()+" spin: // "+teams[0].robot[i].GetSpinInput()); inputs[i * 2] = (int) (teams[0].robot[i].GetSpeedInput() * MAX_SPEED * -1); inputs[i * 2 + 1] = (int) (teams[0].robot[i].GetSpinInput() * MAX_SPEED * -1); // if (i == 0) // System.out.println("new speed: "+inputs[i*2]+" spin: "+inputs[i*2+1]); } for (int i = 0; i < 10; i++) { if (inputs[i] > MAX_SPEED) inputs[i] = MAX_SPEED; if (inputs[i] < -MAX_SPEED) inputs[i] = -MAX_SPEED; toSend[2 * i + 0 + 3] = (byte) ((inputs[i]) & 0xff); toSend[2 * i + 1 + 3] = (byte) ((inputs[i] >> 8) & 0xff); } } /* for (int team = 0;team<1;team++) for (int i = 0;i<5;i++){ int linV = (int) (teams[team].robot[i].GetSpeedInput()*MAX_SPEED); int angV = (int) (teams[team].robot[i].GetSpinInput() *MAX_SPEED); toSend[team*20+ 4*i+0+3] = (byte)( (linV ) & 0xff); toSend[team*20+ 4*i+1+3] = (byte)( (linV>>8) & 0xff); toSend[team*20+ 4*i+2+3] = (byte)( (angV ) & 0xff); toSend[team*20+ 4*i+3+3] = (byte)( (angV>>8) & 0xff); } */ byte checksum = 0; for (int i = 0; i < 47; i++) { checksum += toSend[i]; } toSend[47] = (byte) -checksum; try { comOS.write(toSend); } catch (IOException e) { e.printStackTrace(); } } int upto = 0; float goalX1 = 0.001f; float wallX1 = 0.095f; float wallX2 = 2.111f; float goalX2 = 2.208f; float Xoffset = -wallX1; float Xmultiplier = (FIELD_WIDTH / 100) / (wallX2 - wallX1); public void run() { try { Thread.sleep(1000); // writeSerial(false); // Thread.sleep(1000); // writeSerial(true); // System.exit(0); while (true) { long delta = System.currentTimeMillis() - lastTime; lastTime = System.currentTimeMillis(); double multiplier = (delta == 0 ? (1000 / 1) : (1000 / delta)) / SCALE; for (int team = 0; team < 2; team++) for (int i = 0; i < 5; i++) { // System.out.print("[ "); for (int o = 0; o < 3; o++) { double read = in.readDouble(); // System.out.print(o+" Read: "+read); double newValue = toBigEndian(read); // System.out.print(" Converted: "+newValue); if (o == 0) { // Convert X newValue += Xoffset; newValue *= Xmultiplier; } if (o == 1) { // Flip Y newValue = (1.8 - newValue); } if (o == 2) { // Convert angle newValue = -1 * toRadians(newValue); } robotVelocitys[team][i][o] = (newValue - robotPositions[team][i][o]) * multiplier; robotPositions[team][i][o] = newValue; // System.out.print(" "+newValue+" ("+robotVelocitys[team][i][o]+") "); /* if (team == 0 && i == 0){ System.out.print(newValue+" "); if (o == 2) System.out.println(); }*/ // System.out.println(); } // System.out.print("] "); } // Get the ball for (int i = 0; i < 2; i++) { double newValue = toBigEndian(in.readDouble()); if (i == 0) { // Convert X newValue += Xoffset; newValue *= Xmultiplier; } if (i == 1) { // Flip Y newValue = 1.8 - newValue; } ballVelocity[i] = (newValue - ballPosition[i]) * multiplier; ballPosition[i] = newValue; } // Put unknown positions (enemies) at -10000 for (int i = 0; i < 2; i++) for (int o = 0; o < 5; o++) for (int p = 0; p < 2; p++) { if (robotPositions[i][o][p] < -1 || robotPositions[i][o][p] > 2.6) { System.out.println( i + " " + o + " " + p + " Out of bounds! " + robotPositions[i][o][p]); robotPositions[i][o][p] = -10000; } } // Set frame data! for (int i = 0; i < 2; i++) for (int o = 0; o < 5; o++) { teams[i].robot[o].body.setType(BodyType.STATIC); teams[i].robot[o].body.setTransform( new Vec2( (float) robotPositions[i][o][0] * 100, (float) robotPositions[i][o][1] * 100), (float) (robotPositions[i][o][2])); // System.out.println("Setting to "+(float)robotPositions[i][o][0]*100+" // "+(float)robotPositions[i][o][1]*100); teams[i].robot[o].body.setType(BodyType.DYNAMIC); teams[i].robot[o].body.setLinearVelocity( new Vec2( (float) robotVelocitys[i][o][0] * 100, (float) robotVelocitys[i][o][1] * 100)); teams[i].robot[o].body.setAngularVelocity((float) robotVelocitys[i][o][2]); } teams[1].ball.setType(BodyType.STATIC); teams[1].ball.setTransform( new Vec2((float) ballPosition[0] * 100, (float) ballPosition[1] * 100), 0); teams[1].ball.setType(BodyType.DYNAMIC); teams[1].ball.setLinearVelocity( new Vec2((float) ballVelocity[0] * 100, (float) ballVelocity[1] * 100)); teams[1].ball.setAngularVelocity(0); // Not sent, reset it! // Simulate a frame! for (int i = 0; i < 2; i++) teams[i].gameFrame(); // Send information to serial port! if (Server.useSerial) writeSerial(false); } } catch (IOException e) { Server.threads.remove(this); e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public void run() { try { Thread.sleep(1000); // writeSerial(false); // Thread.sleep(1000); // writeSerial(true); // System.exit(0); while (true) { long delta = System.currentTimeMillis() - lastTime; lastTime = System.currentTimeMillis(); double multiplier = (delta == 0 ? (1000 / 1) : (1000 / delta)) / SCALE; for (int team = 0; team < 2; team++) for (int i = 0; i < 5; i++) { // System.out.print("[ "); for (int o = 0; o < 3; o++) { double read = in.readDouble(); // System.out.print(o+" Read: "+read); double newValue = toBigEndian(read); // System.out.print(" Converted: "+newValue); if (o == 0) { // Convert X newValue += Xoffset; newValue *= Xmultiplier; } if (o == 1) { // Flip Y newValue = (1.8 - newValue); } if (o == 2) { // Convert angle newValue = -1 * toRadians(newValue); } robotVelocitys[team][i][o] = (newValue - robotPositions[team][i][o]) * multiplier; robotPositions[team][i][o] = newValue; // System.out.print(" "+newValue+" ("+robotVelocitys[team][i][o]+") "); /* if (team == 0 && i == 0){ System.out.print(newValue+" "); if (o == 2) System.out.println(); }*/ // System.out.println(); } // System.out.print("] "); } // Get the ball for (int i = 0; i < 2; i++) { double newValue = toBigEndian(in.readDouble()); if (i == 0) { // Convert X newValue += Xoffset; newValue *= Xmultiplier; } if (i == 1) { // Flip Y newValue = 1.8 - newValue; } ballVelocity[i] = (newValue - ballPosition[i]) * multiplier; ballPosition[i] = newValue; } // Put unknown positions (enemies) at -10000 for (int i = 0; i < 2; i++) for (int o = 0; o < 5; o++) for (int p = 0; p < 2; p++) { if (robotPositions[i][o][p] < -1 || robotPositions[i][o][p] > 2.6) { System.out.println( i + " " + o + " " + p + " Out of bounds! " + robotPositions[i][o][p]); robotPositions[i][o][p] = -10000; } } // Set frame data! for (int i = 0; i < 2; i++) for (int o = 0; o < 5; o++) { teams[i].robot[o].body.setType(BodyType.STATIC); teams[i].robot[o].body.setTransform( new Vec2( (float) robotPositions[i][o][0] * 100, (float) robotPositions[i][o][1] * 100), (float) (robotPositions[i][o][2])); // System.out.println("Setting to "+(float)robotPositions[i][o][0]*100+" // "+(float)robotPositions[i][o][1]*100); teams[i].robot[o].body.setType(BodyType.DYNAMIC); teams[i].robot[o].body.setLinearVelocity( new Vec2( (float) robotVelocitys[i][o][0] * 100, (float) robotVelocitys[i][o][1] * 100)); teams[i].robot[o].body.setAngularVelocity((float) robotVelocitys[i][o][2]); } teams[1].ball.setType(BodyType.STATIC); teams[1].ball.setTransform( new Vec2((float) ballPosition[0] * 100, (float) ballPosition[1] * 100), 0); teams[1].ball.setType(BodyType.DYNAMIC); teams[1].ball.setLinearVelocity( new Vec2((float) ballVelocity[0] * 100, (float) ballVelocity[1] * 100)); teams[1].ball.setAngularVelocity(0); // Not sent, reset it! // Simulate a frame! for (int i = 0; i < 2; i++) teams[i].gameFrame(); // Send information to serial port! if (Server.useSerial) writeSerial(false); } } catch (IOException e) { Server.threads.remove(this); e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
public synchronized void serialEvent(SerialPortEvent oEvent) { if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { int available = input.available(); if (count < BUF_SIZE) { count = count + input.read( buf, count, (available > BUF_SIZE - count) ? BUF_SIZE - count : available); } start = newline; for (int i = newline; i <= count; i++) { if (buf[i] == 'U' || buf[i] == '$') { // start byte start = i; break; } } for (int i = start; i <= count; i++) { if (buf[i] == '\n') { // end byte newline = i; break; } } if (newline <= start) { if (count == BUF_SIZE) { // buf full an no valid datagram found, clear the buffer // need to copy the stuff after the start byte to the beginning if ((count - start) <= 128) { System.arraycopy(buf, start, buf, 0, count - start); count = count - start; start = 0; newline = 0; } else { // buf full and last start byte is more than max packet size clear all of the // buffer count = 0; // no need to copy since the buf is grabage start = 0; newline = 0; } } return; } if (buf[start] == '$') { buf[newline] = '\0'; System.out.println(new String(buf, start + 1, newline - start)); } // found valid datagram // parse datagram comma delimited buf[newline] = ','; String newbuf = new String(buf, start, newline - start); StringTokenizer st = new StringTokenizer(newbuf, ","); int[] data = new int[5]; int i = 0; while (st.hasMoreElements() && i < 5) { String temp = st.nextToken(); try { data[i] = Integer.parseInt(temp, 16); } catch (NumberFormatException e) { } i++; } RobotEvent ev = new RobotEvent(); int checksum; ev.setCommand(EventEnum.getEvent(data[1])); ev.setIndex((short) data[2]); ev.setValue((int) data[3]); checksum = data[4]; int checksum2 = (int) (((int) (ev.getCommand().getValue() & 0x000000FF) + (int) (ev.getIndex() & 0x000000FF) + (int) (ev.getValue() & 0x000000FF) + (int) ((ev.getValue() & 0x0000FF00) >> 8)) % 256); if (checksum2 == checksum) { // log event received recv.put(ev); } } catch (Exception e) { } } }
protected boolean executeUploadCommand(Collection commandDownloader) throws RunnerException { firstErrorFound = false; // haven't found any errors yet secondErrorFound = false; notFoundError = false; int result = 0; // pre-initialized to quiet a bogus warning from jikes String userdir = System.getProperty("user.dir") + File.separator; try { String[] commandArray = new String[commandDownloader.size()]; commandDownloader.toArray(commandArray); String avrBasePath; if (Base.isLinux()) { avrBasePath = new String(Base.getHardwarePath() + "/tools/"); } else { avrBasePath = new String(Base.getHardwarePath() + "/tools/avr/bin/"); } commandArray[0] = avrBasePath + commandArray[0]; if (verbose || Preferences.getBoolean("upload.verbose")) { for (int i = 0; i < commandArray.length; i++) { System.out.print(commandArray[i] + " "); } System.out.println(); } Process process = Runtime.getRuntime().exec(commandArray); new MessageSiphon(process.getInputStream(), this); new MessageSiphon(process.getErrorStream(), this); // wait for the process to finish. if interrupted // before waitFor returns, continue waiting // boolean compiling = true; while (compiling) { try { result = process.waitFor(); compiling = false; } catch (InterruptedException intExc) { } } if (exception != null) { exception.hideStackTrace(); throw exception; } if (result != 0) return false; } catch (Exception e) { String msg = e.getMessage(); if ((msg != null) && (msg.indexOf("uisp: not found") != -1) && (msg.indexOf("avrdude: not found") != -1)) { // System.err.println("uisp is missing"); // JOptionPane.showMessageDialog(editor.base, // "Could not find the compiler.\n" + // "uisp is missing from your PATH,\n" + // "see readme.txt for help.", // "Compiler error", // JOptionPane.ERROR_MESSAGE); return false; } else { e.printStackTrace(); result = -1; } } // System.out.println("result2 is "+result); // if the result isn't a known, expected value it means that something // is fairly wrong, one possibility is that jikes has crashed. // if (exception != null) throw exception; if ((result != 0) && (result != 1)) { exception = new RunnerException(SUPER_BADNESS); // editor.error(exception); // PdeBase.openURL(BUGS_URL); // throw new PdeException(SUPER_BADNESS); } return (result == 0); // ? true : false; }
// The user has done something. respond to it. public void actionPerformed(ActionEvent e) { Object subject = e.getSource(); if (subject == buttonZoomIn) { previewPane.ZoomIn(); return; } if (subject == buttonZoomOut) { previewPane.ZoomOut(); return; } if (subject == buttonOpenFile) { OpenFileDialog(); return; } if (subject == buttonStart) { if (fileOpened) { paused = false; running = true; UpdateMenuBar(); linesProcessed = 0; previewPane.setRunning(running); previewPane.setLinesProcessed(linesProcessed); statusBar.Start(); SendFileCommand(); } return; } if (subject == buttonPause) { if (running) { if (paused == true) { buttonPause.setText("Pause"); paused = false; // @TODO: if the robot is not ready to unpause, this might fail and the program would // appear to hang. SendFileCommand(); } else { buttonPause.setText("Unpause"); paused = true; } } return; } if (subject == buttonDrive) { Drive(); return; } if (subject == buttonHalt) { Halt(); return; } if (subject == buttonRescan) { ListSerialPorts(); UpdateMenuBar(); return; } if (subject == buttonConfig) { UpdateConfig(); return; } if (subject == buttonJogMotors) { JogMotors(); return; } if (subject == buttonAbout) { JOptionPane.showMessageDialog( null, "Created by Dan Royer ([email protected]).\n\n" + "Find out more at http://www.marginallyclever.com/\n" + "Get the latest version and read the documentation online @ http://github.com/i-make-robots/DrawBot/"); return; } if (subject == buttonCheckForUpdate) { CheckForUpdate(); return; } if (subject == buttonExit) { System.exit(0); // @TODO: be more graceful? return; } int i; for (i = 0; i < 10; ++i) { if (subject == buttonRecent[i]) { OpenFileOnDemand(recentFiles[i]); return; } } for (i = 0; i < portsDetected.length; ++i) { if (subject == buttonPorts[i]) { OpenPort(portsDetected[i]); return; } } }
public class DrawbotGUI extends JPanel implements ActionListener, SerialPortEventListener { static final long serialVersionUID = 1; private static final String cue = "> "; private static final String eol = ";"; private static final String NL = System.getProperty("line.separator"); private static DrawbotGUI singletonObject; // Serial connection private static int BAUD_RATE = 57600; private CommPortIdentifier portIdentifier; private CommPort commPort; private SerialPort serialPort; private InputStream in; private OutputStream out; private String[] portsDetected; private boolean portOpened = false; private boolean portConfirmed = false; // Preferences private Preferences prefs = Preferences.userRoot().node("DrawBot"); private String[] recentFiles; private String recentPort; // Robot config private long robot_uid = 0; private double limit_top = 10; private double limit_bottom = -10; private double limit_left = -10; private double limit_right = 10; // paper area (stock material private double paper_top = 10; private double paper_bottom = -10; private double paper_left = -10; private double paper_right = 10; private boolean m1invert = false; private boolean m2invert = false; // GUI elements private static JFrame mainframe; private JMenuBar menuBar; private JMenuItem buttonOpenFile, buttonExit; private JMenuItem buttonConfig, buttonRescan, buttonJogMotors; private JMenuItem buttonStart, buttonPause, buttonHalt, buttonDrive; private JMenuItem buttonZoomIn, buttonZoomOut; private JMenuItem buttonAbout, buttonCheckForUpdate; private JMenuItem[] buttonRecent = new JMenuItem[10]; private JMenuItem[] buttonPorts; private JTextPane log; private JScrollPane logPane; HTMLEditorKit kit; HTMLDocument doc; private DrawPanel previewPane; private StatusBar statusBar; // parsing input from Drawbot private String line3 = ""; // reading file private boolean running = false; private boolean paused = true; private long linesTotal = 0; private long linesProcessed = 0; private boolean fileOpened = false; private ArrayList<String> gcode; private float estimated_time = 0; // Singleton stuff private DrawbotGUI() { LoadConfig(); GetRecentFiles(); GetRecentPaperSize(); GetRecentPort(); } public static DrawbotGUI getSingleton() { if (singletonObject == null) { singletonObject = new DrawbotGUI(); } return singletonObject; } // data access public ArrayList<String> getGcode() { return gcode; } // manages the vertical split in the GUI public class Splitter extends JSplitPane { static final long serialVersionUID = 1; public Splitter(int split_direction) { super(split_direction); setResizeWeight(0.9); setDividerLocation(0.9); } } public void LoadImage(String filename) { BufferedImage img; try { img = ImageIO.read(new File(filename)); Filter_BlackAndWhite bwc = new Filter_BlackAndWhite(); img = bwc.Process(img); Filter_Resize rs = new Filter_Resize(paper_top, paper_bottom, paper_left, paper_right, 1, 0.9f); img = rs.Process(img); Filter_DitherFloydSteinberg dither = new Filter_DitherFloydSteinberg(); img = dither.Process(img); String ngcPair = filename.substring(0, filename.lastIndexOf('.')) + ".ngc"; Filter_TSPGcodeGenerator tsp = new Filter_TSPGcodeGenerator(ngcPair); tsp.Process(img); } catch (IOException e) { } } // returns angle of dy/dx as a value from 0...2PI private double atan3(double dy, double dx) { double a = Math.atan2(dy, dx); if (a < 0) a = (Math.PI * 2.0) + a; return a; } // appends a message to the log tab and system out. public void Log(String msg) { try { kit.insertHTML(doc, doc.getLength(), msg, 0, 0, null); int over_length = doc.getLength() - msg.length() - 5000; doc.remove(0, over_length); } catch (BadLocationException e) { // TODO Auto-generated catch block // e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block // e.printStackTrace(); } } public void ClearLog() { try { doc.replace(0, doc.getLength(), "", null); kit.insertHTML(doc, 0, "", 0, 0, null); } catch (BadLocationException e) { // TODO Auto-generated catch block // e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block // e.printStackTrace(); } } public void ClosePort() { if (portOpened) { if (serialPort != null) { try { // Close the I/O streams. out.close(); in.close(); // Close the port. serialPort.removeEventListener(); serialPort.close(); } catch (IOException e) { // Don't care } } ClearLog(); portOpened = false; portConfirmed = false; previewPane.setConnected(false); UpdateMenuBar(); } } // open a serial connection to a device. We won't know it's the robot until public int OpenPort(String portName) { if (portOpened && portName.equals(recentPort)) return 0; ClosePort(); Log("<font color='green'>Connecting to " + portName + "...</font>\n"); // find the port try { portIdentifier = CommPortIdentifier.getPortIdentifier(portName); } catch (Exception e) { Log("<span style='color:red'>Ports could not be identified:" + e.getMessage() + "</span>\n"); e.printStackTrace(); return 1; } if (portIdentifier.isCurrentlyOwned()) { Log( "<span style='color:red'>Error: Another program is currently using this port." + "</span>\n"); return 2; } // open the port try { commPort = portIdentifier.open("DrawbotGUI", 2000); } catch (Exception e) { Log("Port could not be opened:" + e.getMessage() + NL); e.printStackTrace(); return 3; } if ((commPort instanceof SerialPort) == false) { Log("<span style='color:red'>Only serial ports are handled by this example." + "</span>\n"); return 4; } // set the port parameters (like baud rate) serialPort = (SerialPort) commPort; try { serialPort.setSerialPortParams( BAUD_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (Exception e) { Log("<span style='color:red'>Port could not be configured:" + e.getMessage() + "</span>\n"); return 5; } try { in = serialPort.getInputStream(); out = serialPort.getOutputStream(); } catch (Exception e) { Log("<span style='color:red'>Streams could not be opened:" + e.getMessage() + "</span>\n"); return 6; } try { serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); } catch (TooManyListenersException e) { Log("<span style='color:red'>Streams could not be opened:" + e.getMessage() + "</span>\n"); return 7; } Log("<span style='green'>Opened.</span>\n"); SetRecentPort(portName); portOpened = true; UpdateMenuBar(); return 0; } /** * Complete the handshake, load robot-specific configuration, update the menu, repaint the preview * with the limits. * * @return true if handshake succeeds. */ public boolean ConfirmPort() { if (portConfirmed == true) return true; String hello = "HELLO WORLD! I AM DRAWBOT #"; int found = line3.lastIndexOf(hello); if (found >= 0) { portConfirmed = true; // get the UID reported by the robot String[] lines = line3.substring(found + hello.length()).split("\\r?\\n"); if (lines.length > 0) { try { robot_uid = Long.parseLong(lines[0]); } catch (NumberFormatException e) { } } // new robots have UID=0 if (robot_uid == 0) GetNewRobotUID(); mainframe.setTitle("Drawbot #" + Long.toString(robot_uid) + " connected"); // load machine specific config GetRecentPaperSize(); LoadConfig(); if (limit_top == 0 && limit_bottom == 0 && limit_left == 0 && limit_right == 0) { UpdateConfig(); } previewPane.setMachineLimits(limit_top, limit_bottom, limit_left, limit_right); SendConfig(); UpdateMenuBar(); previewPane.setConnected(true); } return portConfirmed; } /** based on http://www.exampledepot.com/egs/java.net/Post.html */ private void GetNewRobotUID() { try { // Send data URL url = new URL("http://marginallyclever.com/drawbot_getuid.php"); URLConnection conn = url.openConnection(); BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); robot_uid = Long.parseLong(rd.readLine()); rd.close(); } catch (Exception e) { } // did read go ok? if (robot_uid != 0) { SendLineToRobot("UID " + robot_uid); } } // find all available serial ports for the settings->ports menu. public String[] ListSerialPorts() { @SuppressWarnings("unchecked") Enumeration<CommPortIdentifier> ports = (Enumeration<CommPortIdentifier>) CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portList = new ArrayList<String>(); while (ports.hasMoreElements()) { CommPortIdentifier port = (CommPortIdentifier) ports.nextElement(); if (port.getPortType() == CommPortIdentifier.PORT_SERIAL) { portList.add(port.getName()); } } portsDetected = (String[]) portList.toArray(new String[0]); return portsDetected; } // pull the last connected port from prefs public void GetRecentPort() { recentPort = prefs.get("recent-port", ""); } // update the prefs with the last port connected and refreshes the menus. // @TODO: only update when the port is confirmed? public void SetRecentPort(String portName) { prefs.put("recent-port", portName); recentPort = portName; UpdateMenuBar(); } // save paper limits public void SetRecentPaperSize() { String id = Long.toString(robot_uid); prefs.putDouble(id + "_paper_left", paper_left); prefs.putDouble(id + "_paper_right", paper_right); prefs.putDouble(id + "_paper_top", paper_top); prefs.putDouble(id + "_paper_bottom", paper_bottom); previewPane.setPaperSize(paper_top, paper_bottom, paper_left, paper_right); } public void GetRecentPaperSize() { String id = Long.toString(robot_uid); paper_left = Double.parseDouble(prefs.get(id + "_paper_left", "0")); paper_right = Double.parseDouble(prefs.get(id + "_paper_right", "0")); paper_top = Double.parseDouble(prefs.get(id + "_paper_top", "0")); paper_bottom = Double.parseDouble(prefs.get(id + "_paper_bottom", "0")); } // close the file, clear the preview tab public void CloseFile() { if (fileOpened == true) { fileOpened = false; } } void EstimateDrawTime() { int i, j; float drawScale = 1.0f; double px = 0, py = 0, pz = 0; float feed_rate = 1.0f; estimated_time = 0; float estimated_length = 0; int estimate_count = 0; for (i = 0; i < gcode.size(); ++i) { String line = gcode.get(i); String[] pieces = line.split(";"); if (pieces.length == 0) continue; String[] tokens = pieces[0].split("\\s"); if (tokens.length == 0) continue; for (j = 0; j < tokens.length; ++j) { if (tokens[j].equals("G20")) drawScale = 0.393700787f; if (tokens[j].equals("G21")) drawScale = 0.1f; if (tokens[j].startsWith("F")) { feed_rate = Float.valueOf(tokens[j].substring(1)) * drawScale; Log("<span style='color:green'>feed rate=" + feed_rate + "</span>\n"); feed_rate *= 1; } } double x = px; double y = py; double z = pz; double ai = px; double aj = py; for (j = 1; j < tokens.length; ++j) { if (tokens[j].startsWith("X")) x = Float.valueOf(tokens[j].substring(1)) * drawScale; if (tokens[j].startsWith("Y")) y = Float.valueOf(tokens[j].substring(1)) * drawScale; if (tokens[j].startsWith("Z")) z = Float.valueOf(tokens[j].substring(1)) * drawScale; if (tokens[j].startsWith("I")) ai = px + Float.valueOf(tokens[j].substring(1)) * drawScale; if (tokens[j].startsWith("J")) aj = py + Float.valueOf(tokens[j].substring(1)) * drawScale; } if (tokens[0].equals("G00") || tokens[0].equals("G0") || tokens[0].equals("G01") || tokens[0].equals("G1")) { // draw a line double ddx = x - px; double ddy = y - py; double dd = Math.sqrt(ddx * ddx + ddy * ddy); estimated_time += dd / feed_rate; estimated_length += dd; ++estimate_count; px = x; py = y; pz = z; } else if (tokens[0].equals("G02") || tokens[0].equals("G2") || tokens[0].equals("G03") || tokens[0].equals("G3")) { // draw an arc int dir = (tokens[0].equals("G02") || tokens[0].equals("G2")) ? -1 : 1; double dx = px - ai; double dy = py - aj; double radius = Math.sqrt(dx * dx + dy * dy); // find angle of arc (sweep) double angle1 = atan3(dy, dx); double angle2 = atan3(y - aj, x - ai); double theta = angle2 - angle1; if (dir > 0 && theta < 0) angle2 += 2.0 * Math.PI; else if (dir < 0 && theta > 0) angle1 += 2.0 * Math.PI; theta = Math.abs(angle2 - angle1); // Draw the arc from a lot of little line segments. for (int k = 0; k <= theta * DrawPanel.STEPS_PER_DEGREE; ++k) { double angle3 = (angle2 - angle1) * ((double) k / (theta * DrawPanel.STEPS_PER_DEGREE)) + angle1; float nx = (float) (ai + Math.cos(angle3) * radius); float ny = (float) (aj + Math.sin(angle3) * radius); double ddx = nx - px; double ddy = ny - py; double dd = Math.sqrt(ddx * ddx + ddy * ddy); estimated_time += dd / feed_rate; estimated_length += dd; ++estimate_count; px = nx; py = ny; } double ddx = x - px; double ddy = y - py; double dd = Math.sqrt(ddx * ddx + ddy * ddy); estimated_time += dd / feed_rate; estimated_length += dd; ++estimate_count; px = x; py = y; pz = z; } } // for ( each instruction ) estimated_time += estimate_count * 0.007617845117845f; Log( "<font color='green'>" + estimate_count + " line segments.\n" + estimated_length + "cm of line.\n" + "Estimated " + statusBar.formatTime((long) (estimated_time * 10000)) + "s to draw.</font>\n"); } /** * Opens a file. If the file can be opened, get a drawing time estimate, update recent files list, * and repaint the preview tab. * * @param filename what file to open */ public void LoadGCode(String filename) { CloseFile(); try { Scanner scanner = new Scanner(new FileInputStream(filename)); linesTotal = 0; gcode = new ArrayList<String>(); try { while (scanner.hasNextLine()) { gcode.add(scanner.nextLine()); ++linesTotal; } } finally { scanner.close(); } } catch (IOException e) { Log("<span style='color:red'>File could not be opened.</span>\n"); RemoveRecentFile(filename); return; } previewPane.setGCode(gcode); fileOpened = true; EstimateDrawTime(); UpdateRecentFiles(filename); Halt(); } /** * changes the order of the recent files list in the File submenu, saves the updated prefs, and * refreshes the menus. * * @param filename the file to push to the top of the list. */ public void UpdateRecentFiles(String filename) { int cnt = recentFiles.length; String[] newFiles = new String[cnt]; newFiles[0] = filename; int i, j = 1; for (i = 0; i < cnt; ++i) { if (!filename.equals(recentFiles[i]) && recentFiles[i] != "") { newFiles[j++] = recentFiles[i]; if (j == cnt) break; } } recentFiles = newFiles; // update prefs for (i = 0; i < cnt; ++i) { if (recentFiles[i] != null && !recentFiles[i].isEmpty()) { prefs.put("recent-files-" + i, recentFiles[i]); } } UpdateMenuBar(); } // A file failed to load. Remove it from recent files, refresh the menu bar. public void RemoveRecentFile(String filename) { int i; for (i = 0; i < recentFiles.length - 1; ++i) { if (recentFiles[i] == filename) { break; } } for (; i < recentFiles.length - 1; ++i) { recentFiles[i] = recentFiles[i + 1]; } recentFiles[recentFiles.length - 1] = ""; // update prefs for (i = 0; i < recentFiles.length; ++i) { if (recentFiles[i] != null && !recentFiles[i].isEmpty()) { prefs.put("recent-files-" + i, recentFiles[i]); } } UpdateMenuBar(); } // Load recent files from prefs public void GetRecentFiles() { recentFiles = new String[10]; int i; for (i = 0; i < recentFiles.length; ++i) { recentFiles[i] = prefs.get("recent-files-" + i, ""); } } // User has asked that a file be opened. public void OpenFileOnDemand(String filename) { Log("<font color='green'>Opening file " + recentFiles[0] + "...</font>\n"); String ext = filename.substring(filename.lastIndexOf('.')); if (!ext.equalsIgnoreCase(".ngc")) { LoadImage(filename); } else { LoadGCode(filename); } statusBar.Clear(); } // creates a file open dialog. If you don't cancel it opens that file. public void OpenFileDialog() { // Note: source for ExampleFileFilter can be found in FileChooserDemo, // under the demo/jfc directory in the Java 2 SDK, Standard Edition. String filename = (recentFiles[0].length() > 0) ? filename = recentFiles[0] : ""; FileFilter filterImage = new FileNameExtensionFilter( "Images (jpg/bmp/png/gif)", "jpg", "jpeg", "png", "wbmp", "bmp", "gif"); FileFilter filterGCODE = new FileNameExtensionFilter("GCODE files (ngc)", "ngc"); JFileChooser fc = new JFileChooser(new File(filename)); fc.addChoosableFileFilter(filterImage); fc.addChoosableFileFilter(filterGCODE); if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { OpenFileOnDemand(fc.getSelectedFile().getAbsolutePath()); } } public void GoHome() { SendLineToRobot("G00 X0 Y0 Z0"); } /** * Open the config dialog, send the config update to the robot, save it for future, and refresh * the preview tab. */ public void UpdateConfig() { final JDialog driver = new JDialog(mainframe, "Configure Limits", true); driver.setLayout(new GridBagLayout()); final JTextField mtop = new JTextField(String.valueOf(limit_top)); final JTextField mbottom = new JTextField(String.valueOf(limit_bottom)); final JTextField mleft = new JTextField(String.valueOf(limit_left)); final JTextField mright = new JTextField(String.valueOf(limit_right)); final JTextField ptop = new JTextField(String.valueOf(paper_top)); final JTextField pbottom = new JTextField(String.valueOf(paper_bottom)); final JTextField pleft = new JTextField(String.valueOf(paper_left)); final JTextField pright = new JTextField(String.valueOf(paper_right)); final JButton cancel = new JButton("Cancel"); final JButton save = new JButton("Save"); GridBagConstraints c = new GridBagConstraints(); c.gridx = 3; c.gridy = 0; driver.add(mtop, c); c.gridx = 3; c.gridy = 5; driver.add(mbottom, c); c.gridx = 0; c.gridy = 3; driver.add(mleft, c); c.gridx = 5; c.gridy = 3; driver.add(mright, c); c.gridx = 3; c.gridy = 1; driver.add(ptop, c); c.gridx = 3; c.gridy = 4; driver.add(pbottom, c); c.gridx = 1; c.gridy = 3; driver.add(pleft, c); c.gridx = 4; c.gridy = 3; driver.add(pright, c); c.gridx = 4; c.gridy = 6; driver.add(save, c); c.gridx = 5; c.gridy = 6; driver.add(cancel, c); Dimension s = ptop.getPreferredSize(); s.width = 80; ptop.setPreferredSize(s); pbottom.setPreferredSize(s); pleft.setPreferredSize(s); pright.setPreferredSize(s); mtop.setPreferredSize(s); mbottom.setPreferredSize(s); mleft.setPreferredSize(s); mright.setPreferredSize(s); ActionListener driveButtons = new ActionListener() { public void actionPerformed(ActionEvent e) { Object subject = e.getSource(); if (subject == save) { paper_top = Float.valueOf(ptop.getText()); paper_bottom = Float.valueOf(pbottom.getText()); paper_right = Float.valueOf(pright.getText()); paper_left = Float.valueOf(pleft.getText()); limit_top = Float.valueOf(mtop.getText()); limit_bottom = Float.valueOf(mbottom.getText()); limit_right = Float.valueOf(mright.getText()); limit_left = Float.valueOf(mleft.getText()); previewPane.setMachineLimits(limit_top, limit_bottom, limit_left, limit_right); previewPane.setPaperSize(paper_top, paper_bottom, paper_left, paper_right); SetRecentPaperSize(); SaveConfig(); SendConfig(); driver.dispose(); } if (subject == cancel) { driver.dispose(); } } }; save.addActionListener(driveButtons); cancel.addActionListener(driveButtons); SendLineToRobot("M114"); // "where" command driver.pack(); driver.setVisible(true); } void LoadConfig() { String id = Long.toString(robot_uid); limit_top = Double.valueOf(prefs.get(id + "_limit_top", "0")); limit_bottom = Double.valueOf(prefs.get(id + "_limit_bottom", "0")); limit_left = Double.valueOf(prefs.get(id + "_limit_left", "0")); limit_right = Double.valueOf(prefs.get(id + "_limit_right", "0")); m1invert = Boolean.parseBoolean(prefs.get(id + "_m1invert", "false")); m2invert = Boolean.parseBoolean(prefs.get(id + "_m2invert", "false")); } void SaveConfig() { String id = Long.toString(robot_uid); prefs.put(id + "_limit_top", Double.toString(limit_top)); prefs.put(id + "_limit_bottom", Double.toString(limit_bottom)); prefs.put(id + "_limit_right", Double.toString(limit_right)); prefs.put(id + "_limit_left", Double.toString(limit_left)); prefs.put(id + "_m1invert", Boolean.toString(m1invert)); prefs.put(id + "_m2invert", Boolean.toString(m2invert)); } void SendConfig() { if (!portConfirmed) return; // Send a command to the robot with new configuration values String line = "CONFIG T" + limit_top + " B" + limit_bottom + " L" + limit_left + " R" + limit_right + " I" + (m1invert ? "-1" : "1") + " J" + (m2invert ? "-1" : "1"); SendLineToRobot(line); SendLineToRobot("TELEPORT X0 Y0 Z0"); } // Take the next line from the file and send it to the robot, if permitted. public void SendFileCommand() { if (running == false || paused == true || fileOpened == false || portConfirmed == false || linesProcessed >= linesTotal) return; String line; do { // are there any more commands? line = gcode.get((int) linesProcessed++).trim(); previewPane.setLinesProcessed(linesProcessed); statusBar.SetProgress(linesProcessed, linesTotal); // loop until we find a line that gets sent to the robot, at which point we'll // pause for the robot to respond. Also stop at end of file. } while (ProcessLine(line) && linesProcessed < linesTotal); if (linesProcessed == linesTotal) { // end of file Halt(); } } /** * removes comments, processes commands drawbot shouldn't have to handle. * * @param line command to send * @return true if the robot is ready for another command to be sent. */ public boolean ProcessLine(String line) { // tool change request? String[] tokens = line.split("\\s"); // tool change? if (Arrays.asList(tokens).contains("M06") || Arrays.asList(tokens).contains("M6")) { for (int i = 0; i < tokens.length; ++i) { if (tokens[i].startsWith("T")) { JOptionPane.showMessageDialog( null, "Please change to tool #" + tokens[i].substring(1) + " and click OK."); } } // still ready to send return true; } // end of program? if (tokens[0] == "M02" || tokens[0] == "M2") { Halt(); return false; } // other machine code to ignore? if (tokens[0].startsWith("M")) { Log("<font color='pink'>" + line + "</font>\n"); return true; } // contains a comment? if so remove it int index = line.indexOf('('); if (index != -1) { String comment = line.substring(index + 1, line.lastIndexOf(')')); line = line.substring(0, index).trim(); Log("<font color='grey'>* " + comment + "</font\n"); if (line.length() == 0) { // entire line was a comment. return true; // still ready to send } } // send relevant part of line to the robot SendLineToRobot(line); return false; } /** * Sends a single command the robot. Could be anything. * * @param line command to send. * @return true means the command is sent. false means it was not. */ public void SendLineToRobot(String line) { if (!portConfirmed) return; line += eol; Log("<font color='white'>" + line + "</font>"); try { out.write(line.getBytes()); } catch (IOException e) { } } /** * stop sending file commands to the robot. * * @todo add an e-stop command? */ public void Halt() { running = false; paused = false; linesProcessed = 0; previewPane.setLinesProcessed(0); previewPane.setRunning(running); UpdateMenuBar(); } // The user has done something. respond to it. public void actionPerformed(ActionEvent e) { Object subject = e.getSource(); if (subject == buttonZoomIn) { previewPane.ZoomIn(); return; } if (subject == buttonZoomOut) { previewPane.ZoomOut(); return; } if (subject == buttonOpenFile) { OpenFileDialog(); return; } if (subject == buttonStart) { if (fileOpened) { paused = false; running = true; UpdateMenuBar(); linesProcessed = 0; previewPane.setRunning(running); previewPane.setLinesProcessed(linesProcessed); statusBar.Start(); SendFileCommand(); } return; } if (subject == buttonPause) { if (running) { if (paused == true) { buttonPause.setText("Pause"); paused = false; // @TODO: if the robot is not ready to unpause, this might fail and the program would // appear to hang. SendFileCommand(); } else { buttonPause.setText("Unpause"); paused = true; } } return; } if (subject == buttonDrive) { Drive(); return; } if (subject == buttonHalt) { Halt(); return; } if (subject == buttonRescan) { ListSerialPorts(); UpdateMenuBar(); return; } if (subject == buttonConfig) { UpdateConfig(); return; } if (subject == buttonJogMotors) { JogMotors(); return; } if (subject == buttonAbout) { JOptionPane.showMessageDialog( null, "Created by Dan Royer ([email protected]).\n\n" + "Find out more at http://www.marginallyclever.com/\n" + "Get the latest version and read the documentation online @ http://github.com/i-make-robots/DrawBot/"); return; } if (subject == buttonCheckForUpdate) { CheckForUpdate(); return; } if (subject == buttonExit) { System.exit(0); // @TODO: be more graceful? return; } int i; for (i = 0; i < 10; ++i) { if (subject == buttonRecent[i]) { OpenFileOnDemand(recentFiles[i]); return; } } for (i = 0; i < portsDetected.length; ++i) { if (subject == buttonPorts[i]) { OpenPort(portsDetected[i]); return; } } } // Deal with something robot has sent. public void serialEvent(SerialPortEvent events) { switch (events.getEventType()) { case SerialPortEvent.DATA_AVAILABLE: try { final byte[] buffer = new byte[1024]; int len = in.read(buffer); if (len > 0) { String line2 = new String(buffer, 0, len); Log("<span style='color:#FFA500'>" + line2.replace("\n", "<br>") + "</span>"); line3 += line2; // wait for the cue ("> ") to send another command if (line3.lastIndexOf(cue) != -1) { if (ConfirmPort()) { line3 = ""; SendFileCommand(); } } } } catch (IOException e) { } break; } } public void CheckForUpdate() { /* try { // Send data URL url = new URL("http://marginallyclever.com/drawbot_get.php"); URLConnection conn = url.openConnection(); BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); robot_uid = Long.parseLong(rd.readLine()); rd.close(); } catch (Exception e) {} */ // TODO Get latest version // TODO Offer to download latest version? } /** Open the config dialog, update the paper size, refresh the preview tab. */ public void Drive() { JDialog driver = new JDialog(mainframe, "Manual Control", true); driver.setLayout(new GridBagLayout()); JButton find = new JButton("FIND HOME"); JButton home = new JButton("GO HOME"); JButton center = new JButton("THIS IS HOME"); JButton up1 = new JButton("Y1"); JButton up10 = new JButton("Y10"); JButton up100 = new JButton("Y100"); JButton down1 = new JButton("Y-1"); JButton down10 = new JButton("Y-10"); JButton down100 = new JButton("Y-100"); JButton left1 = new JButton("X-1"); JButton left10 = new JButton("X-10"); JButton left100 = new JButton("X-100"); JButton right1 = new JButton("X1"); JButton right10 = new JButton("X10"); JButton right100 = new JButton("X100"); GridBagConstraints c = new GridBagConstraints(); c.gridx = 3; c.gridy = 0; driver.add(up100, c); c.gridx = 3; c.gridy = 1; driver.add(up10, c); c.gridx = 3; c.gridy = 2; driver.add(up1, c); c.gridx = 3; c.gridy = 4; driver.add(down1, c); c.gridx = 3; c.gridy = 5; driver.add(down10, c); c.gridx = 3; c.gridy = 6; driver.add(down100, c); c.gridx = 0; c.gridy = 3; driver.add(left100, c); c.gridx = 1; c.gridy = 3; driver.add(left10, c); c.gridx = 2; c.gridy = 3; driver.add(left1, c); c.gridx = 4; c.gridy = 3; driver.add(right1, c); c.gridx = 5; c.gridy = 3; driver.add(right10, c); c.gridx = 6; c.gridy = 3; driver.add(right100, c); c.gridx = 3; c.gridy = 3; driver.add(home, c); c.gridx = 6; c.gridy = 0; driver.add(center, c); c.gridx = 6; c.gridy = 1; driver.add(find, c); ActionListener driveButtons = new ActionListener() { public void actionPerformed(ActionEvent e) { Object subject = e.getSource(); JButton b = (JButton) subject; String t = b.getText(); if (t == "GO HOME") { GoHome(); SendLineToRobot("M114"); } else if (t == "FIND HOME") { SendLineToRobot("G28"); } else if (t == "THIS IS HOME") { SendLineToRobot("TELEPORT XO YO"); } else { SendLineToRobot("G91"); SendLineToRobot("G00 " + b.getText()); SendLineToRobot("G90"); SendLineToRobot("M114"); } } }; up1.addActionListener(driveButtons); up10.addActionListener(driveButtons); up100.addActionListener(driveButtons); down1.addActionListener(driveButtons); down10.addActionListener(driveButtons); down100.addActionListener(driveButtons); left1.addActionListener(driveButtons); left10.addActionListener(driveButtons); left100.addActionListener(driveButtons); right1.addActionListener(driveButtons); right10.addActionListener(driveButtons); right100.addActionListener(driveButtons); center.addActionListener(driveButtons); home.addActionListener(driveButtons); find.addActionListener(driveButtons); SendLineToRobot("M114"); driver.pack(); driver.setVisible(true); } protected void JogMotors() { JDialog driver = new JDialog(mainframe, "Jog Motors", true); driver.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); final JButton buttonAneg = new JButton("IN"); final JButton buttonApos = new JButton("OUT"); final JCheckBox m1i = new JCheckBox("Invert", m1invert); final JButton buttonBneg = new JButton("IN"); final JButton buttonBpos = new JButton("OUT"); final JCheckBox m2i = new JCheckBox("Invert", m2invert); c.gridx = 0; c.gridy = 0; driver.add(new JLabel("L"), c); c.gridx = 0; c.gridy = 1; driver.add(new JLabel("R"), c); c.gridx = 1; c.gridy = 0; driver.add(buttonAneg, c); c.gridx = 1; c.gridy = 1; driver.add(buttonBneg, c); c.gridx = 2; c.gridy = 0; driver.add(buttonApos, c); c.gridx = 2; c.gridy = 1; driver.add(buttonBpos, c); c.gridx = 3; c.gridy = 0; driver.add(m1i, c); c.gridx = 3; c.gridy = 1; driver.add(m2i, c); ActionListener driveButtons = new ActionListener() { public void actionPerformed(ActionEvent e) { Object subject = e.getSource(); if (subject == buttonApos) SendLineToRobot("D00 L100"); if (subject == buttonAneg) SendLineToRobot("D00 L-100"); if (subject == buttonBpos) SendLineToRobot("D00 R100"); if (subject == buttonBneg) SendLineToRobot("D00 R-100"); SendLineToRobot("M114"); } }; ActionListener invertButtons = new ActionListener() { public void actionPerformed(ActionEvent e) { m1invert = m1i.isSelected(); m2invert = m2i.isSelected(); SaveConfig(); SendConfig(); } }; buttonApos.addActionListener(driveButtons); buttonAneg.addActionListener(driveButtons); buttonBpos.addActionListener(driveButtons); buttonBneg.addActionListener(driveButtons); m1i.addActionListener(invertButtons); m2i.addActionListener(invertButtons); SendLineToRobot("M114"); driver.pack(); driver.setVisible(true); } public JMenuBar CreateMenuBar() { // If the menu bar exists, empty it. If it doesn't exist, create it. menuBar = new JMenuBar(); UpdateMenuBar(); return menuBar; } // Rebuild the contents of the menu based on current program state public void UpdateMenuBar() { JMenu menu; int i; menuBar.removeAll(); // Build the first menu. menu = new JMenu("File"); menu.setMnemonic(KeyEvent.VK_F); menuBar.add(menu); buttonOpenFile = new JMenuItem("Open File...", KeyEvent.VK_O); buttonOpenFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); buttonOpenFile.getAccessibleContext().setAccessibleDescription("Open a g-code file..."); buttonOpenFile.addActionListener(this); menu.add(buttonOpenFile); menu.addSeparator(); // list recent files if (recentFiles != null && recentFiles.length > 0) { // list files here for (i = 0; i < recentFiles.length; ++i) { if (recentFiles[i] == null || recentFiles[i].length() == 0) break; buttonRecent[i] = new JMenuItem((1 + i) + " " + recentFiles[i], KeyEvent.VK_1 + i); if (buttonRecent[i] != null) { buttonRecent[i].addActionListener(this); menu.add(buttonRecent[i]); } } if (i != 0) menu.addSeparator(); } buttonExit = new JMenuItem("Exit", KeyEvent.VK_Q); buttonExit.getAccessibleContext().setAccessibleDescription("Goodbye..."); buttonExit.addActionListener(this); menu.add(buttonExit); menuBar.add(menu); // settings menu menu = new JMenu("Settings"); menu.setMnemonic(KeyEvent.VK_T); menu.getAccessibleContext().setAccessibleDescription("Adjust the robot settings."); JMenu subMenu = new JMenu("Port"); subMenu.setMnemonic(KeyEvent.VK_P); subMenu.getAccessibleContext().setAccessibleDescription("What port to connect to?"); subMenu.setEnabled(!running); ButtonGroup group = new ButtonGroup(); ListSerialPorts(); buttonPorts = new JRadioButtonMenuItem[portsDetected.length]; for (i = 0; i < portsDetected.length; ++i) { buttonPorts[i] = new JRadioButtonMenuItem(portsDetected[i]); if (recentPort.equals(portsDetected[i]) && portOpened) { buttonPorts[i].setSelected(true); } buttonPorts[i].addActionListener(this); group.add(buttonPorts[i]); subMenu.add(buttonPorts[i]); } subMenu.addSeparator(); buttonRescan = new JMenuItem("Rescan", KeyEvent.VK_N); buttonRescan.getAccessibleContext().setAccessibleDescription("Rescan the available ports."); buttonRescan.addActionListener(this); subMenu.add(buttonRescan); menu.add(subMenu); buttonConfig = new JMenuItem("Configure limits", KeyEvent.VK_L); buttonConfig.getAccessibleContext().setAccessibleDescription("Adjust the robot & paper shape."); buttonConfig.addActionListener(this); buttonConfig.setEnabled(portConfirmed && !running); menu.add(buttonConfig); buttonJogMotors = new JMenuItem("Jog Motors", KeyEvent.VK_J); buttonJogMotors.addActionListener(this); buttonJogMotors.setEnabled(portConfirmed && !running); menu.add(buttonJogMotors); buttonDrive = new JMenuItem("Drive Manually", KeyEvent.VK_R); buttonDrive.getAccessibleContext().setAccessibleDescription("Etch-a-sketch style driving"); buttonDrive.addActionListener(this); buttonDrive.setEnabled(portConfirmed && !running); menu.add(buttonDrive); menuBar.add(menu); // Draw menu menu = new JMenu("Draw"); menu.setMnemonic(KeyEvent.VK_D); menu.getAccessibleContext().setAccessibleDescription("Start & Stop progress"); buttonStart = new JMenuItem("Start", KeyEvent.VK_S); buttonStart.getAccessibleContext().setAccessibleDescription("Start sending g-code"); buttonStart.addActionListener(this); buttonStart.setEnabled(portConfirmed && !running); menu.add(buttonStart); buttonPause = new JMenuItem("Pause", KeyEvent.VK_P); buttonPause.getAccessibleContext().setAccessibleDescription("Pause sending g-code"); buttonPause.addActionListener(this); buttonPause.setEnabled(portConfirmed && running); menu.add(buttonPause); buttonHalt = new JMenuItem("Halt", KeyEvent.VK_H); buttonHalt.getAccessibleContext().setAccessibleDescription("Halt sending g-code"); buttonHalt.addActionListener(this); buttonHalt.setEnabled(portConfirmed && running); menu.add(buttonHalt); menuBar.add(menu); // tools menu menu = new JMenu("Tools"); buttonZoomOut = new JMenuItem("Zoom -"); buttonZoomOut.addActionListener(this); buttonZoomOut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.ALT_MASK)); menu.add(buttonZoomOut); buttonZoomIn = new JMenuItem("Zoom +", KeyEvent.VK_EQUALS); buttonZoomIn.addActionListener(this); buttonZoomIn.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, ActionEvent.ALT_MASK)); menu.add(buttonZoomIn); menuBar.add(menu); // Help menu menu = new JMenu("Help"); menu.setMnemonic(KeyEvent.VK_H); menu.getAccessibleContext().setAccessibleDescription("Get help"); buttonAbout = new JMenuItem("About", KeyEvent.VK_A); menu.getAccessibleContext().setAccessibleDescription("Find out about this program"); buttonAbout.addActionListener(this); menu.add(buttonAbout); buttonCheckForUpdate = new JMenuItem("Check for updates", KeyEvent.VK_U); menu.getAccessibleContext().setAccessibleDescription("Is there a newer version available?"); buttonCheckForUpdate.addActionListener(this); buttonCheckForUpdate.setEnabled(false); menu.add(buttonCheckForUpdate); menuBar.add(menu); // finish menuBar.updateUI(); } public Container CreateContentPane() { // Create the content-pane-to-be. JPanel contentPane = new JPanel(new BorderLayout()); contentPane.setOpaque(true); // the log panel log = new JTextPane(); log.setEditable(false); log.setBackground(Color.BLACK); logPane = new JScrollPane(log); kit = new HTMLEditorKit(); doc = new HTMLDocument(); log.setEditorKit(kit); log.setDocument(doc); DefaultCaret c = (DefaultCaret) log.getCaret(); c.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); ClearLog(); // the preview panel previewPane = new DrawPanel(); previewPane.setPaperSize(paper_top, paper_bottom, paper_left, paper_right); // status bar statusBar = new StatusBar(); Font f = statusBar.getFont(); statusBar.setFont(f.deriveFont(Font.BOLD, 15)); Dimension d = statusBar.getMinimumSize(); d.setSize(d.getWidth(), d.getHeight() + 30); statusBar.setMinimumSize(d); // layout Splitter split = new Splitter(JSplitPane.VERTICAL_SPLIT); split.add(previewPane); split.add(logPane); split.setDividerSize(8); contentPane.add(statusBar, BorderLayout.SOUTH); contentPane.add(split, BorderLayout.CENTER); // open the file if (recentFiles[0].length() > 0) { OpenFileOnDemand(recentFiles[0]); } // connect to the last port ListSerialPorts(); if (Arrays.asList(portsDetected).contains(recentPort)) { OpenPort(recentPort); } return contentPane; } // Create the GUI and show it. For thread safety, this method should be invoked from the // event-dispatching thread. private static void CreateAndShowGUI() { // Create and set up the window. mainframe = new JFrame("No Drawbot Connected"); mainframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Create and set up the content pane. DrawbotGUI demo = DrawbotGUI.getSingleton(); mainframe.setJMenuBar(demo.CreateMenuBar()); mainframe.setContentPane(demo.CreateContentPane()); // Display the window. mainframe.setSize(800, 700); mainframe.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event-dispatching thread: // creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater( new Runnable() { public void run() { CreateAndShowGUI(); } }); } }