diff options
author | David Crocker <dcrocker@eschertech.com> | 2015-04-02 22:19:17 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2015-04-02 22:19:17 +0300 |
commit | 52b21d0eed5ba2f5e226b38675ef7dccaeed5447 (patch) | |
tree | c3fda0d5a7668b0141a28ba643361a5cd1149fb9 | |
parent | 2791322800315bf26aceaa1e67e19b2efe88573b (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.h | 51 | ||||
-rw-r--r-- | DDA.h | 1 | ||||
-rw-r--r-- | GCodes.cpp | 85 | ||||
-rw-r--r-- | GCodes.h | 2 | ||||
-rw-r--r-- | Heat.cpp | 31 | ||||
-rw-r--r-- | Heat.h | 14 | ||||
-rw-r--r-- | Matrix.h | 115 | ||||
-rw-r--r-- | Move.cpp | 434 | ||||
-rw-r--r-- | Move.h | 38 | ||||
-rw-r--r-- | Network.cpp | 36 | ||||
-rw-r--r-- | Network.h | 5 | ||||
-rw-r--r-- | Platform.cpp | 152 | ||||
-rw-r--r-- | Platform.h | 19 | ||||
-rw-r--r-- | Release/RepRapFirmware-1.04c-dc42.bin | bin | 0 -> 212712 bytes | |||
-rw-r--r-- | RepRapFirmware.cpp | 262 | ||||
-rw-r--r-- | Reprap.h | 16 | ||||
-rw-r--r-- | SD-image/sys-MiniKossel/bed.g | 34 | ||||
-rw-r--r-- | SD-image/sys-MiniKossel/config.g | 1 | ||||
-rw-r--r-- | Tool.cpp | 41 | ||||
-rw-r--r-- | Tool.h | 5 | ||||
-rw-r--r-- | Webserver.cpp | 26 |
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" @@ -127,6 +127,7 @@ private: inline void DDA::SetDriveCoordinate(int32_t a, size_t drive) { endPoint[drive] = a; + endCoordinatesValid = false; } #endif /* DDA_H_ */ @@ -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()); @@ -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 @@ -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); } @@ -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_ */ @@ -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 @@ -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; @@ -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); } @@ -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 Binary files differnew file mode 100644 index 00000000..ee1bdb00 --- /dev/null +++ b/Release/RepRapFirmware-1.04c-dc42.bin 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)) @@ -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 @@ -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 @@ -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) |