From 53f99a5ff38b2d8c04d5764e331b7dc3a16faadf Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 12 Jun 2006 16:32:35 +0100 Subject: [PATCH] added visualizer --- src/edu/berkeley/obits/AtmelSerial.java | 9 +- src/edu/berkeley/obits/Visual.java | 396 ++++++++++++++++++++ src/edu/berkeley/obits/device/atmel/At40k.java | 48 +++ .../berkeley/obits/device/atmel/AtmelDevice.java | 6 +- src/edu/berkeley/obits/device/atmel/AvrDrone.java | 45 ++- 5 files changed, 483 insertions(+), 21 deletions(-) create mode 100644 src/edu/berkeley/obits/Visual.java diff --git a/src/edu/berkeley/obits/AtmelSerial.java b/src/edu/berkeley/obits/AtmelSerial.java index a67d936..444c944 100644 --- a/src/edu/berkeley/obits/AtmelSerial.java +++ b/src/edu/berkeley/obits/AtmelSerial.java @@ -29,7 +29,8 @@ public class AtmelSerial { } public static int PIPELEN=20; public static void main(String[] s) throws Exception { - AvrDrone device = new AvrDrone(detectObitsPort()); + //AvrDrone device = new AvrDrone(detectObitsPort()); + AvrDrone device = new AvrDrone(); At40k at40k = new At40k.At40k10(device); int count = 0; try { @@ -424,6 +425,12 @@ public class AtmelSerial { //scan(at40k, cell, YLUT, false); //device.scanFPGA(true); + + Visual vis = new Visual(at40k); + vis.show(); + vis.setSize(600, 600); + synchronized(AtmelSerial.class) { AtmelSerial.class.wait(); } + Visualizer v = new Visualizer(at40k, device); v.show(); v.setSize(1380, 1080); diff --git a/src/edu/berkeley/obits/Visual.java b/src/edu/berkeley/obits/Visual.java new file mode 100644 index 0000000..9e20da0 --- /dev/null +++ b/src/edu/berkeley/obits/Visual.java @@ -0,0 +1,396 @@ +package edu.berkeley.obits; + +import static edu.berkeley.obits.device.atmel.AtmelDevice.Constants.*; +import static edu.berkeley.obits.device.atmel.AtmelDevice.Util.*; +import edu.berkeley.obits.device.atmel.*; +import java.awt.*; +import java.awt.geom.*; +import java.awt.event.*; +import java.awt.color.*; +import org.ibex.util.*; +import java.io.*; +import java.util.*; +import javax.swing.*; + +public class Visual extends JFrame implements KeyListener { + + public static int SIZE = 92; + public static int RINGS = 3; + public static int BEVEL = 5; + public static int CORE_SIZE = 64; + public static int CORE_OFFSET = 10; + + public static int HOFF = 52; + + /* + public static void main(String[] s) { + Visual v = new Visual(); + v.show(); + v.setSize(400, 400); + } + */ + + At40k at40k; + + public Visual(At40k at40k) { + this.at40k = at40k; + for(int x=0; x<7; x++) + for(int y=0; y<7; y++) + new Cell(x,y, at40k.cell(x+7, y+7)); + addKeyListener(this); + } + + private HashSet cells = new HashSet(); + + public class Cell { + Graphics2D g; + At40k.Cell cell; + int _x, _y; + public Cell(int x, int y, At40k.Cell cell) { + _x = x; + _y = y; + this.cell = cell; + cells.add(this); + } + public void draw() { + drawHwires(); + drawVwires(); + drawInternalRouting(); + drawLocal(); + drawGates(); + drawMux(); + drawRegister(); + drawBorder(); + } + public void drawHwires() { + g.setColor(Color.magenta); + for(int i=0; i<5; i++) + if (cell.hwire(i).isDriven()) + g.drawLine(0, SIZE-(2*(1+RINGS)+2*i), SIZE, SIZE-(2*(1+RINGS)+2*i)); + } + public void drawVwires() { + g.setColor(Color.magenta); + for(int i=0; i<5; i++) + if (cell.vwire(i).isDriven()) + g.drawLine(2*(1+RINGS)+2*i, 0, 2*(1+RINGS)+2*i, SIZE); + } + public void drawInternalRouting() { + } + + public void drawLocal() { + if (!cell.ylut_relevant() && !cell.ylut_relevant()) return; + Point2D in = new Point2D.Double(HOFF, 0); + Point2D join = new Point2D.Double(HOFF, CORE_OFFSET); + rotateOuter(in); + rotateInner(join); + int rot = rot(); + switch(rot) { + case 0: case 2: + join.setLocation(in.getX(), join.getY()); + break; + case 1: case 3: + join.setLocation(join.getX(), in.getY()); + break; + } + + Point2D xi = null; + g.setColor(new Color(0xff, 0x00, 0x00)); + int xring = 4; + switch(cell.xi()) { + case NW: + xi = new Point2D.Double(0+2*xring, SIZE-2*xring); + g.draw(new Line2D.Double(new Point2D.Double(0, SIZE), xi)); + break; + + case SW: + xi = new Point2D.Double(0+2*xring, 0+2*xring); + g.draw(new Line2D.Double(new Point2D.Double(0, 0), xi)); + break; + + case NE: + xi = new Point2D.Double(SIZE-2*xring, SIZE-2*xring); + g.draw(new Line2D.Double(new Point2D.Double(SIZE, SIZE), xi)); + break; + + case SE: + xi = new Point2D.Double(SIZE-2*xring, 0+2*xring); + g.draw(new Line2D.Double(new Point2D.Double(SIZE, 0), xi)); + break; + + } + + if (cell.xlut_relevant()) { + g.setColor(new Color(0x00, 0x00, 0xff)); + Point2D c = new Point2D.Double(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 6, 20); + rotateInner(c); + route(in, c, 5); + + g.setColor(new Color(0xff, 0x00, 0x00)); + c = new Point2D.Double(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 3, 20); + rotateInner(c); + if (xi != null) + route(xi, c, 4); + + Point2D xo = new Point2D.Double(SIZE-CORE_OFFSET-CORE_SIZE+17 - 2, CORE_OFFSET + 41 - 3); + Point2D xout = new Point2D.Double(SIZE-CORE_OFFSET-CORE_SIZE+17 - 2, CORE_OFFSET + CORE_SIZE - 3); + rotateInner(xo); + rotateInner(xout); + g.setColor(new Color(0xff, 0xcc, 0xcc)); + g.draw(new Line2D.Double(xo, xout)); + if (cell.ne() != null && cell.ne().xi()==SW) { + Point2D xoo = new Point2D.Double(SIZE-2*xring, SIZE-2*xring); + g.draw(new Line2D.Double(new Point2D.Double(SIZE, SIZE), xoo)); + route(xout, xoo, xring); + } + if (cell.nw() != null && cell.nw().xi()==SE) { + Point2D xoo = new Point2D.Double(0+2*xring, SIZE-2*xring); + g.draw(new Line2D.Double(new Point2D.Double(0, SIZE), xoo)); + route(xout, xoo, xring); + } + if (cell.se() != null && cell.se().xi()==NW) { + Point2D xoo = new Point2D.Double(SIZE-2*xring, 0+2*xring); + g.draw(new Line2D.Double(new Point2D.Double(SIZE, 0), xoo)); + route(xout, xoo, xring); + } + if (cell.sw() != null && cell.sw().xi()==NE) { + Point2D xoo = new Point2D.Double(0+2*xring, 0+2*xring); + g.draw(new Line2D.Double(new Point2D.Double(0, 0), xoo)); + route(xout, xoo, xring); + } + } + + if (cell.ylut_relevant()) { + g.setColor(new Color(0x00, 0x00, 0xff)); + Point2D c = new Point2D.Double(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 6, 20); + rotateInner(c); + route(in, c, 5); + + g.setColor(new Color(0xff, 0x00, 0x00)); + c = new Point2D.Double(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 3, 20); + rotateInner(c); + if (xi != null) + route(xi, c, 4); + + Point2D yo = new Point2D.Double(SIZE-CORE_OFFSET-CORE_SIZE+51 - 2, CORE_OFFSET + 41 - 3); + Point2D yout = new Point2D.Double(SIZE-CORE_OFFSET-CORE_SIZE+51 - 2, CORE_OFFSET + CORE_SIZE - 3); + rotateInner(yo); + rotateInner(yout); + g.setColor(new Color(0xbb, 0xbb, 0xff)); + //g.setColor(new Color(0x00, 0x00, 0xff)); + g.draw(new Line2D.Double(yo, yout)); + if (cell.north() != null && cell.north().yi()==SOUTH) route(yout, new Point2D.Double(SIZE-40, SIZE+ 0), 2); + if (cell.east() != null && cell.east().yi()==WEST) route(yout, new Point2D.Double(SIZE+ 0, 40), 2); + if (cell.south() != null && cell.south().yi()==NORTH) route(yout, new Point2D.Double( 40, 0), 2); + if (cell.west() != null && cell.west().yi()==EAST) route(yout, new Point2D.Double( 0, SIZE-40), 2); + } + + } + + private void rotateOuter(Point2D p) { + int rot = rot(); + AffineTransform a = new AffineTransform(); + a.rotate((Math.PI/2) * rot); + switch(rot) { + case 0: break; + case 1: a.translate(0, -SIZE); break; + case 2: a.translate(-SIZE, -SIZE); break; + case 3: a.translate(-SIZE, 0); break; + } + a.transform(p, p); + } + + private void rotateInner(Point2D p) { + int rot = rot(); + AffineTransform a = new AffineTransform(); + a.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET); + a.rotate((Math.PI/2) * rot); + switch(rot) { + case 0: break; + case 1: a.translate(0, -CORE_SIZE); break; + case 2: a.translate(-CORE_SIZE, -CORE_SIZE); break; + case 3: a.translate(-CORE_SIZE, 0); break; + } + a.translate(-1 * (SIZE-CORE_SIZE-CORE_OFFSET), -CORE_OFFSET); + a.transform(p, p); + } + + private Point2D project(Point2D p1, int ring) { + double north = Math.abs( (SIZE-(ring*2)) - p1.getY() ); + double south = Math.abs( ( (ring*2)) - p1.getY() ); + double east = Math.abs( (SIZE-(ring*2)) - p1.getX() ); + double west = Math.abs( ( (ring*2)) - p1.getX() ); + if (north < south && north < east && north < west) { + return new Point2D.Double(p1.getX(), SIZE-ring*2); + } else if (south < east && south < west) { + return new Point2D.Double(p1.getX(), ring*2); + } else if (east < west) { + return new Point2D.Double(SIZE-ring*2, p1.getY()); + } else { + return new Point2D.Double(ring*2, p1.getY()); + } + } + + private void route(Point2D p1, Point2D p2, int ring) { + int ringpos = ring * 2; + Point2D projected = project(p1, ring); + g.draw(new Line2D.Double(p1, projected)); + p1 = projected; + + projected = project(p2, ring); + g.draw(new Line2D.Double(p2, projected)); + p2 = projected; + + double x1 = p1.getX(); + double y1 = p1.getY(); + double x2 = p2.getX(); + double y2 = p2.getY(); + + if (x1==x2 || y1==y2) { + g.draw(new Line2D.Double(p1, p2)); + return; + } + + if ((x1==SIZE-ring*2 || x1==ring*2) && !(y1==SIZE-ring*2 || y1==ring*2)) { + Point2D p3 = new Point2D.Double(x1, y2 > SIZE/2 ? SIZE-ring*2 : ring*2); + g.draw(new Line2D.Double(p1, p3)); + route(p3, p2, ring); + } + + if (y1==SIZE-ring*2 || y1==ring*2) { + Point2D p3 = new Point2D.Double(x2 > SIZE/2 ? SIZE-ring*2 : ring*2, y1); + g.draw(new Line2D.Double(p1, p3)); + route(p3, p2, ring); + } + + } + + private int rot() { + int rot = 0; + switch(cell.yi()) { + case SOUTH: rot = 0; break; + case NORTH: rot = 2; break; + case EAST: rot = 1; break; + case WEST: rot = 3; break; + default: { + // FIXME: choose based on xin + if (cell.north() != null && cell.north().yi()==SOUTH) { rot = 0; break; } + if (cell.south() != null && cell.south().yi()==NORTH) { rot = 2; break; } + if (cell.east() != null && cell.east().yi()==WEST) { rot = 3; break; } + if (cell.west() != null && cell.west().yi()==EAST) { rot = 1; break; } + } + } + return rot; + } + + public void drawGates() { + AffineTransform t = g.getTransform(); + try { + g.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET); + + int rot = rot(); + g.rotate((Math.PI/2) * rot); + switch(rot) { + case 0: break; + case 1: g.translate(0, -CORE_SIZE); break; + case 2: g.translate(-CORE_SIZE, -CORE_SIZE); break; + case 3: g.translate(-CORE_SIZE, 0); break; + } + + //g.setColor(Color.gray); + //g.drawRect(0, 0, CORE_SIZE, CORE_SIZE); + g.scale(1, -1); + + GeneralPath p = new GeneralPath(); + p.moveTo(29.141f, 36.301f); + p.lineTo(29.141f, 36.301f-7.161f); + p.curveTo(27.71f, 11.24f, 23.413f, 9.45f, 14.82f, 0.5f); + p.curveTo(6.229f, 9.45f, 1.932f, 11.24f, 0.5f, 29.141f); + p.lineTo(0.5f, 29.141f+7.161f); + float x = 0.5f; + float y = 29.141f+7.161f; + p.curveTo(5.729f+x, -1.789f+y, + 6.444f+x, -2.686f+y, + 14.32f+x, -3.58f+y); + p.curveTo(22.697f, 33.616f, 23.413f, 34.512f, 29.141f, 36.301f); + g.translate(0, -40f); + if (cell.xlut_relevant()) { + g.setColor(Color.white); + g.fill(p); + g.setColor(Color.red); + g.draw(p); + } + g.translate(34f, 0f); + if (cell.ylut_relevant()) { + g.setColor(Color.white); + g.fill(p); + g.setColor(Color.blue); + g.draw(p); + } + } finally { + g.setTransform(t); + } + } + public void drawMux() { + if (cell.c() != ZMUX) return; + g.setColor(Color.black); + g.drawLine(46, 54, 46+2, 54+5); + g.drawLine(46+2, 54+5, 60-2, 54+5); + g.drawLine(60-2, 54+5, 60, 54); + g.drawLine(60, 54, 46, 54); + } + public void drawRegister() { + } + public void drawBorder() { + g.setColor(Color.gray); + //g.drawLine(0, BEVEL, BEVEL, 0); + g.drawLine(BEVEL, 0, SIZE-BEVEL, 0); + //g.drawLine(SIZE-BEVEL, 0, SIZE, BEVEL); + g.drawLine(SIZE, BEVEL, SIZE, SIZE-BEVEL); + //g.drawLine(SIZE, SIZE-BEVEL, SIZE-BEVEL, SIZE); + g.drawLine(SIZE-BEVEL, SIZE, BEVEL, SIZE); + //g.drawLine(BEVEL, SIZE, 0, SIZE-BEVEL); + g.drawLine(0, SIZE-BEVEL, 0, BEVEL); + } + } + + public void paint(Graphics _g) { + Graphics2D g = (Graphics2D)_g; + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g.setStroke(new BasicStroke((float)0.5)); + g.translate(10, 0); + g.scale(1, -1); + g.translate(5, -1 * getHeight() + 10); + g.scale(scale,scale); + for(Cell c : cells) { + AffineTransform t = g.getTransform(); + g.translate( c._x * SIZE/* + (10 * (c._x/4))*/, c._y * SIZE/* + (10 * (c._y/4))*/); + c.g = g; + c.draw(); + c.g = null; + g.setTransform(t); + } + } + + double scale = 1.0; + + public void clear() { + Graphics2D g = (Graphics2D)getGraphics(); + //g.setColor(Color.black); + //g.setColor(Color.lightGray); + g.clearRect(0, 0, getWidth(), getHeight()); + } + + public void keyTyped(KeyEvent k) { + } + public void keyReleased(KeyEvent k) { + } + public void keyPressed(KeyEvent keyevent) { + char c = keyevent.getKeyChar(); + switch(c) { + case '+': scale += 0.1; clear(); paint(getGraphics()); return; + case '-': scale -= 0.1; clear(); paint(getGraphics()); return; + } + } + +} diff --git a/src/edu/berkeley/obits/device/atmel/At40k.java b/src/edu/berkeley/obits/device/atmel/At40k.java index c7aace0..828ad3e 100644 --- a/src/edu/berkeley/obits/device/atmel/At40k.java +++ b/src/edu/berkeley/obits/device/atmel/At40k.java @@ -51,6 +51,14 @@ public class At40k { this.col= horizontal ? (col & ~0x3) : col; this.row=!horizontal ? (row & ~0x3) : row; } + public boolean isDriven() { + // FIXME: bridging connections (horiz-to-vert) + for(int i=0; i<4; i++) + if (cell(horizontal ? col+i : col, + horizontal ? row : row+i).out(plane)) return true; + // FIXME: sector switchbox drivers + return false; + } private int z(int z) { return (horizontal ? 0x30 : 0x20) | z; } public int code(boolean topleft) { switch(plane) { @@ -146,6 +154,10 @@ public class At40k { public Cell west() { return cell(col-1, row); } public Cell north() { return cell(col, row+1); } public Cell south() { return cell(col, row-1); } + public Cell ne() { return cell(col+1, row+1); } + public Cell nw() { return cell(col-1, row+1); } + public Cell se() { return cell(col+1, row-1); } + public Cell sw() { return cell(col-1, row-1); } public Sector sector() { return new Sector(this); } public Cell(int col, int row) { @@ -301,6 +313,32 @@ public class At40k { dev.mode4(1, row, col, result, 0x34); } + public boolean xlut_relevant() { + if ((c()==XLUT || c()==ZMUX) && c_relevant()) return true; + if (xo()) return false; + if (nw() != null && nw().xi()==SE) return true; + if (ne() != null && ne().xi()==SW) return true; + if (sw() != null && sw().xi()==NE) return true; + if (se() != null && se().xi()==NW) return true; + return false; + } + public boolean ylut_relevant() { + if ((c()==YLUT || c()==ZMUX) && c_relevant()) return true; + if (yo()) return false; + if (north() != null && north().yi()==SOUTH) return true; + if (east() != null && east().yi()==WEST) return true; + if (south() != null && south().yi()==NORTH) return true; + if (west() != null && west().yi()==EAST) return true; + return false; + } + public boolean c_relevant() { + // FIXME: feedback line! + for(int i=0; i<5; i++) + if (out(i)) return true; + if (xo() || yo()) return true; + return false; + } + public void c(int source) { switch(source) { case XLUT: dev.mode4(1, row, col, 0x00, 0xc0); break; @@ -319,6 +357,8 @@ public class At40k { } public void b(boolean registered) { dev.mode4(1, row, col, 3, !registered); } public void f(boolean registered) { dev.mode4(1, row, col, 2, !registered); } + public boolean xo() { return (dev.mode4(1, row, col) & 0x01) != 0; } + public boolean yo() { return (dev.mode4(1, row, col) & 0x02) != 0; } public void xo(boolean center) { dev.mode4(1, row, col, 1, center); } public void yo(boolean center) { dev.mode4(1, row, col, 0, center); } public boolean b() { return (dev.mode4(1, row, col) >> 3)!=1; } @@ -326,6 +366,14 @@ public class At40k { public boolean x() { return (dev.mode4(1, row, col) >> 1)==1; } public boolean y() { return (dev.mode4(1, row, col) >> 0)==1; } + public int oe() { + switch (dev.mode4(0x02, row, col) & 0x3) { + case 0: return NONE; + case 1: return H4; + case 2: return V4; + default: throw new RuntimeException("invalid argument"); + } + } public void oe(int source) { switch(source) { case NONE: dev.mode4(0x02, row, col, 0, 0x3); break; diff --git a/src/edu/berkeley/obits/device/atmel/AtmelDevice.java b/src/edu/berkeley/obits/device/atmel/AtmelDevice.java index 50c5c47..27f6c36 100644 --- a/src/edu/berkeley/obits/device/atmel/AtmelDevice.java +++ b/src/edu/berkeley/obits/device/atmel/AtmelDevice.java @@ -29,9 +29,9 @@ public abstract class AtmelDevice extends Bits implements Device { public static final int L4 = 4; public static final int NORTH = 8; - public static final int SOUTH = 9; - public static final int EAST = 10; - public static final int WEST = 11; + public static final int WEST = 9; + public static final int SOUTH = 10; + public static final int EAST = 11; public static final int XLUT = 12; public static final int YLUT = 13; diff --git a/src/edu/berkeley/obits/device/atmel/AvrDrone.java b/src/edu/berkeley/obits/device/atmel/AvrDrone.java index 2e50094..fc65f01 100644 --- a/src/edu/berkeley/obits/device/atmel/AvrDrone.java +++ b/src/edu/berkeley/obits/device/atmel/AvrDrone.java @@ -15,6 +15,7 @@ public class AvrDrone extends AtmelDevice { final SerialPort sp; + public AvrDrone() { sp = null; in = null; out = null; } public AvrDrone(SerialPort sp) throws IOException, UnsupportedCommOperationException, InterruptedException, DeviceException { this.sp = sp; //sp.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); @@ -38,6 +39,7 @@ public class AvrDrone extends AtmelDevice { } public synchronized void scanFPGA(boolean on) throws DeviceException { + if (sp==null) return; try { if (on) { out.writeByte(3); @@ -50,6 +52,7 @@ public class AvrDrone extends AtmelDevice { // fixme! public static int retval = 0; public synchronized int readCount() throws DeviceException { + if (sp==null) return 0; try { if (reader != null) { reader.start(); @@ -85,7 +88,7 @@ public class AvrDrone extends AtmelDevice { public void run() { while(true) { try { - byte b = in.readByte(); + byte b = sp==null ? 0 : in.readByte(); ByteCallback bc = (ByteCallback)callbacks.remove(0); bc.call(b); } catch (Exception e) { @@ -98,8 +101,10 @@ public class AvrDrone extends AtmelDevice { public synchronized void readBus(ByteCallback bc) throws DeviceException { try { callbacks.add(bc); - out.writeByte(2); - out.flush(); + if (sp!=null) { + out.writeByte(2); + out.flush(); + } if (reader != null) { reader.start(); reader = null; @@ -110,8 +115,10 @@ public class AvrDrone extends AtmelDevice { public synchronized void readInterrupts(ByteCallback bc) throws DeviceException { try { callbacks.add(bc); - out.writeByte(6); - out.flush(); + if (sp!=null) { + out.writeByte(6); + out.flush(); + } if (reader != null) { reader.start(); reader = null; @@ -120,6 +127,7 @@ public class AvrDrone extends AtmelDevice { } public synchronized void reset() throws DeviceException { + if (sp==null) return; try { Log.info(this, "resetting device"); sp.setDTR(true); @@ -165,18 +173,20 @@ public class AvrDrone extends AtmelDevice { boolean xdec = x==lastx-1; //System.out.println(zchange + " " + ychange + " " + xchange); - out.writeByte(0x80 - | (zinc?0x40:zdec?0x04:zchange?0x44:0x00) - | (yinc?0x20:ydec?0x02:ychange?0x22:0x00) - | (xinc?0x10:xdec?0x01:xchange?0x11:0x00)); - if (!zinc && !zdec && zchange) out.writeByte(z); else save++; - if (!yinc && !ydec && ychange) out.writeByte(y); else save++; - if (!xinc && !xdec && xchange) out.writeByte(x); else save++; - saveof++; - lastz = z; - lastx = x; - lasty = y; - out.writeByte(d); + if (sp!=null) { + out.writeByte(0x80 + | (zinc?0x40:zdec?0x04:zchange?0x44:0x00) + | (yinc?0x20:ydec?0x02:ychange?0x22:0x00) + | (xinc?0x10:xdec?0x01:xchange?0x11:0x00)); + if (!zinc && !zdec && zchange) out.writeByte(z); else save++; + if (!yinc && !ydec && ychange) out.writeByte(y); else save++; + if (!xinc && !xdec && xchange) out.writeByte(x); else save++; + saveof++; + lastz = z; + lastx = x; + lasty = y; + out.writeByte(d); + } if (cache[x & 0xff]==null) cache[x & 0xff] = new byte[24][]; if (cache[x & 0xff][y & 0xff]==null) cache[x & 0xff][y & 0xff] = new byte[256]; cache[x & 0xff][y & 0xff][z & 0xff] = (byte)(d & 0xff); @@ -184,6 +194,7 @@ public class AvrDrone extends AtmelDevice { } public synchronized void flush() throws DeviceException { + if (sp==null) return; try { out.flush(); } catch (IOException e) { throw new DeviceException(e); } -- 1.7.10.4