diff --git a/.cproject b/.cproject index 868045e8e2..9148db89bc 100644 --- a/.cproject +++ b/.cproject @@ -106,7 +106,7 @@ - + @@ -216,7 +216,6 @@ - @@ -231,7 +230,7 @@ - + @@ -337,7 +336,6 @@ - @@ -353,7 +351,7 @@ - + @@ -368,9 +366,11 @@ + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index a324ff3331..02bb3c1190 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + @@ -27,7 +27,7 @@ - + diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index 56c0bff4d4..e296b81082 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -5,9 +5,6 @@ environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.9764 environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/LINK_FLAGS_2/delimiter=; environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/LINK_FLAGS_2/operation=append environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/LINK_FLAGS_2/value=-Wl,--end-group -lm -gcc -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/PATH/delimiter=; -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/PATH/operation=replace -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/PATH/value=C\:/Arduino-1.5.8/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/;C\:/Program Files (x86)/Java/jre7/bin/client;C\:/Program Files (x86)/Java/jre7/bin;C\:/Program Files (x86)/Java/jre7/lib/i386;C\:\\Windows\\system32;C\:\\Windows;C\:\\Windows\\System32\\Wbem;C\:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\Common Files\\Sage SData\\;C\:\\Program Files (x86)\\Common Files\\Sage SBD\\;C\:\\Program Files (x86)\\GNU\\GnuPG\\pub;C\:\\Program Files (x86)\\MiKTeX 2.9\\miktex\\bin\\;C\:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C\:\\WINDOWS\\system32;C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;C\:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\ATI Technologies\\ATI.ACE\\Core-Static;C\:\\Program Files (x86)\\AMD\\ATI.ACE\\Core-Static;C\:\\Strawberry\\c\\bin;C\:\\Strawberry\\perl\\site\\bin;C\:\\Strawberry\\perl\\bin;C\:\\Program Files\\nodejs\\;C\:\\Program Files (x86)\\Skype\\Phone\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15\\drv\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15;C\:\\SPARK\\gpl-2014\\bin;C\:\\GNAT\\2014\\bin;C\:\\Bin;C\:\\Python27;C\:\\Users\\David\\AppData\\Roaming\\npm;C\:\\eclipse-juno environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/append=true environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451/appendContributed=true environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/LINK_FLAGS_1/delimiter=; @@ -16,9 +13,6 @@ environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.9764 environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/LINK_FLAGS_2/delimiter=; environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/LINK_FLAGS_2/operation=append environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/LINK_FLAGS_2/value=-Wl,--end-group -lm -gcc -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/PATH/delimiter=; -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/PATH/operation=replace -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/PATH/value=C\:/Arduino-1.5.8/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/;C\:/Program Files (x86)/Java/jre7/bin/client;C\:/Program Files (x86)/Java/jre7/bin;C\:/Program Files (x86)/Java/jre7/lib/i386;C\:\\Windows\\system32;C\:\\Windows;C\:\\Windows\\System32\\Wbem;C\:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\Common Files\\Sage SData\\;C\:\\Program Files (x86)\\Common Files\\Sage SBD\\;C\:\\Program Files (x86)\\GNU\\GnuPG\\pub;C\:\\Program Files (x86)\\MiKTeX 2.9\\miktex\\bin\\;C\:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C\:\\WINDOWS\\system32;C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;C\:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\ATI Technologies\\ATI.ACE\\Core-Static;C\:\\Program Files (x86)\\AMD\\ATI.ACE\\Core-Static;C\:\\Strawberry\\c\\bin;C\:\\Strawberry\\perl\\site\\bin;C\:\\Strawberry\\perl\\bin;C\:\\Program Files\\nodejs\\;C\:\\Program Files (x86)\\Skype\\Phone\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15\\drv\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15;C\:\\SPARK\\gpl-2014\\bin;C\:\\GNAT\\2014\\bin;C\:\\Bin;C\:\\Python27;C\:\\Users\\David\\AppData\\Roaming\\npm;C\:\\eclipse-juno environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/append=true environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850/appendContributed=true environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/LINK_FLAGS_1/delimiter=; @@ -27,8 +21,5 @@ environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/LINK environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/LINK_FLAGS_2/delimiter=; environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/LINK_FLAGS_2/operation=append environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/LINK_FLAGS_2/value=-Wl,--end-group -lm -gcc -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/PATH/delimiter=; -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/PATH/operation=replace -environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/PATH/value=C\:/Arduino-1.5.8/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/;C\:/Program Files (x86)/Java/jre7/bin/client;C\:/Program Files (x86)/Java/jre7/bin;C\:/Program Files (x86)/Java/jre7/lib/i386;C\:\\Windows\\system32;C\:\\Windows;C\:\\Windows\\System32\\Wbem;C\:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\Common Files\\Sage SData\\;C\:\\Program Files (x86)\\Common Files\\Sage SBD\\;C\:\\Program Files (x86)\\GNU\\GnuPG\\pub;C\:\\Program Files (x86)\\MiKTeX 2.9\\miktex\\bin\\;C\:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C\:\\WINDOWS\\system32;C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;C\:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\ATI Technologies\\ATI.ACE\\Core-Static;C\:\\Program Files (x86)\\AMD\\ATI.ACE\\Core-Static;C\:\\Strawberry\\c\\bin;C\:\\Strawberry\\perl\\site\\bin;C\:\\Strawberry\\perl\\bin;C\:\\Program Files\\nodejs\\;C\:\\Program Files (x86)\\Skype\\Phone\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15\\drv\\;C\:\\Program Files (x86)\\Atmel\\sam-ba_2.15;C\:\\SPARK\\gpl-2014\\bin;C\:\\GNAT\\2014\\bin;C\:\\Bin;C\:\\Python27;C\:\\Users\\David\\AppData\\Roaming\\npm;C\:\\eclipse-juno environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/append=true environment/project/cdt.managedbuild.config.gnu.cross.exe.release.516195201/appendContributed=true diff --git a/Driver/duet.inf b/Driver/duet.inf new file mode 100644 index 0000000000..2c32363013 --- /dev/null +++ b/Driver/duet.inf @@ -0,0 +1,86 @@ +; Windows 2000, XP, Vista, 7 and 8 (x32 and x64) setup file for Duet 3D printer control electronics +; Copyright (c) 2000-2013 ATMEL, Inc. + +[Version] +Signature = "$Windows NT$" +Class = Ports +ClassGuid = {4D36E978-E325-11CE-BFC1-08002BE10318} + +Provider = %Provider% +CatalogFile = duetinf.cat +DriverVer = 05/01/2016,1.12.0.0 + +;---------------------------------------------------------- +; Targets +;---------------------------------------------------------- +[Manufacturer] +%Provider%=DeviceList, NTAMD64, NT + +[DeviceList] +%DUET%=DriverInstall, USB\VID_03EB&PID_2404 + +[DeviceList.NTAMD64] +%DUET%=DriverInstall.NTamd64, USB\VID_03EB&PID_2404 + +[DeviceList.NT] +%DUET%=DriverInstall.NT, USB\VID_03EB&PID_2404 + +;------------------------------------------------------------ +; Windows XP, Vista, Windows 7, Windows 8, Windows 10 - 32bit +;------------------------------------------------------------ +[DestinationDirs] +DefaultDestDir=12 +FakeModemCopyFileSection=12 + +[DriverInstall.NT] +include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=DriverInstall.NT.AddReg + +[DriverInstall.NT.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NT.Services] +AddService = usbser, 0x00000002, DriverService.NT + +[DriverService.NT] +DisplayName = %Serial.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\usbser.sys +LoadOrderGroup = Base + +;------------------------------------------------------------ +; Windows XP, Vista, Windows 7, Windows 8, Windows 10 - 64bit +;------------------------------------------------------------ +[DriverInstall.NTamd64] +include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=DriverInstall.NTamd64.AddReg + +[DriverInstall.NTamd64.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NTamd64.Services] +AddService=usbser, 0x00000002, DriverService.NTamd64 + +[DriverService.NTamd64] +DisplayName=%Serial.SvcDesc% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;---------------------------------------------------------- +; String +;---------------------------------------------------------- +[Strings] +Provider = "Duet 3D printer electronics driver" +DUET = "Duet 3D printer control electronics" +Serial.SvcDesc = "USB Serial emulation driver" + diff --git a/Driver/duetinf.cat b/Driver/duetinf.cat new file mode 100644 index 0000000000..387ff227b1 Binary files /dev/null and b/Driver/duetinf.cat differ diff --git a/Release/RepRapFirmware-1.12-dc42.bin b/Release/RepRapFirmware-1.12-dc42.bin new file mode 100644 index 0000000000..dab6692b8f Binary files /dev/null and b/Release/RepRapFirmware-1.12-dc42.bin differ diff --git a/Scripts/signdriver.bat b/Scripts/signdriver.bat new file mode 100644 index 0000000000..84702bc75a --- /dev/null +++ b/Scripts/signdriver.bat @@ -0,0 +1,6 @@ +rem CD to the RepRapFirmware root directory before running this +"C:\Program Files (x86)\Windows Kits\10\bin\x86\Inf2Cat.exe" /driver:Driver /os:XP_X86,Vista_X86,Vista_X64,7_X86,7_X64,8_X86,8_X64,6_3_X86,6_3_X64,10_X86,10_X64 +set PASSWORD= +set /P PASSWORD=Private key password: %=% +"C:\Program Files (x86)\Windows Kits\10\bin\x86\signtool.exe" sign /f g:\EscherTechnologies.p12 /p %PASSWORD% /tr http://timestamp.comodoca.com /v Driver/duetinf.cat +"C:\Program Files (x86)\Windows Kits\10\bin\x86\signtool.exe" verify /pa /tw Driver/duetinf.cat \ No newline at end of file diff --git a/src/Configuration.h b/src/Configuration.h index 68721557cd..e650dec156 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -26,11 +26,11 @@ Licence: GPL // Firmware name is now defined in the Pins file #ifndef VERSION -# define VERSION "1.11a" +# define VERSION "1.12" #endif #ifndef DATE -# define DATE "2016-04-24" +# define DATE "2016-05-07" #endif #define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman" @@ -164,6 +164,7 @@ const float FILAMENT_WIDTH = 1.75; // Millimetres #define BED_EQUATION_G "bed.g" #define PAUSE_G "pause.g" #define RESUME_G "resume.g" +#define CANCEL_G "cancel.g" #define STOP_G "stop.g" #define SLEEP_G "sleep.g" diff --git a/src/DDA.cpp b/src/DDA.cpp index 07424b3acb..d54efc57a4 100644 --- a/src/DDA.cpp +++ b/src/DDA.cpp @@ -80,14 +80,14 @@ void DDA::Init() } // Set up a real move. Return true if it represents real movement, else false. -bool DDA::Init(const GCodes::RawMove *nextMove, bool doMotorMapping) +bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) { // 1. Compute the new endpoints and the movement vector const int32_t *positionNow = prev->DriveCoordinates(); const Move *move = reprap.GetMove(); if (doMotorMapping) { - move->MotorTransform(nextMove->coords, endPoint); // transform the axis coordinates if on a delta or CoreXY printer + move->MotorTransform(nextMove.coords, endPoint); // transform the axis coordinates if on a delta or CoreXY printer isDeltaMovement = move->IsDeltaMode() && (endPoint[X_AXIS] != positionNow[X_AXIS] || endPoint[Y_AXIS] != positionNow[Y_AXIS] || endPoint[Z_AXIS] != positionNow[Z_AXIS]); } @@ -106,13 +106,13 @@ bool DDA::Init(const GCodes::RawMove *nextMove, bool doMotorMapping) accelerations[drive] = normalAccelerations[drive]; if (drive >= AXES || !doMotorMapping) { - endPoint[drive] = Move::MotorEndPointToMachine(drive, nextMove->coords[drive]); + endPoint[drive] = Move::MotorEndPointToMachine(drive, nextMove.coords[drive]); } int32_t delta; if (drive < AXES) { - endCoordinates[drive] = nextMove->coords[drive]; + endCoordinates[drive] = nextMove.coords[drive]; delta = endPoint[drive] - positionNow[drive]; } else @@ -123,7 +123,7 @@ bool DDA::Init(const GCodes::RawMove *nextMove, bool doMotorMapping) DriveMovement& dm = ddm[drive]; if (drive < AXES && !isSpecialDeltaMove) { - directionVector[drive] = nextMove->coords[drive] - prev->GetEndCoordinate(drive, false); + directionVector[drive] = nextMove.coords[drive] - prev->GetEndCoordinate(drive, false); dm.state = (isDeltaMovement || delta != 0) ? DMState::moving // on a delta printer, if one tower moves then we assume they all do : DMState::idle; @@ -168,9 +168,9 @@ bool DDA::Init(const GCodes::RawMove *nextMove, bool doMotorMapping) } // 3. Store some values - endStopsToCheck = nextMove->endStopsToCheck; - filePos = nextMove->filePos; - usePressureAdvance = nextMove->usePressureAdvance; + endStopsToCheck = nextMove.endStopsToCheck; + filePos = nextMove.filePos; + usePressureAdvance = nextMove.usePressureAdvance; // The end coordinates will be valid at the end of this move if it does not involve endstop checks and is not a special move on a delta printer endCoordinatesValid = (endStopsToCheck == 0) && (doMotorMapping || !move->IsDeltaMode()); @@ -271,7 +271,7 @@ bool DDA::Init(const GCodes::RawMove *nextMove, bool doMotorMapping) // Set the speed to the smaller of the requested and maximum speed. // Also enforce a minimum speed of 0.5mm/sec. We need a minimum speed to avoid overflow in the movement calculations. - float reqSpeed = nextMove->feedRate; + float reqSpeed = nextMove.feedRate; if (isSpecialDeltaMove) { // Special case of a raw or homing move on a delta printer @@ -338,6 +338,7 @@ float DDA::GetMotorPosition(size_t drive) const return Move::MotorEndpointToPosition(endPoint[drive], drive); } +// Try to increase the ending speed of this move to allow the next move to start at targetNextSpeed void DDA::DoLookahead(DDA *laDDA) //pre(state == provisional) { @@ -350,32 +351,34 @@ void DDA::DoLookahead(DDA *laDDA) bool recurse = false; if (goingUp) { - // We have been asked to adjust the end speed of this move to targetStartSpeed + // We have been asked to adjust the end speed of this move to match the next move starting at targetNextSpeed if (laDDA->topSpeed == laDDA->requestedSpeed) { // This move already reaches its top speed, so just need to adjust the deceleration part - laDDA->endSpeed = laDDA->requestedSpeed; - laDDA->CalcNewSpeeds(); + laDDA->endSpeed = laDDA->requestedSpeed; // remove the deceleration phase + laDDA->CalcNewSpeeds(); // put it back if necessary } else if (laDDA->decelDistance == laDDA->totalDistance && laDDA->prev->state == provisional) { - // This move doesn't reach its requested speed, so we may have to adjust the previous move as well to get optimum behaviour + // This is a deceleration-only move, so we may have to adjust the previous move as well to get optimum behaviour laDDA->endSpeed = laDDA->requestedSpeed; laDDA->CalcNewSpeeds(); - laDDA->prev->targetNextSpeed = min(sqrtf((laDDA->endSpeed * laDDA->endSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)), laDDA->requestedSpeed); + laDDA->prev->targetNextSpeed = min(sqrtf(fsquare(laDDA->endSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)), + laDDA->requestedSpeed); recurse = true; } else { - // This move doesn't reach its requested speed, but we can't adjust the previous one - laDDA->endSpeed = min(sqrtf((laDDA->startSpeed * laDDA->startSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)), laDDA->requestedSpeed); + // This move doesn't reach its requested speed, but it isn't a deceleration-only move, or we can't adjust the previous one + laDDA->endSpeed = min(sqrtf(fsquare(laDDA->startSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)), + laDDA->requestedSpeed); laDDA->CalcNewSpeeds(); } } else { laDDA->startSpeed = laDDA->prev->targetNextSpeed; - float maxEndSpeed = sqrtf((laDDA->startSpeed * laDDA->startSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)); + float maxEndSpeed = sqrtf(fsquare(laDDA->startSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)); if (maxEndSpeed < laDDA->endSpeed) { // Oh dear, we were too optimistic! Have another go. @@ -410,18 +413,18 @@ void DDA::DoLookahead(DDA *laDDA) // Recalculate the top speed, acceleration distance and deceleration distance, and whether we can pause after this move void DDA::RecalculateMove() { - accelDistance = ((requestedSpeed * requestedSpeed) - (startSpeed * startSpeed))/(2.0 * acceleration); - decelDistance = ((requestedSpeed * requestedSpeed) - (endSpeed * endSpeed))/(2.0 * acceleration); + accelDistance = (fsquare(requestedSpeed) - fsquare(startSpeed))/(2.0 * acceleration); + decelDistance = (fsquare(requestedSpeed) - fsquare(endSpeed))/(2.0 * acceleration); if (accelDistance + decelDistance >= totalDistance) { // It's an accelerate-decelerate move. If V is the peak speed, then (V^2 - u^2)/2a + (V^2 - v^2)/2a = distance. // So (2V^2 - u^2 - v^2)/2a = distance // So V^2 = a * distance + 0.5(u^2 + v^2) - float vsquared = (acceleration * totalDistance) + 0.5 * ((startSpeed * startSpeed) + (endSpeed * endSpeed)); + float vsquared = (acceleration * totalDistance) + 0.5 * (fsquare(startSpeed) + fsquare(endSpeed)); // Calculate accelerate distance from: V^2 = u^2 + 2as if (vsquared >= 0.0) { - accelDistance = max((vsquared - (startSpeed * startSpeed))/(2.0 * acceleration), 0.0); + accelDistance = max((vsquared - fsquare(startSpeed))/(2.0 * acceleration), 0.0); decelDistance = totalDistance - accelDistance; topSpeed = sqrtf(vsquared); } @@ -593,9 +596,48 @@ void DDA::Prepare() params.decelStartDistance = totalDistance - decelDistance; // Convert the accelerate/decelerate distances to times - const float accelStopTime = (topSpeed - startSpeed)/acceleration; - const float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed; - const float totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration; + float accelStopTime = (topSpeed - startSpeed)/acceleration; + float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed; + float totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration; + + // Enforce the maximum average acceleration + if (isPrintingMove && topSpeed > startSpeed && topSpeed > endSpeed) + { + const float maxAverageAcceleration = reprap.GetPlatform()->GetMaxAverageAcceleration(); + if (2 * topSpeed - startSpeed - endSpeed > totalTime * maxAverageAcceleration) + { + // Reduce the top speed to comply with the maximum average acceleration + const float a2 = fsquare(acceleration); + const float am2 = fsquare(maxAverageAcceleration); + const float aam = acceleration * maxAverageAcceleration; + const float discriminant = (a2 + (2 * aam) - am2) * (fsquare(startSpeed) + fsquare(endSpeed)) + + (2 * a2 + 2 * am2 - 4 * aam) * startSpeed * endSpeed + + (8 * a2 * maxAverageAcceleration - 4 * acceleration * am2) * totalDistance; + const float oldTopSpeed = topSpeed; + if (discriminant < 0.0) + { + topSpeed = max(startSpeed, endSpeed); + } + else + { + const float temp = (sqrtf(discriminant) + (acceleration - maxAverageAcceleration) * (startSpeed + endSpeed)) + /(4 * acceleration - 2 * maxAverageAcceleration); + topSpeed = max(max(temp, startSpeed), endSpeed); + } + + //DEBUG + debugPrintf("ots %f nts %f ss %f es %f\n", oldTopSpeed, topSpeed, startSpeed, endSpeed); + + // Recalculate parameters + accelDistance = (fsquare(topSpeed) - fsquare(startSpeed))/(2 * acceleration); + decelDistance = (fsquare(topSpeed) - fsquare(endSpeed))/(2 * acceleration); + params.decelStartDistance = totalDistance - decelDistance; + accelStopTime = (topSpeed - startSpeed)/acceleration; + decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed; + totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration; + } + } + clocksNeeded = (uint32_t)(totalTime * stepClockRate); params.startSpeedTimesCdivA = (uint32_t)((startSpeed * stepClockRate)/acceleration); @@ -896,7 +938,7 @@ bool DDA::Step() uint32_t finishTime = moveStartTime + clocksNeeded; // calculate how long this move should take Move *move = reprap.GetMove(); move->CurrentMoveCompleted(); // tell Move that the current move is complete - return move->StartNextMove(finishTime); // schedule the next move + return move->TryStartNextMove(finishTime); // schedule the next move } return false; } diff --git a/src/DDA.h b/src/DDA.h index 92053f54d6..ddb3913118 100644 --- a/src/DDA.h +++ b/src/DDA.h @@ -30,7 +30,7 @@ class DDA DDA(DDA* n); - bool Init(const GCodes::RawMove *nextMove, bool doMotorMapping); // Set up a new move, returning true if it represents real movement + bool Init(const GCodes::RawMove &nextMove, bool doMotorMapping); // Set up a new move, returning true if it represents real movement void Init(); // Set up initial positions for machine startup bool Start(uint32_t tim); // Start executing the DDA, i.e. move the move. bool Step(); // Take one step of the DDA, called by timed interrupt. diff --git a/src/Duet/Pins_duet.h b/src/Duet/Pins_duet.h index b6f2151226..79637b2ce7 100644 --- a/src/Duet/Pins_duet.h +++ b/src/Duet/Pins_duet.h @@ -50,7 +50,6 @@ const float SENSE_RESISTOR = 0.1; // Stepper motor current sense resist const float MAX_STEPPER_DIGIPOT_VOLTAGE = (3.3 * 2.5 / (2.7 + 2.5)); // Stepper motor current reference voltage const float STEPPER_DAC_VOLTAGE_RANGE = 2.02; // Stepper motor current reference voltage for E1 if using a DAC const float STEPPER_DAC_VOLTAGE_OFFSET = -0.025; // Stepper motor current offset voltage for E1 if using a DAC -const int DAC0_DIGITAL_PIN = 66; // Arduino Due pin number corresponding to DAC0 output pin // HEATERS @@ -100,7 +99,7 @@ const Pin Z_PROBE_MOD_PIN = 52; // Digital pin number to turn the IR L const Pin Z_PROBE_MOD_PIN07 = X12; // Digital pin number to turn the IR LED on (high) or off (low) on Duet v0.7 and v0.8.5 (PC10) // Pin number that the DAC that controls the second extruder motor current on the Duet 0.8.5 is connected to -const int Dac0DigitalPin = 66; // Arduino Due pin number corresponding to DAC0 output pin +const int Dac0DigitalPin = 66; // Arduino Due pin number corresponding to DAC0 output pin // COOLING FANS diff --git a/src/Duet/Webserver.cpp b/src/Duet/Webserver.cpp index 2dffd96fe8..d3352163ee 100644 --- a/src/Duet/Webserver.cpp +++ b/src/Duet/Webserver.cpp @@ -609,6 +609,42 @@ void Webserver::HttpInterpreter::DoFastUpload() if (transaction->ReadBuffer(buffer, len)) { network->Unlock(); +#if 1 + // Write data in sector-aligned chunks. This also means that the buffer in fatfs is only used to hold the FAT. + static const size_t writeBufLength = 2048; // use a multiple of the 512b sector size + static uint32_t writeBufStorage[writeBufLength/4]; // aligned buffer for file writes + static size_t writeBufIndex; + char* const writeBuf = (char *)writeBufStorage; + + if (uploadedBytes == 0) + { + writeBufIndex = 0; + } + + while (len != 0) + { + size_t lengthToCopy = min(writeBufLength - writeBufIndex, len); + memcpy(writeBuf + writeBufIndex, buffer, lengthToCopy); + writeBufIndex += lengthToCopy; + uploadedBytes += lengthToCopy; + buffer += lengthToCopy; + len -= lengthToCopy; + if (writeBufIndex == writeBufLength || uploadedBytes >= postFileLength) + { + bool success = fileBeingUploaded.Write(writeBuf, writeBufIndex); + writeBufIndex = 0; + if (!success) + { + platform->Message(GENERIC_MESSAGE, "Error: Could not write upload data!\n"); + CancelUpload(); + + while (!network->Lock()); + SendJsonResponse("upload"); + return; + } + } + } +#else if (!fileBeingUploaded.Write(buffer, len)) { platform->Message(GENERIC_MESSAGE, "Error: Could not write upload data!\n"); @@ -619,6 +655,7 @@ void Webserver::HttpInterpreter::DoFastUpload() return; } uploadedBytes += len; +#endif while (!network->Lock()); } diff --git a/src/ExternalDrivers.cpp b/src/ExternalDrivers.cpp index a8a6c92c8b..985803a434 100644 --- a/src/ExternalDrivers.cpp +++ b/src/ExternalDrivers.cpp @@ -370,7 +370,7 @@ namespace ExternalDrivers USART_EXT_DRV->US_BRGR = VARIANT_MCK/DriversSpiClockFrequency; // 1MHz SPI clock USART_EXT_DRV->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS | US_CR_RSTSTA; - // We need a few microseconds of delay here foe the USART to sort itself out, + // We need a few microseconds of delay here for the USART to sort itself out, // otherwise the processor generates two short reset pulses on its own NRST pin, and resets itself. // But it looks like the TMC drivers need a longer delay anyway to get used to CS being high, // otherwise they ignore the command we send to set the microstepping to x16 and start up in full-step mode. diff --git a/src/GCodes.cpp b/src/GCodes.cpp index e1a04c2406..be7fa929f0 100644 --- a/src/GCodes.cpp +++ b/src/GCodes.cpp @@ -2582,7 +2582,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) bool error = false; int code = gb->GetIValue(); - if (simulating && (code < 20 || code > 37) && code != 82 && code != 83 && code != 111 && code != 105 && code != 122 && code != 999) + if (simulating && (code < 20 || code > 37) && code != 82 && code != 83 && code != 111 && code != 105 && code != 122 && code != 408 && code != 999) { return true; // we don't yet simulate most M codes } @@ -2592,22 +2592,39 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) case 0: // Stop case 1: // Sleep if (!AllMovesAreFinishedAndMoveBufferIsLoaded()) + { return false; + } + + // Reset everything + CancelPrint(); - if (fileBeingPrinted.IsLive()) + if (isPaused) { - fileBeingPrinted.Close(); + isPaused = false; + reply.copy("Print cancelled"); + // If we are cancelling a paused print with M0 and cancel.g exists then run it + if (code == 0) + { + if (DoFileMacro(CANCEL_G, false)) + { + break; + } + } } - // Deselect the active tool + // Otherwise, deselect the active tool, if any { Tool* tool = reprap.GetCurrentTool(); - if (tool != NULL) + if (tool != nullptr) { reprap.StandbyTool(tool->Number()); } } + // Turn the heaters off + reprap.GetHeat()->SwitchOffAll(); + // zpl 2014-18-10: Although RRP says M0 is supposed to turn off all drives and heaters, // I think M1 is sufficient for this purpose. Leave M0 for a normal reset. if (code == 1) @@ -2618,16 +2635,6 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) { platform->SetDrivesIdle(); } - - reprap.GetHeat()->SwitchOffAll(); - if (isPaused) - { - isPaused = false; - reply.copy("Print cancelled"); - } - - // Reset everything - CancelPrint(); break; #if SUPPORT_ROLAND @@ -3724,6 +3731,13 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) } } + if (gb->Seen('P')) + { + // Set max average printing acceleration + platform->SetMaxAverageAcceleration(gb->GetFValue() * distanceScale); + seen = true; + } + if (!seen) { reply.printf("Accelerations: X: %.1f, Y: %.1f, Z: %.1f, E: ", @@ -3737,6 +3751,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) reply.cat(":"); } } + reply.catf(", avg. printing: %.1f", platform->GetMaxAverageAcceleration()); } } break; @@ -5119,7 +5134,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) isFlashing = false; // should never get here, but leave this here in case an error has occurred } #ifdef DUET_NG - else if (sparam == 1 || sparam == 2) + else if (sparam >= 1 && sparam <= 3) { reprap.GetNetwork()->FirmwareUpdate(sparam); } diff --git a/src/Heat.cpp b/src/Heat.cpp index a33fcde5bc..3be29da23a 100644 --- a/src/Heat.cpp +++ b/src/Heat.cpp @@ -317,7 +317,7 @@ void PID::Spin() } // Now check how long it takes to warm up. If too long, maybe the thermistor is not in contact with the heater - if (heatingUp && heater != reprap.GetHeat()->GetBedHeater()) // FIXME - also check bed warmup time? + if (heatingUp && heater != reprap.GetHeat()->GetBedHeater() && heater != reprap.GetHeat()->GetChamberHeater()) // FIXME - also check bed warmup time? { float tmp = (active) ? activeTemperature : standbyTemperature; if (temperature < tmp - TEMPERATURE_CLOSE_ENOUGH) diff --git a/src/Move.cpp b/src/Move.cpp index ee3ce5c444..9dbb2e7543 100644 --- a/src/Move.cpp +++ b/src/Move.cpp @@ -190,7 +190,7 @@ void Move::Spin() { Transform(nextMove.coords); } - if (ddaRingAddPointer->Init(&nextMove, doMotorMapping)) + if (ddaRingAddPointer->Init(nextMove, doMotorMapping)) { ddaRingAddPointer = ddaRingAddPointer->GetNext(); idleCount = 0; @@ -200,19 +200,7 @@ void Move::Spin() } } - if (simulating) - { - if (idleCount > 10 && !DDARingEmpty()) - { - // No move added this time, so simulate executing one already in the queue - DDA *dda = ddaRingGetPointer; - simulationTime += dda->CalcTime(); - liveCoordinatesValid = dda->FetchEndPosition(const_cast(liveEndPoints), const_cast(liveCoordinates)); - dda->Complete(); - ddaRingGetPointer = ddaRingGetPointer->GetNext(); - } - } - else if (!deltaProbing) + if (!deltaProbing) { // See whether we need to kick off a move DDA *cdda = currentDda; // currentDda is volatile, so copy it @@ -228,20 +216,27 @@ void Move::Spin() } if (dda->GetState() == DDA::frozen) { - cpu_irq_disable(); // must call StartNextMove and Interrupt with interrupts disabled - if (StartNextMove(Platform::GetInterruptClocks())) // start the next move if none is executing already + if (simulating) { - Interrupt(); + currentDda = ddaRingGetPointer; // pretend we are executing this move + } + else + { + cpu_irq_disable(); // must call StartNextMove and Interrupt with interrupts disabled + if (StartNextMove(Platform::GetInterruptClocks())) // start the next move + { + Interrupt(); + } + cpu_irq_enable(); } - cpu_irq_enable(); iState = IdleState::busy; } - else if (iState == IdleState::busy && !reprap.GetGCodes()->IsPaused() && idleTimeout > 0.0) + else if (!simulating && iState == IdleState::busy && !reprap.GetGCodes()->IsPaused() && idleTimeout > 0.0) { lastMoveTime = reprap.GetPlatform()->Time(); // record when we first noticed that the machine was idle iState = IdleState::timing; } - else if (iState == IdleState::timing && reprap.GetPlatform()->Time() - lastMoveTime >= idleTimeout) + else if (!simulating && iState == IdleState::timing && reprap.GetPlatform()->Time() - lastMoveTime >= idleTimeout) { reprap.GetPlatform()->SetDrivesIdle(); // put all drives in idle hold iState = IdleState::idle; @@ -271,6 +266,15 @@ void Move::Spin() cdda = cdda->GetNext(); st = cdda->GetState(); } + + if (simulating) + { + // Simulate completion of the current move +//DEBUG +//currentDda->DebugPrint(); + simulationTime += currentDda->CalcTime(); + CurrentMoveCompleted(); + } } } @@ -1133,13 +1137,12 @@ void Move::CurrentMoveCompleted() ddaRingGetPointer = ddaRingGetPointer->GetNext(); } -// Start the next move. Must be called with interrupts disabled, to avoid a race condition. -bool Move::StartNextMove(uint32_t startTime) +// Try to start another move. Must be called with interrupts disabled, to avoid a race condition. +bool Move::TryStartNextMove(uint32_t startTime) { if (ddaRingGetPointer->GetState() == DDA::frozen) { - currentDda = ddaRingGetPointer; - return currentDda->Start(startTime); + return StartNextMove(startTime); } else { diff --git a/src/Move.h b/src/Move.h index 0ff228e889..e8b3ed6273 100644 --- a/src/Move.h +++ b/src/Move.h @@ -77,10 +77,10 @@ class Move void SetCoreXYMode(int mode) { coreXYMode = mode; } float GetCoreAxisFactor(size_t axis) const { return axisFactors[axis]; } void setCoreAxisFactor(size_t axis, float f) { axisFactors[axis] = f; } - bool IsCoreXYAxis(size_t axis) const; // return true if the specified axis shares its motors with another + bool IsCoreXYAxis(size_t axis) const; // Return true if the specified axis shares its motors with another - void CurrentMoveCompleted(); // signals that the current move has just been completed - bool StartNextMove(uint32_t startTime); // start the next move, returning true if Step() needs to be called immediately + void CurrentMoveCompleted(); // Signal that the current move has just been completed + bool TryStartNextMove(uint32_t startTime); // Try to start another move, returning true if Step() needs to be called immediately void MotorTransform(const float machinePos[AXES], int32_t motorPos[AXES]) const; // Convert Cartesian coordinates to delta motor coordinates float MotorFactor(size_t drive, const float directionVector[]) const; // Calculate the movement fraction for a single axis motor of a Cartesian or CoreXY printer void MachineToEndPoint(const int32_t motorPos[], float machinePos[], size_t numDrives) const; // Convert motor coordinates to machine coordinates @@ -107,6 +107,7 @@ class Move enum class IdleState : uint8_t { idle, busy, timing }; + bool StartNextMove(uint32_t startTime); // start the next move, returning true if Step() needs to be called immediately void SetProbedBedEquation(size_t numPoints, StringRef& reply); // When we have a full set of probed points, work out the bed's equation void DoDeltaCalibration(size_t numPoints, StringRef& reply); void BedTransform(float move[AXES]) const; // Take a position and apply the bed compensations @@ -180,11 +181,9 @@ inline bool Move::NoLiveMovement() const return DDARingEmpty() && currentDda == nullptr; // must test currentDda and DDARingEmpty *in this order* ! } -// To wait until all the current moves in the buffers are -// complete, call this function repeatedly and wait for it to -// return true. Then do whatever you wanted to do after all -// current moves have finished. THEN CALL THE ResumeMoving() FUNCTION -// OTHERWISE NOTHING MORE WILL EVER HAPPEN. +// To wait until all the current moves in the buffers are complete, call this function repeatedly and wait for it to return true. +// Then do whatever you wanted to do after all current moves have finished. +// Then call ResumeMoving() otherwise nothing more will ever happen. inline bool Move::AllMovesAreFinished() { addNoMoreMoves = true; @@ -196,4 +195,12 @@ inline void Move::ResumeMoving() addNoMoreMoves = false; } +// Start the next move. Must be called with interrupts disabled, to avoid a race with the step ISR. +inline bool Move::StartNextMove(uint32_t startTime) +//pre(ddaRingGetPointer->GetState() == DDA::frozen) +{ + currentDda = ddaRingGetPointer; + return currentDda->Start(startTime); +} + #endif /* MOVE_H_ */ diff --git a/src/Platform.cpp b/src/Platform.cpp index e3ff82b96c..509b2ffff6 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -209,6 +209,7 @@ void Platform::Init() maxStepperDigipotVoltage = MAX_STEPPER_DIGIPOT_VOLTAGE; stepperDacVoltageRange = STEPPER_DAC_VOLTAGE_RANGE; stepperDacVoltageOffset = STEPPER_DAC_VOLTAGE_OFFSET; + maxAverageAcceleration = 10000.0; // high enough to have no effect until it is changed // Z PROBE @@ -242,6 +243,10 @@ void Platform::Init() } // Motors + for (size_t drive = 0; drive < DRIVES; drive++) + { + driverNumbers[drive] = -1; // needed so that SetPhysicalDrive() behaves correctly + } for (size_t drive = 0; drive < DRIVES; drive++) { @@ -1611,7 +1616,7 @@ void Platform::EnableDrive(size_t drive) UpdateMotorCurrent(driver); // the current may have been reduced by the idle timeout #ifdef EXTERNAL_DRIVERS - if (drive >= FIRST_EXTERNAL_DRIVE) + if (driver >= FIRST_EXTERNAL_DRIVE) { ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, true); } @@ -1637,7 +1642,7 @@ void Platform::DisableDrive(size_t drive) { const size_t driver = driverNumbers[drive]; #ifdef EXTERNAL_DRIVERS - if (drive >= FIRST_EXTERNAL_DRIVE) + if (driver >= FIRST_EXTERNAL_DRIVE) { ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, false); } @@ -1729,7 +1734,7 @@ void Platform::UpdateMotorCurrent(size_t drive) } #ifndef DUET_NG } - else + else if (driver < 8) // on a Duet 0.6 we have a maximum of 8 drives { mcpExpansion.setNonVolatileWiper(potWipes[driver], pot); mcpExpansion.setVolatileWiper(potWipes[driver], pot); @@ -1806,13 +1811,22 @@ unsigned int Platform::GetMicrostepping(size_t drive, bool& interpolation) const void Platform::SetPhysicalDrive(size_t driverNumber, int8_t physicalDrive) { int oldDrive = GetPhysicalDrive(driverNumber); - if (oldDrive >= 0) + if (oldDrive != physicalDrive) { - driverNumbers[oldDrive] = -1; - stepPinDescriptors[oldDrive] = OutputPin(); + if (oldDrive >= 0) + { + DisableDrive(oldDrive); // turn off the motor current + driverNumbers[oldDrive] = -1; + stepPinDescriptors[oldDrive] = OutputPin(); + } + + if (physicalDrive >= 0) + { + driverNumbers[physicalDrive] = driverNumber; + stepPinDescriptors[physicalDrive] = OutputPin(stepPins[driverNumber]); + driveState[physicalDrive] = DriveStatus::disabled; + } } - driverNumbers[physicalDrive] = driverNumber; - stepPinDescriptors[physicalDrive] = OutputPin(stepPins[driverNumber]); } // Return the physical drive used by this driver, or -1 if not found @@ -2281,8 +2295,10 @@ float Platform::ActualInstantDv(size_t drive) const if (drive >= AXES) { float eComp = elasticComp[drive - AXES]; - // If we are using elastic compensation then we need to limit the instantDv to avoid velocity mismatches - return (eComp <= 0.0) ? idv : min(idv, 1.0/(eComp * driveStepsPerUnit[drive])); + // If we are using elastic compensation then we need to limit the extruder instantDv to avoid velocity mismatches. + // Assume that we want the extruder motor position to be accurate to within 0.01mm of extrusion. + // TODO remove this limit and add/remove steps to the previous and/or next move instead + return (eComp <= 0.0) ? idv : min(idv, 0.01/eComp); } else { diff --git a/src/Platform.h b/src/Platform.h index d097a2f8a7..956917aa60 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -516,6 +516,8 @@ class Platform float Acceleration(size_t drive) const; const float* Accelerations() const; void SetAcceleration(size_t drive, float value); + const float GetMaxAverageAcceleration() const { return maxAverageAcceleration; } + void SetMaxAverageAcceleration(float f) { maxAverageAcceleration = f; } float MaxFeedrate(size_t drive) const; const float* MaxFeedrates() const; void SetMaxFeedrate(size_t drive, float value); @@ -723,6 +725,7 @@ class Platform float motorCurrents[DRIVES]; float idleCurrentFactor; size_t slowestDrive; + float maxAverageAcceleration; // Digipots diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp index 6771a6908d..6a186e5b86 100644 --- a/src/PrintMonitor.cpp +++ b/src/PrintMonitor.cpp @@ -593,9 +593,17 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp if (filename != nullptr && filename[0] != 0) { GCodeFileInfo info; - if (!GetFileInfo(FS_PREFIX, filename, info)) + + // Getting file information take a few runs. Speed it up when we are not printing by calling it several times. + uint32_t startTime = millis(); + bool gotFileInfo; + do + { + gotFileInfo = GetFileInfo(FS_PREFIX, filename, info); + } while (!gotFileInfo && !isPrinting && millis() - startTime < MAX_FILEINFO_PROCESS_TIME); + + if (!gotFileInfo) { - // This may take a few runs... return false; } diff --git a/src/PrintMonitor.h b/src/PrintMonitor.h index 243fa89883..380bfc6a9c 100644 --- a/src/PrintMonitor.h +++ b/src/PrintMonitor.h @@ -26,7 +26,7 @@ const FilePosition GCODE_FOOTER_SIZE = 192000uL; // How many bytes to read from #ifdef DUET_NG const size_t GCODE_READ_SIZE = 4096; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) #else -const size_t GCODE_READ_SIZE = 2048; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) +const size_t GCODE_READ_SIZE = 1024; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) #endif const size_t GCODE_OVERLAP_SIZE = 100; // Size of the overlapping buffer for searching (should be a multiple of 4) @@ -39,6 +39,7 @@ const float ESTIMATION_MIN_FILE_USAGE = 0.001; // Minium per cent of the file t const float FIRST_LAYER_SPEED_FACTOR = 0.25; // First layer speed factor compared to other layers (only for layer-based estimation) const uint32_t PRINTMONITOR_UPDATE_INTERVAL = 200; // Update interval in milliseconds +const uint32_t MAX_FILEINFO_PROCESS_TIME = 100; // Maximum time to spend polling for file info in each call enum PrintEstimationMethod {