Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2015-04-02 22:19:17 +0300
committerDavid Crocker <dcrocker@eschertech.com>2015-04-02 22:19:17 +0300
commit52b21d0eed5ba2f5e226b38675ef7dccaeed5447 (patch)
treec3fda0d5a7668b0141a28ba643361a5cd1149fb9
parent2791322800315bf26aceaa1e67e19b2efe88573b (diff)
Version 1.04c
Implemented rr_config web request for zpl's latest web interface Implemented 7-factor auto calibration for delta printers Fix bug with fileinfo calls corrupting memory M563 can now be used to delete tools
-rw-r--r--Configuration.h51
-rw-r--r--DDA.h1
-rw-r--r--GCodes.cpp85
-rw-r--r--GCodes.h2
-rw-r--r--Heat.cpp31
-rw-r--r--Heat.h14
-rw-r--r--Matrix.h115
-rw-r--r--Move.cpp434
-rw-r--r--Move.h38
-rw-r--r--Network.cpp36
-rw-r--r--Network.h5
-rw-r--r--Platform.cpp152
-rw-r--r--Platform.h19
-rw-r--r--Release/RepRapFirmware-1.04c-dc42.binbin0 -> 212712 bytes
-rw-r--r--RepRapFirmware.cpp262
-rw-r--r--Reprap.h16
-rw-r--r--SD-image/sys-MiniKossel/bed.g34
-rw-r--r--SD-image/sys-MiniKossel/config.g1
-rw-r--r--Tool.cpp41
-rw-r--r--Tool.h5
-rw-r--r--Webserver.cpp26
21 files changed, 1002 insertions, 366 deletions
diff --git a/Configuration.h b/Configuration.h
index 3531f30b..2eb95f84 100644
--- a/Configuration.h
+++ b/Configuration.h
@@ -2,8 +2,8 @@
RepRapFirmware - Configuration
-This is where all machine-independent configuration and other definitions are set up. Nothing that
-depends on any particular RepRap, RepRap component, or RepRap controller should go in here. Define
+This is where all machine-independent configuration and other definitions are set up. Nothing that
+depends on any particular RepRap, RepRap component, or RepRap controller should go in here. Define
machine-dependent things in Platform.h
-----------------------------------------------------------------------------------------------------
@@ -24,8 +24,8 @@ Licence: GPL
#define CONFIGURATION_H
#define NAME "RepRapFirmware"
-#define VERSION "1.04b-dc42"
-#define DATE "2015-03-24"
+#define VERSION "1.04c-dc42"
+#define DATE "2015-04-02"
#define AUTHORS "reprappro, dc42, zpl"
#define FLASH_SAVE_ENABLED (1)
@@ -46,24 +46,25 @@ enum Compatibility
#define AUX_BAUD_RATE (57600)
-const unsigned int GcodeLength = 100; // Maximum length of a G Code string that we handle
-const unsigned int MaxFilenameLength = 100; // Maximum length of a path + filename on the SD card
+const unsigned int GcodeLength = 100; // Maximum length of a G Code string that we handle
+const unsigned int MaxFilenameLength = 100; // Maximum length of a path + filename on the SD card
-const float defaultIdleCurrentFactor = 0.3; // Proportion of normal motor current that we use for idle hold
+const float defaultIdleCurrentFactor = 0.3; // Proportion of normal motor current that we use for idle hold
const float defaultIdleTimeout = 30.0;
-#define ABS_ZERO (-273.15) // Celsius
+#define ABS_ZERO (-273.15) // Celsius
+#define NEARLY_ABS_ZERO (-273) // Celsius
#define INCH_TO_MM (25.4)
-#define HEAT_SAMPLE_TIME (0.5) // Seconds
-#define HEAT_PWM_AVERAGE_TIME (5.0) // Seconds
+#define HEAT_SAMPLE_TIME (0.5) // Seconds
+#define HEAT_PWM_AVERAGE_TIME (5.0) // Seconds
-#define TEMPERATURE_CLOSE_ENOUGH (2.5) // Celsius
-#define TEMPERATURE_LOW_SO_DONT_CARE (40.0) // Celsius
-#define HOT_ENOUGH_TO_EXTRUDE (160.0) // Celsius
-#define HOT_ENOUGH_TO_RETRACT (90.0) // Celsius
-#define TIME_TO_HOT (150.0) // Seconds
+#define TEMPERATURE_CLOSE_ENOUGH (2.5) // Celsius
+#define TEMPERATURE_LOW_SO_DONT_CARE (40.0) // Celsius
+#define HOT_ENOUGH_TO_EXTRUDE (160.0) // Celsius
+#define HOT_ENOUGH_TO_RETRACT (90.0) // Celsius
+#define TIME_TO_HOT (150.0) // Seconds
// If temperatures fall outside this range, something nasty has happened.
@@ -71,18 +72,22 @@ const float defaultIdleTimeout = 30.0;
#define BAD_LOW_TEMPERATURE -10.0
#define BAD_HIGH_TEMPERATURE 300.0
-#define NUMBER_OF_PROBE_POINTS 9 // Maximum number of probe points
-#define Z_DIVE 5.0 // Default height from which to probe the bed (mm)
-#define TRIANGLE_0 -0.001 // Slightly less than 0 for point-in-triangle tests
+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)
+
+#define TRIANGLE_0 -0.001 // Slightly less than 0 for point-in-triangle tests
#define SILLY_Z_VALUE -9999.0
// String lengths
#define STRING_LENGTH 1024
-#define SHORT_STRING_LENGTH 40
-
-#define GCODE_REPLY_LENGTH 2048
+const size_t MaxPasswordLength = 20;
+const size_t MaxNameLength = 40;
+const size_t MaxMessageLength = 40;
+const size_t MaxGcodeReplyLength = 2048;
// Print estimation defaults
#define NOZZLE_DIAMETER 0.5 // Thickness of the nozzle
@@ -95,9 +100,9 @@ const float defaultIdleTimeout = 30.0;
#define DEFAULT_PASSWORD "reprap"
#define DEFAULT_NAME "My RepRap 1"
#define INDEX_PAGE "reprap.htm"
-//#define MESSAGE_FILE "messages.txt" // currently unused
+//#define MESSAGE_FILE "messages.txt" // currently unused
#define FOUR04_FILE "html404.htm"
-#define CONFIG_FILE "config.g" // The file that sets the machine's parameters
+#define CONFIG_FILE "config.g" // The file that sets the machine's parameters
#define DEFAULT_FILE "default.g" // If the config file isn't found
#define HOME_X_G "homex.g"
#define HOME_Y_G "homey.g"
diff --git a/DDA.h b/DDA.h
index a002de30..6228177c 100644
--- a/DDA.h
+++ b/DDA.h
@@ -127,6 +127,7 @@ private:
inline void DDA::SetDriveCoordinate(int32_t a, size_t drive)
{
endPoint[drive] = a;
+ endCoordinatesValid = false;
}
#endif /* DDA_H_ */
diff --git a/GCodes.cpp b/GCodes.cpp
index e78d614e..63ed654a 100644
--- a/GCodes.cpp
+++ b/GCodes.cpp
@@ -278,7 +278,7 @@ void GCodes::Spin()
}
}
state = GCodeState::toolChange2;
- if (reprap.GetTool(newToolNumber) != NULL)
+ if (reprap.GetTool(newToolNumber) != NULL && AllAxesAreHomed())
{
scratchString.printf("tpre%d.g", newToolNumber);
DoFileMacro(scratchString.Pointer());
@@ -288,7 +288,7 @@ void GCodes::Spin()
case GCodeState::toolChange2: // Select the new tool (even if it doesn't exist - that just deselects all tools)
reprap.SelectTool(newToolNumber);
state = GCodeState::toolChange3;
- if (reprap.GetTool(newToolNumber) != NULL)
+ if (reprap.GetTool(newToolNumber) != NULL && AllAxesAreHomed())
{
scratchString.printf("tpost%d.g", newToolNumber);
DoFileMacro(scratchString.Pointer());
@@ -840,21 +840,18 @@ void GCodes::FileMacroCyclesReturn()
// you want (if action[DRIVES] is true).
bool GCodes::DoCannedCycleMove(EndstopChecks ce)
{
- if (!AllMovesAreFinishedAndMoveBufferIsLoaded())
+ if (AllMovesAreFinishedAndMoveBufferIsLoaded())
{
- return false;
- }
+ if (cannedCycleMoveQueued) // if the move has already been queued, it must have finished
+ {
+ Pop();
+ cannedCycleMoveQueued = false;
+ return true;
+ }
- // Is the move already running?
- if (cannedCycleMoveQueued)
- { // Yes.
- Pop();
- cannedCycleMoveQueued = false;
- return true;
- }
- else
- { // No.
+ // Otherwise, the move has not been queued yet
Push();
+
for (size_t drive = 0; drive <= DRIVES; drive++)
{
if (activeDrive[drive])
@@ -865,6 +862,11 @@ bool GCodes::DoCannedCycleMove(EndstopChecks ce)
endStopsToCheck = ce;
cannedCycleMoveQueued = true;
moveAvailable = true;
+
+ if ((ce & ZProbeActive) && reprap.GetPlatform()->GetZProbeResult() == lowHit)
+ {
+ platform->Message(BOTH_ERROR_MESSAGE, "Z probe warning: probe already triggered at start of probing move\n");
+ }
}
return false;
}
@@ -947,7 +949,7 @@ bool GCodes::OffsetAxes(GCodeBuffer* gb)
// This lifts Z a bit, moves to the probe XY coordinates (obtained by a call to GetProbeCoordinates() ),
// probes the bed height, and records the Z coordinate probed. If you want to program any general
// internal canned cycle, this shows how to do it.
-// On entry, probePointIndex specifies which of the 3, 4 or 5 points this is.
+// On entry, probePointIndex specifies which of the points this is.
bool GCodes::DoSingleZProbeAtPoint(int probePointIndex)
{
reprap.GetMove()->SetIdentityTransform(); // It doesn't matter if these are called repeatedly
@@ -959,7 +961,7 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex)
switch (cannedCycleMoveCount)
{
- case 0: // Raise Z to 5mm. This only does anything on the first move; on all the others Z is already there
+ 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();
activeDrive[Z_AXIS] = true;
moveToDo[DRIVES] = platform->MaxFeedrate(Z_AXIS);
@@ -984,7 +986,9 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex)
return false;
case 2: // Probe the bed
- moveToDo[Z_AXIS] = -2.0 * platform->AxisMaximum(Z_AXIS);
+ 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;
@@ -1008,20 +1012,21 @@ bool GCodes::DoSingleZProbeAtPoint(int probePointIndex)
}
return false;
- case 3: // Raise the head 5mm
+ case 3: // Raise the head back up to the dive height
moveToDo[Z_AXIS] = platform->GetZProbeDiveHeight();
activeDrive[Z_AXIS] = true;
moveToDo[DRIVES] = platform->MaxFeedrate(Z_AXIS);
activeDrive[DRIVES] = true;
if (DoCannedCycleMove(0))
{
- cannedCycleMoveCount++;
+ cannedCycleMoveCount = 0;
+ reprap.GetMove()->SetZBedProbePoint(probePointIndex, lastProbedZ);
+ return true;
}
return false;
- default:
+ default: // should not happen
cannedCycleMoveCount = 0;
- reprap.GetMove()->SetZBedProbePoint(probePointIndex, lastProbedZ);
return true;
}
}
@@ -1069,7 +1074,7 @@ bool GCodes::SetSingleZProbeAtAPosition(GCodeBuffer *gb, StringRef& reply)
return DoSingleZProbe();
int probePointIndex = gb->GetIValue();
- if (probePointIndex < 0 || probePointIndex >= NUMBER_OF_PROBE_POINTS)
+ if (probePointIndex < 0 || probePointIndex >= MaxProbePoints)
{
reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE, "Z probe point index out of range.\n");
return true;
@@ -1530,7 +1535,7 @@ void GCodes::SetOrReportOffsets(StringRef& reply, GCodeBuffer *gb)
}
}
-void GCodes::AddNewTool(GCodeBuffer *gb, StringRef& reply)
+void GCodes::ManageTool(GCodeBuffer *gb, StringRef& reply)
{
if (!gb->Seen('P'))
{
@@ -1543,9 +1548,16 @@ void GCodes::AddNewTool(GCodeBuffer *gb, StringRef& reply)
return;
}
- int toolNumber = gb->GetLValue();
+ // Check tool number
bool seen = false;
+ int toolNumber = gb->GetLValue();
+ if (toolNumber < 0)
+ {
+ platform->Message(BOTH_ERROR_MESSAGE, "Tool number must be positive!\n");
+ return;
+ }
+ // Check drives
long drives[DRIVES - AXES]; // There can never be more than we have...
int dCount = DRIVES - AXES; // Sets the limit and returns the count
if (gb->Seen('D'))
@@ -1558,6 +1570,7 @@ void GCodes::AddNewTool(GCodeBuffer *gb, StringRef& reply)
dCount = 0;
}
+ // Check heaters
long heaters[HEATERS];
int hCount = HEATERS;
if (gb->Seen('H'))
@@ -1572,8 +1585,18 @@ void GCodes::AddNewTool(GCodeBuffer *gb, StringRef& reply)
if (seen)
{
- Tool* tool = new Tool(toolNumber, drives, dCount, heaters, hCount);
- reprap.AddTool(tool);
+ // Add or delete tool
+ // M563 P# D-1 H-1 removes an existing tool
+ if (dCount == 1 && hCount == 1 && drives[0] == -1 && heaters[0] == -1)
+ {
+ Tool *tool = reprap.GetTool(toolNumber);
+ reprap.DeleteTool(tool);
+ }
+ else
+ {
+ Tool* tool = new Tool(toolNumber, drives, dCount, heaters, hCount);
+ reprap.AddTool(tool);
+ }
}
else
{
@@ -3401,7 +3424,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
if (gb->Seen('P'))
{
int point = gb->GetIValue();
- if (point < 0 || point >= NUMBER_OF_PROBE_POINTS)
+ if (point < 0 || point >= MaxProbePoints)
{
reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE, "Z probe point index out of range.\n");
}
@@ -3526,7 +3549,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
break;
case 563: // Define tool
- AddNewTool(gb, reply);
+ ManageTool(gb, reply);
break;
case 564: // Think outside the box?
@@ -3842,8 +3865,8 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
}
if (!seen)
{
- reply.printf("Endstop adjustments X%.2f Y%.2f Z%.2f\n", params.GetEndstopAdjustment(X_AXIS),
- params.GetEndstopAdjustment(Y_AXIS), params.GetEndstopAdjustment(Z_AXIS));
+ reply.printf("Endstop adjustments X%.2f Y%.2f Z%.2f\n",
+ params.GetEndstopAdjustment(X_AXIS),params.GetEndstopAdjustment(Y_AXIS), params.GetEndstopAdjustment(Z_AXIS));
}
}
break;
@@ -3973,7 +3996,7 @@ bool GCodes::HandleTcode(GCodeBuffer* gb, StringRef& reply)
// If old and new are the same still follow the sequence - the user may want the macros run.
Tool *oldTool = reprap.GetCurrentTool();
state = GCodeState::toolChange1;
- if (oldTool != NULL)
+ if (oldTool != NULL && AllAxesAreHomed())
{
scratchString.printf("tfree%d.g", oldTool->Number());
DoFileMacro(scratchString.Pointer());
diff --git a/GCodes.h b/GCodes.h
index 74c5cf43..b86396ea 100644
--- a/GCodes.h
+++ b/GCodes.h
@@ -148,7 +148,7 @@ class GCodes
void SetPidParameters(GCodeBuffer *gb, int heater, StringRef& reply); // Set the P/I/D parameters for a heater
void SetHeaterParameters(GCodeBuffer *gb, StringRef& reply); // Set the thermistor and ADC parameters for a heater
int8_t Heater(int8_t head) const; // Legacy G codes start heaters at 0, but we use 0 for the bed. This sorts that out.
- void AddNewTool(GCodeBuffer *gb, StringRef& reply); // Create a new tool definition
+ void ManageTool(GCodeBuffer *gb, StringRef& reply); // Create a new tool definition
void SetToolHeaters(Tool *tool, float temperature); // Set all a tool's heaters to the temperature. For M104...
bool ToolHeatersAtSetTemperatures(const Tool *tool) const; // Wait for the heaters associated with the specified tool to reach their set temperatures
bool AllAxesAreHomed() const; // Return true if all axes are homed
diff --git a/Heat.cpp b/Heat.cpp
index 37fbad43..646a1d68 100644
--- a/Heat.cpp
+++ b/Heat.cpp
@@ -148,24 +148,24 @@ void PID::Spin()
// are not switched on. This is safe, as the next bit of code always turns our
// heater off in that case anyway.
- if(temperatureFault || switchedOff)
+ if (temperatureFault || switchedOff)
{
platform->SetHeater(heater, 0.0); // Make sure...
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount);
+ averagePWM *= (1.0 - invHeatPwmAverageCount);
return;
}
// We are switched on. Check for faults. Temperature silly-low or silly-high mean open-circuit
// or shorted thermistor respectively.
- if(temperature < BAD_LOW_TEMPERATURE || temperature > BAD_HIGH_TEMPERATURE)
+ if (temperature < BAD_LOW_TEMPERATURE || temperature > BAD_HIGH_TEMPERATURE)
{
badTemperatureCount++;
- if(badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT)
+ if (badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT)
{
platform->SetHeater(heater, 0.0);
temperatureFault = true;
- switchedOff = true;
+ //switchedOff = true;
platform->Message(BOTH_MESSAGE, "Temperature fault on heater %d, T = %.1f\n", heater, temperature);
reprap.FlagTemperatureFault(heater);
}
@@ -177,18 +177,18 @@ void PID::Spin()
// Now check how long it takes to warm up. If too long, maybe the thermistor is not in contact with the heater
- if(heatingUp && heater != HOT_BED) // FIXME - also check bed warmup time?
+ if (heatingUp && heater != HOT_BED) // FIXME - also check bed warmup time?
{
float tmp = (active) ? activeTemperature : standbyTemperature;
- if(temperature < tmp - TEMPERATURE_CLOSE_ENOUGH)
+ if (temperature < tmp - TEMPERATURE_CLOSE_ENOUGH)
{
float tim = platform->Time() - timeSetHeating;
float limit = platform->TimeToHot();
- if(tim > limit && limit > 0.0)
+ if (tim > limit && limit > 0.0)
{
platform->SetHeater(heater, 0.0);
temperatureFault = true;
- switchedOff = true;
+ //switchedOff = true;
platform->Message(BOTH_MESSAGE, "Heating fault on heater %d, T = %.1f C; still not at temperature %.1f after %f seconds.\n", heater, temperature, tmp, tim);
reprap.FlagTemperatureFault(heater);
}
@@ -208,11 +208,12 @@ void PID::Spin()
if(error > 0.0)
{
platform->SetHeater(heater, pp.kS);
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount) + pp.kS;
- } else
+ averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + pp.kS;
+ }
+ else
{
platform->SetHeater(heater, 0.0);
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount);
+ averagePWM *= (1.0 - invHeatPwmAverageCount);
}
return;
}
@@ -222,7 +223,7 @@ void PID::Spin()
// actual temperature is well above target
temp_iState = (targetTemperature + pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
platform->SetHeater(heater, 0.0);
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount);
+ averagePWM *= (1.0 - invHeatPwmAverageCount);
lastTemperature = temperature;
return;
}
@@ -231,7 +232,7 @@ void PID::Spin()
// actual temperature is well below target
temp_iState = (targetTemperature - pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
platform->SetHeater(heater, pp.kS);
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount) + pp.kS;
+ averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + pp.kS;
lastTemperature = temperature;
return;
}
@@ -271,7 +272,7 @@ void PID::Spin()
platform->SetHeater(heater, result * pp.kS);
}
- averagePWM = averagePWM*(1.0 - invHeatPwmAverageCount) + result;
+ averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + result;
// debugPrintf("Heater %d: e=%f, P=%f, I=%f, d=%f, r=%f\n", heater, error, pp.kP*error, temp_iState, temp_dState, result);
}
diff --git a/Heat.h b/Heat.h
index a8127745..b2b090d3 100644
--- a/Heat.h
+++ b/Heat.h
@@ -44,7 +44,7 @@ class PID
bool SwitchedOff() const; // Are we switched off?
void ResetFault(); // Reset a fault condition - only call this if you know what you are doing
float GetTemperature() const; // Get the current temperature
- float GetAveragePWM() const; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
+ float GetAveragePWM() const; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
private:
@@ -88,6 +88,7 @@ class Heat
void Standby(int8_t heater); // Set a heater idle
float GetTemperature(int8_t heater) const; // Get the temperature of a heater
HeaterStatus GetStatus(int8_t heater) const; // Get the off/standby/active status
+ void SwitchOff(int8_t heater); // Turn off a specific heater
void SwitchOffAll(); // Turn all heaters off
void ResetFault(int8_t heater); // Reset a heater fault - only call this if you know what you are doing
bool AllHeatersAtSetTemperatures(bool includingBed) const; // Is everything at temperature within tolerance?
@@ -137,7 +138,7 @@ inline float PID::GetStandbyTemperature() const
inline float PID::GetTemperature() const
{
- return temperature;
+ return (temperatureFault ? ABS_ZERO : temperature);
}
inline void PID::Activate()
@@ -165,6 +166,7 @@ inline void PID::Standby()
inline void PID::ResetFault()
{
temperatureFault = false;
+ timeSetHeating = platform->Time(); // otherwise we will get another timeout immediately
badTemperatureCount = 0;
}
@@ -234,6 +236,14 @@ inline void Heat::Activate(int8_t heater)
}
}
+inline void Heat::SwitchOff(int8_t heater)
+{
+ if (heater >= 0 && heater < HEATERS)
+ {
+ pids[heater]->SwitchOff();
+ }
+}
+
inline void Heat::SwitchOffAll()
{
for (int8_t heater = 0; heater < HEATERS; ++heater)
diff --git a/Matrix.h b/Matrix.h
new file mode 100644
index 00000000..d21e5e45
--- /dev/null
+++ b/Matrix.h
@@ -0,0 +1,115 @@
+/*
+ * Matrix.h
+ *
+ * Created on: 31 Mar 2015
+ * Author: David
+ */
+
+#ifndef MATRIX_H_
+#define MATRIX_H_
+
+#include <cstddef> // for size_t
+
+// Base class for matrices, allows us to write functions that work with any size matrix
+template<class T> class MathMatrix
+{
+public:
+ virtual size_t rows() const = 0;
+ virtual size_t cols() const = 0;
+ virtual T& operator() (size_t r, size_t c) = 0;
+ virtual const T& operator() (size_t r, size_t c) const = 0;
+ virtual ~MathMatrix() { } // to keep Eclipse code analysis happy
+};
+
+// Fixed size matrix class
+template<class T, size_t ROWS, size_t COLS> class FixedMatrix : public MathMatrix<T>
+{
+public:
+ size_t rows() const override { return ROWS; }
+ size_t cols() const override { return COLS; }
+ T& operator() (size_t r, size_t c) override
+ //pre(r < ROWS; c < COLS)
+ {
+ return data[r * COLS + c];
+ }
+
+ const T& operator() (size_t r, size_t c) const override
+ //pre(r < ROWS; c < COLS)
+ {
+ return data[r * COLS + c];
+ }
+
+ void SwapRows(size_t i, size_t j)
+ //pre(i < ROWS; j < ROWS)
+ ;
+
+ void GaussJordan(T *solution, size_t numRows)
+ //pre(numRows <= ROWS; numRows + 1 <= COLS)
+ ;
+
+private:
+ T data[ROWS * COLS];
+};
+
+// Swap 2 rows of a matrix
+template<class T, size_t ROWS, size_t COLS> inline void FixedMatrix<T, ROWS, COLS>::SwapRows(size_t i, size_t j)
+{
+ if (i != j)
+ {
+ for (size_t k = i; k < COLS; ++k)
+ {
+ T temp = (*this)(i, k);
+ (*this)(i, k) = (*this)(j, k);
+ (*this)(j, k) = temp;
+ }
+ }
+}
+
+// Perform Gauss-Jordan elimination on a N x (N+1) matrix.
+// Returns a pointer to the solution vector.
+template<class T, size_t ROWS, size_t COLS> void FixedMatrix<T, ROWS, COLS>::GaussJordan(T *solution, size_t numRows)
+{
+ for (size_t i = 0; i < numRows; ++i)
+ {
+ // Swap the rows around for stable Gauss-Jordan elimination
+ float vmax = fabs((*this)(i, i));
+ for (size_t j = i + 1; j < numRows; ++j)
+ {
+ const float rmax = fabs((*this)(j, i));
+ if (rmax > vmax)
+ {
+ SwapRows(i, j);
+ vmax = rmax;
+ }
+ }
+
+ // Use row i to eliminate the ith element from previous and subsequent rows
+ float v = (*this)(i, i);
+ for (size_t j = 0; j < i; ++j)
+ {
+ float factor = (*this)(j, i)/v;
+ (*this)(j, i) = 0.0;
+ for (size_t k = i + 1; k <= numRows; ++k)
+ {
+ (*this)(j, k) -= (*this)(i, k) * factor;
+ }
+ }
+
+ for (size_t j = i + 1; j < numRows; ++j)
+ {
+ float factor = (*this)(j, i)/v;
+ (*this)(j, i) = 0.0;
+ for (size_t k = i + 1; k <= numRows; ++k)
+ {
+ (*this)(j, k) -= (*this)(i, k) * factor;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < numRows; ++i)
+ {
+ solution[i] = (*this)(i, numRows) / (*this)(i, i);
+ }
+}
+
+#endif /* MATRIX_H_ */
diff --git a/Move.cpp b/Move.cpp
index 90c30347..93105dd0 100644
--- a/Move.cpp
+++ b/Move.cpp
@@ -46,7 +46,6 @@ void DeltaParameters::Recalc()
deltaMode = (radius > 0.0 && diagonal > radius);
if (deltaMode)
{
- homedCarriageHeight = homedHeight + sqrtf(fsquare(diagonal) - fsquare(radius));
Xbc = towerX[C_AXIS] - towerX[B_AXIS];
Xca = towerX[A_AXIS] - towerX[C_AXIS];
Xab = towerX[B_AXIS] - towerX[A_AXIS];
@@ -58,17 +57,36 @@ void DeltaParameters::Recalc()
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(fsquare(diagonal) - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[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[]) const
+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);
@@ -90,7 +108,7 @@ void DeltaParameters::InverseTransform(float Ha, float Hb, float Hc, float machi
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) - fsquare(diagonal)) * Q2;
+ 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);
@@ -100,8 +118,13 @@ void DeltaParameters::InverseTransform(float Ha, float Hb, float Hc, float machi
machinePos[Z_AXIS] = z;
}
-// Compute the derivative of height with respect to a parameter
-float DeltaParameters::ComputeDerivative(unsigned int deriv, const float machinePos[AXES])
+// 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
+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);
@@ -119,18 +142,26 @@ float DeltaParameters::ComputeDerivative(unsigned int deriv, const float machine
break;
case 5:
- hiParams.towerY[C_AXIS] += perturb;
- loParams.towerY[C_AXIS] -= perturb;
+ {
+ 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;
}
hiParams.Recalc();
loParams.Recalc();
- float ha = Transform(machinePos, A_AXIS);
- float hb = Transform(machinePos, B_AXIS);
- float hc = Transform(machinePos, C_AXIS);
-
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];
@@ -140,24 +171,58 @@ float DeltaParameters::ComputeDerivative(unsigned int deriv, const float machine
return (zHi - zLo)/(2 * perturb);
}
-// Perform 6-factor adjustment
-void DeltaParameters::SixFactorAdjust(float ea, float eb, float ec, float xa, float xb, float yc)
+// Perform 4-factor adjustment.
+// The input vector contains the following parameters in this order:
+// X, Y and Z endstop adjustments
+// Delta radius
+void DeltaParameters::AdjustFour(const float v[4])
{
- const float eav = (ea + eb + ec)/3;
- endstopAdjustments[A_AXIS] += ea - eav;
- endstopAdjustments[B_AXIS] += eb - eav;
- endstopAdjustments[C_AXIS] += ec - eav;
- homedHeight += eav;
- towerX[A_AXIS] += xa;
- towerX[B_AXIS] += xb;
- towerY[C_AXIS] += yc;
+ endstopAdjustments[A_AXIS] += v[0];
+ endstopAdjustments[B_AXIS] += v[1];
+ endstopAdjustments[C_AXIS] += v[2];
+ NormaliseEndstopAdjustments();
+ SetRadius(radius + v[3]); // this sets isEquilateral true, recalculates tower positions, then calls Recalc()
+}
+
+// Perform 7-factor adjustment.
+// The input vector contains the following parameters in this order:
+// X, Y and Z endstop adjustments
+// X tower X position adjustment
+// Y tower X position adjustment
+// Z tower Y position adjustment
+// Diagonal rod length adjustment
+void DeltaParameters::AdjustSeven(const float v[7])
+{
+ const float oldCarriageHeightA = GetHomedCarriageHeight(A_AXIS); // save for later
+
+ endstopAdjustments[A_AXIS] += v[0];
+ endstopAdjustments[B_AXIS] += v[1];
+ endstopAdjustments[C_AXIS] += v[2];
+ NormaliseEndstopAdjustments();
+
+ 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);
+ diagonal += v[6];
isEquilateral = false;
+
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, ", endstopAdjustments[A_AXIS], endstopAdjustments[B_AXIS], endstopAdjustments[C_AXIS], homedHeight);
+ 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);
@@ -224,10 +289,13 @@ void Move::Init()
currentFeedrate = reprap.GetPlatform()->HomeFeedRate(slow);
// Set up default bed probe points. This is only a guess, because we don't know the bed size yet.
- for (size_t point = 0; point < NUMBER_OF_PROBE_POINTS; point++)
+ for (size_t point = 0; point < MaxProbePoints; point++)
{
- xBedProbePoints[point] = (0.3 + 0.6*(float)(point%2))*reprap.GetPlatform()->AxisMaximum(X_AXIS);
- yBedProbePoints[point] = (0.0 + 0.9*(float)(point/2))*reprap.GetPlatform()->AxisMaximum(Y_AXIS);
+ if (point < 4)
+ {
+ xBedProbePoints[point] = (0.3 + 0.6*(float)(point%2))*reprap.GetPlatform()->AxisMaximum(X_AXIS);
+ yBedProbePoints[point] = (0.0 + 0.9*(float)(point/2))*reprap.GetPlatform()->AxisMaximum(Y_AXIS);
+ }
zBedProbePoints[point] = 0.0;
probePointSet[point] = unset;
}
@@ -298,7 +366,42 @@ void Move::Spin()
FilePosition filePos;
if (reprap.GetGCodes()->ReadMove(nextMove, endStopsToCheck, moveType, filePos))
{
+ // We have a new move
currentFeedrate = nextMove[DRIVES]; // might be G1 with just an F field
+
+#if 0 //*** This code is not finished yet ***
+ // If we are doing bed compensation and the move crosses a compensation boundary by a significant amount,
+ // segment it so that we can apply proper bed compensation
+ // Issues here:
+ // 1. Are there enough DDAs? need to make nextMove static and remember whether we have the remains of a move in there.
+ // 2. Restarting: if we restart a segmented move when we have already executed part of it, we will extrude too much.
+ // Perhaps remember how much of the last move we executed? Or always insist on completing all the segments in a move?
+ bool isSegmented;
+ do
+ {
+ float tempMove[DRIVES + 1];
+ memcpy(tempMove, nextMove, sizeof(tempMove));
+ isSegmented = SegmentMove(tempMove);
+ if (isSegmented)
+ {
+ // Extruder moves are relative, so we need to adjust the extrusion amounts in the original move
+ for (size_t drive = AXES; drive < DRIVES; ++drive)
+ {
+ nextMove[drive] -= tempMove[drive];
+ }
+ }
+ bool doMotorMapping = (moveType == 0) || (moveType == 1 && !IsDeltaMode());
+ if (doMotorMapping)
+ {
+ Transform(tempMove);
+ }
+ if (ddaRingAddPointer->Init(tempMove, endStopsToCheck, doMotorMapping, filePos))
+ {
+ ddaRingAddPointer = ddaRingAddPointer->GetNext();
+ idleCount = 0;
+ }
+ } while (isSegmented);
+#else // Use old code
bool doMotorMapping = (moveType == 0) || (moveType == 1 && !IsDeltaMode());
if (doMotorMapping)
{
@@ -309,6 +412,7 @@ void Move::Spin()
ddaRingAddPointer = ddaRingAddPointer->GetNext();
idleCount = 0;
}
+#endif
}
}
}
@@ -800,56 +904,52 @@ float Move::TriangleZ(float x, float y) const
// sParam is the value of the S parameter in the G30 command that provoked this call.
void Move::FinishedBedProbing(int sParam, StringRef& reply)
{
- if (reprap.Debug(moduleMove))
+ if (sParam < 0)
{
- debugPrintf("Z probe offsets:");
+ // A negative sParam just prints the probe heights
+ reply.copy("Bed probe heights:");
for (size_t i = 0; i < NumberOfProbePoints(); ++i)
{
- debugPrintf(" %.2f", zBedProbePoints[i]);
+ reply.catf(" %.2f", zBedProbePoints[i]);
}
- debugPrintf("\n");
+ reply.cat("\n");
}
-
- bool ok = false;
- switch (sParam)
+ else if (NumberOfProbePoints() < sParam)
{
- case 0:
- SetProbedBedEquation(reply);
- ok = true;
- break;
-
- case 4:
- // On a delta, this calibrates the endstop adjustments and delta radius automatically after a 4 point probe.
- // Probe points 1,2,3 must be near the bases of the X, Y and Z towers in that order. Point 4 must be in the centre.
- if (IsDeltaMode() && NumberOfProbePoints() >= 4)
+ reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE,
+ "Bed calibration error: %d points requested but only %s provided\n", sParam, NumberOfProbePoints());
+ }
+ else
+ {
+ if (reprap.Debug(moduleMove))
{
- FourPointDeltaCalibration(reply);
- ok = true;
+ debugPrintf("Z probe offsets:");
+ for (size_t i = 0; i < NumberOfProbePoints(); ++i)
+ {
+ debugPrintf(" %.2f", zBedProbePoints[i]);
+ }
+ debugPrintf("\n");
}
- break;
- case 6:
- // On a delta, this calibrates the endstop adjustments and tower positions automatically after a 6 point probe.
- if (IsDeltaMode() && NumberOfProbePoints() >= 6)
+ if (sParam == 0)
{
- SixPointDeltaCalibration(reply);
- ok = true;
+ sParam = NumberOfProbePoints();
}
- break;
-
- default:
- break;
- }
- if (!ok)
- {
- reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE, "Bed probe type %d with %d points not supported on this machine\n", sParam, NumberOfProbePoints());
+ if (IsDeltaMode())
+ {
+ DoDeltaCalibration(sParam, reply);
+ }
+ else
+ {
+ SetProbedBedEquation(sParam, reply);
+ }
}
}
-void Move::SetProbedBedEquation(StringRef& reply)
+void Move::SetProbedBedEquation(size_t numPoints, StringRef& reply)
{
- switch(NumberOfProbePoints())
+ switch(numPoints)
{
case 3:
/*
@@ -894,7 +994,7 @@ void Move::SetProbedBedEquation(StringRef& reply)
break;
case 5:
- for(int8_t i = 0; i < 4; i++)
+ for (size_t i = 0; i < 4; i++)
{
float x10 = xBedProbePoints[i] - xBedProbePoints[4];
float y10 = yBedProbePoints[i] - yBedProbePoints[4];
@@ -910,7 +1010,8 @@ void Move::SetProbedBedEquation(StringRef& reply)
break;
default:
- reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE, "Attempt to set bed compensation before all probe points have been recorded.");
+ reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE, "Bed calibration error: %d points provided but only 3, 4 and 5 supported\n", numPoints);
+ return;
}
reply.copy("Bed equation fits points");
@@ -921,6 +1022,43 @@ void Move::SetProbedBedEquation(StringRef& reply)
reply.cat("\n");
}
+// Perform 4- or 7-factor delta adjustment
+void Move::AdjustDeltaParameters(const float v[], bool allSeven)
+{
+ // Save the old home carriage heights
+ float homedCarriageHeights[AXES];
+ for (size_t drive = 0; drive < AXES; ++drive)
+ {
+ homedCarriageHeights[drive] = deltaParams.GetHomedCarriageHeight(drive);
+ }
+
+ // Adjust the delta parameters
+ if (allSeven)
+ {
+ deltaParams.AdjustSeven(v);
+ }
+ else
+ {
+ deltaParams.AdjustFour(v);
+ }
+
+ // Adjust the motor endpoints to allow for the change in endstop adjustments
+ DDA *lastQueuedMove = ddaRingAddPointer->GetPrevious();
+ const int32_t *endCoordinates = lastQueuedMove->DriveCoordinates();
+ const float *driveStepsPerUnit = reprap.GetPlatform()->GetDriveStepsPerUnit();
+
+ for (size_t drive = 0; drive < AXES; ++drive)
+ {
+ const float heightAdjust = deltaParams.GetHomedCarriageHeight(drive) - homedCarriageHeights[drive];
+ int32_t ep = endCoordinates[drive] + (int32_t)(heightAdjust * driveStepsPerUnit[drive]);
+ lastQueuedMove->SetDriveCoordinate(ep, drive);
+ liveEndPoints[drive] = ep;
+ }
+
+ liveCoordinatesValid = false; // force the live XYZ position to be recalculated
+}
+
+#if 0
// Do 4-point delta calibration. We adjust the 3 endstop corrections and the delta radius.
void Move::FourPointDeltaCalibration(StringRef& reply)
{
@@ -944,6 +1082,7 @@ void Move::FourPointDeltaCalibration(StringRef& reply)
// Adjust the homed height to account for the error at the centre and the change in average endstop correction
deltaParams.SetHomedHeight(deltaParams.GetHomedHeight() + averageEndstopOffset - zBedProbePoints[3]);
+ liveCoordinatesValid = false; // we've updated the delta parameters, so we need to recalculate the position
// Print the parameters so the user can see when they have converged
deltaParams.PrintParameters(reply, false);
@@ -959,7 +1098,7 @@ void Move::SixPointDeltaCalibration(StringRef& reply)
}
// Build a 6x7 matrix of derivatives with respect to xa, xb, yc, za, zb, zc and the height errors.
- float matrix[6][7];
+ FixedMatrix<float, 6, 7> matrix;
for (size_t i = 0; i < 6; ++i)
{
float machinePos[3];
@@ -968,9 +1107,9 @@ void Move::SixPointDeltaCalibration(StringRef& reply)
machinePos[2] = 0.0; // the height doesn't matter
for (size_t j = 0; j < 6; ++j)
{
- matrix[i][j] = deltaParams.ComputeDerivative(j, machinePos);
+ matrix(i, j) = deltaParams.ComputeDerivative(j, machinePos);
}
- matrix[i][6] = -zBedProbePoints[i];
+ matrix(i, 6) = -zBedProbePoints[i];
}
if (reprap.Debug(moduleMove))
@@ -978,57 +1117,112 @@ void Move::SixPointDeltaCalibration(StringRef& reply)
PrintMatrix("Raw matrix", matrix);
}
- for (size_t i = 0; i < 6; ++i)
+ float solution[6];
+ matrix.GaussJordan(solution);
+
+ if (reprap.Debug(moduleMove))
+ {
+ PrintMatrix("Solved matrix", matrix);
+ PrintVector("Solution", solution, 6);
+ }
+
+ AdjustDeltaParameters(solution, true);
+ liveCoordinatesValid = false; // we've updated the delta parameters, so we need to recalculate the position
+ deltaParams.PrintParameters(reply, true);
+}
+#endif
+
+// Do delta calibration. We adjust the three endstop corrections, and either the delta radius,
+// or the X positions of the front two towers, the Y position of the rear tower, and the diagonal rod length.
+void Move::DoDeltaCalibration(size_t numPoints, StringRef& reply)
+{
+ if (numPoints < 4 || numPoints > MaxDeltaCalibrationPoints)
+ {
+ reprap.GetPlatform()->Message(BOTH_ERROR_MESSAGE,
+ "Delta calibration error: %d probe points provided but must be between 4 and %d\n", MaxDeltaCalibrationPoints);
+ return;
+ }
+
+ if (reprap.Debug(moduleMove))
{
- // Swap the rows around for stable Gauss-Jordan elimination
- float vmax = fabs(matrix[i][i]);
- for (size_t j = i + 1; j < 6; ++j)
+ deltaParams.PrintParameters(scratchString, true);
+ debugPrintf("%s\n", scratchString.Pointer());
+ }
+
+ size_t numFactors = (numPoints >= 7) ? 7 : 4;
+
+ // Build a Nx7 matrix of derivatives with respect to xa, xb, yc, za, zb, zc, diagonal.
+ FixedMatrix<float, MaxDeltaCalibrationPoints, 7> derivativeMatrix;
+ for (size_t i = 0; i < numPoints; ++i)
+ {
+ float machinePos[3];
+ machinePos[0] = xBedProbePoints[i];
+ machinePos[1] = yBedProbePoints[i];
+ machinePos[2] = 0.0; // the height doesn't matter
+
+ float ha = deltaParams.Transform(machinePos, A_AXIS);
+ float hb = deltaParams.Transform(machinePos, B_AXIS);
+ float hc = deltaParams.Transform(machinePos, C_AXIS);
+ for (size_t j = 0; j < numFactors; ++j)
{
- const float rmax = fabs(matrix[j][i]);
- if (rmax > vmax)
- {
- // swap rows i and j
- for (size_t k = i; k < 7; ++k)
- {
- swap(matrix[i][k], matrix[j][k]);
- }
- vmax = rmax;
- }
+ derivativeMatrix(i, j) = deltaParams.ComputeDerivative(j, ha, hb, hc);
}
+ }
- // Use row i to eliminate the ith element from previous and subsequent rows
- float v = matrix[i][i];
- for (size_t j = 0; j < i; ++j)
+ if (reprap.Debug(moduleMove))
+ {
+ PrintMatrix("Derivative matrix", derivativeMatrix, numPoints, numFactors);
+ }
+
+ // Now build the normal equations for least squares fitting
+ FixedMatrix<float, 7, 8> normalMatrix;
+ for (size_t i = 0; i < numFactors; ++i)
+ {
+ for (size_t j = 0; j < numFactors; ++j)
{
- float factor = matrix[j][i]/v;
-// matrix[j][i] = 0.0;
-// for (size_t k = i + 1; k < 7; ++k)
- for (size_t k = i; k < 7; ++k)
+ float temp = derivativeMatrix(0, i) * derivativeMatrix(0, j);
+ for (size_t k = 1; k < numPoints; ++k)
{
- matrix[j][k] -= matrix[i][k] * factor;
+ temp += derivativeMatrix(k, i) * derivativeMatrix(k, j);
}
+ normalMatrix(i, j) = temp;
}
-
- for (size_t j = i + 1; j < 6; ++j)
+ float temp = derivativeMatrix(0, i) * -zBedProbePoints[0];
+ for (size_t k = 1; k < numPoints; ++k)
{
- float factor = matrix[j][i]/v;
-// matrix[j][i] = 0.0;
-// for (size_t k = i + 1; k < 7; ++k)
- for (size_t k = i; k < 7; ++k)
- {
- matrix[j][k] -= matrix[i][k] * factor;
- }
+ temp += derivativeMatrix(k, i) * -zBedProbePoints[k];
}
+ normalMatrix(i, numFactors) = temp;
}
if (reprap.Debug(moduleMove))
{
- PrintMatrix("Diagonalised matrix", matrix);
+ PrintMatrix("Normal matrix", normalMatrix, numFactors, numFactors + 1);
}
- deltaParams.SixFactorAdjust(matrix[0][6]/matrix[0][0], matrix[1][6]/matrix[1][1], matrix[2][6]/matrix[2][2],
- matrix[3][6]/matrix[3][3], matrix[4][6]/matrix[4][4], matrix[5][6]/matrix[5][5]);
+ float solution[7];
+ normalMatrix.GaussJordan(solution, numFactors);
+
+ if (reprap.Debug(moduleMove))
+ {
+ PrintMatrix("Solved matrix", normalMatrix, numFactors, numFactors + 1);
+ PrintVector("Solution", solution, numFactors);
+
+ // Calculate and display the residuals
+ float residuals[MaxDeltaCalibrationPoints];
+ for (size_t i = 0; i < numPoints; ++i)
+ {
+ residuals[i] = zBedProbePoints[i];
+ for (size_t j = 0; j < numFactors; ++j)
+ {
+ residuals[i] += solution[j] * derivativeMatrix(i, j);
+ }
+ }
+
+ PrintVector("Residuals", residuals, numPoints);
+ }
+ AdjustDeltaParameters(solution, numFactors == 7);
deltaParams.PrintParameters(reply, true);
}
@@ -1212,7 +1406,7 @@ void Move::SetLiveCoordinates(const float coords[DRIVES])
void Move::SetXBedProbePoint(int index, float x)
{
- if(index < 0 || index >= NUMBER_OF_PROBE_POINTS)
+ if(index < 0 || index >= MaxProbePoints)
{
reprap.GetPlatform()->Message(BOTH_MESSAGE, "Z probe point X index out of range.\n");
return;
@@ -1223,7 +1417,7 @@ void Move::SetXBedProbePoint(int index, float x)
void Move::SetYBedProbePoint(int index, float y)
{
- if(index < 0 || index >= NUMBER_OF_PROBE_POINTS)
+ if(index < 0 || index >= MaxProbePoints)
{
reprap.GetPlatform()->Message(BOTH_MESSAGE, "Z probe point Y index out of range.\n");
return;
@@ -1234,7 +1428,7 @@ void Move::SetYBedProbePoint(int index, float y)
void Move::SetZBedProbePoint(int index, float z)
{
- if(index < 0 || index >= NUMBER_OF_PROBE_POINTS)
+ if(index < 0 || index >= MaxProbePoints)
{
reprap.GetPlatform()->Message(BOTH_MESSAGE, "Z probe point Z index out of range.\n");
return;
@@ -1270,26 +1464,26 @@ bool Move::XYProbeCoordinatesSet(int index) const
int Move::NumberOfProbePoints() const
{
- for(int i = 0; i < NUMBER_OF_PROBE_POINTS; i++)
+ for(int i = 0; i < MaxProbePoints; i++)
{
if(!AllProbeCoordinatesSet(i))
{
return i;
}
}
- return NUMBER_OF_PROBE_POINTS;
+ return MaxProbePoints;
}
int Move::NumberOfXYProbePoints() const
{
- for(int i = 0; i < NUMBER_OF_PROBE_POINTS; i++)
+ for(int i = 0; i < MaxProbePoints; i++)
{
if(!XYProbeCoordinatesSet(i))
{
return i;
}
}
- return NUMBER_OF_PROBE_POINTS;
+ return MaxProbePoints;
}
// Enter or leave simulation mode
@@ -1321,13 +1515,35 @@ const char* Move::GetGeometryString() const
: "cartesian";
}
-/*static*/ void Move::PrintMatrix(const char* s, float matrix[6][7])
+/*static*/ void Move::PrintMatrix(const char* s, const MathMatrix<float>& m, size_t maxRows, size_t maxCols)
{
debugPrintf("%s\n", s);
- for (size_t i = 0; i < 6; ++i)
+ if (maxRows == 0)
+ {
+ maxRows = m.rows();
+ }
+ if (maxCols == 0)
+ {
+ maxCols = m.cols();
+ }
+
+ for (size_t i = 0; i < maxRows; ++i)
+ {
+ for (size_t j = 0; j < maxCols; ++j)
+ {
+ debugPrintf("%7.3f%c", m(i, j), (j == maxCols - 1) ? '\n' : ' ');
+ }
+ }
+}
+
+/*static*/ void Move::PrintVector(const char *s, const float *v, size_t numElems)
+{
+ debugPrintf("%s:", s);
+ for (size_t i = 0; i < numElems; ++i)
{
- debugPrintf("%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f = %6.3f\n", matrix[i][0], matrix[i][1], matrix[i][2], matrix[i][3], matrix[i][4], matrix[i][5], matrix[i][6]);
+ debugPrintf(" %7.3f", v[i]);
}
+ debugPrintf("\n");
}
// End
diff --git a/Move.h b/Move.h
index af7582e1..3017c760 100644
--- a/Move.h
+++ b/Move.h
@@ -9,6 +9,7 @@
#define MOVE_H_
#include "DDA.h"
+#include "Matrix.h"
const unsigned int DdaRingLength = 20;
@@ -46,14 +47,16 @@ public:
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[]) const; // Calculate the Cartesian position from the motor positions
+ 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, const float pos[AXES]); // Compute the derivative of height with respect to a parameter at a point
- void SixFactorAdjust(float ea, float eb, float ec, float xa, float xb, float yc); // Perform 6-factor adjustment
+ 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 AdjustFour(const float v[4]); // Perform 4-factor adjustment
+ void AdjustSeven(const float v[7]); // Perform 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
@@ -71,7 +74,7 @@ private:
float homedCarriageHeight;
float Xbc, Xca, Xab, Ybc, Yca, Yab;
float coreFa, coreFb, coreFc;
- float Q, Q2;
+ float Q, Q2, D2;
};
/**
@@ -145,9 +148,8 @@ private:
enum class IdleState : uint8_t { idle, busy, timing };
- void SetProbedBedEquation(StringRef& reply); // When we have a full set of probed points, work out the bed's equation
- void FourPointDeltaCalibration(StringRef& reply);
- void SixPointDeltaCalibration(StringRef& reply);
+ void SetProbedBedEquation(size_t numPoints, StringRef& reply); // When we have a full set of probed points, work out the bed's equation
+ void DoDeltaCalibration(size_t numPoints, StringRef& reply);
void BedTransform(float move[AXES]) const; // Take a position and apply the bed compensations
void GetCurrentMachinePosition(float m[DRIVES + 1], bool disableMotorMapping) const; // Get the current position and feedrate in untransformed coords
void InverseBedTransform(float move[AXES]) const; // Go from a bed-transformed point back to user coordinates
@@ -157,8 +159,10 @@ private:
size_t p2, float x, float y, float& l1, // (see http://en.wikipedia.org/wiki/Barycentric_coordinate_system).
float& l2, float& l3) const;
float TriangleZ(float x, float y) const; // Interpolate onto a triangular grid
+ void AdjustDeltaParameters(const float v[], bool allSeven); // Perform 4- or 7-factor delta adjustment
- static void PrintMatrix(const char* s, float matrix[6][7]); // for debugging
+ static void PrintMatrix(const char* s, const MathMatrix<float>& m, size_t numRows = 0, size_t maxCols = 0); // for debugging
+ static void PrintVector(const char *s, const float *v, size_t numElems); // for debugging
bool DDARingAdd(); // Add a processed look-ahead entry to the DDA ring
DDA* DDARingGet(); // Get the next DDA ring entry to be run
@@ -178,13 +182,13 @@ private:
volatile bool liveCoordinatesValid; // True if the XYZ live coordinates are reliable (the extruder ones always are)
volatile int32_t liveEndPoints[DRIVES]; // The XYZ endpoints of the last completed move in motor coordinates
- float xBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The X coordinates of the points on the bed at which to probe
- float yBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The Y coordinates of the points on the bed at which to probe
- float zBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The Z coordinates of the points on the bed at which to probe
- float baryXBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The X coordinates of the triangle corner points
- float baryYBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The Y coordinates of the triangle corner points
- float baryZBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The Z coordinates of the triangle corner points
- uint8_t probePointSet[NUMBER_OF_PROBE_POINTS]; // Has the XY of this point been set? Has the Z been probed?
+ float xBedProbePoints[MaxProbePoints]; // The X coordinates of the points on the bed at which to probe
+ float yBedProbePoints[MaxProbePoints]; // The Y coordinates of the points on the bed at which to probe
+ float zBedProbePoints[MaxProbePoints]; // The Z coordinates of the points on the bed at which to probe
+ float baryXBedProbePoints[5]; // The X coordinates of the triangle corner points
+ float baryYBedProbePoints[5]; // The Y coordinates of the triangle corner points
+ float baryZBedProbePoints[5]; // The Z coordinates of the triangle corner points
+ uint8_t probePointSet[MaxProbePoints]; // Has the XY of this point been set? Has the Z been probed?
float aX, aY, aC; // Bed plane explicit equation z' = z + aX*x + aY*y + aC
float tanXY, tanYZ, tanXZ; // Axis compensation - 90 degrees + angle gives angle between axes
bool identityBedTransform; // Is the bed transform in operation?
@@ -207,7 +211,7 @@ inline bool Move::DDARingEmpty() const
inline bool Move::NoLiveMovement() const
{
- return currentDda == nullptr && DDARingEmpty();
+ return DDARingEmpty() && currentDda == nullptr; // must test currentDda and DDARingEmpty *in this order* !
}
// To wait until all the current moves in the buffers are
@@ -218,7 +222,7 @@ inline bool Move::NoLiveMovement() const
inline bool Move::AllMovesAreFinished()
{
addNoMoreMoves = true;
- return DDARingEmpty() && NoLiveMovement();
+ return NoLiveMovement();
}
inline void Move::ResumeMoving()
diff --git a/Network.cpp b/Network.cpp
index 9adb6815..3083843c 100644
--- a/Network.cpp
+++ b/Network.cpp
@@ -251,15 +251,8 @@ static err_t conn_accept(void *arg, tcp_pcb *pcb, err_t err)
tcp_accepted(telnet_pcb);
break;
- default:
- if (pcb->local_port == httpPort)
- {
- tcp_accepted(http_pcb);
- }
- else // FTP data
- {
- tcp_accepted(ftp_pasv_pcb);
- }
+ default: // HTTP and FTP data
+ tcp_accepted((pcb->local_port == httpPort) ? http_pcb : ftp_pasv_pcb);
break;
}
tcp_arg(pcb, cs); // tell LWIP that this is the structure we wish to be passed for our callbacks
@@ -333,17 +326,17 @@ Network::Network(Platform* p)
freeTransactions(NULL), readyTransactions(NULL), writingTransactions(NULL),
dataCs(NULL), ftpCs(NULL), telnetCs(NULL), freeSendBuffers(NULL), freeConnections(NULL)
{
- for (int8_t i = 0; i < networkTransactionCount; i++)
+ for (unsigned int i = 0; i < networkTransactionCount; i++)
{
freeTransactions = new NetworkTransaction(freeTransactions);
}
- for (int8_t i = 0; i < tcpOutputBufferCount; i++)
+ for (unsigned int i = 0; i < tcpOutputBufferCount; i++)
{
freeSendBuffers = new SendBuffer(freeSendBuffers);
}
- for (int8_t i = 0; i < numConnections; i++)
+ for (unsigned int i = 0; i < numConnections; i++)
{
ConnectionState *cs = new ConnectionState;
cs->next = freeConnections;
@@ -523,14 +516,25 @@ bool Network::IsEnabled() const
return isEnabled;
}
-unsigned int Network::GetHttpPort() const
+uint16_t Network::GetHttpPort() const
{
return httpPort;
}
-void Network::SetHttpPort(unsigned int port)
+void Network::SetHttpPort(uint16_t port)
{
- httpPort = (uint16_t)port;
+ if (state == NetworkActive && port != httpPort)
+ {
+ // Close old HTTP port
+ tcp_close(http_pcb);
+
+ // Create a new one for the new port
+ tcp_pcb* pcb = tcp_new();
+ tcp_bind(pcb, IP_ADDR_ANY, port);
+ http_pcb = tcp_listen(pcb);
+ tcp_accept(http_pcb, conn_accept);
+ }
+ httpPort = port;
}
bool Network::AllocateSendBuffer(SendBuffer *&buffer)
@@ -1062,7 +1066,7 @@ uint16_t ConnectionState::GetRemotePort() const
return pcb->remote_port;
}
-// NetRing class members
+// NetworkTransaction class members
void NetworkTransaction::Set(pbuf *p, ConnectionState *c, TransactionStatus s)
{
cs = c;
diff --git a/Network.h b/Network.h
index 3354b2d0..d5fcd414 100644
--- a/Network.h
+++ b/Network.h
@@ -179,8 +179,9 @@ public:
void Enable();
void Disable();
bool IsEnabled() const;
- unsigned int GetHttpPort() const;
- void SetHttpPort(unsigned int port);
+
+ void SetHttpPort(uint16_t port);
+ uint16_t GetHttpPort() const;
private:
diff --git a/Platform.cpp b/Platform.cpp
index 988a9afa..48cc0e73 100644
--- a/Platform.cpp
+++ b/Platform.cpp
@@ -137,17 +137,7 @@ void Platform::Init()
SerialUSB.begin(baudRates[0]);
Serial.begin(baudRates[1]); // this can't be done in the constructor because the Arduino port initialisation isn't complete at that point
-#if __cplusplus >= 201103L
static_assert(sizeof(FlashData) + sizeof(SoftwareResetData) <= FLASH_DATA_LENGTH, "NVData too large");
-#else
- // We are relying on the compiler optimizing this out if the condition is false
- // Watch out for the build warning "undefined reference to 'BadStaticAssert()' if this fails.
- if (!(sizeof(FlashData) + sizeof(SoftwareResetData) <= FLASH_DATA_LENGTH))
- {
- extern void BadStaticAssert();
- BadStaticAssert();
- }
-#endif
ResetNvData();
@@ -155,6 +145,12 @@ void Platform::Init()
aux->Init();
messageIndent = 0;
+ // We need to initialize at least some of the time stuff before we call MassStorage::Init()
+ addToTime = 0.0;
+ lastTimeCall = 0;
+ lastTime = Time();
+ longWait = lastTime;
+
massStorage->Init();
for (size_t file = 0; file < MAX_FILES; file++)
@@ -283,8 +279,6 @@ void Platform::Init()
InitialiseInterrupts();
- addToTime = 0.0;
- lastTimeCall = 0;
lastTime = Time();
longWait = lastTime;
}
@@ -370,14 +364,13 @@ int Platform::ZProbe() const
{
switch (nvData.zProbeType)
{
- case 1:
- case 3:
- case 4:
- // Simple IR sensor, or direct-mode ultrasonic sensor
+ case 1: // Simple or intelligent IR sensor
+ case 3: // Alternate sensor
+ case 4: // Mechanical Z probe
return (int) ((zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum()) / (8 * numZProbeReadingsAveraged));
- case 2:
- // Modulated IR sensor. We assume that zProbeOnFilter and zprobeOffFilter average the same number of readings.
+ case 2: // Modulated IR sensor.
+ // We assume that zProbeOnFilter and zprobeOffFilter average the same number of readings.
// 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())
/ (4 * numZProbeReadingsAveraged));
@@ -460,7 +453,7 @@ float Platform::GetZProbeDiveHeight() const
case 4:
return nvData.switchZProbeParameters.diveHeight;
default:
- return Z_DIVE;
+ return DefaultZDive;
}
}
@@ -1040,7 +1033,7 @@ void Platform::Diagnostics()
// Show the current probe position heights
AppendMessage(BOTH_MESSAGE, "Bed probe heights:");
- for (size_t i = 0; i < NUMBER_OF_PROBE_POINTS; ++i)
+ for (size_t i = 0; i < MaxProbePoints; ++i)
{
AppendMessage(BOTH_MESSAGE, " %.3f", reprap.GetMove()->ZBedProbePoint(i));
}
@@ -1660,45 +1653,96 @@ void Platform::ResetChannel(size_t chan)
*/
-MassStorage::MassStorage(Platform* p)
+MassStorage::MassStorage(Platform* p) : platform(p)
{
- platform = p;
+ memset(&fileSystem, 0, sizeof(fileSystem));
}
void MassStorage::Init()
{
- hsmciPinsinit();
// Initialize SD MMC stack
+ hsmciPinsinit();
sd_mmc_init();
delay(20);
- int sdPresentCount = 0;
- while ((CTRL_NO_PRESENT == sd_mmc_check(0)) && (sdPresentCount < 5))
- {
- //platform->Message(HOST_MESSAGE, "Please plug in the SD card.\n");
- //delay(1000);
- sdPresentCount++;
- }
- if (sdPresentCount >= 5)
- {
- platform->Message(HOST_MESSAGE, "Can't find the SD card.\n");
- return;
- }
+ bool abort = false;
+ sd_mmc_err_t err;
+ do {
+ err = sd_mmc_check(0);
+ if (err > SD_MMC_ERR_NO_CARD)
+ {
+ abort = true;
+ delay(3000); // Wait a few seconds, so users have a chance to see the following error message
+ }
+ else
+ {
+ abort = (err == SD_MMC_ERR_NO_CARD && platform->Time() > 5.0);
+ }
- //print card info
+ if (abort)
+ {
+ platform->Message(HOST_MESSAGE, "Cannot initialize the SD card: ");
+ switch (err)
+ {
+ case SD_MMC_ERR_NO_CARD:
+ platform->AppendMessage(HOST_MESSAGE, "Card not found\n");
+ break;
+ case SD_MMC_ERR_UNUSABLE:
+ platform->AppendMessage(HOST_MESSAGE, "Card is unusable, try another one\n");
+ break;
+ case SD_MMC_ERR_SLOT:
+ platform->AppendMessage(HOST_MESSAGE, "Slot unknown\n");
+ break;
+ case SD_MMC_ERR_COMM:
+ platform->AppendMessage(HOST_MESSAGE, "General communication error\n");
+ break;
+ case SD_MMC_ERR_PARAM:
+ platform->AppendMessage(HOST_MESSAGE, "Illegal input parameter\n");
+ break;
+ case SD_MMC_ERR_WP:
+ platform->AppendMessage(HOST_MESSAGE, "Card write protected\n");
+ break;
+ default:
+ platform->AppendMessage(HOST_MESSAGE, "Unknown (code %d)\m", err);
+ break;
+ }
+ return;
+ }
+ } while (err != SD_MMC_OK);
-// SerialUSB.print("sd_mmc_card->capacity: ");
-// SerialUSB.print(sd_mmc_get_capacity(0));
-// SerialUSB.print(" bytes\n");
-// SerialUSB.print("sd_mmc_card->clock: ");
-// SerialUSB.print(sd_mmc_get_bus_clock(0));
-// SerialUSB.print(" Hz\n");
-// SerialUSB.print("sd_mmc_card->bus_width: ");
-// SerialUSB.println(sd_mmc_get_bus_width(0));
+ // Print some card details (optional)
+
+ /*platform->Message(HOST_MESSAGE, "SD card detected!\nCapacity: %d\n", sd_mmc_get_capacity(0));
+ platform->AppendMessage(HOST_MESSAGE, "Bus clock: %d\n", sd_mmc_get_bus_clock(0));
+ platform->AppendMessage(HOST_MESSAGE, "Bus width: %d\nCard type: ", sd_mmc_get_bus_width(0));
+ switch (sd_mmc_get_type(0))
+ {
+ case CARD_TYPE_SD | CARD_TYPE_HC:
+ platform->AppendMessage(HOST_MESSAGE, "SDHC\n");
+ break;
+ case CARD_TYPE_SD:
+ platform->AppendMessage(HOST_MESSAGE, "SD\n");
+ break;
+ case CARD_TYPE_MMC | CARD_TYPE_HC:
+ platform->AppendMessage(HOST_MESSAGE, "MMC High Density\n");
+ break;
+ case CARD_TYPE_MMC:
+ platform->AppendMessage(HOST_MESSAGE, "MMC\n");
+ break;
+ case CARD_TYPE_SDIO:
+ platform->AppendMessage(HOST_MESSAGE, "SDIO\n");
+ return;
+ case CARD_TYPE_SD_COMBO:
+ platform->AppendMessage(HOST_MESSAGE, "SD COMBO\n");
+ break;
+ case CARD_TYPE_UNKNOWN:
+ default:
+ platform->AppendMessage(HOST_MESSAGE, "Unknown\n");
+ return;
+ }*/
+
+ // Mount the file system
- memset(&fileSystem, 0, sizeof(FATFS));
- //f_mount (LUN_ID_SD_MMC_0_MEM, NULL);
- //int mounted = f_mount(LUN_ID_SD_MMC_0_MEM, &fileSystem);
int mounted = f_mount(0, &fileSystem);
if (mounted != FR_OK)
{
@@ -1752,10 +1796,10 @@ const char* MassStorage::CombineName(const char* directory, const char* fileName
// Open a directory to read a file list. Returns true if it contains any files, false otherwise.
bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
{
- TCHAR loc[64 + 1];
+ TCHAR loc[MaxFilenameLength + 1];
// Remove the trailing '/' from the directory name
- size_t len = strnlen(directory, ARRAY_SIZE(loc) - 1); // the -1 ensures we have room for a null terminator
+ size_t len = strnlen(directory, ARRAY_UPB(loc));
if (len == 0)
{
loc[0] = 0;
@@ -1771,6 +1815,7 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
loc[len] = 0;
}
+ findDir.lfn = nullptr;
FRESULT res = f_opendir(&findDir, loc);
if (res == FR_OK)
{
@@ -1814,6 +1859,7 @@ bool MassStorage::FindNext(FileInfo &file_info)
entry.lfname = file_info.fileName;
entry.lfsize = ARRAY_SIZE(file_info.fileName);
+ findDir.lfn = nullptr;
if (f_readdir(&findDir, &entry) != FR_OK || entry.fname[0] == 0)
{
//f_closedir(findDir);
@@ -1899,6 +1945,7 @@ bool MassStorage::Rename(const char *oldFilename, const char *newFilename)
bool MassStorage::FileExists(const char *file) const
{
FILINFO fil;
+ fil.lfname = nullptr;
return (f_stat(file, &fil) == FR_OK);
}
@@ -1906,14 +1953,15 @@ bool MassStorage::FileExists(const char *file) const
bool MassStorage::PathExists(const char *path) const
{
DIR dir;
+ dir.lfn = nullptr;
return (f_opendir(&dir, path) == FR_OK);
}
-bool MassStorage::PathExists(const char* directory, const char* fileName)
+bool MassStorage::PathExists(const char* directory, const char* subDirectory)
{
const char* location = (directory != NULL)
- ? platform->GetMassStorage()->CombineName(directory, fileName)
- : fileName;
+ ? platform->GetMassStorage()->CombineName(directory, subDirectory)
+ : subDirectory;
return PathExists(location);
}
diff --git a/Platform.h b/Platform.h
index 001caf35..220dbc4e 100644
--- a/Platform.h
+++ b/Platform.h
@@ -193,7 +193,6 @@ const unsigned int adDisconnectedVirtual = adDisconnectedReal << adOversampleBit
#define MAX_FILES (10) // must be large enough to handle the max number of simultaneous web requests + file being printed
#define FILE_BUF_LEN (256)
-#define SD_SPI (4) //Pin
#define WEB_DIR "0:/www/" // Place to find web files on the SD card
#define GCODE_DIR "0:/gcodes/" // Ditto - g-codes
#define SYS_DIR "0:/sys/" // Ditto - system files
@@ -215,7 +214,7 @@ const int atxPowerPin = 12; // Arduino Due pin number that controls the ATX
const uint16_t lineInBufsize = 256; // use a power of 2 for good performance
const uint16_t lineOutBufSize = 2048; // ideally this should be large enough to hold the results of an M503 command,
// but could be reduced if we ever need the memory
-const size_t messageStringLength = 1024; // max length of a message chunk sent via Message or AppendMessage
+const size_t messageStringLength = 256; // max length of a message chunk sent via Message or AppendMessage
/****************************************************************************************************/
@@ -325,7 +324,7 @@ public:
uint8_t day;
uint8_t month;
uint16_t year;
- char fileName[255];
+ char fileName[MaxFilenameLength];
};
class MassStorage
@@ -342,7 +341,7 @@ public:
bool Rename(const char *oldFilename, const char *newFilename);
bool FileExists(const char *file) const;
bool PathExists(const char *path) const;
- bool PathExists(const char* directory, const char* fileName);
+ bool PathExists(const char* directory, const char* subDirectory);
friend class Platform;
@@ -353,10 +352,10 @@ protected:
private:
- char combinedName[MaxFilenameLength + 1];
Platform* platform;
FATFS fileSystem;
DIR findDir;
+ char combinedName[MaxFilenameLength + 1];
};
// This class handles input from, and output to, files.
@@ -434,7 +433,7 @@ struct ZProbeParameters
height = h;
calibTemperature = 20.0;
temperatureCoefficient = 0.0; // no default temperature correction
- diveHeight = Z_DIVE;
+ diveHeight = DefaultZDive;
}
float GetStopHeight(float temperature) const
@@ -693,7 +692,7 @@ public:
// void SetMixingDrives(int);
// int GetMixingDrives();
- uint8_t SlowestDrive() const;
+ size_t SlowestDrive() const;
// Heat and temperature
@@ -790,7 +789,7 @@ private:
// bool disableDrives[DRIVES]; // not currently used
volatile DriveStatus driveState[DRIVES];
bool directions[DRIVES];
- int8_t endStopPins[DRIVES];
+ Pin endStopPins[DRIVES];
float maxFeedrates[DRIVES];
float accelerations[DRIVES];
float driveStepsPerUnit[DRIVES];
@@ -801,7 +800,7 @@ private:
MCP4461 mcpDuet;
MCP4461 mcpExpansion;
- int8_t slowestDrive;
+ size_t slowestDrive;
Pin potWipes[DRIVES];
float senseResistor;
@@ -1076,7 +1075,7 @@ inline void Platform::SetInstantDv(size_t drive, float value)
SetSlowestDrive();
}
-inline uint8_t Platform::SlowestDrive() const
+inline size_t Platform::SlowestDrive() const
{
return slowestDrive;
}
diff --git a/Release/RepRapFirmware-1.04c-dc42.bin b/Release/RepRapFirmware-1.04c-dc42.bin
new file mode 100644
index 00000000..ee1bdb00
--- /dev/null
+++ b/Release/RepRapFirmware-1.04c-dc42.bin
Binary files differ
diff --git a/RepRapFirmware.cpp b/RepRapFirmware.cpp
index 6521f996..c46cc88d 100644
--- a/RepRapFirmware.cpp
+++ b/RepRapFirmware.cpp
@@ -177,7 +177,7 @@ const char *moduleName[] =
// Do nothing more in the constructor; put what you want in RepRap:Init()
RepRap::RepRap() : active(false), debug(0), stopped(false), spinningModule(noModule), ticksInSpinState(0),
- resetting(false), gcodeReply(gcodeReplyBuffer, GCODE_REPLY_LENGTH)
+ resetting(false), gcodeReply(gcodeReplyBuffer, ARRAY_SIZE(gcodeReplyBuffer))
{
platform = new Platform();
network = new Network(platform);
@@ -192,8 +192,10 @@ RepRap::RepRap() : active(false), debug(0), stopped(false), spinningModule(noMod
void RepRap::Init()
{
debug = 0;
- activeExtruders = 1; // we always report at least 1 extruder to the web interface
- activeHeaters = 2; // we always report the bed heater + 1 extruder heater to the web interface
+
+ // zpl thinks it's a bad idea to count the bed as an active heater...
+ activeExtruders = activeHeaters = 0;
+
SetPassword(DEFAULT_PASSWORD);
SetName(DEFAULT_NAME);
@@ -215,8 +217,8 @@ void RepRap::Init()
message[0] = 0;
const uint32_t wdtTicks = 256; // number of watchdog ticks @ 32768Hz/128 before the watchdog times out (max 4095)
WDT_Enable(WDT, (wdtTicks << WDT_MR_WDV_Pos) | (wdtTicks << WDT_MR_WDD_Pos) | WDT_MR_WDRSTEN); // enable watchdog, reset the mcu if it times out
- coldExtrude = true; // DC42 changed default to true for compatibility because for now we are aiming for compatibility with RRP 0.78
- active = true; // must do this before we start the network, else the watchdog may time out
+ coldExtrude = false; // don't allow cold extrusion
+ active = true; // must do this before we start the network, else the watchdog may time out
platform->Message(HOST_MESSAGE, "%s Version %s dated %s\n", NAME, VERSION, DATE);
FileStore *startup = platform->GetFileStore(platform->GetSysDir(), platform->GetConfigFile(), false);
@@ -320,6 +322,18 @@ void RepRap::Spin()
spinningModule = noModule;
ticksInSpinState = 0;
+ // Check if we need to display a cold extrusion warning
+
+ bool displayWarning = false;
+ for (Tool *t = toolList; t != NULL; t = t->Next())
+ {
+ displayWarning |= t->DisplayColdExtrudeWarning();
+ }
+ if (displayWarning)
+ {
+ platform->Message(BOTH_MESSAGE, "Warning: Tools can only be driven if their heater temperatures are high!\n");
+ }
+
// Keep track of the loop time
float t = platform->Time();
@@ -429,22 +443,68 @@ void RepRap::PrintDebug()
}
}
-/*
- * The first tool added becomes the one selected. This will not happen in future releases.
- */
-
void RepRap::AddTool(Tool* tool)
{
if(toolList == NULL)
{
toolList = tool;
- currentTool = tool;
- tool->Activate(currentTool);
+ }
+ else
+ {
+ toolList->AddTool(tool);
+ }
+ tool->UpdateExtruderAndHeaterCount(activeExtruders, activeHeaters);
+}
+
+void RepRap::DeleteTool(Tool* tool)
+{
+ // Must have a valid tool...
+ if (tool == NULL)
+ {
return;
}
- toolList->AddTool(tool);
- tool->UpdateExtruderAndHeaterCount(activeExtruders, activeHeaters);
+ // Deselect it if necessary
+ if (GetCurrentTool() == tool)
+ {
+ SelectTool(-1);
+ }
+
+ // Switch off any associated heater
+ for(size_t i=0; i<tool->HeaterCount(); i++)
+ {
+ reprap.GetHeat()->SwitchOff(tool->Heater(i));
+ }
+
+ // Purge any references to this tool
+ Tool *parent = NULL;
+ for(Tool *t = toolList; t != NULL; t = t->Next())
+ {
+ if (t->Next() == tool)
+ {
+ parent = t;
+ break;
+ }
+ }
+
+ if (parent == NULL)
+ {
+ toolList = tool->Next();
+ }
+ else
+ {
+ parent->next = tool->next;
+ }
+
+ // Delete it
+ delete tool;
+
+ // Update the number of active heaters and extruder drives
+ activeExtruders = activeHeaters = 0;
+ for(Tool *t = toolList; t != NULL; t = t->Next())
+ {
+ t->UpdateExtruderAndHeaterCount(activeExtruders, activeHeaters);
+ }
}
void RepRap::SelectTool(int toolNumber)
@@ -572,11 +632,11 @@ void RepRap::Tick()
if (ticksInSpinState >= 20000) // if we stall for 20 seconds, save diagnostic data and reset
{
resetting = true;
- for(uint8_t i = 0; i < HEATERS; i++)
+ for(size_t i = 0; i < HEATERS; i++)
{
platform->SetHeater(i, 0.0);
}
- for(uint8_t i = 0; i < DRIVES; i++)
+ for(size_t i = 0; i < DRIVES; i++)
{
platform->DisableDrive(i);
// We can't set motor currents to 0 here because that requires interrupts to be working, and we are in an ISR
@@ -625,6 +685,11 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
ch = ',';
}
+ if (ch == '[')
+ {
+ response.cat("[");
+ }
+
// XYZ positions
response.cat("],\"xyz\":");
ch = '[';
@@ -636,7 +701,7 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
}
// Current tool number
- int toolNumber = (currentTool == NULL) ? 0 : currentTool->Number();
+ int toolNumber = (currentTool == NULL) ? -1 : currentTool->Number();
response.catf("]},\"currentTool\":%d", toolNumber);
/* Output - only reported once */
@@ -682,11 +747,13 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
// Speed and Extrusion factors
response.catf(",\"speedFactor\":%.2f,\"extrFactors\":", gCodes->GetSpeedFactor() * 100.0);
+ char ch = '[';
for (uint8_t extruder = 0; extruder < GetExtrudersInUse(); extruder++)
{
- response.catf("%c%.2f", (extruder == 0) ? '[' : ',', gCodes->GetExtrusionFactors()[extruder] * 100.0);
+ response.catf("%c%.2f", ch, gCodes->GetExtrusionFactors()[extruder] * 100.0);
+ ch = ',';
}
- response.cat("]}");
+ response.cat((ch == '[') ? "[]}" : "]}");
}
// G-code reply sequence for webserver
@@ -741,40 +808,44 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
// Current temperatures
char ch = '[';
- for (int8_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
+ for (size_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
{
response.catf("%c%.1f", ch, heat->GetTemperature(heater));
ch = ',';
}
+ response.cat((ch == '[') ? "[]" : "]");
// Active temperatures
- response.catf("],\"active\":");
+ response.catf(",\"active\":");
ch = '[';
- for (int8_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
+ for (size_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
{
response.catf("%c%.1f", ch, heat->GetActiveTemperature(heater));
ch = ',';
}
+ response.cat((ch == '[') ? "[]" : "]");
// Standby temperatures
- response.catf("],\"standby\":");
+ response.catf(",\"standby\":");
ch = '[';
- for (int8_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
+ for (size_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
{
response.catf("%c%.1f", ch, heat->GetStandbyTemperature(heater));
ch = ',';
}
+ response.cat((ch == '[') ? "[]" : "]");
// Heater statuses (0=off, 1=standby, 2=active, 3=fault)
- response.cat("],\"state\":");
+ response.cat(",\"state\":");
ch = '[';
- for (int8_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
+ for (size_t heater = E0_HEATER; heater < GetHeatersInUse(); heater++)
{
response.catf("%c%d", ch, (int)heat->GetStatus(heater));
ch = ',';
}
+ response.cat((ch == '[') ? "[]" : "]");
}
- response.cat("]}}");
+ response.cat("}}");
}
// Time since last reset
@@ -864,6 +935,10 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
response.catf("%c%.1f", ch, gCodes->GetRawExtruderPosition(drive));
ch = ',';
}
+ if (ch == '[')
+ {
+ response.cat("]");
+ }
// Fraction of file printed
response.catf("],\"fractionPrinted\":%.1f", (gCodes->PrintingAFile()) ? (gCodes->FractionOfFilePrinted() * 100.0) : 0.0);
@@ -896,6 +971,119 @@ void RepRap::GetStatusResponse(StringRef& response, uint8_t type, bool forWebser
response.cat("}");
}
+void RepRap::GetConfigResponse(StringRef& response)
+{
+ // Axis minima
+ response.copy("{\"axisMins\":");
+ char ch = '[';
+ for (size_t axis = 0; axis < AXES; axis++)
+ {
+ response.catf("%c%.2f", ch, platform->AxisMinimum(axis));
+ ch = ',';
+ }
+
+ // Axis maxima
+ response.cat("],\"axisMaxes\":");
+ ch = '[';
+ for (size_t axis = 0; axis < AXES; axis++)
+ {
+ response.catf("%c%.2f", ch, platform->AxisMaximum(axis));
+ ch = ',';
+ }
+
+ // Accelerations
+ response.cat("],\"accelerations\":");
+ ch = '[';
+ for (size_t drive = 0; drive < DRIVES; drive++)
+ {
+ response.catf("%c%.2f", ch, platform->Acceleration(drive));
+ ch = ',';
+ }
+
+ // Firmware details
+ response.catf("],\"firmwareElectronics\":\"%s\"", ELECTRONICS);
+ response.catf(",\"firmwareName\":\"%s\"", NAME);
+ response.catf(",\"firmwareVersion\":\"%s\"", VERSION);
+ response.catf(",\"firmwareDate\":\"%s\"", DATE);
+
+ // Minimum feedrates
+ response.cat(",\"minFeedrates\":");
+ ch = '[';
+ for (size_t drive = 0; drive < DRIVES; drive++)
+ {
+ response.catf("%c%.2f", ch, platform->ConfiguredInstantDv(drive));
+ ch = ',';
+ }
+
+ // Maximum feedrates
+ response.cat("],\"maxFeedrates\":");
+ ch = '[';
+ for (size_t drive = 0; drive < DRIVES; drive++)
+ {
+ response.catf("%c%.2f", ch, platform->MaxFeedrate(drive));
+ ch = ',';
+ }
+
+ // Configuration File (whitespaces are skipped, otherwise we risk overflowing the response buffer)
+ response.cat("],\"configFile\":\"");
+ FileStore *configFile = platform->GetFileStore(platform->GetSysDir(), platform->GetConfigFile(), false);
+ if (configFile == NULL)
+ {
+ response.cat("not found");
+ }
+ else
+ {
+ char c;
+ bool readingWhitespace = false;
+ while (configFile->Read(c))
+ {
+ if (!readingWhitespace || (c != ' ' && c != '\t'))
+ {
+ char esc;
+ switch (c)
+ {
+ case '\r':
+ esc = 'r';
+ break;
+ case '\n':
+ esc = 'n';
+ break;
+ case '\t':
+ esc = 't';
+ break;
+ case '"':
+ esc = '"';
+ break;
+ case '\\':
+ esc = '\\';
+ break;
+ default:
+ esc = 0;
+ break;
+ }
+
+ if (esc)
+ {
+ response.catf("\\%c", esc);
+ }
+ else
+ {
+ response.catf("%c", c);
+ }
+
+ if (response.strlen() >= response.Length() - 4)
+ {
+ // Leave 4 chars to finish this response
+ break;
+ }
+ }
+ readingWhitespace = (c == ' ' || c == '\t');
+ }
+ configFile->Close();
+ }
+ response.cat("\"}");
+}
+
// Get the JSON status response for the web server or M105 command.
// Type 0 is the old-style webserver status response (we should be able to bet rid of this soon).
// Type 1 is the new-style webserver status response.
@@ -968,30 +1156,32 @@ void RepRap::GetLegacyStatusResponse(StringRef& response, uint8_t type, int seq)
}
response.catf("],\"pos\":"); // announce the XYZ position
ch = '[';
- for (int8_t drive = 0; drive < AXES; drive++)
+ for (size_t drive = 0; drive < AXES; drive++)
{
response.catf("%c%.2f", ch, liveCoordinates[drive]);
ch = ',';
}
// Send extruder total extrusion since power up, last G92 or last M23
- response.catf("],\"extr\":"); // announce the extruder positions
+ response.cat("],\"extr\":"); // announce the extruder positions
ch = '[';
- for (int8_t drive = 0; drive < reprap.GetExtrudersInUse(); drive++) // loop through extruders
+ for (size_t drive = 0; drive < reprap.GetExtrudersInUse(); drive++) // loop through extruders
{
response.catf("%c%.1f", ch, gCodes->GetRawExtruderPosition(drive));
ch = ',';
}
- response.cat("]");
+ response.cat((ch == ']') ? "[]" : "]");
// Send the speed and extruder override factors
response.catf(",\"sfactor\":%.2f,\"efactor\":", gCodes->GetSpeedFactor() * 100.0);
const float *extrusionFactors = gCodes->GetExtrusionFactors();
- for (unsigned int i = 0; i < reprap.GetExtrudersInUse(); ++i)
+ ch = '[';
+ for (size_t i = 0; i < reprap.GetExtrudersInUse(); ++i)
{
- response.catf("%c%.2f", (i == 0) ? '[' : ',', extrusionFactors[i] * 100.0);
+ response.catf("%c%.2f", ch, extrusionFactors[i] * 100.0);
+ ch = ',';
}
- response.cat("]");
+ response.cat((ch == '[') ? "[]" : "]");
// Send the current tool number
int toolNumber = (currentTool == NULL) ? 0 : currentTool->Number();
@@ -1005,14 +1195,14 @@ void RepRap::GetLegacyStatusResponse(StringRef& response, uint8_t type, int seq)
// RRP reversed the order at version 0.65 to send the positions before the heaters, but we haven't yet done that.
char c = (gCodes->PrintingAFile()) ? 'P' : 'I';
response.printf("{\"poll\":[\"%c\",", c); // Printing
- for (int8_t heater = 0; heater < HEATERS; heater++)
+ for (size_t heater = 0; heater < HEATERS; heater++)
{
response.catf("\"%.1f\",", reprap.GetHeat()->GetTemperature(heater));
}
// Send XYZ and extruder positions
float liveCoordinates[DRIVES];
reprap.GetMove()->LiveCoordinates(liveCoordinates);
- for (int8_t drive = 0; drive < DRIVES; drive++) // loop through extruders
+ for (size_t drive = 0; drive < DRIVES; drive++) // loop through extruders
{
char ch = (drive == DRIVES - 1) ? ']' : ','; // append ] to the last one but , to the others
response.catf("\"%.2f\"%c", liveCoordinates[drive], ch);
@@ -1082,7 +1272,7 @@ void RepRap::GetLegacyStatusResponse(StringRef& response, uint8_t type, int seq)
{
// Add the static fields. For now this is just geometry and the machine name, but other fields could be added e.g. axis lengths.
response.catf(",\"geometry\":\"%s\",\"myName\":", move->GetGeometryString());
- EncodeString(response, myName, 2, false);
+ EncodeString(response, GetName(), 2, false);
}
if (type < 2 || (seq != -1 && replySeq != seq))
diff --git a/Reprap.h b/Reprap.h
index 8cd51c07..f1dc671e 100644
--- a/Reprap.h
+++ b/Reprap.h
@@ -49,16 +49,17 @@ class RepRap
void SetPassword(const char* pw);
void AddTool(Tool* t);
+ void DeleteTool(Tool* t);
void SelectTool(int toolNumber);
void StandbyTool(int toolNumber);
Tool* GetCurrentTool();
Tool* GetTool(int toolNumber);
- Tool* GetToolByDrive(int driveNumber);
+ //Tool* GetToolByDrive(int driveNumber);
void SetToolVariables(int toolNumber, float* standbyTemperatures, float* activeTemperatures);
void AllowColdExtrude();
void DenyColdExtrude();
- bool ColdExtrude();
+ bool ColdExtrude() const;
void GetExtruderCapabilities(bool canDrive[], const bool directions[]) const;
void PrintTool(int toolNumber, StringRef& reply) const;
@@ -81,6 +82,7 @@ class RepRap
uint16_t GetHeatersInUse() const;
void GetStatusResponse(StringRef& response, uint8_t type, bool forWebserver);
+ void GetConfigResponse(StringRef& response);
void GetLegacyStatusResponse(StringRef &response, uint8_t type, int seq) const;
void GetNameResponse(StringRef& response) const;
void GetFilesResponse(StringRef& response, const char* dir) const;
@@ -127,13 +129,13 @@ class RepRap
bool resetting;
bool processingConfig;
- char password[SHORT_STRING_LENGTH + 1];
- char myName[SHORT_STRING_LENGTH + 1];
+ char password[MaxPasswordLength + 1];
+ char myName[MaxNameLength + 1];
int beepFrequency, beepDuration;
- char message[SHORT_STRING_LENGTH + 1];
+ char message[MaxMessageLength + 1];
- char gcodeReplyBuffer[GCODE_REPLY_LENGTH];
+ char gcodeReplyBuffer[MaxGcodeReplyLength];
StringRef gcodeReply;
unsigned int replySeq;
};
@@ -152,7 +154,7 @@ inline Module RepRap::GetSpinningModule() const { return spinningModule; }
inline Tool* RepRap::GetCurrentTool() { return currentTool; }
inline uint16_t RepRap::GetExtrudersInUse() const { return activeExtruders; }
inline uint16_t RepRap::GetHeatersInUse() const { return activeHeaters; }
-inline bool RepRap::ColdExtrude() { return coldExtrude; }
+inline bool RepRap::ColdExtrude() const { return coldExtrude; }
inline void RepRap::AllowColdExtrude() { coldExtrude = true; }
inline void RepRap::DenyColdExtrude() { coldExtrude = false; }
inline void RepRap::Interrupt() { move->Interrupt(); }
diff --git a/SD-image/sys-MiniKossel/bed.g b/SD-image/sys-MiniKossel/bed.g
index e8488e4f..c5915d0a 100644
--- a/SD-image/sys-MiniKossel/bed.g
+++ b/SD-image/sys-MiniKossel/bed.g
@@ -12,25 +12,23 @@ M98 Pdeployprobe.g ; deploy the mechanical Z probe
; The first time the probe is used after deployment, it gives slightly different results.
; So do an extra dummy probe here. The value stored gets overwritten later.
-G30 P3 X0 Y0 Z-99999
+G30 P0 X0 Y0 Z-99999
-;*** Adjust the XY coordinates in the following M557 commands if necessary to suit your build and the position of the zprobe.
-; These must place the probe near the base of the X (left) tower, Y (right) tower, Z (back) tower, and bed centre in that order.
-G30 P0 X-60.62 Y-35 Z-99999
-G30 P1 X60.62 Y-35 Z-99999
-G30 P2 X0 Y70 Z-99999
-G30 P3 X0 Y0 Z-99999 S4 ; the S4 argument causes the endstops, delta radius and homed height to be adjusted
+; Probe the bed and do auto calibration
+G30 P0 X-73.6 Y-42.5 Z-99999 ; X tower
+G30 P1 X0 Y-85 Z-99999 ; between X and Y towers
+G30 P2 X73.6 Y-42.5 Z-99999 ; Y tower
+G30 P3 X73.6 Y20 Z-99999 ; between Y and Z towers
+G30 P4 X0 Y67 Z-99999 ; Z tower
+G30 P5 X-73.6 Y20 Z-99999 ; between Z and X towers
+G30 P6 X-36.8 Y-21.25 Z-99999 ; half way to X tower
+G30 P7 X36.8 Y-21.25 Z-99999 ; half way to Y tower
+G30 P8 X0 Y42.5 Z-99999 ; half way to Z tower
+G30 P9 X0 Y0 Z-99999 S10 ; centre, and auto-calibrate
-G1 Z210 F10000 ; go part way up to speed up homing
-G28 ; Home the printer again so as to activate the new endstop adjustments
-
-;*** Adjust the XY coordinates in the following M557 commands if necessary to suit your build and the position of the zprobe.
-G30 P0 X-60.62 Y-35 Z-99999
-G30 P1 X60.62 Y-35 Z-99999
-G30 P2 X0 Y70 Z-99999
-G30 P3 X0 Y0 Z-99999 S4 ; the S4 argument causes the endstops, delta radius and homed height to be adjusted
-
-;*** Remove the following line if your Z probe does not need to be deployed
+;*** Remove the following line if your Z probe does not need to be retracted
M98 Pretractprobe.g ; deploy the mechanical Z probe
-G1 Z210 F10000 ; go part way up to speed up homing
+G91
+G1 S1 X170 Y170 Z170 F15000 ; go part way up to speed up homing, endstops activated just in case
+G90
G28 ; Home the printer again so as to activate the new endstop adjustments
diff --git a/SD-image/sys-MiniKossel/config.g b/SD-image/sys-MiniKossel/config.g
index 995bd269..cc791a3c 100644
--- a/SD-image/sys-MiniKossel/config.g
+++ b/SD-image/sys-MiniKossel/config.g
@@ -35,6 +35,7 @@ M566 X1200 Y1200 Z1200 E1200 ; Maximum instant speed changes mm/minute
M305 P0 T100000 B3950 R1000 H30 L0 ; Put your own H and/or L values here to set the bed thermistor ADC correction
M305 P1 T100000 B3974 R1000 H30 L0 ; Put your own H and/or L values here to set the first nozzle thermistor ADC correction
M305 P2 T100000 B3974 R1000 H30 L0 ; Put your own H and/or L values here to set the second nozzle thermistor ADC correction
+M570 S180 ; E3d hot end is a little slow to heat up so allow it 180 seconds
; Tool definitions
M563 P0 D0 H1 ; Define tool 0
diff --git a/Tool.cpp b/Tool.cpp
index b00a7693..be8a12c8 100644
--- a/Tool.cpp
+++ b/Tool.cpp
@@ -34,6 +34,7 @@ Tool::Tool(int toolNumber, long d[], int dCount, long h[], int hCount)
heaterCount = hCount;
heaterFault = false;
mixing = false;
+ displayColdExtrudeWarning = false;
for(size_t axis = 0; axis < AXES; axis++)
{
@@ -266,15 +267,23 @@ void Tool::SetVariables(const float* standby, const float* active)
{
for (size_t heater = 0; heater < heaterCount; heater++)
{
- if (active[heater] < BAD_HIGH_TEMPERATURE)
+ if (active[heater] < NEARLY_ABS_ZERO && standby[heater] < NEARLY_ABS_ZERO)
{
- activeTemperatures[heater] = active[heater];
- reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
+ // Temperatures close to ABS_ZERO turn off all associated heaters
+ reprap.GetHeat()->SwitchOff(heaters[heater]);
}
- if (standby[heater] < BAD_HIGH_TEMPERATURE)
+ else
{
- standbyTemperatures[heater] = standby[heater];
- reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
+ if (active[heater] < BAD_HIGH_TEMPERATURE)
+ {
+ activeTemperatures[heater] = active[heater];
+ reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
+ }
+ if (standby[heater] < BAD_HIGH_TEMPERATURE)
+ {
+ standbyTemperatures[heater] = standby[heater];
+ reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
+ }
}
}
}
@@ -288,14 +297,17 @@ void Tool::GetVariables(float* standby, float* active) const
}
}
-bool Tool::ToolCanDrive(bool extrude) const
+// May be called from ISR
+bool Tool::ToolCanDrive(bool extrude)
{
if (heaterFault)
- {
return false;
- }
- return reprap.ColdExtrude() || AllHeatersAtHighTemperature(extrude);
+ if (reprap.ColdExtrude() || AllHeatersAtHighTemperature(extrude))
+ return true;
+
+ displayColdExtrudeWarning = true;
+ return false;
}
// Update the number of active drives and extruders in use to reflect what this tool uses
@@ -311,11 +323,18 @@ void Tool::UpdateExtruderAndHeaterCount(uint16_t &numExtruders, uint16_t &numHea
for (size_t heater = 0; heater < heaterCount; heater++)
{
- if (heaters[heater] >= numHeaters)
+ if (heaters[heater] != HOT_BED && heaters[heater] >= numHeaters)
{
numHeaters = heaters[heater] + 1;
}
}
}
+bool Tool::DisplayColdExtrudeWarning()
+{
+ bool result = displayColdExtrudeWarning;
+ displayColdExtrudeWarning = false;
+ return result;
+}
+
// End
diff --git a/Tool.h b/Tool.h
index 7ce376c1..930195fc 100644
--- a/Tool.h
+++ b/Tool.h
@@ -35,7 +35,7 @@ public:
void SetOffset(const float offs[AXES]);
int DriveCount() const;
int Drive(int driveNumber) const;
- bool ToolCanDrive(bool extrude) const;
+ bool ToolCanDrive(bool extrude);
int HeaterCount() const;
int Heater(int heaterNumber) const;
int Number() const;
@@ -61,6 +61,7 @@ protected:
void FlagTemperatureFault(int8_t dudHeater);
void ClearTemperatureFault(int8_t wasDudHeater);
void UpdateExtruderAndHeaterCount(uint16_t &extruders, uint16_t &heaters) const;
+ bool DisplayColdExtrudeWarning();
private:
@@ -80,6 +81,8 @@ private:
bool active;
bool heaterFault;
float offset[AXES];
+
+ volatile bool displayColdExtrudeWarning;
};
inline int Tool::Drive(int driveNumber) const
diff --git a/Webserver.cpp b/Webserver.cpp
index 96c2324d..73b32a7f 100644
--- a/Webserver.cpp
+++ b/Webserver.cpp
@@ -164,7 +164,7 @@ void Webserver::Spin()
uint16_t localPort = req->GetLocalPort();
switch (localPort)
{
- case ftpPort: /* FTP */
+ case ftpPort: /* FTP */
interpreter = ftpInterpreter;
break;
@@ -172,7 +172,7 @@ void Webserver::Spin()
interpreter = telnetInterpreter;
break;
- default: /* FTP data */
+ default: /* HTTP and FTP data */
if (localPort == network->GetHttpPort())
{
interpreter = httpInterpreter;
@@ -296,14 +296,14 @@ void Webserver::ProcessGcode(const char* gc)
reprap.MessageToGCodeReply("");
char c;
- bool reading_whitespace = false;
+ bool readingWhitespace = false;
while (configFile->Read(c))
{
- if (!reading_whitespace || (c != ' ' && c != '\t'))
+ if (!readingWhitespace || (c != ' ' && c != '\t'))
{
reprap.AppendCharToStatusResponse(c);
}
- reading_whitespace = (c == ' ' || c == '\t');
+ readingWhitespace = (c == ' ' || c == '\t');
}
configFile->Close();
@@ -423,7 +423,7 @@ void Webserver::ConnectionLost(const ConnectionState *cs)
ProtocolInterpreter *interpreter;
switch (localPort)
{
- case ftpPort: /* FTP */
+ case ftpPort: /* FTP */
interpreter = ftpInterpreter;
break;
@@ -431,7 +431,7 @@ void Webserver::ConnectionLost(const ConnectionState *cs)
interpreter = telnetInterpreter;
break;
- default: /* FTP data */
+ default: /* HTTP and FTP data */
if (localPort == network->GetHttpPort())
{
interpreter = httpInterpreter;
@@ -1084,11 +1084,7 @@ bool Webserver::HttpInterpreter::GetJsonResponse(const char* request, StringRef&
}
else if (StringEquals(request, "config"))
{
- if (StringEquals(key, "type"))
- {
- int type = max<int>(2, min<int>(0, atoi(value)));
- // TODO: implement this
- }
+ reprap.GetConfigResponse(response);
}
else
{
@@ -1857,10 +1853,10 @@ void Webserver::FtpInterpreter::ProcessLine()
// but check the password
else if (StringStartsWith(clientMessage, "PASS"))
{
- char pass[SHORT_STRING_LENGTH];
- int pass_length = 0;
+ char pass[MaxPasswordLength + 1];
+ size_t pass_length = 0;
bool reading_pass = false;
- for(int i=4; i<clientPointer && i<SHORT_STRING_LENGTH +3; i++)
+ for(size_t i = 4; i < clientPointer && i < MaxPasswordLength + 4; i++)
{
reading_pass |= (clientMessage[i] != ' ' && clientMessage[i] != '\t');
if (reading_pass)