diff --git a/Configuration.h b/Configuration.h index 06a086b..7702416 100644 --- a/Configuration.h +++ b/Configuration.h @@ -24,8 +24,8 @@ Licence: GPL #define CONFIGURATION_H #define NAME "RepRapFirmware" -#define VERSION "1.04g-dc42" -#define DATE "2015-04-20" +#define VERSION "1.09a-dc42" +#define DATE "2015-05-17" #define AUTHORS "reprappro, dc42, zpl" #define FLASH_SAVE_ENABLED (1) @@ -77,7 +77,7 @@ const float DefaultFeedRate = 3000; // The initial requested feed rate after const size_t MaxProbePoints = 16; // Maximum number of probe points const size_t MaxDeltaCalibrationPoints = 16; // Must be <= MaxProbePoints, may be smaller to reduce matrix storage requirements. Preferably a power of 2. -const float DefaultZDive = 5.0; // Default height from which to probe the bed (mm) +const float DefaultZDive = 3.0; // Default height from which to probe the bed (mm) #define TRIANGLE_0 -0.001 // Slightly less than 0 for point-in-triangle tests diff --git a/DDA.cpp b/DDA.cpp index df24bf4..b364532 100644 --- a/DDA.cpp +++ b/DDA.cpp @@ -730,12 +730,12 @@ bool DDA::Step() // because we have both a high endstop and a Z probe, and the Z motor is not the same thing as the Z axis. switch (reprap.GetPlatform()->GetZProbeResult()) { - case lowHit: + case EndStopHit::lowHit: MoveAborted(now); // set the state to completed and recalculate the endpoints reprap.GetMove()->ZProbeTriggered(this); break; - case lowNear: + case EndStopHit::lowNear: ReduceHomingSpeed(reprap.GetPlatform()->ConfiguredInstantDv(Z_AXIS)); break; @@ -757,7 +757,7 @@ bool DDA::Step() { switch(reprap.GetPlatform()->Stopped(drive)) { - case lowHit: + case EndStopHit::lowHit: endStopsToCheck &= ~(1 << drive); // clear this check so that we can check for more if (endStopsToCheck == 0) // if no more endstops to check { @@ -770,7 +770,7 @@ bool DDA::Step() reprap.GetMove()->HitLowStop(drive, this); break; - case highHit: + case EndStopHit::highHit: endStopsToCheck &= ~(1 << drive); // clear this check so that we can check for more if (endStopsToCheck == 0) // if no more endstops to check { @@ -783,7 +783,7 @@ bool DDA::Step() reprap.GetMove()->HitHighStop(drive, this); break; - case lowNear: + case EndStopHit::lowNear: // Only reduce homing speed if there are no more axes to be homed. // This allows us to home X and Y simultaneously. if (endStopsToCheck == (1 << drive)) diff --git a/DeltaParameters.cpp b/DeltaParameters.cpp new file mode 100644 index 0000000..b816e0d --- /dev/null +++ b/DeltaParameters.cpp @@ -0,0 +1,248 @@ +/* + * DeltaParameters.cpp + * + * Created on: 20 Apr 2015 + * Author: David + */ + +#include "RepRapFirmware.h" + +void DeltaParameters::Init() +{ + deltaMode = false; + diagonal = 0.0; + radius = 0.0; + printRadius = defaultPrintRadius; + homedHeight = defaultDeltaHomedHeight; + isEquilateral = true; + + for (size_t axis = 0; axis < AXES; ++axis) + { + endstopAdjustments[axis] = 0.0; + towerX[axis] = towerY[axis] = 0.0; + } +} + +void DeltaParameters::SetRadius(float r) +{ + radius = r; + isEquilateral = true; + + const float cos30 = sqrtf(3.0)/2.0; + const float sin30 = 0.5; + + towerX[A_AXIS] = -(r * cos30); + towerX[B_AXIS] = r * cos30; + towerX[C_AXIS] = 0.0; + + towerY[A_AXIS] = towerY[B_AXIS] = -(r * sin30); + towerY[C_AXIS] = r; + + Recalc(); +} + +void DeltaParameters::Recalc() +{ + deltaMode = (radius > 0.0 && diagonal > radius); + if (deltaMode) + { + Xbc = towerX[C_AXIS] - towerX[B_AXIS]; + Xca = towerX[A_AXIS] - towerX[C_AXIS]; + Xab = towerX[B_AXIS] - towerX[A_AXIS]; + Ybc = towerY[C_AXIS] - towerY[B_AXIS]; + Yca = towerY[A_AXIS] - towerY[C_AXIS]; + Yab = towerY[B_AXIS] - towerY[A_AXIS]; + coreFa = fsquare(towerX[A_AXIS]) + fsquare(towerY[A_AXIS]); + coreFb = fsquare(towerX[B_AXIS]) + fsquare(towerY[B_AXIS]); + coreFc = fsquare(towerX[C_AXIS]) + fsquare(towerY[C_AXIS]); + Q = 2 * (Xca * Yab - Xab * Yca); + Q2 = fsquare(Q); + D2 = fsquare(diagonal); + + // Calculate the base carriage height when the printer is homed. + const float tempHeight = diagonal; // any sensible height will do here, probably even zero + float machinePos[AXES]; + InverseTransform(tempHeight + endstopAdjustments[X_AXIS], tempHeight + endstopAdjustments[Y_AXIS], tempHeight + endstopAdjustments[X_AXIS], + machinePos); + homedCarriageHeight = homedHeight + tempHeight - machinePos[Z_AXIS]; + } +} + +// Make the average of the endstop adjustments zero, without changing the individual homed carriage heights +void DeltaParameters::NormaliseEndstopAdjustments() +{ + const float eav = (endstopAdjustments[A_AXIS] + endstopAdjustments[B_AXIS] + endstopAdjustments[C_AXIS])/3.0; + endstopAdjustments[A_AXIS] -= eav; + endstopAdjustments[B_AXIS] -= eav; + endstopAdjustments[C_AXIS] -= eav; + homedHeight += eav; + homedCarriageHeight += eav; // no need for a full recalc, this is sufficient +} + +// Calculate the motor position for a single tower from a Cartesian coordinate +float DeltaParameters::Transform(const float machinePos[AXES], size_t axis) const +{ + return machinePos[Z_AXIS] + + sqrt(D2 - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[axis])); +} + +void DeltaParameters::InverseTransform(float Ha, float Hb, float Hc, float machinePos[AXES]) const +{ + const float Fa = coreFa + fsquare(Ha); + const float Fb = coreFb + fsquare(Hb); + const float Fc = coreFc + fsquare(Hc); + +// debugPrintf("Ha=%f Hb=%f Hc=%f Fa=%f Fb=%f Fc=%f Xbc=%f Xca=%f Xab=%f Ybc=%f Yca=%f Yab=%f\n", +// Ha, Hb, Hc, Fa, Fb, Fc, Xbc, Xca, Xab, Ybc, Yca, Yab); + + // Setup PQRSU such that x = -(S - uz)/P, y = (P - Rz)/Q + const float P = (Xbc * Fa) + (Xca * Fb) + (Xab * Fc); + const float S = (Ybc * Fa) + (Yca * Fb) + (Yab * Fc); + + const float R = 2 * ((Xbc * Ha) + (Xca * Hb) + (Xab * Hc)); + const float U = 2 * ((Ybc * Ha) + (Yca * Hb) + (Yab * Hc)); + +// debugPrintf("P= %f R=%f S=%f U=%f Q=%f\n", P, R, S, U, Q); + + const float R2 = fsquare(R), U2 = fsquare(U); + + float A = U2 + R2 + Q2; + float minusHalfB = S * U + P * R + Ha * Q2 + towerX[A_AXIS] * U * Q - towerY[A_AXIS] * R * Q; + float C = fsquare(S + towerX[A_AXIS] * Q) + fsquare(P - towerY[A_AXIS] * Q) + (fsquare(Ha) - D2) * Q2; + +// debugPrintf("A=%f minusHalfB=%f C=%f\n", A, minusHalfB, C); + + float z = (minusHalfB - sqrtf(fsquare(minusHalfB) - A * C)) / A; + machinePos[X_AXIS] = (U * z - S) / Q; + machinePos[Y_AXIS] = (P - R * z) / Q; + machinePos[Z_AXIS] = z; +} + +// Compute the derivative of height with respect to a parameter at the specified motor endpoints. +// 'deriv' indicates the parameter as follows: +// 0, 1, 2 = X, Y, Z tower endstop adjustments +// 3, 4 = X, Y tower X position +// 5 = Z tower Y position +// 6 = diagonal rod length +// 7 = delta radius (only if isEquilateral is true) +float DeltaParameters::ComputeDerivative(unsigned int deriv, float ha, float hb, float hc) +{ + const float perturb = 0.2; // perturbation amount in mm + DeltaParameters hiParams(*this), loParams(*this); + switch(deriv) + { + case 0: + case 1: + case 2: + break; + + case 3: + case 4: + hiParams.towerX[deriv - 3] += perturb; + loParams.towerX[deriv - 3] -= perturb; + break; + + case 5: + { + const float yAdj = perturb * (1.0/3.0); + hiParams.towerY[A_AXIS] -= yAdj; + hiParams.towerY[B_AXIS] -= yAdj; + hiParams.towerY[C_AXIS] += (perturb - yAdj); + loParams.towerY[A_AXIS] += yAdj; + loParams.towerY[B_AXIS] += yAdj; + loParams.towerY[C_AXIS] -= (perturb - yAdj); + } + break; + + case 6: + hiParams.diagonal += perturb; + loParams.diagonal -= perturb; + break; + + case 7: + hiParams.SetRadius(radius + perturb); + loParams.SetRadius(radius - perturb); + break; + } + + hiParams.Recalc(); + loParams.Recalc(); + + float newPos[AXES]; + hiParams.InverseTransform((deriv == 0) ? ha + perturb : ha, (deriv == 1) ? hb + perturb : hb, (deriv == 2) ? hc + perturb : hc, newPos); + float zHi = newPos[Z_AXIS]; + loParams.InverseTransform((deriv == 0) ? ha - perturb : ha, (deriv == 1) ? hb - perturb : hb, (deriv == 2) ? hc - perturb : hc, newPos); + float zLo = newPos[Z_AXIS]; + + return (zHi - zLo)/(2 * perturb); +} + +// Perform 3, 4, 6 or 7-factor adjustment. +// The input vector contains the following parameters in this order: +// X, Y and Z endstop adjustments +// If we are doing 4-factor adjustment, the next argument is the delta radius. Otherwise: +// X tower X position adjustment +// Y tower X position adjustment +// Z tower Y position adjustment +// Diagonal rod length adjustment +void DeltaParameters::Adjust(size_t numFactors, const float v[]) +{ + const float oldCarriageHeightA = GetHomedCarriageHeight(A_AXIS); // save for later + + // Update endstop adjustments + endstopAdjustments[A_AXIS] += v[0]; + endstopAdjustments[B_AXIS] += v[1]; + endstopAdjustments[C_AXIS] += v[2]; + NormaliseEndstopAdjustments(); + + if (numFactors == 4) + { + // 4-factor adjustment, so update delta radius + SetRadius(radius + v[3]); // this sets isEquilateral true, recalculates tower positions, then calls Recalc() + } + else if (numFactors > 3) + { + // 6- or 7-factor adjustment + towerX[A_AXIS] += v[3]; + towerX[B_AXIS] += v[4]; + + const float yAdj = v[5] * (1.0/3.0); + towerY[A_AXIS] -= yAdj; + towerY[B_AXIS] -= yAdj; + towerY[C_AXIS] += (v[5] - yAdj); + isEquilateral = false; + + if (numFactors == 7) + { + diagonal += v[6]; + } + + Recalc(); + } + + // Adjusting the diagonal and the tower positions affects the homed carriage height. + // We need to adjust homedHeight to allow for this, to get the change that was requested in the endstop corrections. + const float heightError = GetHomedCarriageHeight(A_AXIS) - oldCarriageHeightA - v[0]; + homedHeight -= heightError; + homedCarriageHeight -= heightError; +} + +void DeltaParameters::PrintParameters(StringRef& reply, bool full) +{ + reply.printf("Endstops X%.2f Y%.2f Z%.2f, height %.2f, diagonal %.2f, ", + endstopAdjustments[A_AXIS], endstopAdjustments[B_AXIS], endstopAdjustments[C_AXIS], homedHeight, diagonal); + if (isEquilateral && !full) + { + reply.catf("radius %.2f\n", radius); + } + else + { + reply.catf("towers (%.2f,%.2f) (%.2f,%.2f) (%.2f,%.2f)\n", + towerX[A_AXIS], towerY[A_AXIS], towerX[B_AXIS], towerY[B_AXIS], towerX[C_AXIS], towerY[C_AXIS]); + } +} + +// End + + + diff --git a/DeltaParameters.h b/DeltaParameters.h new file mode 100644 index 0000000..81b3607 --- /dev/null +++ b/DeltaParameters.h @@ -0,0 +1,67 @@ +/* + * DeltaParameters.h + * + * Created on: 20 Apr 2015 + * Author: David + */ + +#ifndef DELTAPARAMETERS_H_ +#define DELTAPARAMETERS_H_ + +// Class to hold the parameter for a delta machine. +// Some of the values that are currently calculated on demand could be pre-calculated in Recalc() and stored instead. +class DeltaParameters +{ +public: + DeltaParameters() { Init(); } + + bool IsDeltaMode() const { return deltaMode; } + bool IsEquilateral() const { return isEquilateral; } + float GetDiagonal() const { return diagonal; } + float GetRadius() const { return radius; } + float GetPrintRadius() const { return printRadius; } + float GetTowerX(size_t axis) const { return towerX[axis]; } + float GetTowerY(size_t axis) const { return towerY[axis]; } + float GetEndstopAdjustment(size_t axis) const { return endstopAdjustments[axis]; } + float GetHomedCarriageHeight(size_t axis) const { return homedCarriageHeight + endstopAdjustments[axis]; } + float GetPrintRadiusSquared() const { return printRadiusSquared; } + + void Init(); + void SetDiagonal(float d) { diagonal = d; Recalc(); } + void SetRadius(float r); + void SetEndstopAdjustment(size_t axis, float x) { endstopAdjustments[axis] = x; } + void SetPrintRadius(float r) { printRadius = r; printRadiusSquared = r * r; } + float GetHomedHeight() const { return homedHeight; } + void SetHomedHeight(float h) { homedHeight = h; Recalc(); } + + float Transform(const float machinePos[AXES], size_t axis) const; // Calculate the motor position for a single tower from a Cartesian coordinate + void InverseTransform(float Ha, float Hb, float Hc, float machinePos[AXES]) const; // Calculate the Cartesian position from the motor positions + + float ComputeDerivative(unsigned int deriv, float ha, float hb, float hc); // Compute the derivative of height with respect to a parameter at a set of motor endpoints + void Adjust(size_t numFactors, const float v[]); // Perform 4-, 6- or 7-factor adjustment + void PrintParameters(StringRef& reply, bool full); + +private: + void Recalc(); + void NormaliseEndstopAdjustments(); // Make the average of the endstop adjustments zero + + // Core parameters + float diagonal; // The diagonal rod length, all 3 are assumed to be the same length + float radius; // The nominal delta radius, before any fine tuning of tower positions + float towerX[AXES]; // The X coordinate of each tower + float towerY[AXES]; // The Y coordinate of each tower + float endstopAdjustments[AXES]; // How much above or below the ideal position each endstop is + float printRadius; + float homedHeight; + + // Derived values + bool deltaMode; // True if this is a delta printer + bool isEquilateral; // True if the towers are at the corners of an equilateral triangle + float printRadiusSquared; + float homedCarriageHeight; + float Xbc, Xca, Xab, Ybc, Yca, Yab; + float coreFa, coreFb, coreFc; + float Q, Q2, D2; +}; + +#endif /* DELTAPARAMETERS_H_ */ diff --git a/DeltaProbe.cpp b/DeltaProbe.cpp new file mode 100644 index 0000000..d52472d --- /dev/null +++ b/DeltaProbe.cpp @@ -0,0 +1,136 @@ +/* + * DeltaProbe.cpp + * + * Created on: 20 Apr 2015 + * Author: David + */ + +#include "RepRapFirmware.h" + +// Set up to probe +bool DeltaProbe::Init(float frequency, float amplitude, float rate, float height) +{ +debugPrintf("Start probe f=%.1f a=%.2f r=%.2f h=%.1f\n", frequency, amplitude, rate, height); + // Sanity check the inputs (we check the max amplitude later) + if (frequency < 50.0 || frequency > 1000.0 || amplitude < 0.02 || rate < 0.1 || rate > 10.0 || height < 0.5) + { + return false; + } + +debugPrintf("ok so far\n"); + // Calculate the number of steps for the peak to peak amplitude + const float zRate = reprap.GetPlatform()->DriveStepsPerUnit(Z_AXIS); + normalSteps = (size_t)(amplitude * zRate); + if (normalSteps > MaxSteps) + { + return false; + } + +debugPrintf("normalSteps=%u\n", normalSteps); + // Build the tables of step times for sinusoidal motion + const float recipOmega = (float)DDA::stepClockRate/(frequency * 2.0 * PI); + + for (size_t i = 0; i < normalSteps - 1; ++i) + { + normalStepTable[i] = acos(1.0 - (float)(2 * (i + 1))/(float)normalSteps) * recipOmega; + } + + for (size_t i = 0; i < normalSteps; ++i) + { + incStepTable[i] = acos(1.0 - (float)(2 * (i + 1))/(float)(normalSteps + 1)) * recipOmega; + } + + halfCycleTime = (uint32_t)((float)DDA::stepClockRate/(2.0 * frequency)); + incStepTable[normalSteps] = normalStepTable[normalSteps - 1] = halfCycleTime; + + halfCyclesPerIncrement = 2 * (unsigned int)((frequency / (rate * zRate)) + 0.5); + if (halfCyclesPerIncrement < 4) + { + halfCyclesPerIncrement = 4; + } + maxIncrements = height * zRate; + +const float peakAccel = fsquare(2.0 * PI * frequency) * amplitude * 0.5; +debugPrintf("halfCycleTime=%u halfCyclesPerIncrement=%u peak accel=%.1f\n", halfCycleTime, halfCyclesPerIncrement, peakAccel); +debugPrintf("normalTable="); +for (unsigned int i = 0; i < normalSteps; ++i) +{ + debugPrintf(" %u", normalStepTable[i]); +} +debugPrintf(" incStepTable="); +for (unsigned int i = 0; i <= normalSteps; ++i) +{ + debugPrintf(" %u", incStepTable[i]); +} +debugPrintf("\n"); + return true; +} + +// Start probing, and return the time that the next step is due +uint32_t DeltaProbe::Start() +{ + // Initialise the dynamic values + stepsDone = 0; + halfCycleCount = 0; + numIncrements = 0; + incrementing = false; + state = State::normal; + return normalStepTable[0]; +} + +bool DeltaProbe::GetDirection() const +{ + return (halfCycleCount & 1) ? FORWARDS : BACKWARDS; +} + +// Calculate the next step time. Returns 0xFFFFFFFF to stop. +uint32_t DeltaProbe::CalcNextStepTime() +{ + if (state == State::stopped || state == State::overran) + { + return 0xFFFFFFFF; + } + + ++stepsDone; + if (stepsDone == ((incrementing) ? normalSteps + 1 : normalSteps)) + { + stepsDone = 0; + ++halfCycleCount; + if (state == State::stopping && (halfCycleCount & 1) == 0) + { + state = State::stopped; + return 0xFFFFFFFF; + } + + if (incrementing) + { + ++numIncrements; + incrementing = false; + } + + if (halfCycleCount == halfCyclesPerIncrement) + { + if (numIncrements == maxIncrements) + { + state = State::overran; // another increment is due, but we have already gone down as far as we were asked to + return 0xFFFFFFFF; + } + halfCycleCount = 0; + incrementing = true; + } + } + + return (incrementing) + ? (halfCyclesPerIncrement * numIncrements * halfCycleTime) + incStepTable[stepsDone] + : (halfCyclesPerIncrement * numIncrements * halfCycleTime) + normalStepTable[stepsDone]; +} + +void DeltaProbe::Trigger() +{ + if (state == State::normal) + { + state = State::stopping; + } +} + +// End diff --git a/DeltaProbe.h b/DeltaProbe.h new file mode 100644 index 0000000..50e0cc5 --- /dev/null +++ b/DeltaProbe.h @@ -0,0 +1,44 @@ +/* + * DeltaProbe.h + * + * Created on: 20 Apr 2015 + * Author: David + */ + +#ifndef DELTAPROBE_H_ +#define DELTAPROBE_H_ + +// Class to hold the parameters for my new Z probing method +class DeltaProbe +{ + enum class State { normal, stopping, stopped, overran }; + + // Fixed parameters + static const unsigned int MaxSteps = 30; // 15 corresponds to 0.375mm p-p movement @ 80 steps/mm + + // Static parameters, set up before we start probing and unchanged during probing + unsigned int normalSteps; // the number of steps we use to achieve the requested amplitude + unsigned int halfCyclesPerIncrement; // how many half cycles between lowering the head by 1 step + unsigned int maxIncrements; // max number of steps we lower the head + uint32_t halfCycleTime; // how many interrupt clocks per quarter cycle + uint32_t normalStepTable[MaxSteps]; // table of step times for the first half cycle, in interrupt clocks from start + uint32_t incStepTable[MaxSteps + 1]; // table of step times for the first half cycle, when we are moving down a step + + // Dynamic parameters, to track the progress of the probe + unsigned int stepsDone; // how many steps since the start of this quarter cycle + unsigned int halfCycleCount; // how many quarter cycles since we started or lowered the head + unsigned int numIncrements; // how many steps we have lowered the head since we started + bool incrementing; // true if we are lowering the head 2 step in this half cycle + State state; // what state the probe is in + +public: + bool Init(float frequency, float amplitude, float rate, float height); // Get ready to probe + uint32_t Start(); // start the process, return the next step time + bool GetDirection() const; // get the direction for the current step + uint32_t CalcNextStepTime(); // calculate when the next step is due + void Trigger(); // cease probing + bool Finished() const { return state == State::stopped || state == State::overran; } + bool Overran() const { return state == State::overran; } +}; + +#endif /* DELTAPROBE_H_ */ diff --git a/GCodes.cpp b/GCodes.cpp index 8197bd5..43fe3b1 100644 --- a/GCodes.cpp +++ b/GCodes.cpp @@ -152,6 +152,7 @@ void GCodes::DoFilePrint(GCodeBuffer* gb, StringRef& reply) else if (AllMovesAreFinishedAndMoveBufferIsLoaded()) { fileBeingPrinted.Close(); + reprap.GetPrintMonitor()->StoppedPrint(); } break; } @@ -170,7 +171,7 @@ void GCodes::Spin() // Check for M105 poll requests from Pronterface and PanelDue so that the status is kept up to date during execution of file macros etc. // No need to read multiple characters at a time in this case because the polling rate is quite low. if (!serialGCode->Active() && serialGCode->WritingFileDirectory() == nullptr - && (platform->GetLine()->Status() & byteAvailable)) + && (platform->GetLine()->Status() & (uint8_t)IOStatus::byteAvailable)) { char b; platform->GetLine()->Read(b); @@ -184,7 +185,7 @@ void GCodes::Spin() } } - if (!auxGCode->Active() && (platform->GetAux()->Status() & byteAvailable)) + if (!auxGCode->Active() && (platform->GetAux()->Status() & (uint8_t)IOStatus::byteAvailable)) { char b; platform->GetAux()->Read(b); @@ -407,7 +408,7 @@ void GCodes::StartNextGCode(StringRef& reply) // Now the serial interfaces. - if (platform->GetLine()->Status() & byteAvailable) + if (platform->GetLine()->Status() & (uint8_t)IOStatus::byteAvailable) { // First check the special case of uploading the reprap.htm file if (serialGCode->WritingFileDirectory() == platform->GetWebDir()) @@ -443,7 +444,7 @@ void GCodes::StartNextGCode(StringRef& reply) break; // stop after receiving a complete gcode in case we haven't finished processing it } ++i; - } while (i < 16 && (platform->GetLine()->Status() & byteAvailable)); + } while (i < 16 && (platform->GetLine()->Status() & (uint8_t)IOStatus::byteAvailable)); platform->ClassReport(longWait); return; } @@ -451,7 +452,7 @@ void GCodes::StartNextGCode(StringRef& reply) // Now run the G-Code buffers. It's important to fill up the G-Code buffers before we do this, // otherwise we wouldn't have a chance to pause/cancel running prints. - if (!auxGCode->Active() && (platform->GetAux()->Status() & byteAvailable)) + if (!auxGCode->Active() && (platform->GetAux()->Status() & (uint8_t)IOStatus::byteAvailable)) { int8_t i = 0; do @@ -465,7 +466,7 @@ void GCodes::StartNextGCode(StringRef& reply) break; // stop after receiving a complete gcode in case we haven't finished processing it } ++i; - } while (i < 16 && (platform->GetAux()->Status() & byteAvailable)); + } while (i < 16 && (platform->GetAux()->Status() & (uint8_t)IOStatus::byteAvailable)); } else if (webGCode->Active()) { @@ -949,7 +950,7 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex) switch (cannedCycleMoveCount) { case 0: // Move Z to the dive height. This only does anything on the first move; on all the others Z is already there - moveToDo[Z_AXIS] = platform->GetZProbeDiveHeight(); + moveToDo[Z_AXIS] = platform->GetZProbeDiveHeight() + max(platform->ZProbeStopHeight(), 0.0); activeDrive[Z_AXIS] = true; moveToDo[DRIVES] = platform->MaxFeedrate(Z_AXIS); activeDrive[DRIVES] = true; @@ -973,50 +974,50 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex) return false; case 2: // Probe the bed - if (!cannedCycleMoveQueued && reprap.GetPlatform()->GetZProbeResult() == lowHit) { - // Z probe is already triggered at the start of the move, so abandon the probe and record an error - platform->Message(BOTH_ERROR_MESSAGE, "Z probe warning: probe already triggered at start of probing move\n"); - cannedCycleMoveCount = 0; - reprap.GetMove()->SetZBedProbePoint(probePointIndex, platform->GetZProbeDiveHeight(), true, true); - return true; - } + const float height = (axisIsHomed[Z_AXIS]) + ? 2 * platform->GetZProbeDiveHeight() // Z axis has been homed, so no point in going very far + : 1.1 * platform->AxisTotalLength(Z_AXIS); // Z axis not homed yet, so treat this as a homing move + switch(DoZProbe(height)) + { + case 0: + // Z probe is already triggered at the start of the move, so abandon the probe and record an error + platform->Message(BOTH_ERROR_MESSAGE, "Z probe warning: probe already triggered at start of probing move\n"); + cannedCycleMoveCount++; + reprap.GetMove()->SetZBedProbePoint(probePointIndex, platform->GetZProbeDiveHeight(), true, true); + break; - moveToDo[Z_AXIS] = (axisIsHomed[Z_AXIS]) - ? -platform->GetZProbeDiveHeight() // Z axis has been homed, so no point in going very far - : -1.1 * platform->AxisTotalLength(Z_AXIS); // Z axis not homed yet, so treat this as a homing move - activeDrive[Z_AXIS] = true; - moveToDo[DRIVES] = platform->HomeFeedRate(Z_AXIS); - activeDrive[DRIVES] = true; - if (DoCannedCycleMove(ZProbeActive)) - { - // The head has been moved down until the probe was triggered. Get the height from the live coordinates. - // DoCannedCycleMove has already loaded the current position into moveBuffer - if (axisIsHomed[Z_AXIS]) - { - lastProbedZ = moveBuffer[Z_AXIS] - platform->ZProbeStopHeight(); + case 1: + if (axisIsHomed[Z_AXIS]) + { + lastProbedZ = moveBuffer[Z_AXIS] - platform->ZProbeStopHeight(); + } + else + { + // The Z axis has not yet been homed, so treat this probe as a homing move. + moveBuffer[Z_AXIS] = platform->ZProbeStopHeight(); + SetPositions(moveBuffer); + axisIsHomed[Z_AXIS] = true; + lastProbedZ = 0.0; + } + reprap.GetMove()->SetZBedProbePoint(probePointIndex, lastProbedZ, true, false); + cannedCycleMoveCount++; + break; + + default: + break; } - else - { - // The Z axis has not yet been homed, so treat this probe as a homing move. - moveBuffer[Z_AXIS] = platform->ZProbeStopHeight(); - SetPositions(moveBuffer); - axisIsHomed[Z_AXIS] = true; - lastProbedZ = 0.0; - } - cannedCycleMoveCount++; } return false; case 3: // Raise the head back up to the dive height - moveToDo[Z_AXIS] = platform->GetZProbeDiveHeight(); + moveToDo[Z_AXIS] = platform->GetZProbeDiveHeight() + max(platform->ZProbeStopHeight(), 0.0); activeDrive[Z_AXIS] = true; moveToDo[DRIVES] = platform->MaxFeedrate(Z_AXIS); activeDrive[DRIVES] = true; if (DoCannedCycleMove(0)) { cannedCycleMoveCount = 0; - reprap.GetMove()->SetZBedProbePoint(probePointIndex, lastProbedZ, true, false); return true; } return false; @@ -1027,30 +1028,62 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex) } } -// This simply moves down till the Z probe/switch is triggered. +// This simply moves down till the Z probe/switch is triggered. Call it repeatedly until it returns true. // Called when we do a G30 with no P parameter. bool GCodes::DoSingleZProbe() { - for (size_t drive = 0; drive <= DRIVES; drive++) + switch (DoZProbe(1.1 * platform->AxisTotalLength(Z_AXIS))) { - activeDrive[drive] = false; - } + case 0: // failed + return true; - moveToDo[Z_AXIS] = -1.1 * platform->AxisTotalLength(Z_AXIS); - activeDrive[Z_AXIS] = true; - moveToDo[DRIVES] = platform->HomeFeedRate(Z_AXIS); - activeDrive[DRIVES] = true; - if (DoCannedCycleMove(ZProbeActive)) - { - // The head has been moved down until the probe was triggered. Get the height from the live coordinates. - // DoCannedCycleMove has already loaded the current position into moveBuffer + case 1: // success moveBuffer[Z_AXIS] = platform->ZProbeStopHeight(); SetPositions(moveBuffer); axisIsHomed[Z_AXIS] = true; lastProbedZ = 0.0; return true; + + default: // not finished yet + return false; + } +} + +// Do a Z probe cycle up to the maximum specified distance. +// Returns -1 if not complete yet +// Returns 0 if failed +// Returns 1 if success, with lastProbedZ set to the height we stopped at and the current position in moveBuffer +int GCodes::DoZProbe(float distance) +{ + if (platform->GetZProbeType() == 5) + { + const ZProbeParameters& params = platform->GetZProbeParameters(); + return reprap.GetMove()->DoDeltaProbe(params.param1, params.param2, platform->HomeFeedRate(Z_AXIS), distance); + } + else + { + if (!cannedCycleMoveQueued && reprap.GetPlatform()->GetZProbeResult() == EndStopHit::lowHit) + { + return 0; + } + + // Do a normal canned cycle Z movement with Z probe enabled + for (size_t drive = 0; drive <= DRIVES; drive++) + { + activeDrive[drive] = false; + } + + moveToDo[Z_AXIS] = -distance; + activeDrive[Z_AXIS] = true; + moveToDo[DRIVES] = platform->HomeFeedRate(Z_AXIS); + activeDrive[DRIVES] = true; + + if (DoCannedCycleMove(ZProbeActive)) + { + return 1; + } + return -1; } - return false; } // This is called to execute a G30. @@ -1339,11 +1372,17 @@ void GCodes::WriteGCodeToFile(GCodeBuffer *gb) // Set up a file to print, but don't print it yet. void GCodes::QueueFileToPrint(const char* fileName) { - fileToPrint.Close(); - fileGCode->CancelPause(); // if we paused it and then asked to print a new file, cancel any pending command FileStore *f = platform->GetFileStore(platform->GetGCodeDir(), fileName, false); if (f != NULL) { + // Cancel current print if there is any + if (PrintingAFile()) + { + CancelPrint(); + } + + fileGCode->SetToolNumberAdjust(0); // clear tool number adjustment + // Reset all extruder positions when starting a new print for (size_t extruder = AXES; extruder < DRIVES; extruder++) { @@ -1351,10 +1390,6 @@ void GCodes::QueueFileToPrint(const char* fileName) } fileToPrint.Set(f); - if (!fileBeingPrinted.IsLive()) - { - fileGCode->SetToolNumberAdjust(0); // clear tool number adjustment - } } else { @@ -2092,9 +2127,21 @@ bool GCodes::HandleGcode(GCodeBuffer* gb, StringRef& reply) if (toBeHomed == 0 || toBeHomed == ((1 << X_AXIS) | (1 << Y_AXIS) | (1 << Z_AXIS))) { + // Homing everything SetAllAxesNotHomed(); DoFileMacro(HOME_ALL_G); } + else if ( platform->MustHomeXYBeforeZ() + && ((toBeHomed & (1 << Z_AXIS)) != 0) + && ( (((toBeHomed & (1 << X_AXIS)) == 0) && !axisIsHomed[X_AXIS]) + || (((toBeHomed & (1 << Y_AXIS)) == 0) && !axisIsHomed[Y_AXIS]) + ) + ) + { + // We can only home Z if both X and Y have already been homed or are being homed + reply.copy("Must home X and Y before homing Z"); + error = true; + } else { state = GCodeState::homing; @@ -2215,6 +2262,9 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) isPaused = false; reply.copy("Print cancelled\n"); } + + // Reset everything + CancelPrint(); break; case 18: // Motors off @@ -2332,10 +2382,10 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) { const char* filename = gb->GetUnprecedentedString(); - reprap.GetPrintMonitor()->StartingFilePrint(filename); QueueFileToPrint(filename); if (fileToPrint.IsLive()) { + reprap.GetPrintMonitor()->StartingPrint(filename); if (platform->Emulating() == marlin && gb == serialGCode) { reply.copy("File opened\nFile selected\n"); @@ -2349,7 +2399,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) if (code == 32) { fileBeingPrinted.MoveFrom(fileToPrint); - reprap.GetPrintMonitor()->StartedFilePrint(); + reprap.GetPrintMonitor()->StartedPrint(); } } else @@ -2379,7 +2429,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) else { fileBeingPrinted.MoveFrom(fileToPrint); - reprap.GetPrintMonitor()->StartedFilePrint(); + reprap.GetPrintMonitor()->StartedPrint(); } break; @@ -2859,19 +2909,19 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) const char* es; switch (platform->Stopped(axis)) { - case lowHit: + case EndStopHit::lowHit: es = "at min stop"; break; - case highHit: + case EndStopHit::highHit: es = "at max stop"; break; - case lowNear: + case EndStopHit::lowNear: es = "near min stop"; break; - case noStop: + case EndStopHit::noStop: default: es = "not stopped"; } @@ -3522,10 +3572,31 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) seen = true; } + if (gb->Seen('S')) + { + ZProbeParameters params = platform->GetZProbeParameters(); + params.param1 = gb->GetFValue(); + platform->SetZProbeParameters(params); + seen = true; + } + + if (gb->Seen('T')) + { + ZProbeParameters params = platform->GetZProbeParameters(); + params.param2 = gb->GetFValue(); + platform->SetZProbeParameters(params); + seen = true; + } + if (!seen) { - reply.printf("Z Probe type is %d on channel %d with dive height %.1f and it is used for these axes:", - platform->GetZProbeType(), platform->GetZProbeChannel(), platform->GetZProbeDiveHeight()); + reply.printf("Z Probe type %d, channel %d, dive height %.1f", platform->GetZProbeType(), platform->GetZProbeChannel(), platform->GetZProbeDiveHeight()); + if (platform->GetZProbeType() == 5) + { + ZProbeParameters params = platform->GetZProbeParameters(); + reply.catf(", parameters %.2f %.2f", params.param1, params.param2); + } + reply.cat(", used for these axes:"); for (size_t axis = 0; axis < AXES; axis++) { if (zProbeAxes[axis]) @@ -3773,8 +3844,8 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) bool logic; platform->GetEndStopConfiguration(axis, config, logic); reply.catf(" %c %s %s %c", axisLetters[axis], - (config == highEndStop) ? "high end" : (config == lowEndStop) ? "low end" : "none", - (config == noEndStop) ? "" : (logic) ? " (active high)" : " (active low)", + (config == EndStopType::highEndStop) ? "high end" : (config == EndStopType::lowEndStop) ? "low end" : "none", + (config == EndStopType::noEndStop) ? "" : (logic) ? " (active high)" : " (active low)", (axis == AXES - 1) ? '\n' : ','); } } @@ -3996,7 +4067,10 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) result = DoDwellTime(0.5);// wait half a second to allow the response to be sent back to the web server, otherwise it may retry if (result) { - platform->SoftwareReset(SoftwareResetReason::user); // doesn't return + uint16_t reason = (gb->Seen('S') && gb->GetIValue() == 4321) + ? SoftwareResetReason::erase + : SoftwareResetReason::user; + platform->SoftwareReset(reason); // doesn't return } break; @@ -4056,6 +4130,21 @@ void GCodes::PauseSDPrint() } } +// Cancel the current SD card print +void GCodes::CancelPrint() +{ + moveAvailable = false; + + fileGCode->Init(); + + if (fileBeingPrinted.IsLive()) + { + fileBeingPrinted.Close(); + } + + reprap.GetPrintMonitor()->StoppedPrint(); +} + // Return true if all the heaters for the specified tool are at their set temperatures bool GCodes::ToolHeatersAtSetTemperatures(const Tool *tool) const { diff --git a/GCodes.h b/GCodes.h index b86396e..af4dbcc 100644 --- a/GCodes.h +++ b/GCodes.h @@ -119,11 +119,13 @@ class GCodes bool HandleGcode(GCodeBuffer* gb, StringRef& reply); // Do a G code bool HandleMcode(GCodeBuffer* gb, StringRef& reply); // Do an M code bool HandleTcode(GCodeBuffer* gb, StringRef& reply); // Do a T code + void CancelPrint(); // Cancel the current print int SetUpMove(GCodeBuffer* gb, StringRef& reply); // Pass a move on to the Move module bool DoDwell(GCodeBuffer *gb); // Wait for a bit bool DoDwellTime(float dwell); // Really wait for a bit bool DoSingleZProbeAtPoint(int probePointIndex); // Probe at a given point bool DoSingleZProbe(); // Probe where we are + int DoZProbe(float distance); // Do a Z probe cycle up to the maximum specified distance bool SetSingleZProbeAtAPosition(GCodeBuffer *gb, StringRef& reply); // Probes at a given position - see the comment at the head of the function itself void SetBedEquationWithProbe(int sParam, StringRef& reply); // Probes a series of points and sets the bed equation bool SetPrintZProbe(GCodeBuffer *gb, StringRef& reply); // Either return the probe value, or set its threshold @@ -232,8 +234,8 @@ inline bool GCodes::HaveIncomingData() const { return fileBeingPrinted.IsLive() || webserver->GCodeAvailable() || - (platform->GetLine()->Status() & byteAvailable) || - (platform->GetAux()->Status() & byteAvailable); + (platform->GetLine()->Status() & (uint8_t)IOStatus::byteAvailable) || + (platform->GetAux()->Status() & (uint8_t)IOStatus::byteAvailable); } // This function takes care of the fact that the heater and head indices don't match because the bed is heater 0. diff --git a/network/ethernet_sam.c b/Libraries/EMAC/ethernet_sam.c similarity index 93% rename from network/ethernet_sam.c rename to Libraries/EMAC/ethernet_sam.c index 1854265..5e03943 100644 --- a/network/ethernet_sam.c +++ b/Libraries/EMAC/ethernet_sam.c @@ -68,23 +68,13 @@ #include "lwip/src/include/netif/etharp.h" #include "lwip/src/sam/include/netif/ethernetif.h" -#include "emac.h" +#include "include/emac.h" extern void RepRapNetworkMessage(const char*); /* Global variable containing MAC Config (hw addr, IP, GW, ...) */ struct netif gs_net_if; -//*****************************AB -//Pass through function for interface status -//by including ethernetif.h directly and calling ethernetif_phy_link_status(); this function is not required -bool status_link_up() -{ - return ethernetif_phy_link_status(); -} -//*****************************AB - - struct netif* ethernet_get_configuration() { return &gs_net_if; @@ -193,10 +183,13 @@ static void ethernet_configure_interface(unsigned char ipAddress[], unsigned cha /** \brief Initialize the Ethernet subsystem. * */ -void init_ethernet(void) +void init_ethernet(const u8_t macAddress[], const char *hostname) { lwip_init(); ethernet_hardware_init(); + + ethernetif_set_mac_address(macAddress); + netif_set_hostname(&gs_net_if, hostname); } /** \brief Try to establish a physical link at, returning true if successful. @@ -216,13 +209,6 @@ void start_ethernet(const unsigned char ipAddress[], const unsigned char netMask ethernet_configure_interface(ipAddress, netMask, gateWay); } -/** \brief Set the DHCP hostname. - * - */ -void set_dhcp_hostname(const char *hostname) -{ - gs_net_if.hostname = hostname; -} //************************************************************************************************************* /** @@ -237,7 +223,7 @@ void ethernet_status_callback(struct netif *netif) { RepRapNetworkMessage("Network up, IP="); ipaddr_ntoa_r(&(netif->ip_addr), c_mess, sizeof(c_mess)); - strncat(c_mess, sizeof(c_mess) - strlen(c_mess) - 1, "\n"); + strncat(c_mess, sizeof(c_mess) - 1, "\n"); RepRapNetworkMessage(c_mess); netif->flags |= NETIF_FLAG_LINK_UP; } @@ -248,11 +234,10 @@ void ethernet_status_callback(struct netif *netif) } - /**0 * \brief Manage the Ethernet packets, if any received process them. * After processing any packets, manage the lwIP timers. -* + * * \return Returns true if data has been processed. */ bool ethernet_read(void) @@ -275,6 +260,5 @@ bool ethernet_read(void) */ void ethernet_set_rx_callback(emac_dev_tx_cb_t callback) { - ethernetif_set_rx_callback(callback); } diff --git a/network/ethernet_sam.h b/Libraries/EMAC/ethernet_sam.h similarity index 95% rename from network/ethernet_sam.h rename to Libraries/EMAC/ethernet_sam.h index 192e993..8700c9e 100644 --- a/network/ethernet_sam.h +++ b/Libraries/EMAC/ethernet_sam.h @@ -54,18 +54,14 @@ extern "C" { /**INDENT-ON**/ /// @endcond -bool status_link_up();//*****************************AB - /** * \brief Initialize the ethernet interface. * */ -//void init_ethernet(void); +void init_ethernet(const u8_t macAddress[], const char *hostname); -void init_ethernet(void); bool establish_ethernet_link(void); void start_ethernet(const unsigned char ipAddress[], const unsigned char netMask[], const unsigned char gateWay[]); -void set_dhcp_hostname(const char *hostname); struct netif* ethernet_get_configuration(); diff --git a/Libraries/Lwip/contrib/apps/netbios/netbios.c b/Libraries/Lwip/contrib/apps/netbios/netbios.c new file mode 100644 index 0000000..ef6be80 --- /dev/null +++ b/Libraries/Lwip/contrib/apps/netbios/netbios.c @@ -0,0 +1,337 @@ +/** + * @file + * NetBIOS name service sample + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwipopts.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/src/include/lwip/udp.h" +#include "lwip/src/include/lwip/netif.h" + +#include + +/** This is an example implementation of a NetBIOS name server. + * It responds to name queries for a configurable name. + * Name resolving is not supported. + * + * Note that the device doesn't broadcast it's own name so can't + * detect duplicate names! + */ + +/** NetBIOS name of LWIP device + * This must be uppercase until NETBIOS_STRCMP() is defined to a string + * comparision function that is case insensitive. + * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): + * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") + */ +#ifndef NETBIOS_LWIP_NAME +#define NETBIOS_LWIP_NAME (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "DUET" : "DUET") +#endif + +/** Since there's no standard function for case-insensitive string comparision, + * we need another define here: + * define this to stricmp() for windows or strcasecmp() for linux. + * If not defined, comparision is case sensitive and NETBIOS_LWIP_NAME must be + * uppercase + */ +#ifndef NETBIOS_STRCMP +#define NETBIOS_STRCMP(str1, str2) stricmp(str1, str2) +#endif + +/** default port number for "NetBIOS Name service */ +#define NETBIOS_PORT 137 + +/** size of a NetBIOS name */ +#define NETBIOS_NAME_LEN 16 + +/** The Time-To-Live for NetBIOS name responds (in seconds) + * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ +#define NETBIOS_NAME_TTL 300000 + +/** NetBIOS header flags */ +#define NETB_HFLAG_RESPONSE 0x8000U +#define NETB_HFLAG_OPCODE 0x7800U +#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U +#define NETB_HFLAG_AUTHORATIVE 0x0400U +#define NETB_HFLAG_TRUNCATED 0x0200U +#define NETB_HFLAG_RECURS_DESIRED 0x0100U +#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U +#define NETB_HFLAG_BROADCAST 0x0010U +#define NETB_HFLAG_REPLYCODE 0x0008U +#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U + +/** NetBIOS name flags */ +#define NETB_NFLAG_UNIQUE 0x8000U +#define NETB_NFLAG_NODETYPE 0x6000U +#define NETB_NFLAG_NODETYPE_HNODE 0x6000U +#define NETB_NFLAG_NODETYPE_MNODE 0x4000U +#define NETB_NFLAG_NODETYPE_PNODE 0x2000U +#define NETB_NFLAG_NODETYPE_BNODE 0x0000U + +/** NetBIOS message header */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_hdr { + PACK_STRUCT_FIELD(u16_t trans_id); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(u16_t questions); + PACK_STRUCT_FIELD(u16_t answerRRs); + PACK_STRUCT_FIELD(u16_t authorityRRs); + PACK_STRUCT_FIELD(u16_t additionalRRs); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** NetBIOS message name part */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_name_hdr { + PACK_STRUCT_FIELD(u8_t nametype); + PACK_STRUCT_FIELD(u8_t encname[(NETBIOS_NAME_LEN*2)+1]); + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t cls); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t datalen); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(ip_addr_p_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** NetBIOS message */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_resp +{ + struct netbios_hdr resp_hdr; + struct netbios_name_hdr resp_name; +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** NetBIOS decoding name */ +static int +netbios_name_decoding( char *name_enc, char *name_dec, int name_dec_len) +{ + char *pname; + char cname; + char cnbname; + int index = 0; + + LWIP_UNUSED_ARG(name_dec_len); + + /* Start decoding netbios name. */ + pname = name_enc; + for (;;) { + /* Every two characters of the first level-encoded name + * turn into one character in the decoded name. */ + cname = *pname; + if (cname == '\0') + break; /* no more characters */ + if (cname == '.') + break; /* scope ID follows */ + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + return -1; + } + cname -= 'A'; + cnbname = cname << 4; + pname++; + + cname = *pname; + if (cname == '\0' || cname == '.') { + /* No more characters in the name - but we're in + * the middle of a pair. Not legal. */ + return -1; + } + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + return -1; + } + cname -= 'A'; + cnbname |= cname; + pname++; + + /* Do we have room to store the character? */ + if (index < NETBIOS_NAME_LEN) { + /* Yes - store the character. */ + name_dec[index++] = (cnbname!=' '?cnbname:'\0'); + } + } + + return 0; +} + +#if 0 /* function currently unused */ +/** NetBIOS encoding name */ +static int +netbios_name_encoding(char *name_enc, char *name_dec, int name_dec_len) +{ + char *pname; + char cname; + unsigned char ucname; + int index = 0; + + /* Start encoding netbios name. */ + pname = name_enc; + + for (;;) { + /* Every two characters of the first level-encoded name + * turn into one character in the decoded name. */ + cname = *pname; + if (cname == '\0') + break; /* no more characters */ + if (cname == '.') + break; /* scope ID follows */ + if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { + /* Not legal. */ + return -1; + } + + /* Do we have room to store the character? */ + if (index >= name_dec_len) { + return -1; + } + + /* Yes - store the character. */ + ucname = cname; + name_dec[index++] = ('A'+((ucname>>4) & 0x0F)); + name_dec[index++] = ('A'+( ucname & 0x0F)); + pname++; + } + + /* Fill with "space" coding */ + for (;indexpayload; + struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1); + + /* we only answer if we got a default interface */ + if (netif_default != NULL) { + /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ + /* if the packet is a NetBIOS name query question */ + if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && + ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && + (netbios_hdr->questions == PP_NTOHS(1))) { + /* decode the NetBIOS name */ + netbios_name_decoding( (char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); + /* if the packet is for us */ + if (NETBIOS_STRCMP(netbios_name, NETBIOS_LWIP_NAME) == 0) { + struct pbuf *q; + struct netbios_resp *resp; + + q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); + if (q != NULL) { + resp = (struct netbios_resp*)q->payload; + + /* prepare NetBIOS header response */ + resp->resp_hdr.trans_id = netbios_hdr->trans_id; + resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | + NETB_HFLAG_OPCODE_NAME_QUERY | + NETB_HFLAG_AUTHORATIVE | + NETB_HFLAG_RECURS_DESIRED); + resp->resp_hdr.questions = 0; + resp->resp_hdr.answerRRs = PP_HTONS(1); + resp->resp_hdr.authorityRRs = 0; + resp->resp_hdr.additionalRRs = 0; + + /* prepare NetBIOS header datas */ + MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); + resp->resp_name.nametype = netbios_name_hdr->nametype; + resp->resp_name.type = netbios_name_hdr->type; + resp->resp_name.cls = netbios_name_hdr->cls; + resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); + resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr)); + resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); + ip_addr_copy(resp->resp_name.addr, netif_default->ip_addr); + + /* send the NetBIOS response */ + udp_sendto(upcb, q, addr, port); + + /* free the "reference" pbuf */ + pbuf_free(q); + } + } + } + } + /* free the pbuf */ + pbuf_free(p); + } +} + +void netbios_init(void) +{ + struct udp_pcb *pcb; + + LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); + + pcb = udp_new(); + if (pcb != NULL) { + /* we have to be allowed to send broadcast packets! */ + pcb->so_options |= SOF_BROADCAST; + udp_bind(pcb, IP_ADDR_ANY, NETBIOS_PORT); + udp_recv(pcb, netbios_recv, pcb); + } +} +#endif /* LWIP_UDP */ diff --git a/Libraries/Lwip/contrib/apps/netbios/netbios.h b/Libraries/Lwip/contrib/apps/netbios/netbios.h new file mode 100644 index 0000000..2c73f78 --- /dev/null +++ b/Libraries/Lwip/contrib/apps/netbios/netbios.h @@ -0,0 +1,6 @@ +#ifndef __NETBIOS_H__ +#define __NETBIOS_H__ + +void netbios_init(void); + +#endif /* __NETBIOS_H__ */ diff --git a/Libraries/Lwip/lwip/src/include/lwip/sys.h b/Libraries/Lwip/lwip/src/include/lwip/sys.h index d1bced6..2286fd0 100644 --- a/Libraries/Lwip/lwip/src/include/lwip/sys.h +++ b/Libraries/Lwip/lwip/src/include/lwip/sys.h @@ -76,7 +76,7 @@ typedef u8_t sys_mbox_t; */ #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT -#include "lwip/err.h" +#include "err.h" #include "arch/sys_arch.h" /** Function prototype for thread functions */ diff --git a/Libraries/Lwip/lwip/src/sam/include/netif/ethernetif.h b/Libraries/Lwip/lwip/src/sam/include/netif/ethernetif.h index 4e41667..98d7eeb 100644 --- a/Libraries/Lwip/lwip/src/sam/include/netif/ethernetif.h +++ b/Libraries/Lwip/lwip/src/sam/include/netif/ethernetif.h @@ -53,12 +53,11 @@ bool ethernetif_phy_link_status(void); //*****************************AB err_t ethernetif_init(struct netif *netif); +void ethernetif_set_params(const u8_t macAddress[], const char *hostname); bool ethernetif_input(void *pv_parameters); void ethernet_hardware_init(void); bool ethernet_establish_link(void); -void RepRapNetworkSetMACAddress(const u8_t macAddress[]); -void ethernetif_set_rx_callback(emac_dev_tx_cb_t callback); #endif /* ETHERNETIF_H_INCLUDED */ diff --git a/Libraries/Lwip/lwip/src/sam/netif/ethernetif.c b/Libraries/Lwip/lwip/src/sam/netif/ethernetif.c index 3201b19..f2e6532 100644 --- a/Libraries/Lwip/lwip/src/sam/netif/ethernetif.c +++ b/Libraries/Lwip/lwip/src/sam/netif/ethernetif.c @@ -423,34 +423,18 @@ bool ethernetif_input(void * pvParameters) struct netif *netif = (struct netif *)pvParameters; struct pbuf *p; -#ifdef FREERTOS_USED - for( ;; ) { - do { -#endif - /* move received packet into a new pbuf */ - p = low_level_input( netif ); - if( p == NULL ) - { -#ifdef FREERTOS_USED - /* No packet could be read. Wait a for an interrupt to tell us - there is more data available. */ - vTaskDelay(100); - } - }while( p == NULL ); -#else - return false; - } -#endif - - if( ERR_OK != netif->input( p, netif ) ) - { - pbuf_free(p); - p = NULL; - } -#ifdef FREERTOS_USED + /* move received packet into a new pbuf */ + p = low_level_input( netif ); + if( p == NULL ) + { + return false; } -#endif + if( ERR_OK != netif->input( p, netif ) ) + { + pbuf_free(p); + p = NULL; + } return true; } @@ -475,7 +459,7 @@ err_t ethernetif_init(struct netif *netif) #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ - netif->hostname = "lwip"; +// netif->hostname = "lwip"; // Unused! Duet sets hostname explicitly #endif /* LWIP_NETIF_HOSTNAME */ /* @@ -517,17 +501,15 @@ err_t ethernetif_init(struct netif *netif) return ERR_OK; } -void RepRapNetworkSetMACAddress(const u8_t macAddress[]) -{ - size_t i; - for (i = 0; i < 8; ++i) - { - gs_uc_mac_address[i] = macAddress[i]; - } -} - - void ethernetif_set_rx_callback(emac_dev_tx_cb_t callback) { emac_dev_set_rx_callback(&gs_emac_dev, callback); } + +void ethernetif_set_mac_address(const u8_t macAddress[]) +{ + for (size_t i = 0; i < 8; ++i) + { + gs_uc_mac_address[i] = macAddress[i]; + } +} diff --git a/network/lwipopts.h b/Libraries/Lwip/lwipopts.h similarity index 97% rename from network/lwipopts.h rename to Libraries/Lwip/lwipopts.h index 0bba35b..cebbdd8 100644 --- a/network/lwipopts.h +++ b/Libraries/Lwip/lwipopts.h @@ -53,9 +53,6 @@ /* Include user defined options first */ #include "conf_eth.h" -#ifdef LWIP_DEBUG -#include "lwip/src/include/lwip/debug.h" -#endif /* ---------- System options ---------- */ /* Specify NO_SYS because we are not using an RTOS */ @@ -101,10 +98,10 @@ a lot of data that needs to be copied, this should be set high. */ #define UDP_TTL 255 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ -#define MEMP_NUM_UDP_PCB 1 +#define MEMP_NUM_UDP_PCB 2 /* MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. */ -#define MEMP_NUM_TCP_PCB 12 +#define MEMP_NUM_TCP_PCB 16 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 4 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ @@ -268,11 +265,4 @@ a lot of data that needs to be copied, this should be set high. */ // \note For a list of all possible lwIP configurations, check http://lwip.wikia.com/wiki/Lwipopts.h -/** EMAC PHY address */ -#define BOARD_EMAC_PHY_ADDR 2 -/*! EMAC RMII mode */ -#define BOARD_EMAC_MODE_RMII 1 - -/**/ - #endif /* __LWIPOPTS_H__ */ diff --git a/Move.cpp b/Move.cpp index b1c51ec..628858b 100644 --- a/Move.cpp +++ b/Move.cpp @@ -7,242 +7,6 @@ #include "RepRapFirmware.h" -void DeltaParameters::Init() -{ - deltaMode = false; - diagonal = 0.0; - radius = 0.0; - printRadius = defaultPrintRadius; - homedHeight = defaultDeltaHomedHeight; - isEquilateral = true; - - for (size_t axis = 0; axis < AXES; ++axis) - { - endstopAdjustments[axis] = 0.0; - towerX[axis] = towerY[axis] = 0.0; - } -} - -void DeltaParameters::SetRadius(float r) -{ - radius = r; - isEquilateral = true; - - const float cos30 = sqrtf(3.0)/2.0; - const float sin30 = 0.5; - - towerX[A_AXIS] = -(r * cos30); - towerX[B_AXIS] = r * cos30; - towerX[C_AXIS] = 0.0; - - towerY[A_AXIS] = towerY[B_AXIS] = -(r * sin30); - towerY[C_AXIS] = r; - - Recalc(); -} - -void DeltaParameters::Recalc() -{ - deltaMode = (radius > 0.0 && diagonal > radius); - if (deltaMode) - { - Xbc = towerX[C_AXIS] - towerX[B_AXIS]; - Xca = towerX[A_AXIS] - towerX[C_AXIS]; - Xab = towerX[B_AXIS] - towerX[A_AXIS]; - Ybc = towerY[C_AXIS] - towerY[B_AXIS]; - Yca = towerY[A_AXIS] - towerY[C_AXIS]; - Yab = towerY[B_AXIS] - towerY[A_AXIS]; - coreFa = fsquare(towerX[A_AXIS]) + fsquare(towerY[A_AXIS]); - coreFb = fsquare(towerX[B_AXIS]) + fsquare(towerY[B_AXIS]); - coreFc = fsquare(towerX[C_AXIS]) + fsquare(towerY[C_AXIS]); - Q = 2 * (Xca * Yab - Xab * Yca); - Q2 = fsquare(Q); - D2 = fsquare(diagonal); - - // Calculate the base carriage height when the printer is homed. - const float tempHeight = diagonal; // any sensible height will do here, probably even zero - float machinePos[AXES]; - InverseTransform(tempHeight + endstopAdjustments[X_AXIS], tempHeight + endstopAdjustments[Y_AXIS], tempHeight + endstopAdjustments[X_AXIS], - machinePos); - homedCarriageHeight = homedHeight + tempHeight - machinePos[Z_AXIS]; - } -} - -// Make the average of the endstop adjustments zero, without changing the individual homed carriage heights -void DeltaParameters::NormaliseEndstopAdjustments() -{ - const float eav = (endstopAdjustments[A_AXIS] + endstopAdjustments[B_AXIS] + endstopAdjustments[C_AXIS])/3.0; - endstopAdjustments[A_AXIS] -= eav; - endstopAdjustments[B_AXIS] -= eav; - endstopAdjustments[C_AXIS] -= eav; - homedHeight += eav; - homedCarriageHeight += eav; // no need for a full recalc, this is sufficient -} - -// Calculate the motor position for a single tower from a Cartesian coordinate -float DeltaParameters::Transform(const float machinePos[AXES], size_t axis) const -{ - return machinePos[Z_AXIS] - + sqrt(D2 - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[axis])); -} - -void DeltaParameters::InverseTransform(float Ha, float Hb, float Hc, float machinePos[AXES]) const -{ - const float Fa = coreFa + fsquare(Ha); - const float Fb = coreFb + fsquare(Hb); - const float Fc = coreFc + fsquare(Hc); - -// debugPrintf("Ha=%f Hb=%f Hc=%f Fa=%f Fb=%f Fc=%f Xbc=%f Xca=%f Xab=%f Ybc=%f Yca=%f Yab=%f\n", -// Ha, Hb, Hc, Fa, Fb, Fc, Xbc, Xca, Xab, Ybc, Yca, Yab); - - // Setup PQRSU such that x = -(S - uz)/P, y = (P - Rz)/Q - const float P = (Xbc * Fa) + (Xca * Fb) + (Xab * Fc); - const float S = (Ybc * Fa) + (Yca * Fb) + (Yab * Fc); - - const float R = 2 * ((Xbc * Ha) + (Xca * Hb) + (Xab * Hc)); - const float U = 2 * ((Ybc * Ha) + (Yca * Hb) + (Yab * Hc)); - -// debugPrintf("P= %f R=%f S=%f U=%f Q=%f\n", P, R, S, U, Q); - - const float R2 = fsquare(R), U2 = fsquare(U); - - float A = U2 + R2 + Q2; - float minusHalfB = S * U + P * R + Ha * Q2 + towerX[A_AXIS] * U * Q - towerY[A_AXIS] * R * Q; - float C = fsquare(S + towerX[A_AXIS] * Q) + fsquare(P - towerY[A_AXIS] * Q) + (fsquare(Ha) - D2) * Q2; - -// debugPrintf("A=%f minusHalfB=%f C=%f\n", A, minusHalfB, C); - - float z = (minusHalfB - sqrtf(fsquare(minusHalfB) - A * C)) / A; - machinePos[X_AXIS] = (U * z - S) / Q; - machinePos[Y_AXIS] = (P - R * z) / Q; - machinePos[Z_AXIS] = z; -} - -// Compute the derivative of height with respect to a parameter at the specified motor endpoints. -// 'deriv' indicates the parameter as follows: -// 0, 1, 2 = X, Y, Z tower endstop adjustments -// 3, 4 = X, Y tower X position -// 5 = Z tower Y position -// 6 = diagonal rod length -// 7 = delta radius (only if isEquilateral is true) -float DeltaParameters::ComputeDerivative(unsigned int deriv, float ha, float hb, float hc) -{ - const float perturb = 0.2; // perturbation amount in mm - DeltaParameters hiParams(*this), loParams(*this); - switch(deriv) - { - case 0: - case 1: - case 2: - break; - - case 3: - case 4: - hiParams.towerX[deriv - 3] += perturb; - loParams.towerX[deriv - 3] -= perturb; - break; - - case 5: - { - const float yAdj = perturb * (1.0/3.0); - hiParams.towerY[A_AXIS] -= yAdj; - hiParams.towerY[B_AXIS] -= yAdj; - hiParams.towerY[C_AXIS] += (perturb - yAdj); - loParams.towerY[A_AXIS] += yAdj; - loParams.towerY[B_AXIS] += yAdj; - loParams.towerY[C_AXIS] -= (perturb - yAdj); - } - break; - - case 6: - hiParams.diagonal += perturb; - loParams.diagonal -= perturb; - break; - - case 7: - hiParams.SetRadius(radius + perturb); - loParams.SetRadius(radius - perturb); - break; - } - - hiParams.Recalc(); - loParams.Recalc(); - - float newPos[AXES]; - hiParams.InverseTransform((deriv == 0) ? ha + perturb : ha, (deriv == 1) ? hb + perturb : hb, (deriv == 2) ? hc + perturb : hc, newPos); - float zHi = newPos[Z_AXIS]; - loParams.InverseTransform((deriv == 0) ? ha - perturb : ha, (deriv == 1) ? hb - perturb : hb, (deriv == 2) ? hc - perturb : hc, newPos); - float zLo = newPos[Z_AXIS]; - - return (zHi - zLo)/(2 * perturb); -} - -// Perform 3, 4, 6 or 7-factor adjustment. -// The input vector contains the following parameters in this order: -// X, Y and Z endstop adjustments -// If we are doing 4-factor adjustment, the next argument is the delta radius. Otherwise: -// X tower X position adjustment -// Y tower X position adjustment -// Z tower Y position adjustment -// Diagonal rod length adjustment -void DeltaParameters::Adjust(size_t numFactors, const float v[]) -{ - const float oldCarriageHeightA = GetHomedCarriageHeight(A_AXIS); // save for later - - // Update endstop adjustments - endstopAdjustments[A_AXIS] += v[0]; - endstopAdjustments[B_AXIS] += v[1]; - endstopAdjustments[C_AXIS] += v[2]; - NormaliseEndstopAdjustments(); - - if (numFactors == 4) - { - // 4-factor adjustment, so update delta radius - SetRadius(radius + v[3]); // this sets isEquilateral true, recalculates tower positions, then calls Recalc() - } - else if (numFactors > 3) - { - // 6- or 7-factor adjustment - towerX[A_AXIS] += v[3]; - towerX[B_AXIS] += v[4]; - - const float yAdj = v[5] * (1.0/3.0); - towerY[A_AXIS] -= yAdj; - towerY[B_AXIS] -= yAdj; - towerY[C_AXIS] += (v[5] - yAdj); - isEquilateral = false; - - if (numFactors == 7) - { - diagonal += v[6]; - } - - Recalc(); - } - - // Adjusting the diagonal and the tower positions affects the homed carriage height. - // We need to adjust homedHeight to allow for this, to get the change that was requested in the endstop corrections. - const float heightError = GetHomedCarriageHeight(A_AXIS) - oldCarriageHeightA - v[0]; - homedHeight -= heightError; - homedCarriageHeight -= heightError; -} - -void DeltaParameters::PrintParameters(StringRef& reply, bool full) -{ - reply.printf("Endstops X%.2f Y%.2f Z%.2f, height %.2f, diagonal %.2f, ", - endstopAdjustments[A_AXIS], endstopAdjustments[B_AXIS], endstopAdjustments[C_AXIS], homedHeight, diagonal); - if (isEquilateral && !full) - { - reply.catf("radius %.2f\n", radius); - } - else - { - reply.catf("towers (%.2f,%.2f) (%.2f,%.2f) (%.2f,%.2f)\n", - towerX[A_AXIS], towerY[A_AXIS], towerX[B_AXIS], towerY[B_AXIS], towerX[C_AXIS], towerY[C_AXIS]); - } -} - - Move::Move(Platform* p, GCodes* g) : currentDda(NULL) { active = false; @@ -265,6 +29,7 @@ void Move::Init() // Reset Cartesian mode deltaParams.Init(); coreXYMode = 0; + deltaProbing = false; // Empty the ring ddaRingGetPointer = ddaRingAddPointer; @@ -437,7 +202,7 @@ void Move::Spin() ddaRingGetPointer = ddaRingGetPointer->GetNext(); } } - else + else if (!deltaProbing) { // See whether we need to kick off a move DDA *cdda = currentDda; // currentDda is volatile, so copy it @@ -1242,13 +1007,59 @@ float Move::SecondDegreeTransformZ(float x, float y) const return (1.0 - x)*(1.0 - y)*zBedProbePoints[0] + x*(1.0 - y)*zBedProbePoints[3] + (1.0 - x)*y*zBedProbePoints[1] + x*y*zBedProbePoints[2]; } +static void ShortDelay() +{ + for (unsigned int i = 0; i < 10; ++i) + { + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + } +} + // This is the function that's called by the timer interrupt to step the motors. void Move::Interrupt() { - bool again = true; - while (again && currentDda != nullptr) + if (deltaProbing) { - again = currentDda->Step(); + bool again = true; + while (again) + { + if (reprap.GetPlatform()->GetZProbeResult() == EndStopHit::lowHit) + { + deltaProbe.Trigger(); + } + + bool dir = deltaProbe.GetDirection(); + Platform *platform = reprap.GetPlatform(); + platform->SetDirection(X_AXIS, dir); + platform->SetDirection(Y_AXIS, dir); + platform->SetDirection(Z_AXIS, dir); + ShortDelay(); + platform->StepHigh(X_AXIS); + platform->StepHigh(Y_AXIS); + platform->StepHigh(Z_AXIS); + ShortDelay(); + platform->StepLow(X_AXIS); + platform->StepLow(Y_AXIS); + platform->StepLow(Z_AXIS); + uint32_t tim = deltaProbe.CalcNextStepTime(); + again = (tim != 0xFFFFFFFF && platform->ScheduleInterrupt(tim + deltaProbingStartTime)); + } + } + else + { + bool again = true; + while (again && currentDda != nullptr) + { + again = currentDda->Step(); + } } } @@ -1530,6 +1341,49 @@ const char* Move::GetGeometryString() const : "cartesian"; } +// Do a delta probe returning -1 if still probing, 0 if failed, 1 if success +int Move::DoDeltaProbe(float frequency, float amplitude, float rate, float distance) +{ + if (deltaProbing) + { + if (deltaProbe.Finished()) + { + deltaProbing = false; + return (deltaProbe.Overran()) ? 0 : 1; + } + } + else + { + if (currentDda != nullptr || !DDARingEmpty()) + { + return 0; + } + if (!deltaProbe.Init(frequency, amplitude, rate, distance)) + { + return 0; + } + + const uint32_t firstInterruptTime = deltaProbe.Start(); + if (firstInterruptTime != 0xFFFFFFFF) + { + Platform *platform = reprap.GetPlatform(); + platform->EnableDrive(X_AXIS); + platform->EnableDrive(Y_AXIS); + platform->EnableDrive(Z_AXIS); + deltaProbing = true; + iState = IdleState::busy; + const irqflags_t flags = cpu_irq_save(); + deltaProbingStartTime = platform->GetInterruptClocks(); + if (platform->ScheduleInterrupt(firstInterruptTime + deltaProbingStartTime)) + { + Interrupt(); + } + cpu_irq_restore(flags); + } + } + return -1; +} + /*static*/ void Move::PrintMatrix(const char* s, const MathMatrix& m, size_t maxRows, size_t maxCols) { debugPrintf("%s\n", s); diff --git a/Move.h b/Move.h index cd5fbfe..aac9f3e 100644 --- a/Move.h +++ b/Move.h @@ -10,6 +10,8 @@ #include "DDA.h" #include "Matrix.h" +#include "DeltaParameters.h" +#include "DeltaProbe.h" const unsigned int DdaRingLength = 20; @@ -23,62 +25,6 @@ enum PointCoordinateSet probeError = 16 }; -// Class to hold the parameter for a delta machine. -// Some of the values that are currently calculated on demand could be pre-calculated in Recalc() and stored instead. -class DeltaParameters -{ -public: - DeltaParameters() { Init(); } - - bool IsDeltaMode() const { return deltaMode; } - bool IsEquilateral() const { return isEquilateral; } - float GetDiagonal() const { return diagonal; } - float GetRadius() const { return radius; } - float GetPrintRadius() const { return printRadius; } - float GetTowerX(size_t axis) const { return towerX[axis]; } - float GetTowerY(size_t axis) const { return towerY[axis]; } - float GetEndstopAdjustment(size_t axis) const { return endstopAdjustments[axis]; } - float GetHomedCarriageHeight(size_t axis) const { return homedCarriageHeight + endstopAdjustments[axis]; } - float GetPrintRadiusSquared() const { return printRadiusSquared; } - - void Init(); - void SetDiagonal(float d) { diagonal = d; Recalc(); } - void SetRadius(float r); - void SetEndstopAdjustment(size_t axis, float x) { endstopAdjustments[axis] = x; } - void SetPrintRadius(float r) { printRadius = r; printRadiusSquared = r * r; } - float GetHomedHeight() const { return homedHeight; } - void SetHomedHeight(float h) { homedHeight = h; Recalc(); } - - float Transform(const float machinePos[AXES], size_t axis) const; // Calculate the motor position for a single tower from a Cartesian coordinate - void InverseTransform(float Ha, float Hb, float Hc, float machinePos[AXES]) const; // Calculate the Cartesian position from the motor positions - - float ComputeDerivative(unsigned int deriv, float ha, float hb, float hc); // Compute the derivative of height with respect to a parameter at a set of motor endpoints - void Adjust(size_t numFactors, const float v[]); // Perform 4-, 6- or 7-factor adjustment - void PrintParameters(StringRef& reply, bool full); - -private: - void Recalc(); - void NormaliseEndstopAdjustments(); // Make the average of the endstop adjustments zero - - // Core parameters - float diagonal; // The diagonal rod length, all 3 are assumed to be the same length - float radius; // The nominal delta radius, before any fine tuning of tower positions - float towerX[AXES]; // The X coordinate of each tower - float towerY[AXES]; // The Y coordinate of each tower - float endstopAdjustments[AXES]; // How much above or below the ideal position each endstop is - float printRadius; - float homedHeight; - - // Derived values - bool deltaMode; // True if this is a delta printer - bool isEquilateral; // True if the towers are at the corners of an equilateral triangle - float printRadiusSquared; - float homedCarriageHeight; - float Xbc, Xca, Xab, Ybc, Yca, Yab; - float coreFa, coreFb, coreFc; - float Q, Q2, D2; -}; - /** * This is the master movement class. It controls all movement in the machine. */ @@ -143,6 +89,8 @@ public: FilePosition PausePrint(float positions[DRIVES+1]); // Pause the print as soon as we can bool NoLiveMovement() const; // Is a move running, or are there any queued? + int DoDeltaProbe(float frequency, float amplitude, float rate, float distance); + static int32_t MotorEndPointToMachine(size_t drive, float coord); // Convert a single motor position to number of steps static float MotorEndpointToPosition(int32_t endpoint, size_t drive); // Convert number of motor steps to motor position @@ -202,6 +150,9 @@ private: IdleState iState; // whether the idle timer is active DeltaParameters deltaParams; // Information about the delta parameters of this machine + DeltaProbe deltaProbe; // Delta probing state + uint32_t deltaProbingStartTime; + bool deltaProbing; int coreXYMode; // 0 = Cartesian, 1 = CoreXY, 2 = CoreXZ, 3 = CoreYZ }; diff --git a/Network.cpp b/Network.cpp index 3083843..f1374bd 100644 --- a/Network.cpp +++ b/Network.cpp @@ -49,8 +49,7 @@ extern "C" { #include "lwipopts.h" #include "lwip/src/include/lwip/tcp.h" - -void RepRapNetworkSetMACAddress(const u8_t macAddress[]); +#include "contrib/apps/netbios/netbios.h" } static tcp_pcb *http_pcb = NULL; @@ -326,23 +325,24 @@ Network::Network(Platform* p) freeTransactions(NULL), readyTransactions(NULL), writingTransactions(NULL), dataCs(NULL), ftpCs(NULL), telnetCs(NULL), freeSendBuffers(NULL), freeConnections(NULL) { - for (unsigned int i = 0; i < networkTransactionCount; i++) + for (size_t i = 0; i < networkTransactionCount; i++) { freeTransactions = new NetworkTransaction(freeTransactions); } - for (unsigned int i = 0; i < tcpOutputBufferCount; i++) + for (size_t i = 0; i < tcpOutputBufferCount; i++) { freeSendBuffers = new SendBuffer(freeSendBuffers); } - for (unsigned int i = 0; i < numConnections; i++) + for (size_t i = 0; i < numConnections; i++) { ConnectionState *cs = new ConnectionState; cs->next = freeConnections; freeConnections = cs; } + strcpy(hostname, HOSTNAME); ethPinsInit(); } @@ -369,8 +369,7 @@ void Network::Init() platform->Message(HOST_MESSAGE, "Attempting to start the network when it is disabled.\n"); return; } - RepRapNetworkSetMACAddress(platform->MACAddress()); - init_ethernet(); + init_ethernet(platform->MACAddress(), hostname); longWait = platform->Time(); state = NetworkInitializing; } @@ -426,12 +425,13 @@ void Network::Spin() } else if (state == NetworkInitializing && establish_ethernet_link()) { - set_dhcp_hostname(reprap.GetName()); start_ethernet(platform->IPAddress(), platform->NetMask(), platform->GateWay()); + ethernet_set_rx_callback(&emac_read_packet); + httpd_init(); ftpd_init(); telnetd_init(); - ethernet_set_rx_callback(&emac_read_packet); + netbios_init(); state = NetworkActive; } @@ -1039,6 +1039,34 @@ bool Network::AcquireTransaction(ConnectionState *cs) return true; } +// Set the DHCP hostname. Removes all whitespaces and converts the name to lower-case. +void Network::SetHostname(const char *name) +{ + size_t i = 0; + while (*name && i < ARRAY_UPB(hostname)) + { + char c = *name++; + if (c >= 'A' && c <= 'Z') + { + c += 'a' - 'A'; + } + + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '-') || (c == '_')) + { + hostname[i++] = c; + } + } + + if (i) + { + hostname[i] = 0; + } + else + { + strcpy(hostname, HOSTNAME); + } +} + // Initialise a ConnectionState for a new connection void ConnectionState::Init(tcp_pcb *p) { diff --git a/Network.h b/Network.h index d5fcd41..2c2f9f6 100644 --- a/Network.h +++ b/Network.h @@ -38,6 +38,7 @@ const float writeTimeout = 4.0; // seconds to wait for data we have writ #define IP_ADDRESS {192, 168, 1, 10} // Need some sort of default... #define NET_MASK {255, 255, 255, 0} #define GATE_WAY {192, 168, 1, 1} +#define HOSTNAME "duet" /****************************************************************************************************/ @@ -183,6 +184,8 @@ public: void SetHttpPort(uint16_t port); uint16_t GetHttpPort() const; + void SetHostname(const char *name); + private: Platform* platform; @@ -202,6 +205,7 @@ private: enum { NetworkInactive, NetworkInitializing, NetworkActive } state; bool isEnabled; bool volatile readingData; + char hostname[16]; // limit DHCP hostname to 15 characters + terminating 0 ConnectionState *dataCs; ConnectionState *ftpCs; diff --git a/Platform.cpp b/Platform.cpp index 30a676a..c01282e 100644 --- a/Platform.cpp +++ b/Platform.cpp @@ -240,7 +240,7 @@ void Platform::Init() SetElasticComp(drive, 0.0); if (drive <= AXES) { - endStopType[drive] = lowEndStop; // assume all endstops are low endstops + endStopType[drive] = EndStopType::lowEndStop; // assume all endstops are low endstops endStopLogicLevel[drive] = true; } } @@ -337,6 +337,9 @@ void Platform::InitZProbe() pinModeNonDue(endStopPins[E0_AXIS], INPUT_PULLUP); break; + case 5: + break; //TODO + default: break; } @@ -375,6 +378,8 @@ int Platform::ZProbe() const // Because of noise, it is possible to get a negative reading, so allow for this. return (int) (((int32_t) zProbeOnFilter.GetSum() - (int32_t) zProbeOffFilter.GetSum()) / (int)(4 * numZProbeReadingsAveraged)); + case 5: + return (int) ((zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum()) / (8 * numZProbeReadingsAveraged)); //TODO this is temporary default: break; @@ -436,6 +441,7 @@ float Platform::ZProbeStopHeight() const case 2: return nvData.irZProbeParameters.GetStopHeight(GetTemperature(0)); case 3: + case 5: return nvData.alternateZProbeParameters.GetStopHeight(GetTemperature(0)); default: return 0; @@ -450,6 +456,7 @@ float Platform::GetZProbeDiveHeight() const case 2: return nvData.irZProbeParameters.diveHeight; case 3: + case 5: return nvData.alternateZProbeParameters.diveHeight; case 4: return nvData.switchZProbeParameters.diveHeight; @@ -467,6 +474,7 @@ void Platform::SetZProbeDiveHeight(float h) nvData.irZProbeParameters.diveHeight = h; break; case 3: + case 5: nvData.alternateZProbeParameters.diveHeight = h; break; case 4: @@ -479,7 +487,7 @@ void Platform::SetZProbeDiveHeight(float h) void Platform::SetZProbeType(int pt) { - int newZProbeType = (pt >= 0 && pt <= 4) ? pt : 0; + int newZProbeType = (pt >= 0 && pt <= 5) ? pt : 0; if (newZProbeType != nvData.zProbeType) { nvData.zProbeType = newZProbeType; @@ -503,6 +511,7 @@ const ZProbeParameters& Platform::GetZProbeParameters() const case 2: return nvData.irZProbeParameters; case 3: + case 5: return nvData.alternateZProbeParameters; } } @@ -534,6 +543,7 @@ bool Platform::SetZProbeParameters(const struct ZProbeParameters& params) } return true; case 3: + case 5: if (nvData.alternateZProbeParameters != params) { nvData.alternateZProbeParameters = params; @@ -730,41 +740,49 @@ void Platform::Spin() void Platform::SoftwareReset(uint16_t reason) { - if (reason != SoftwareResetReason::user) + if (reason == SoftwareResetReason::erase) { - if (line->inWrite) - { - reason |= SoftwareResetReason::inUsbOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to USB - } - if (reprap.GetNetwork()->InLwip()) - { - reason |= SoftwareResetReason::inLwipSpin; - } - if (aux->inWrite) - { - reason |= SoftwareResetReason::inAuxOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to aux - } - } - reason |= reprap.GetSpinningModule(); - - // Record the reason for the software reset - SoftwareResetData temp; - temp.magic = SoftwareResetData::magicValue; - temp.resetReason = reason; - GetStackUsage(NULL, NULL, &temp.neverUsedRam); - if (reason != SoftwareResetReason::user) - { - strncpy(temp.lastMessage, messageString.Pointer(), sizeof(temp.lastMessage) - 1); - temp.lastMessage[sizeof(temp.lastMessage) - 1] = 0; - } + cpu_irq_disable(); + flash_unlock(0x00080000, 0x000FFFFF, nullptr, nullptr); + flash_clear_gpnvm(1); // tell the system to boot from flash next time + } else { - temp.lastMessage[0] = 0; + if (reason != SoftwareResetReason::user) + { + if (line->inWrite) + { + reason |= SoftwareResetReason::inUsbOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to USB + } + if (reprap.GetNetwork()->InLwip()) + { + reason |= SoftwareResetReason::inLwipSpin; + } + if (aux->inWrite) + { + reason |= SoftwareResetReason::inAuxOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to aux + } + } + reason |= reprap.GetSpinningModule(); + + // Record the reason for the software reset + SoftwareResetData temp; + temp.magic = SoftwareResetData::magicValue; + temp.resetReason = reason; + GetStackUsage(NULL, NULL, &temp.neverUsedRam); + if (reason != SoftwareResetReason::user) + { + strncpy(temp.lastMessage, messageString.Pointer(), sizeof(temp.lastMessage) - 1); + temp.lastMessage[sizeof(temp.lastMessage) - 1] = 0; + } + else + { + temp.lastMessage[0] = 0; + } + + // Save diagnostics data to Flash and reset the software + DueFlashStorage::write(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData)); } - - // Save diagnostics data to Flash and reset the software - DueFlashStorage::write(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData)); - rstc_start_software_reset(RSTC); for(;;) {} } @@ -1190,14 +1208,14 @@ EndStopHit Platform::Stopped(size_t drive) const return GetZProbeResult(); // using the Z probe as am endstop for this axis, so just get its result } - if (endStopPins[drive] >= 0 && endStopType[drive] != noEndStop) + if (endStopPins[drive] >= 0 && endStopType[drive] != EndStopType::noEndStop) { if (digitalReadNonDue(endStopPins[drive]) == ((endStopLogicLevel[drive]) ? 1 : 0)) { - return (endStopType[drive] == highEndStop) ? highHit : lowHit; + return (endStopType[drive] == EndStopType::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } } - return noStop; + return EndStopHit::noStop; } // Return the Z probe result. We assume that if the Z probe is used as an endstop, it is used as the low stop. @@ -1208,9 +1226,9 @@ EndStopHit Platform::GetZProbeResult() const (nvData.zProbeType == 4) ? nvData.switchZProbeParameters.adcValue : (nvData.zProbeType == 3) ? nvData.alternateZProbeParameters.adcValue : nvData.irZProbeParameters.adcValue; - return (zProbeVal >= zProbeADValue) ? lowHit - : (zProbeVal * 10 >= zProbeADValue * 9) ? lowNear // if we are at/above 90% of the target value - : noStop; + return (zProbeVal >= zProbeADValue) ? EndStopHit::lowHit + : (zProbeVal * 10 >= zProbeADValue * 9) ? EndStopHit::lowNear // if we are at/above 90% of the target value + : EndStopHit::noStop; } // This is called from the step ISR as well as other places, so keep it fast, especially in the case where the motor is already enabled @@ -2094,18 +2112,18 @@ float FileStore::FractionRead() const return (float)GetPosition() / (float)len; } -int8_t FileStore::Status() +uint8_t FileStore::Status() { if (!inUse) - return nothing; + return (uint8_t)IOStatus::nothing; if (lastBufferEntry == FILE_BUF_LEN) - return byteAvailable; + return (uint8_t)IOStatus::byteAvailable; if (bufferPointer < lastBufferEntry) - return byteAvailable; + return (uint8_t)IOStatus::byteAvailable; - return nothing; + return (uint8_t)IOStatus::nothing; } bool FileStore::ReadBuffer() @@ -2282,11 +2300,9 @@ Line::Line(Stream& p_iface) : iface(p_iface) { } -int8_t Line::Status() const +uint8_t Line::Status() const { -// if(alternateInput != NULL) -// return alternateInput->Status(); - return inputNumChars == 0 ? nothing : byteAvailable; + return inputNumChars == 0 ? (uint8_t)IOStatus::nothing : (uint8_t)IOStatus::byteAvailable; } // This is only ever called on initialisation, so we diff --git a/Platform.h b/Platform.h index 1ba3bdf..b6d4a95 100644 --- a/Platform.h +++ b/Platform.h @@ -218,7 +218,7 @@ const size_t messageStringLength = 256; // max length of a message chunk sent /****************************************************************************************************/ -enum EndStopHit +enum class EndStopHit { noStop = 0, // no endstop hit lowHit = 1, // low switch hit, or Z-probe in use and above threshold @@ -227,7 +227,7 @@ enum EndStopHit }; // The values of the following enumeration must tally with the definitions for the M574 command -enum EndStopType +enum class EndStopType { noEndStop = 0, lowEndStop = 1, @@ -236,7 +236,7 @@ enum EndStopType /***************************************************************************************************/ -// Input and output - these are ORed into an int8_t +// Input and output - these are ORed into a uint8_t // By the Status() functions of the IO classes. enum IOStatus @@ -255,6 +255,7 @@ namespace SoftwareResetReason enum { user = 0, // M999 command + erase = 55, // special M999 command to erase firmware and reset inAuxOutput = 0x0800, // this bit is or'ed in if we were in aux output at the time stuckInSpin = 0x1000, // we got stuck in a Spin() function for too long inLwipSpin = 0x2000, // we got stuck in a call to LWIP for too long @@ -279,7 +280,7 @@ class Line { public: - int8_t Status() const; // Returns OR of IOStatus + uint8_t Status() const; // Returns OR of IOStatus int Read(char& b); void Write(char b, bool block = false); void Write(const char* s, bool block = false); @@ -367,7 +368,7 @@ class FileStore { public: - int8_t Status(); // Returns OR of IOStatus + uint8_t Status(); // Returns OR of IOStatus bool Read(char& b); // Read 1 byte int Read(char* buf, unsigned int nBytes); // Read a block of nBytes length bool Write(char b); // Write 1 byte @@ -425,6 +426,7 @@ struct ZProbeParameters float calibTemperature; // the temperature at which we did the calibration float temperatureCoefficient; // the variation of height with bed temperature float diveHeight; // the dive height we use when probing + float param1, param2; // extra parameters used by some types of probe e.g. Delta probe void Init(float h) { @@ -434,6 +436,7 @@ struct ZProbeParameters calibTemperature = 20.0; temperatureCoefficient = 0.0; // no default temperature correction diveHeight = DefaultZDive; + param1 = param2 = 0.0; } float GetStopHeight(float temperature) const @@ -449,7 +452,9 @@ struct ZProbeParameters && yOffset == other.yOffset && calibTemperature == other.calibTemperature && temperatureCoefficient == other.temperatureCoefficient - && diveHeight == other.diveHeight; + && diveHeight == other.diveHeight + && param1 == other.param1 + && param2 == other.param2; } bool operator!=(const ZProbeParameters& other) const @@ -1303,7 +1308,7 @@ inline void Platform::GetEndStopConfiguration(size_t axis, EndStopType& esType, // This is called by the tick ISR to get the raw Z probe reading to feed to the filter inline uint16_t Platform::GetRawZProbeReading() const { - if (nvData.zProbeType == 4) + if (nvData.zProbeType >= 4) { bool b = (bool)digitalRead(endStopPins[E0_AXIS]); if (!endStopLogicLevel[AXES]) diff --git a/PrintMonitor.cpp b/PrintMonitor.cpp index 2982c09..f927b68 100644 --- a/PrintMonitor.cpp +++ b/PrintMonitor.cpp @@ -26,6 +26,11 @@ PrintMonitor::PrintMonitor(Platform *p, GCodes *gc) : platform(p), gCodes(gc), f { } +void PrintMonitor::Init() +{ + longWait = platform->Time(); +} + void PrintMonitor::Spin() { if (gCodes->IsPausing() || gCodes->IsPaused() || gCodes->IsResuming()) @@ -135,7 +140,7 @@ void PrintMonitor::Spin() } else { - for(unsigned int i=1; i 0.0 && reprap.GetMove()->NoLiveMovement()) - { - currentLayer = numLayerSamples = 0; - firstLayerDuration = firstLayerHeight = firstLayerFilament = firstLayerProgress = 0.0; - layerEstimatedTimeLeft = printStartTime = warmUpDuration = 0.0; - lastLayerTime = lastLayerFilament = 0.0; - } platform->ClassReport(longWait); } -void PrintMonitor::Init() -{ - longWait = platform->Time(); -} - -void PrintMonitor::StartingFilePrint(const char* filename) +void PrintMonitor::StartingPrint(const char* filename) { fileInfoDetected = GetFileInfo(platform->GetGCodeDir(), filename, currentFileInfo); strncpy(fileBeingPrinted, filename, ARRAY_SIZE(fileBeingPrinted)); fileBeingPrinted[ARRAY_UPB(fileBeingPrinted)] = 0; } -void PrintMonitor::StartedFilePrint() +void PrintMonitor::StartedPrint() { printStartTime = platform->Time(); } +void PrintMonitor::StoppedPrint() +{ + currentLayer = numLayerSamples = 0; + firstLayerDuration = firstLayerHeight = firstLayerFilament = firstLayerProgress = 0.0; + layerEstimatedTimeLeft = printStartTime = warmUpDuration = 0.0; + lastLayerTime = lastLayerFilament = 0.0; +} + bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GcodeFileInfo& info) const { if (reprap.GetPlatform()->GetMassStorage()->PathExists(directory, fileName)) @@ -225,11 +226,11 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, Gcod info.fileSize = f->Length(); info.objectHeight = 0.0; info.layerHeight = 0.0; - info.numFilaments = DRIVES - AXES; + info.numFilaments = 0; info.generatedBy[0] = 0; - for (size_t i = 0; i < DRIVES - AXES; ++i) + for(size_t extr=0; extr= filamentsFound) { - filamentsFound = min(nFilaments, info.numFilaments); + filamentsFound = nFilaments; for (unsigned int i = 0; i < filamentsFound; ++i) { info.filamentNeeded[i] = filaments[i]; @@ -374,7 +375,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, Gcod nFilaments = FindFilamentUsed(buf, sizeToScan, filaments, DRIVES - AXES); if (nFilaments != 0 && nFilaments >= filamentsFound) { - filamentsFound = min(nFilaments, info.numFilaments); + filamentsFound = nFilaments; for (unsigned int i = 0; i < filamentsFound; ++i) { info.filamentNeeded[i] = filaments[i]; diff --git a/PrintMonitor.h b/PrintMonitor.h index fed4f03..5b53cda 100644 --- a/PrintMonitor.h +++ b/PrintMonitor.h @@ -44,8 +44,9 @@ class PrintMonitor void Spin(); void Init(); - void StartingFilePrint(const char *filename); // called to indicate a file will be printed (see M23) - void StartedFilePrint(); // called whenever a new live print starts (see M24) + void StartingPrint(const char *filename); // called to indicate a file will be printed (see M23) + void StartedPrint(); // called whenever a new live print starts (see M24) + void StoppedPrint(); // called whenever a file print has stopped bool GetFileInfo(const char *directory, const char *fileName, GcodeFileInfo& info) const; void GetFileInfoResponse(StringRef& response, const char* filename) const; diff --git a/Release/RepRapFirmware-1.09a-dc42.bin b/Release/RepRapFirmware-1.09a-dc42.bin new file mode 100644 index 0000000..51a7599 Binary files /dev/null and b/Release/RepRapFirmware-1.09a-dc42.bin differ diff --git a/RepRapFirmware.cpp b/RepRapFirmware.cpp index 00f3cf1..5850da5 100644 --- a/RepRapFirmware.cpp +++ b/RepRapFirmware.cpp @@ -1456,6 +1456,9 @@ void RepRap::SetName(const char* nm) { // Users sometimes put a tab character between the machine name and the comment, so allow for this CopyParameterText(nm, myName, ARRAY_SIZE(myName)); + + // Set new DHCP hostname + network->SetHostname(myName); } // Given that we want to extrude/etract the specified extruder drives, check if they are allowed.