diff --git a/src/replicatorg/drivers/gen3/Makerbot4GAlternateDriver.java b/src/replicatorg/drivers/gen3/Makerbot4GAlternateDriver.java index 3e60a13b6..d1a5c4846 100644 --- a/src/replicatorg/drivers/gen3/Makerbot4GAlternateDriver.java +++ b/src/replicatorg/drivers/gen3/Makerbot4GAlternateDriver.java @@ -20,11 +20,11 @@ public class Makerbot4GAlternateDriver extends Makerbot4GDriver { private boolean stepperExtruderFanEnabled = false; - public String getDriverName() { + @Override public String getDriverName() { return "Makerbot4GAlternate"; } - public void reset() { + @Override public void reset() { // We should poll the machine for it's state here, but it is more important to have the // fan on than off. stepperExtruderFanEnabled = false; @@ -32,13 +32,10 @@ public void reset() { super.reset(); } - /** The excess, in steps, from previous operations. */ - protected Point5d stepExcess = new Point5d(); - /** * Overloaded to manage a hijacked axis and run this axis in relative mode instead of the extruder DC motor */ - public void queuePoint(Point5d p) throws RetryException { + @Override public void queuePoint(Point5d p) throws RetryException { // If we don't know our current position, make this move an old-style move, ignoring any hijacked axes. if (positionLost()) { Base.logger.fine("Position invalid, reverting to default speed for next motion"); @@ -69,10 +66,7 @@ public void queuePoint(Point5d p) throws RetryException { // okay, send it off! // TODO: bug: We move all axes (even ones that shouldn't be moved) How to avoid? - Point5d excess = new Point5d(stepExcess); - queueAbsolutePoint(machine.mmToSteps(filteredPoint, excess), longestDDA); - // Only update excess if no retry was thrown. - stepExcess = excess; + queueAbsolutePoint(machine.mmToSteps(filteredPoint), longestDDA); // Finally, recored the position, and mark it as valid. setInternalPosition(filteredPoint); } else { @@ -100,9 +94,8 @@ public void queuePoint(Point5d p) throws RetryException { delta.add(axesmovement); filteredpoint.add(axesmovement); - Point5d excess = new Point5d(stepExcess); // Calculate time for move in usec - Point5d steps = machine.mmToSteps(filteredpoint,excess); + Point5d steps = machine.mmToSteps(filteredpoint); // okay, send it off! // The 4. and 5. dimensions doesn't have a spatial interpretation. Calculate time in 3D space @@ -110,9 +103,6 @@ public void queuePoint(Point5d p) throws RetryException { queueNewPoint(steps, (long) (60 * 1000 * 1000 * minutes), relative); - // Only update excess if no retry was thrown. - stepExcess = excess; - setInternalPosition(filteredpoint); } } @@ -122,7 +112,7 @@ public void queuePoint(Point5d p) throws RetryException { * In legacy use, delayed while a DC motor ran. For compatiblity, this function * creates a Point5D to do 'extrude while sitting still'. */ - public void delay(long millis) throws RetryException { + @Override public void delay(long millis) throws RetryException { Base.logger.finer("Delaying " + millis + " millis."); Point5d steps = pointsFromHijackedAxes( machine.currentTool(), millis / 60000d); @@ -233,7 +223,7 @@ private Point5d pointsFromHijackedAxes(ToolModel curTool, double minutes) { return steps; } - public void stop(boolean abort) { + @Override public void stop(boolean abort) { // Record the toolstate as off, so we don't excite the extruder motor in future moves. machine.currentTool().disableMotor(); @@ -274,38 +264,41 @@ protected void queueNewPoint(Point5d steps, long us, int relative) throws RetryE /** * Overridden to not talk to the DC motor driver. This driver is reused for the stepper motor fan */ - public void enableMotor() throws RetryException { - machine.currentTool().enableMotor(); + @Override public void enableMotor(int toolhead) throws RetryException { + if (toolhead == -1 ) toolhead = machine.currentTool().getIndex(); + machine.getTool(toolhead).enableMotor(); } /** * Overridden to not talk to the DC motor driver. This driver is reused for the stepper motor fan */ - public void disableMotor() throws RetryException { - machine.currentTool().disableMotor(); + @Override public void disableMotor(int toolhead) throws RetryException { + if (toolhead == -1 ) toolhead = machine.currentTool().getIndex(); + + machine.getTool(toolhead).disableMotor(); } /** * Overridden to not talk to the DC motor driver. This driver is reused for the stepper motor fan */ - public void setMotorSpeedPWM(int pwm) throws RetryException { + @Override public void setMotorSpeedPWM(int pwm) throws RetryException { machine.currentTool().setMotorSpeedPWM(pwm); } /** * Overridden to not talk to the DC motor driver. This driver is reused for the stepper motor fan */ - public void setMotorRPM(double rpm, int toolhead) throws RetryException { + @Override public void setMotorRPM(double rpm, int toolhead) throws RetryException { machine.currentTool().setMotorSpeedRPM(rpm); } - public void enableDrives() throws RetryException { + @Override public void enableDrives() throws RetryException { enableStepperExtruderFan(true); super.enableDrives(); } - public void disableDrives() throws RetryException { + @Override public void disableDrives() throws RetryException { enableStepperExtruderFan(false); super.disableDrives(); @@ -315,7 +308,7 @@ public void disableDrives() throws RetryException { * Will turn on/off the stepper extruder fan if it's not already in the correct state. * */ - public void enableStepperExtruderFan(boolean enabled) throws RetryException { + @Override public void enableStepperExtruderFan(boolean enabled) throws RetryException { // Always re-enable the fan when if (this.stepperExtruderFanEnabled == enabled) return; @@ -352,11 +345,10 @@ public void enableStepperExtruderFan(boolean enabled) throws RetryException { /// This is a list of which axis are hijacked for extruder use. EnumMap extruderHijackedMap = new EnumMap(AxisId.class); - @Override /** * When the machine is set for this driver, some toolheads may poach the an extrusion axis. */ - public void setMachine(MachineModel m) { + @Override public void setMachine(MachineModel m) { super.setMachine(m); for (ToolModel tm : m.getTools()) { Element e = (Element)tm.getXml(); @@ -380,12 +372,11 @@ public void setMachine(MachineModel m) { } } - @Override /** * Overridden to not ask the board for the RPM as it would report the RPM from the extruder * controller, which doesn't know about it in this case. */ - public double getMotorRPM() { + @Override public double getMotorRPM() { double rpm = machine.currentTool().getMotorSpeedRPM(); machine.currentTool().setMotorSpeedReadingRPM(rpm); return rpm; diff --git a/src/replicatorg/drivers/gen3/MightyBoard.java b/src/replicatorg/drivers/gen3/MightyBoard.java index 4bbfeba7d..9f5119e15 100644 --- a/src/replicatorg/drivers/gen3/MightyBoard.java +++ b/src/replicatorg/drivers/gen3/MightyBoard.java @@ -475,8 +475,7 @@ public void queuePoint(final Point5d p) throws RetryException { } // calculate absolute position of target in steps - Point5d excess = new Point5d(stepExcess); - Point5d steps = machine.mmToSteps(target,excess); + Point5d steps = machine.mmToSteps(target); double usec = (60 * 1000 * 1000 * minutes); @@ -486,9 +485,6 @@ public void queuePoint(final Point5d p) throws RetryException { int relativeAxes = (1 << AxisId.A.getIndex()) | (1 << AxisId.B.getIndex()); queueNewPoint(steps, (long) usec, relativeAxes); - // Only update excess if no retry was thrown. - stepExcess = excess; - // because of the hinky stuff we've been doing with A & B axes, just pretend we've // moved where we thought we were moving Point5d fakeOut = new Point5d(target); @@ -1023,7 +1019,6 @@ public boolean setConnectedToolIndex(int index) { } - @Override @Deprecated protected void writeToToolEEPROM(int offset, byte[] data) { writeToToolEEPROM(offset, data, machine.currentTool().getIndex()); @@ -1186,7 +1181,6 @@ public int getT0(int which, int toolIndex) { return val; } - @Override @Deprecated protected int read16FromToolEEPROM(int offset, int defaultValue) { return read16FromToolEEPROM(offset, defaultValue, machine.currentTool().getIndex()); diff --git a/src/replicatorg/drivers/gen3/Sanguino3GDriver.java b/src/replicatorg/drivers/gen3/Sanguino3GDriver.java index c488d255f..b0bc4e90b 100644 --- a/src/replicatorg/drivers/gen3/Sanguino3GDriver.java +++ b/src/replicatorg/drivers/gen3/Sanguino3GDriver.java @@ -1003,12 +1003,6 @@ public void setMotorSpeedPWM(int pwm, int toolhead) throws RetryException { super.setMotorSpeedPWM(pwm, toolhead); } - @Deprecated - public void enableMotor() throws RetryException { - /// toolhead -1 indicate auto-detect - this.enableMotor(-1); - } - public void enableMotor(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1060,10 +1054,6 @@ public void disableMotor(int toolhead) throws RetryException { super.disableMotor(toolhead); } - @Deprecated - public int getMotorSpeedPWM() { - return this.getMotorSpeedPWM(machine.currentTool().getIndex()); - } public int getMotorSpeedPWM(int toolhead) { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1118,11 +1108,6 @@ public double getMotorRPM(int toolhead) { } - @Deprecated - public void readToolStatus() { - this.readToolStatus(machine.currentTool().getIndex()); - } - public void readToolStatus(int toolhead) { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1151,7 +1136,7 @@ public void readToolStatus(int toolhead) { + (((status & 0x01) != 0) ? "READY" : "NOT READY") + " "); } - readToolPIDState(); + readToolPIDState(toolhead); } // TODO: This doesn't belong here @@ -1163,10 +1148,6 @@ private int fixSigned(int value) { return value; } - @Deprecated - public void readToolPIDState() { - this.readToolPIDState(machine.currentTool().getIndex()); - } // TODO: Implement a way for this to reach the outside public void readToolPIDState(int toolhead) { @@ -1266,10 +1247,6 @@ public void setServoPos(int index, double degree, int toolhead) throws RetryExce /*************************************************************************** * Spindle interface functions **************************************************************************/ - @Deprecated - public void setSpindleRPM(double rpm) throws RetryException { - this.setSpindleRPM(rpm, machine.currentTool().getIndex() ); - } public void setSpindleRPM(double rpm, int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1296,11 +1273,6 @@ public void setSpindleRPM(double rpm, int toolhead) throws RetryException { super.setSpindleRPM(rpm, toolhead); } - @Deprecated - public void setSpindleSpeedPWM(int pwm) throws RetryException { - this.setSpindleSpeedPWM(pwm, machine.currentTool().getIndex()); - } - public void setSpindleSpeedPWM(int pwm, int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1320,11 +1292,6 @@ public void setSpindleSpeedPWM(int pwm, int toolhead) throws RetryException { super.setSpindleSpeedPWM(pwm, toolhead); } - @Deprecated - public void enableSpindle() throws RetryException { - this.enableSpindle(machine.currentTool().getIndex()); - } - public void enableSpindle(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1352,11 +1319,6 @@ public void enableSpindle(int toolhead) throws RetryException { super.enableSpindle(toolhead); } - @Deprecated - public void disableSpindle() throws RetryException { - disableSpindle(machine.currentTool().getIndex()); - } - public void disableSpindle(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1380,11 +1342,6 @@ public void disableSpindle(int toolhead) throws RetryException { super.disableSpindle(toolhead); } - @Deprecated - public double getSpindleSpeedRPM() throws RetryException { - return this.getSpindleSpeedRPM(machine.currentTool().getIndex()); - } - public double getSpindleSpeedRPM(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1408,11 +1365,6 @@ public double getSpindleSpeedRPM(int toolhead) throws RetryException { return rpm; } - @Deprecated - public int getSpindleSpeedPWM() { - return this.getSpindleSpeedPWM(machine.currentTool().getIndex()); - } - public int getSpindleSpeedPWM(int toolhead) { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1440,11 +1392,6 @@ public int getSpindleSpeedPWM(int toolhead) { * Temperature interface functions * @throws RetryException **************************************************************************/ - @Deprecated - public void setTemperature(double temperature) throws RetryException { - this.setTemperature(temperature, machine.currentTool().getIndex()); - } - public void setTemperature(double temperature, int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1467,12 +1414,6 @@ public void setTemperature(double temperature, int toolhead) throws RetryExcepti super.setTemperature(temperature, toolhead); } - @Deprecated - public void readTemperature() { - readAllTemperatures(); /// for safety, read all the temps we can - //readTemperature(machine.currentTool().getIndex()); - } - @Override public void readAllTemperatures() { Vector tools = machine.getTools(); @@ -1519,11 +1460,6 @@ else if (pr.isEmpty()) * @throws RetryException **************************************************************************/ - @Deprecated - public void setPlatformTemperature(double temperature) throws RetryException { - setAllPlatformTemperatures(temperature); - } - public void setPlatformTemperature(double temperature, int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1553,11 +1489,6 @@ public void setAllPlatformTemperatures(double temperature) throws RetryException } } - @Deprecated - public void readPlatformTemperature() { - this.readAllPlatformTemperatures(); - } - public void readPlatformTemperature(int toolhead) { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. if(toolhead == -1 ) toolhead = machine.currentTool().getIndex(); @@ -1622,11 +1553,6 @@ public void disableMistCoolant() { * * @throws RetryException **************************************************************************/ - @Deprecated - public void enableFan() throws RetryException { - this.enableFan(machine.currentTool().getIndex() ); - } - public void enableFan(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1645,10 +1571,6 @@ public void enableFan(int toolhead) throws RetryException { super.enableFan(toolhead); } - @Deprecated - public void disableFan() throws RetryException { - this.disableFan(machine.currentTool().getIndex()); - } public void disableFan(int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1667,12 +1589,6 @@ public void disableFan(int toolhead) throws RetryException { super.disableFan(toolhead); } - @Deprecated - public void setAutomatedBuildPlatformRunning(boolean state) - throws RetryException { - this.setAutomatedBuildPlatformRunning(state, machine.currentTool().getIndex()); - } - public void setAutomatedBuildPlatformRunning(boolean state, int toolhead) throws RetryException { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. @@ -1698,11 +1614,6 @@ public void setAutomatedBuildPlatformRunning(boolean state, int toolhead) * * @throws RetryException **************************************************************************/ - @Deprecated - public void openValve() throws RetryException { - openValve(machine.currentTool().getIndex()); - } - public void openValve(int toolhead) throws RetryException { Base.logger.fine("Opening valve"); @@ -1722,11 +1633,6 @@ public void openValve(int toolhead) throws RetryException { } - @Deprecated - public void closeValve() throws RetryException { - closeValve(machine.currentTool().getIndex()); - } - public void closeValve(int toolhead) throws RetryException { Base.logger.fine("Closing valve"); @@ -1939,11 +1845,6 @@ protected void writeToEEPROM(int offset, byte[] data) { assert pr.get8() == data.length; } - @Deprecated - protected byte[] readFromToolEEPROM(int offset, int len) - { - return readFromToolEEPROM(offset, len, machine.currentTool().getIndex()); - } protected byte[] readFromToolEEPROM(int offset, int len, int toolhead) { @@ -1972,16 +1873,6 @@ protected byte[] readFromToolEEPROM(int offset, int len, int toolhead) { return null; } - /** - * - * @param offset - * @param data - */ - @Deprecated - protected void writeToToolEEPROM(int offset, byte[] data) { - writeToToolEEPROM(offset, data, machine.currentTool().getIndex()); - } - /** * * @param offset @@ -2556,11 +2447,6 @@ final private static class CoolingFanOffsets { }; - @Deprecated - protected int read16FromToolEEPROM(int offset, int defaultValue) { - return read16FromToolEEPROM(offset, defaultValue, machine.currentTool().getIndex()); - } - protected int read16FromToolEEPROM(int offset, int defaultValue, int toolhead) { /// toolhead -1 indicate auto-detect.Fast hack to get software out.. if(toolhead == -1 ) toolhead = machine.currentTool().getIndex(); @@ -2729,11 +2615,6 @@ public void setEstopConfig(EstopType estop) { writeToEEPROM(Sanguino3GEEPRPOM.EEPROM_ESTOP_CONFIGURATION_OFFSET, b); } - @Deprecated - public double getPlatformTemperatureSetting() { - return this.getPlatformTemperatureSetting(machine.currentTool().getIndex()); - } - public double getPlatformTemperatureSetting(int toolhead) { /// toolhead -1 indicates auto-detect. Fast hack to get software out... if(toolhead == -1 ) toolhead = machine.currentTool().getIndex(); @@ -2753,11 +2634,6 @@ public double getPlatformTemperatureSetting(int toolhead) { return machine.getTool(toolhead).getPlatformTargetTemperature(); } - @Deprecated - public double getTemperatureSetting() { - return this.getTemperatureSetting(machine.currentTool().getIndex()); - } - public double getTemperatureSetting(int toolhead) { /// toolhead -1 indicates auto-detect. Fast hack to get software out... if(toolhead == -1 ) toolhead = machine.currentTool().getIndex(); diff --git a/test/lib/cglib-nodep-2.2.2.jar b/test/lib/cglib-nodep-2.2.2.jar new file mode 100644 index 000000000..02d81e880 Binary files /dev/null and b/test/lib/cglib-nodep-2.2.2.jar differ diff --git a/test/lib/easymock-3.1.jar b/test/lib/easymock-3.1.jar new file mode 100644 index 000000000..f56f07ace Binary files /dev/null and b/test/lib/easymock-3.1.jar differ diff --git a/test/lib/objenesis-1.2.jar b/test/lib/objenesis-1.2.jar new file mode 100644 index 000000000..45cb64168 Binary files /dev/null and b/test/lib/objenesis-1.2.jar differ diff --git a/unittest/machineTests/MachineLoaderTest.java b/unittest/machineTests/MachineLoaderTest.java index f7ca170e1..c01863f62 100644 --- a/unittest/machineTests/MachineLoaderTest.java +++ b/unittest/machineTests/MachineLoaderTest.java @@ -17,6 +17,9 @@ import replicatorg.machine.MachineStateChangeEvent; import replicatorg.machine.MachineToolStatusEvent; +/* + * NOTE: as of 2012-03-08 this test is known to fail! + */ public class MachineLoaderTest { // Simple class to collect Machine events so they can be read back later. public class TestMachineListener implements MachineListener { @@ -103,25 +106,25 @@ public void testGetDriver() { @Test public void testLoad() { // Try loading a garbage machine - assertFalse(loader.getMachineInterface("fake machine")); + assertNull(loader.getMachineInterface("fake machine")); // Now try loading a known good machine - assertTrue(loader.getMachineInterface("Cupcake Basic")); + assertNotNull(loader.getMachineInterface("Cupcake Basic")); // Test that the isLoaded() function actually works assertTrue(loader.isLoaded()); // Now, try loading another garbage machine on top of the known good one. - assertFalse(loader.getMachineInterface("fake machine")); + assertNull(loader.getMachineInterface("fake machine")); // Finally, load the good one again to make sure it can recover. - assertTrue(loader.getMachineInterface("Cupcake Basic")); + assertNotNull(loader.getMachineInterface("Cupcake Basic")); } @Test public void testUnload() { // See if we can bring up and then dispose of a machine - assertTrue(loader.getMachineInterface("Cupcake Basic")); + assertNotNull(loader.getMachineInterface("Cupcake Basic")); loader.unload(); @@ -136,7 +139,7 @@ public void testConnectionInvalidPort() { // This should give us a couple of messages: CONNECTING ERROR // Make sure that we get them both back in order, within a reasonable time. // Finally, unload the machine to receive NOT_ATTACHED. - assertTrue(loader.getMachineInterface("Cupcake Basic")); + assertNotNull(loader.getMachineInterface("Cupcake Basic")); loader.connect(""); event = listener.getMachineStateChangedEvent(commTimeout); @@ -174,7 +177,7 @@ public void testConnectionKnownGoodPort() { // Finally, unload the machine to receive NOT_ATTACHED. for(int i = 0; i < 1; i++) { Base.logger.info("i = " + i ); - assertTrue(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); + assertNotNull(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); loader.connect("/dev/ttyUSB0"); event = listener.getMachineStateChangedEvent(commTimeout); @@ -204,7 +207,7 @@ public void testConnectionKnownGoodPort() { public void testDisconnect() { MachineStateChangeEvent event; - assertTrue(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); + assertNotNull(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); loader.connect("/dev/ttyUSB0"); event = listener.getMachineStateChangedEvent(commTimeout); @@ -241,7 +244,7 @@ public void testDisconnect() { public void testUserDisconnect() { MachineStateChangeEvent event; - assertTrue(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); + assertNotNull(loader.getMachineInterface("Thingomatic w/ HBP and Stepstruder MK6")); loader.connect("/dev/ttyUSB0"); event = listener.getMachineStateChangedEvent(commTimeout); diff --git a/unittest/replicatorg/drivers/gen3/Makerbot4GAlternateDriverTest.java b/unittest/replicatorg/drivers/gen3/Makerbot4GAlternateDriverTest.java new file mode 100644 index 000000000..37f274a6e --- /dev/null +++ b/unittest/replicatorg/drivers/gen3/Makerbot4GAlternateDriverTest.java @@ -0,0 +1,271 @@ +package replicatorg.drivers.gen3; + +import static org.easymock.EasyMock.*; + +import java.io.StringReader; +import java.lang.reflect.Field; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.InputSource; + +import replicatorg.app.util.serial.Serial; +import replicatorg.drivers.RetryException; +import replicatorg.drivers.SerialDriver; +import replicatorg.machine.MachineCallbackHandler; +import replicatorg.machine.MachineProgressEvent; +import replicatorg.machine.MachineStateChangeEvent; +import replicatorg.machine.MachineToolStatusEvent; +import replicatorg.machine.model.MachineModel; +import replicatorg.util.Point5d; + +/** + * Exercises the {@link Makerbot4GAlternateDriver}. + *

+ * The driver wasn't designed with testing in mind, so I had to + * pound it pretty hard to fit it into this jig. If you're not + * fluent in EasyMock this test may be somewhat confusing, and + * for that I apologize. These are the compromises we must make + * to test legacy code. + * + * @author cbiffle + */ +public class Makerbot4GAlternateDriverTest { + /* + * Yeah, I copied and pasted the machine def out of Rob Giseburt's XML file. + * This avoids a filesystem dependency in the unit test. + */ + private static final String CANNED_MACHINE_DEF = + "" + + "3G 5D (RPM) Cupcake (Gen3 XYZ, Mk5/6+Gen4 Extruder)" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "38400" + + "8" + + "" + + "" + + "" + + "" + + "(Turn off steppers after a build.)" + + "M18" + + "" + + ""; + + Serial serial; + MachineCallbackHandler machineCallbackHandler; + Makerbot4GAlternateDriver driver; + + @Before public void setUp() throws Exception { + MachineModel mm = new MachineModel(); + mm.loadXML( + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new InputSource(new StringReader(CANNED_MACHINE_DEF))) + .getDocumentElement()); + + System.out.println("steps per mm: " + mm.getStepsPerMM()); + + /* + * There are two facilities we need to mock to evaluate the + * driver: the serial port, and the MachineCallbackHandler, + * which is used to inform the program of machine status + * changes. We only care about the former. + */ + serial = createMock(Serial.class); + machineCallbackHandler = createMock(MachineCallbackHandler.class); + prepareMachineCallbackHandler(); + replayAll(); + + driver = new Makerbot4GAlternateDriver(); + driver.setMachine(mm); + + // Class design gives us no choice but to break out the chainsaw: + Field serialField = SerialDriver.class.getDeclaredField("serial"); + serialField.setAccessible(true); + serialField.set(driver, serial); + + // Check that the driver hasn't done anything silly during init. + verifyAll(); + resetAll(); + + prepareMachineCallbackHandler(); + } + + /* + * Stubs out the relevant methods in MCH. We don't care about the + * interaction with this object. + */ + private void prepareMachineCallbackHandler() { + machineCallbackHandler.schedule(anyObject(MachineProgressEvent.class)); + expectLastCall().asStub(); + + machineCallbackHandler.schedule(anyObject(MachineStateChangeEvent.class)); + expectLastCall().asStub(); + + machineCallbackHandler.schedule(anyObject(MachineToolStatusEvent.class)); + expectLastCall().asStub(); + } + + @Test public void testZeroLengthMove() throws RetryException { + serial.write(aryEq(makeQueuePointExt(0, 0, 0, 0, 0, 1250))); + prepareOkResponse(); + replayAll(); + + driver.queuePoint(new Point5d(0, 0, 0, 0, 0)); + verifyAll(); + } + + @Test public void testFractionalStepPattern() throws RetryException { + /* + * This test alternates back and forth between the origin and a + * position on positive X. When the excess-tracking code is + * enabled, it demonstrates how dithering hampers repeatability. + */ + final double X = 1.57; // Where we're headed + final int S = 18; // Equivalent in steps + final int US = 18840; // Duration of move at default feedrate + final int A_AXIS = (1 << 3); // Relative-motion flag for A + + /* + * The machine we've selected has 11.767463 steps/mm on X. + * 1.57 * 11.767463 = 18.4749169. + * The excess tracking code rounds this to 18 and accumulates + * the 0.4746169 difference. It takes only three moves for + * this to surface as an unintended step; ITERATIONS records + * the second two (the ones that generate QUEUE_POINT_NEW). + */ + final int ITERATIONS = 2; + + /* + * Here's what we'll see at the serial port: + */ + + // First, the positionLost() logic generates QUEUE_POINT_EXT. + serial.write(aryEq(makeQueuePointExt(0, 0, 0, 0, 0, 1250))); + prepareOkResponse(); // "Machine" acknowledges + + // Next, the driver emits a sequence of QUEUE_POINT_NEW. + for (int i = 0; i < ITERATIONS; ++i) { + serial.write(aryEq(makeQueuePointNew(S, 0, 0, 0, 0, US, A_AXIS))); + prepareOkResponse(); + serial.write(aryEq(makeQueuePointNew(0, 0, 0, 0, 0, US, A_AXIS))); + prepareOkResponse(); + } + replayAll(); + + driver.setFeedrate(5000); + driver.queuePoint(new Point5d(0, 0, 0, 0, 0)); + + for (int i = 0; i < ITERATIONS; ++i) { + driver.queuePoint(new Point5d(X, 0, 0, 0, 0)); + driver.queuePoint(new Point5d(0, 0, 0, 0, 0)); + } + verifyAll(); + } + + @Test public void testSideToSideMoves() throws RetryException { + /* + * This tests the supposition that moves along an axis should + * *never* induce moves on another axis. + * + * When the excess-tracking code is enabled, it demonstrates + * the appearance of "phantom" Z moves during horizontal + * motion along X. + * + * The machine we've selected has 320.0 steps/mm on Z. We + * choose a Z height of 1.57 mm, or in steps, 1.57 * 320 = 502.4. + * The excess-tracking code rounds this to 502 and accumulates + * the 0.4 difference. By the second motion, this passes 0.5 + * and causes the Z position to get rounded up one step, + * inducing a vertical move. From then on each motion along + * X produces opposing vertical motions of one step. + */ + final double X = 1.57; // Where we're headed on X in mm + final int SX = 18; // ...and in steps. + final double Z = X; // Constant Z position in mm + final int SZ = 502; // ...and in steps. + final int US = 37680; // Duration of moves in microseconds + final int A_AXIS = (1 << 3); // Relative motion flag on A + + /* + * Here's what we expect on the serial port: + */ + + // Initial point emitted as QUEUE_POINT_EXT. + serial.write(aryEq(makeQueuePointExt(SX, 0, SZ, 0, 0, 1250))); + prepareOkResponse(); + + // Subsequent two points are QUEUE_POINT_NEW. Z is constant. + serial.write(aryEq(makeQueuePointNew(-SX, 0, SZ, 0, 0, US, A_AXIS))); + prepareOkResponse(); + serial.write(aryEq(makeQueuePointNew(SX, 0, SZ, 0, 0, US, A_AXIS))); + prepareOkResponse(); + replayAll(); + + driver.setFeedrate(5000); + driver.queuePoint(new Point5d(X, 0, Z, 0, 0)); + driver.queuePoint(new Point5d(-X, 0, Z, 0, 0)); + driver.queuePoint(new Point5d(X, 0, Z, 0, 0)); + verifyAll(); + } + + private byte[] makeQueuePointExt(int x, int y, int z, int a, int b, int micros) { + PacketBuilder pb = new PacketBuilder(MotherboardCommandCode.QUEUE_POINT_EXT.getCode()); + pb.add32(x); + pb.add32(y); + pb.add32(z); + pb.add32(a); + pb.add32(b); + pb.add32(micros); + + return pb.getPacket(); + } + + private byte[] makeQueuePointNew(int x, int y, int z, int a, int b, int micros, int relative) { + PacketBuilder pb = new PacketBuilder(MotherboardCommandCode.QUEUE_POINT_NEW.getCode()); + + // just add them in now. + pb.add32(x); + pb.add32(y); + pb.add32(z); + pb.add32(a); + pb.add32(b); + pb.add32(micros); + pb.add8(relative); + + return pb.getPacket(); + } + + private void prepareOkResponse() { + for (byte b : new PacketBuilder(0x01).getPacket()) { + expect(serial.read()).andReturn((int) b); + } + } + + private void replayAll() { + replay(machineCallbackHandler, serial); + } + + private void verifyAll() { + verify(machineCallbackHandler, serial); + } + + private void resetAll() { + reset(machineCallbackHandler, serial); + } +}