diff --git a/Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14.zip b/Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14a.zip similarity index 81% rename from Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14.zip rename to Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14a.zip index c89f82b..18e5ba2 100644 Binary files a/Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14.zip and b/Release/Duet-0.6-0.8.5/Stable/DuetWebControl-1.14a.zip differ diff --git a/Release/Duet-0.6-0.8.5/Stable/RepRapFirmware-1.17c.bin b/Release/Duet-0.6-0.8.5/Stable/RepRapFirmware-1.17c.bin new file mode 100644 index 0000000..02acb7e Binary files /dev/null and b/Release/Duet-0.6-0.8.5/Stable/RepRapFirmware-1.17c.bin differ diff --git a/Release/Duet-WiFi/Stable/DuetWebControl-1.14.bin b/Release/Duet-WiFi/Stable/DuetWebControl-1.14a.bin similarity index 91% rename from Release/Duet-WiFi/Stable/DuetWebControl-1.14.bin rename to Release/Duet-WiFi/Stable/DuetWebControl-1.14a.bin index 5866d33..b79a3a2 100644 Binary files a/Release/Duet-WiFi/Stable/DuetWebControl-1.14.bin and b/Release/Duet-WiFi/Stable/DuetWebControl-1.14a.bin differ diff --git a/Release/Duet-WiFi/Stable/DuetWiFiFirmware-1.17c.bin b/Release/Duet-WiFi/Stable/DuetWiFiFirmware-1.17c.bin new file mode 100644 index 0000000..3f45a8d Binary files /dev/null and b/Release/Duet-WiFi/Stable/DuetWiFiFirmware-1.17c.bin differ diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp index 1db905b..ee85262 100644 --- a/src/GCodes/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer.cpp @@ -170,7 +170,6 @@ bool GCodeBuffer::IsEmpty() const // Is 'c' in the G Code string? // Leave the pointer there for a subsequent read. - bool GCodeBuffer::Seen(char c) { readPointer = 0; @@ -185,6 +184,24 @@ bool GCodeBuffer::Seen(char c) return false; } +// Return the first G, M or T command letter. Needed so that we don't pick up a spurious command letter form inside a string parameter. +char GCodeBuffer::GetCommandLetter() +{ + readPointer = 0; + for (;;) + { + const char b = gcodeBuffer[readPointer]; + if (b == 0 || b == ';') break; + if (b == 'G' || b == 'M' || b == 'T') + { + return b; + } + ++readPointer; + } + readPointer = -1; + return 0; +} + // Get a float after a G Code letter found by a call to Seen() float GCodeBuffer::GetFValue() { diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h index 198512d..79c79d3 100644 --- a/src/GCodes/GCodeBuffer.h +++ b/src/GCodes/GCodeBuffer.h @@ -23,6 +23,7 @@ public: bool Put(const char *str, size_t len); // Add an entire string bool IsEmpty() const; // Does this buffer contain any code? bool Seen(char c); // Is a character present? + char GetCommandLetter(); // Find the first G, M or T command float GetFValue(); // Get a float after a key letter int32_t GetIValue(); // Get an integer after a key letter void TryGetFValue(char c, float& val, bool& seen); diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 2b8b2dd..97bebd8 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -589,7 +589,7 @@ void GCodes::Spin() const uint32_t numPointsProbed = reprap.GetMove()->AccessBedProbeGrid().GetStatistics(mean, deviation); if (numPointsProbed >= 4) { - reply.printf("%u points probed, mean error %.2f, deviation %.2f\n", numPointsProbed, mean, deviation); + reply.printf("%u points probed, mean error %.3f, deviation %.3f\n", numPointsProbed, mean, deviation); error = SaveHeightMap(gb, reply); reprap.GetMove()->AccessBedProbeGrid().UseHeightMap(true); } @@ -1747,8 +1747,9 @@ bool GCodes::DoSingleZProbe(GCodeBuffer& gb, StringRef& reply, bool reportOnly, else { moveBuffer.coords[Z_AXIS] = platform->ZProbeStopHeight() + heightAdjust; - SetPositions(moveBuffer.coords); + SetPositions(moveBuffer.coords, false); // set positions WITHOUT (very important) applying bed compensation SetAxisIsHomed(Z_AXIS); + reprap.GetMove()->GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes()); // update the user position lastProbedZ = 0.0; } return true; @@ -3049,10 +3050,10 @@ bool GCodes::RetractFilament(GCodeBuffer& gb, bool retract) { if (retract != isRetracted && (retractLength != 0.0 || retractHop != 0.0 || (!retract && retractExtra != 0.0))) { - const Tool *tool = reprap.GetCurrentTool(); + const Tool * const tool = reprap.GetCurrentTool(); if (tool != nullptr) { - size_t nDrives = tool->DriveCount(); + const size_t nDrives = tool->DriveCount(); if (nDrives != 0) { if (segmentsLeft != 0) @@ -3060,28 +3061,30 @@ bool GCodes::RetractFilament(GCodeBuffer& gb, bool retract) return false; } - reprap.GetMove()->GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes()); + const uint32_t xAxes = reprap.GetCurrentXAxes(); + reprap.GetMove()->GetCurrentUserPosition(moveBuffer.coords, 0, xAxes); for (size_t i = numAxes; i < DRIVES; ++i) { moveBuffer.coords[i] = 0.0; } // Set the feed rate. If there is any Z hop then we need to pass the Z speed, else we pass the extrusion speed. const float speedToUse = (retract) ? retractSpeed : unRetractSpeed; - moveBuffer.feedRate = (retractHop == 0.0) + moveBuffer.feedRate = (retractHop == 0.0 || retractLength == 0.0) ? speedToUse : speedToUse * retractHop/retractLength; moveBuffer.coords[Z_AXIS] += (retract) ? retractHop : -retractHop; const float lengthToUse = (retract) ? -retractLength : retractLength + retractExtra; for (size_t i = 0; i < nDrives; ++i) { - moveBuffer.coords[E0_AXIS + tool->Drive(i)] = lengthToUse; + moveBuffer.coords[numAxes + tool->Drive(i)] = lengthToUse; } + moveBuffer.moveType = 0; moveBuffer.isFirmwareRetraction = true; moveBuffer.usePressureAdvance = false; moveBuffer.filePos = (&gb == fileGCode) ? gb.MachineState().fileState.GetPosition() : noFilePosition; moveBuffer.canPauseAfter = !retract; // don't pause after a retraction because that could cause too much retraction - moveBuffer.xAxes = reprap.GetCurrentXAxes(); + moveBuffer.xAxes = xAxes; segmentsLeft = 1; } } @@ -3134,14 +3137,14 @@ bool GCodes::ToolHeatersAtSetTemperatures(const Tool *tool, bool waitWhenCooling return true; } -// Set the current position -void GCodes::SetPositions(float positionNow[DRIVES]) +// Set the current position, optionally applying bed and axis compensation +void GCodes::SetPositions(const float positionNow[DRIVES], bool doBedCompensation) { - // Transform the position so that e.g. if the user does G92 Z0, - // the position we report (which gets inverse-transformed) really is Z=0 afterwards - reprap.GetMove()->Transform(positionNow, reprap.GetCurrentXAxes()); - reprap.GetMove()->SetLiveCoordinates(positionNow); - reprap.GetMove()->SetPositions(positionNow); + float newPos[DRIVES]; + memcpy(newPos, positionNow, sizeof(newPos)); // copy to local storage because Transform modifies it + reprap.GetMove()->Transform(newPos, reprap.GetCurrentXAxes(), doBedCompensation); + reprap.GetMove()->SetLiveCoordinates(newPos); + reprap.GetMove()->SetPositions(newPos); } bool GCodes::IsPaused() const diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 5896728..017d98d 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -199,7 +199,7 @@ private: bool ToolHeatersAtSetTemperatures(const Tool *tool, bool waitWhenCooling) const; // Wait for the heaters associated with the specified tool to reach their set temperatures void SetAllAxesNotHomed(); // Flag all axes as not homed - void SetPositions(float positionNow[DRIVES]); // Set the current position to be this + void SetPositions(const float positionNow[DRIVES], bool doBedCompensation = true); // Set the current position to be this const char *TranslateEndStopResult(EndStopHit es); // Translate end stop result to text bool RetractFilament(GCodeBuffer& gb, bool retract); // Retract or un-retract filaments bool ChangeMicrostepping(size_t drive, int microsteps, int mode) const; // Change microstepping on the specified drive diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 51df040..0308fcf 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -45,27 +45,21 @@ bool GCodes::ActOnCode(GCodeBuffer& gb, StringRef& reply) return true; } - // M-code parameters might contain letters T and G, e.g. in filenames. - // dc42 assumes that G-and T-code parameters never contain the letter M. - // Therefore we must check for an M-code first. - if (gb.Seen('M')) - { - return HandleMcode(gb, reply); - } - // dc42 doesn't think a G-code parameter ever contains letter T, or a T-code ever contains letter G. - // So it doesn't matter in which order we look for them. - if (gb.Seen('G')) + // G29 string parameters may contain the letter M, and various M-code string parameter may contain the letter G. + // So we now look for the first G, M or T in the command. + switch (gb.GetCommandLetter()) { + case 'G': return HandleGcode(gb, reply); - } - if (gb.Seen('T')) - { + case 'M': + return HandleMcode(gb, reply); + case 'T': return HandleTcode(gb, reply); + default: + // An invalid command gets discarded + HandleReply(gb, false, ""); + return true; } - - // An invalid or queued buffer gets discarded - HandleReply(gb, false, ""); - return true; } bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply) @@ -73,7 +67,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply) bool result = true; bool error = false; - int code = gb.GetIValue(); + const int code = gb.GetIValue(); if (simulationMode != 0 && code != 0 && code != 1 && code != 4 && code != 10 && code != 20 && code != 21 && code != 90 && code != 91 && code != 92) { return true; // we only simulate some gcodes @@ -885,6 +879,22 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) FileMacroCyclesReturn(gb); break; + case 101: // Un-retract + if (!LockMovement(gb)) + { + return false; + } + result = RetractFilament(gb, false); + break; + + case 103: // Retract + if (!LockMovement(gb)) + { + return false; + } + result = RetractFilament(gb, true); + break; + case 104: // Deprecated. This sets the active temperature of every heater of the active tool if (gb.Seen('S')) { @@ -1676,11 +1686,21 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) float newSpeedFactor = (gb.GetFValue() * 0.01) * secondsToMinutes; // include the conversion from mm/minute to mm/second if (newSpeedFactor > 0.0) { - gb.MachineState().feedrate *= newSpeedFactor / speedFactor; + // Update the feed rate for ALL input sources, and all feed rates on the stack + const float speedFactorRatio = newSpeedFactor / speedFactor; + for (size_t i = 0; i < ARRAY_SIZE(gcodeSources); ++i) + { + GCodeMachineState *ms = &gcodeSources[i]->MachineState(); + while (ms != nullptr) + { + ms->feedrate *= speedFactorRatio; + ms = ms->previous; + } + } + // If the last move hasn't gone yet, update its feed rate too if it is not a firmware retraction if (segmentsLeft != 0 && !moveBuffer.isFirmwareRetraction) { - // The last move has not gone yet, so we can update it - moveBuffer.feedRate *= newSpeedFactor / speedFactor; + moveBuffer.feedRate *= speedFactorRatio; } speedFactor = newSpeedFactor; } diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index 5233387..3b63be5 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -178,7 +178,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) } isPrintingMove = false; - bool realMove = false, xyMoving = false; + bool realMove = false, xyMoving = false, xyzMoving = false; const bool isSpecialDeltaMove = (move->IsDeltaMode() && !doMotorMapping); float accelerations[DRIVES]; const float * const normalAccelerations = reprap.GetPlatform()->Accelerations(); @@ -197,7 +197,16 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) DriveMovement& dm = ddm[drive]; if (drive < numAxes && !isSpecialDeltaMove) { - directionVector[drive] = nextMove.coords[drive] - prev->GetEndCoordinate(drive, false); + const float positionDelta = nextMove.coords[drive] - prev->GetEndCoordinate(drive, false); + directionVector[drive] = positionDelta; + if (positionDelta != 0) + { + xyzMoving = true; + if (drive != Z_AXIS) + { + xyMoving = true; + } + } dm.state = (isDeltaMovement || delta != 0) ? DMState::moving // on a delta printer, if one tower moves then we assume they all do : DMState::idle; @@ -214,22 +223,20 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) dm.direction = (delta >= 0); // for now this is the direction of net movement, but gets adjusted later if it is a delta movement realMove = true; - if (drive < numAxes && drive != Z_AXIS) - { - xyMoving = true; - } - if (drive >= numAxes && xyMoving) { if (delta > 0) { isPrintingMove = true; // we have both movement and extrusion } - const float compensationTime = reprap.GetPlatform()->GetPressureAdvance(drive); - if (compensationTime > 0.0) + if (nextMove.usePressureAdvance) { - // Compensation causes instant velocity changes equal to acceleration * k, so we may need to limit the acceleration - accelerations[drive] = min(accelerations[drive], reprap.GetPlatform()->ConfiguredInstantDv(drive)/compensationTime); + const float compensationTime = reprap.GetPlatform()->GetPressureAdvance(drive - numAxes); + if (compensationTime > 0.0) + { + // Compensation causes instant velocity changes equal to acceleration * k, so we may need to limit the acceleration + accelerations[drive] = min(accelerations[drive], reprap.GetPlatform()->ConfiguredInstantDv(drive)/compensationTime); + } } } } @@ -252,10 +259,11 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) endCoordinatesValid = (endStopsToCheck == 0) && (doMotorMapping || !move->IsDeltaMode()); // 4. Normalise the direction vector and compute the amount of motion. - // If there is any XYZ movement, then we normalise it so that the total XYZ movement has unit length. - // This means that the user gets the feed rate that he asked for. It also makes the delta calculations simpler. - if (xyMoving || ddm[Z_AXIS].state == DMState::moving) + if (xyzMoving) { + // There is some XYZ movement, so normalise the direction vector so that the total XYZ movement has unit length and 'totalDistance' is the XYZ distance moved. + // This means that the user gets the feed rate that he asked for. It also makes the delta calculations simpler. + // First do the bed tilt compensation for deltas. if (isDeltaMovement) { // Add on the Z movement needed to compensate for bed tilt @@ -299,7 +307,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) } else { - // The distance to reversal is the solution to a quadratic equation. One root corresponds to the carriages being above the bed, + // The distance to reversal is the solution to a quadratic equation. One root corresponds to the carriages being below the bed, // the other root corresponds to the carriages being above the bed. const float drev = ((directionVector[Z_AXIS] * sqrt(a2b2D2 - fsquare(A * directionVector[Y_AXIS] - B * directionVector[X_AXIS]))) - aAplusbB)/a2plusb2; @@ -342,16 +350,22 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) } else { + // Extruder-only movement. + // Currently we normalise vector sum of all extruder movement to unit length. + // Alternatives would be: + // 1. Normalise the largest one to unit length. This means that when retracting multiple filaments, they all get the requested retract speed. + // 2. Normalise the sum to unit length. This means that when we use mixing, we get the requested extrusion rate at the nozzle. + // 3. Normalise the sum to the sum of the mixing coefficients (which we would have to include in the move details). totalDistance = Normalise(directionVector, DRIVES, DRIVES); } - // 5. Compute the maximum acceleration available and maximum top speed + // 5. Compute the maximum acceleration available float normalisedDirectionVector[DRIVES]; // Used to hold a unit-length vector in the direction of motion memcpy(normalisedDirectionVector, directionVector, sizeof(normalisedDirectionVector)); Absolute(normalisedDirectionVector, DRIVES); acceleration = VectorBoxIntersection(normalisedDirectionVector, accelerations, DRIVES); - // Set the speed to the smaller of the requested and maximum speed. + // 6. 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; if (isSpecialDeltaMove) @@ -372,13 +386,13 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) reqSpeed /= maxDistance; // because normalisedDirectionVector is unit-normalised } } - requestedSpeed = max(0.5, min(reqSpeed, VectorBoxIntersection(normalisedDirectionVector, reprap.GetPlatform()->MaxFeedrates(), DRIVES))); + requestedSpeed = constrain(reqSpeed, 0.5, VectorBoxIntersection(normalisedDirectionVector, reprap.GetPlatform()->MaxFeedrates(), DRIVES)); // On a Cartesian or CoreXY printer, it is OK to limit the X and Y speeds and accelerations independently, and in consequence to allow greater values // for diagonal moves. On a delta, this is not OK and any movement in the XY plane should be limited to the X/Y axis values, which we assume to be equal. if (isDeltaMovement) { - const float xyFactor = sqrt(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[X_AXIS])); + const float xyFactor = sqrtf(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[X_AXIS])); const float maxSpeed = reprap.GetPlatform()->MaxFeedrates()[X_AXIS]; if (requestedSpeed * xyFactor > maxSpeed) { @@ -392,7 +406,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping) } } - // 6. Calculate the provisional accelerate and decelerate distances and the top speed + // 7. Calculate the provisional accelerate and decelerate distances and the top speed endSpeed = 0.0; // until the next move asks us to adjust it if (prev->state != provisional) @@ -827,13 +841,13 @@ void DDA::Prepare() float DDA::VectorBoxIntersection(const float v[], const float box[], size_t dimensions) { // Generate a vector length that is guaranteed to exceed the size of the box - float biggerThanBoxDiagonal = 2.0*Magnitude(box, dimensions); + const float biggerThanBoxDiagonal = 2.0*Magnitude(box, dimensions); float magnitude = biggerThanBoxDiagonal; for (size_t d = 0; d < dimensions; d++) { if (biggerThanBoxDiagonal*v[d] > box[d]) { - float a = box[d]/v[d]; + const float a = box[d]/v[d]; if (a < magnitude) { magnitude = a; @@ -863,8 +877,7 @@ float DDA::Magnitude(const float v[], size_t dimensions) { magnitude += v[d]*v[d]; } - magnitude = sqrtf(magnitude); - return magnitude; + return sqrtf(magnitude); } // Multiply a vector by a scalar diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index a63ab16..ab419fd 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -185,10 +185,10 @@ void Move::Spin() if (simulationMode < 2) // in simulation mode 2 and higher, we don't process incoming moves beyond this point { - bool doMotorMapping = (nextMove.moveType == 0) || (nextMove.moveType == 1 && !IsDeltaMode()); + const bool doMotorMapping = (nextMove.moveType == 0) || (nextMove.moveType == 1 && !IsDeltaMode()); if (doMotorMapping) { - Transform(nextMove.coords, nextMove.xAxes); + Transform(nextMove.coords, nextMove.xAxes, true); } if (ddaRingAddPointer->Init(nextMove, doMotorMapping)) { @@ -481,7 +481,7 @@ int32_t Move::MotorEndPointToMachine(size_t drive, float coord) // This is computationally expensive on a delta, so only call it when necessary, and never from the step ISR. void Move::MachineToEndPoint(const int32_t motorPos[], float machinePos[], size_t numDrives) const { - const float *stepsPerUnit = reprap.GetPlatform()->GetDriveStepsPerUnit(); + const float * const stepsPerUnit = reprap.GetPlatform()->GetDriveStepsPerUnit(); // Convert the axes if (IsDeltaMode()) @@ -629,10 +629,13 @@ void Move::InverseAxisTransform(float xyzPoint[MAX_AXES]) const xyzPoint[X_AXIS] -= (tanXY*xyzPoint[Y_AXIS] + tanXZ*xyzPoint[Z_AXIS]); } -void Move::Transform(float xyzPoint[MAX_AXES], uint32_t xAxes) const +void Move::Transform(float xyzPoint[MAX_AXES], uint32_t xAxes, bool useBedCompensation) const { AxisTransform(xyzPoint); - BedTransform(xyzPoint, xAxes); + if (useBedCompensation) + { + BedTransform(xyzPoint, xAxes); + } } void Move::InverseTransform(float xyzPoint[MAX_AXES], uint32_t xAxes) const @@ -804,13 +807,13 @@ void Move::SetAxisCompensation(int8_t axis, float tangent) void Move::BarycentricCoordinates(size_t p1, size_t p2, size_t p3, float x, float y, float& l1, float& l2, float& l3) const { - float y23 = baryYBedProbePoints[p2] - baryYBedProbePoints[p3]; - float x3 = x - baryXBedProbePoints[p3]; - float x32 = baryXBedProbePoints[p3] - baryXBedProbePoints[p2]; - float y3 = y - baryYBedProbePoints[p3]; - float x13 = baryXBedProbePoints[p1] - baryXBedProbePoints[p3]; - float y13 = baryYBedProbePoints[p1] - baryYBedProbePoints[p3]; - float iDet = 1.0 / (y23 * x13 + x32 * y13); + const float y23 = baryYBedProbePoints[p2] - baryYBedProbePoints[p3]; + const float x3 = x - baryXBedProbePoints[p3]; + const float x32 = baryXBedProbePoints[p3] - baryXBedProbePoints[p2]; + const float y3 = y - baryYBedProbePoints[p3]; + const float x13 = baryXBedProbePoints[p1] - baryXBedProbePoints[p3]; + const float y13 = baryYBedProbePoints[p1] - baryYBedProbePoints[p3]; + const float iDet = 1.0 / (y23 * x13 + x32 * y13); l1 = (y23 * x3 + x32 * y3) * iDet; l2 = (-y13 * x3 + x13 * y3) * iDet; l3 = 1.0 - l1 - l2; @@ -831,7 +834,7 @@ float Move::TriangleZ(float x, float y) const { for (size_t i = 0; i < 4; i++) { - size_t j = (i + 1) % 4; + const size_t j = (i + 1) % 4; float l1, l2, l3; BarycentricCoordinates(i, j, 4, x, y, l1, l2, l3); if (l1 > TRIANGLE_ZERO && l2 > TRIANGLE_ZERO && l3 > TRIANGLE_ZERO) @@ -1173,7 +1176,10 @@ void Move::DoDeltaCalibration(size_t numFactors, StringRef& reply) // Decide whether to do another iteration. Two is slightly better than one, but three doesn't improve things. // Alternatively, we could stop when the expected RMS error is only slightly worse than the RMS of the residuals. ++iteration; - if (iteration == 2) break; + if (iteration == 2) + { + break; + } } // Print out the calculation time @@ -1235,7 +1241,7 @@ void Move::DeltaProbeInterrupt() deltaProbe.Trigger(); } - bool dir = deltaProbe.GetDirection(); + const bool dir = deltaProbe.GetDirection(); Platform * const platform = reprap.GetPlatform(); platform->SetDirection(X_AXIS, dir); platform->SetDirection(Y_AXIS, dir); @@ -1245,7 +1251,7 @@ void Move::DeltaProbeInterrupt() Platform::StepDriversHigh(steppersMoving); ShortDelay(); Platform::StepDriversLow(); - uint32_t tim = deltaProbe.CalcNextStepTime(); + const uint32_t tim = deltaProbe.CalcNextStepTime(); again = (tim != 0xFFFFFFFF && platform->ScheduleInterrupt(tim + deltaProbingStartTime)); } while (again); } @@ -1295,11 +1301,9 @@ void Move::HitHighStop(size_t axis, DDA* hitDDA) { if (axis < reprap.GetGCodes()->GetNumAxes()) // should always be true { - float hitPoint = (IsDeltaMode()) - ? deltaParams.GetHomedCarriageHeight(axis) - // this is a delta printer, so the motor is at the homed carriage height for this drive - : reprap.GetPlatform()->AxisMaximum(axis); - // this is a Cartesian printer, so we're at the maximum for this axis + const float hitPoint = (IsDeltaMode()) + ? deltaParams.GetHomedCarriageHeight(axis) // this is a delta printer, so the motor is at the homed carriage height for this drive + : reprap.GetPlatform()->AxisMaximum(axis); // this is a Cartesian printer, so we're at the maximum for this axis JustHomed(axis, hitPoint, hitDDA); } } @@ -1335,7 +1339,7 @@ void Move::ZProbeTriggered(DDA* hitDDA) // Return the untransformed machine coordinates void Move::GetCurrentMachinePosition(float m[DRIVES], bool disableMotorMapping) const { - DDA *lastQueuedMove = ddaRingAddPointer->GetPrevious(); + DDA * const lastQueuedMove = ddaRingAddPointer->GetPrevious(); const size_t numAxes = reprap.GetGCodes()->GetNumAxes(); for (size_t i = 0; i < DRIVES; i++) { @@ -1359,7 +1363,7 @@ void Move::GetCurrentMachinePosition(float m[DRIVES], bool disableMotorMapping) bool Move::IsExtruding() const { cpu_irq_disable(); - bool rslt = currentDda != nullptr && currentDda->IsPrintingMove(); + const bool rslt = currentDda != nullptr && currentDda->IsPrintingMove(); cpu_irq_enable(); return rslt; } diff --git a/src/Movement/Move.h b/src/Movement/Move.h index 74747c1..d23090c 100644 --- a/src/Movement/Move.h +++ b/src/Movement/Move.h @@ -77,7 +77,7 @@ public: void SetAxisCompensation(int8_t axis, float tangent); // Set an axis-pair compensation angle float AxisCompensation(int8_t axis) const; // The tangent value void SetIdentityTransform(); // Cancel the bed equation; does not reset axis angle compensation - void Transform(float move[], uint32_t xAxes) const; // Take a position and apply the bed and the axis-angle compensations + void Transform(float move[], uint32_t xAxes, bool useBedCompensation) const; // Take a position and apply the bed and the axis-angle compensations void InverseTransform(float move[], uint32_t xAxes) const; // Go from a transformed point back to user coordinates float GetTaperHeight() const { return (useTaper) ? taperHeight : 0.0; } void SetTaperHeight(float h); diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp index 83fdd3d..e2d2a84 100644 --- a/src/PrintMonitor.cpp +++ b/src/PrintMonitor.cpp @@ -362,7 +362,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod } uint32_t startTime = millis(); - int nbytes = fileBeingParsed->Read(&buf[fileOverlapLength], sizeToRead); + const int nbytes = fileBeingParsed->Read(&buf[fileOverlapLength], sizeToRead); if (nbytes != (int)sizeToRead) { platform->MessageF(HOST_MESSAGE, "Error: Failed to read header of G-Code file \"%s\"\n", fileName); @@ -1010,52 +1010,47 @@ bool PrintMonitor::FindHeight(const char* buf, size_t len, float& height) const // Scan the buffer for the layer height. The buffer is null-terminated. bool PrintMonitor::FindLayerHeight(const char *buf, size_t len, float& layerHeight) const { - // Look for layer_height as generated by Slic3r - const char* layerHeightStringSlic3r = "; layer_height "; - const char *pos = strstr(buf, layerHeightStringSlic3r); - if (pos != nullptr) + static const char* const layerHeightStrings[] = { - pos += strlen(layerHeightStringSlic3r); - while (strchr(" \t=:", *pos)) + "layer_height", // slic3r + "Layer height", // Cura + "layerHeight", // S3D + "layer_thickness_mm", // Kisslicer + "layerThickness" // Matter Control + }; + + if (*buf != 0) + { + ++buf; // make sure we can look back 1 character after we find a match + for (size_t i = 0; i < ARRAY_SIZE(layerHeightStrings); ++i) // search for each string in turn { - ++pos; + const char *pos = buf; + for(;;) // loop until success or strstr returns null + { + pos = strstr(pos, layerHeightStrings[i]); + if (pos == nullptr) + { + break; // didn't find this string in the buffer, so try the next string + } + + const char c = pos[-1]; // fetch the previous character + pos += strlen(layerHeightStrings[i]); // skip the string we matched + if (c == ' ' || c == ';' || c == '\t') // check we are not in the middle of a word + { + while (strchr(" \t=:,", *pos) != nullptr) // skip the possible separators + { + ++pos; + } + char *tailPtr; + const float val = strtod(pos, &tailPtr); + if (tailPtr != pos) // if we found and converted a number + { + layerHeight = val; + return true; + } + } + } } - layerHeight = strtod(pos, nullptr); - return true; - } - - // Look for layer height as generated by Cura - const char* layerHeightStringCura = "Layer height: "; - pos = strstr(buf, layerHeightStringCura); - if (pos != nullptr) - { - pos += strlen(layerHeightStringCura); - while (strchr(" \t=:", *pos)) - { - ++pos; - } - layerHeight = strtod(pos, nullptr); - return true; - } - - // Look for layer height as generated by S3D - const char* layerHeightStringS3D = "layerHeight,"; - pos = strstr(buf, layerHeightStringS3D); - if (pos != nullptr) - { - pos += strlen(layerHeightStringS3D); - layerHeight = strtod(pos, nullptr); - return true; - } - - // Look for layer height as generated by KISSlicer - const char* layerHeightStringKisslicer = "layer_thickness_mm = "; - pos = strstr(buf, layerHeightStringKisslicer); - if (pos != nullptr) - { - pos += strlen(layerHeightStringKisslicer); - layerHeight = strtod(pos, nullptr); - return true; } return false; diff --git a/src/Version.h b/src/Version.h index 376762a..6bf6996 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.17b" +# define VERSION "1.17c" #endif #ifndef DATE -# define DATE "2017-01-07" +# define DATE "2017-01-14" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"