diff options
author | David Crocker <dcrocker@eschertech.com> | 2017-12-13 22:34:01 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2017-12-13 22:34:30 +0300 |
commit | 229508f86623a9969967e1c2bd649858cef65fdd (patch) | |
tree | 6ff6999e9e6733c45436733982b366310c5344cf /src | |
parent | ffb6d27e1af0a7bddab84277eef97b836a6ed508 (diff) |
Version 1.20RC1
New features:
- Heater PWM frequencies are limited to 1kHz to protect
the heater mosfets
- Tool offsets and fan mapping are now passed to
DWC
- More free memory is available, especially in the Duet 0.6/0.8.5
build
- Maximum bed heaters increased to 4 for the Duet WiFi/Ethernet
-
The software reset data now records the date/time of the reset if known
and a longer stack trace
- The maximum length of GCode commands has been
increased, in particular to allow long passwords in M587 commands
Bug
fixes:
- Fixed M28/M29 file upload
- Fixed some USB/Telnet response
formats when in Marlin emulation mode
- Fixed move timing when a long
slow printing move follows a faster printing move
- Heater tuning was
not possible in 1.20RC1
- If a file being printed executed a macro right
at the start, DWC could assume that the print had already finished
(thanks chrishamm)
Diffstat (limited to 'src')
42 files changed, 497 insertions, 422 deletions
diff --git a/src/Configuration.h b/src/Configuration.h index ef38224c..c214acfa 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -77,16 +77,25 @@ constexpr float ThermostatHysteresis = 1.0; // How much hysteresis we use to constexpr float BAD_ERROR_TEMPERATURE = 2000.0; // Must exceed any reasonable 5temperature limit including DEFAULT_TEMPERATURE_LIMIT constexpr uint32_t DefaultHeaterFaultTimeout = 10 * 60 * 1000; // How long we wait (in milliseconds) for user intervention after a heater fault before shutting down +constexpr PwmFrequency MaxHeaterPwmFrequency = 1000; // maximum supported heater PWM frequency, to avoid overheating the mosfets + // Heating model default parameters. For the chamber heater, we use the same values as for the bed heater. // These parameters are about right for an E3Dv6 hot end with 30W heater. constexpr float DefaultHotEndHeaterGain = 340.0; constexpr float DefaultHotEndHeaterTimeConstant = 140.0; constexpr float DefaultHotEndHeaterDeadTime = 5.5; +#if SAM4E || SAME70 +constexpr size_t NumBedHeaters = 4; +constexpr size_t NumChamberHeaters = 2; +constexpr int8_t DefaultBedHeaters[NumBedHeaters] = { 0, -1, -1, -1 }; +constexpr int8_t DefaultChamberHeaters[NumChamberHeaters] = { -1, -1 }; +#else constexpr size_t NumBedHeaters = 1; constexpr size_t NumChamberHeaters = 2; constexpr int8_t DefaultBedHeaters[NumBedHeaters] = { 0 }; constexpr int8_t DefaultChamberHeaters[NumChamberHeaters] = { -1, -1 }; +#endif constexpr int8_t DefaultE0Heater = 1; // Index of the default first extruder heater @@ -170,12 +179,17 @@ constexpr float TRIANGLE_ZERO = -0.001; // Millimetres constexpr float SILLY_Z_VALUE = -9999.0; // Millimetres // String lengths - constexpr size_t FORMAT_STRING_LENGTH = 256; constexpr size_t MACHINE_NAME_LENGTH = 40; constexpr size_t PASSWORD_LENGTH = 20; -constexpr size_t GCODE_LENGTH = 100; +#if SAM4E || SAM4S || SAME70 +// Increased GCODE_LENGTH on the SAM4 because M587 and M589 commands on the Duet WiFi can get very long +constexpr size_t GCODE_LENGTH = 161; // maximum number of non-comment characters in a line of GCode including the null terminator +#else +constexpr size_t GCODE_LENGTH = 101; // maximum number of non-comment characters in a line of GCode including the null terminator +#endif + constexpr size_t GCODE_REPLY_LENGTH = 2048; constexpr size_t MESSAGE_LENGTH = 256; diff --git a/src/Duet/Webserver.cpp b/src/Duet/Webserver.cpp index f356008a..e3637d3e 100644 --- a/src/Duet/Webserver.cpp +++ b/src/Duet/Webserver.cpp @@ -93,8 +93,8 @@ //*************************************************************************************************** -const char* overflowResponse = "overflow"; -const char* badEscapeResponse = "bad escape"; +const char* const overflowResponse = "overflow"; +const char* const badEscapeResponse = "bad escape"; //**************************** Generic Webserver implementation ****************************** @@ -548,55 +548,26 @@ bool Webserver::HttpInterpreter::DoingFastUpload() const return false; } +// Write some data on the SD card void Webserver::HttpInterpreter::DoFastUpload() { - NetworkTransaction *transaction = webserver->currentTransaction; - - // Write some data on the SD card + NetworkTransaction * const transaction = webserver->currentTransaction; const char *buffer; size_t len; if (transaction->ReadBuffer(buffer, len)) { network->Unlock(); - // Write data in sector-aligned chunks. This also means that the buffer in fatfs is only used to hold the FAT. - // Buffer size must be a multiple of the 512b sector size. -#ifdef DUET_NG - static const size_t writeBufLength = 8192; -#else - static const size_t writeBufLength = 2048; -#endif - static uint32_t writeBufStorage[writeBufLength/4]; // aligned buffer for file writes - static size_t writeBufIndex; - char* const writeBuf = reinterpret_cast<char *>(writeBufStorage); - - if (uploadedBytes == 0) - { - writeBufIndex = 0; - } - - while (len != 0) - { - const size_t lengthToCopy = min<size_t>(writeBufLength - writeBufIndex, len); - memcpy(writeBuf + writeBufIndex, buffer, lengthToCopy); - writeBufIndex += lengthToCopy; - uploadedBytes += lengthToCopy; - buffer += lengthToCopy; - len -= lengthToCopy; - if (writeBufIndex == writeBufLength || uploadedBytes >= postFileLength) - { - const bool success = fileBeingUploaded.Write(writeBuf, writeBufIndex); - writeBufIndex = 0; - if (!success) - { - platform->Message(GenericMessage, "Error: Could not write upload data!\n"); - CancelUpload(); + const bool success = fileBeingUploaded.Write(buffer, len); + if (!success) + { + platform->Message(GenericMessage, "Error: Could not write upload data!\n"); + CancelUpload(); - while (!network->Lock()) { } - SendJsonResponse("upload"); - return; - } - } + while (!network->Lock()) { } + SendJsonResponse("upload"); + return; } + uploadedBytes += len; while (!network->Lock()) { } } @@ -604,7 +575,7 @@ void Webserver::HttpInterpreter::DoFastUpload() if (uploadState == uploadOK && uploadedBytes >= postFileLength) { // Reset POST upload state for this client - uint32_t remoteIP = transaction->GetRemoteIP(); + const uint32_t remoteIP = transaction->GetRemoteIP(); for(size_t i = 0; i < numSessions; i++) { if (sessions[i].ip == remoteIP && sessions[i].isPostUploading) diff --git a/src/DuetNG/TMC2660.cpp b/src/DuetNG/TMC2660.cpp index 14ab5cac..e5b9e805 100644 --- a/src/DuetNG/TMC2660.cpp +++ b/src/DuetNG/TMC2660.cpp @@ -590,7 +590,7 @@ namespace SmartDrivers } // Set microstepping or chopper control register - bool SetMicrostepping(size_t drive, int microsteps, int mode) + bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode) { if (drive < numTmc2660Drivers) { diff --git a/src/DuetNG/TMC2660.h b/src/DuetNG/TMC2660.h index 001f6dde..3d61df83 100644 --- a/src/DuetNG/TMC2660.h +++ b/src/DuetNG/TMC2660.h @@ -38,7 +38,7 @@ namespace SmartDrivers void EnableDrive(size_t drive, bool en); uint32_t GetLiveStatus(size_t drive); uint32_t GetAccumulatedStatus(size_t drive, uint32_t bitsToKeep); - bool SetMicrostepping(size_t drive, int microsteps, int mode); + bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode); unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation); void SetDriversPowered(bool powered); void SetStallThreshold(size_t drive, int sgThreshold); diff --git a/src/Fan.cpp b/src/Fan.cpp index 85451751..d704abbe 100644 --- a/src/Fan.cpp +++ b/src/Fan.cpp @@ -95,9 +95,9 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, StringRef& if (gb.Seen('H')) // Set thermostatically-controlled heaters { seen = true; - long heaters[Heaters + MaxVirtualHeaters]; + int32_t heaters[Heaters + MaxVirtualHeaters]; // signed because we use H-1 to disable thermostatic mode size_t numH = ARRAY_SIZE(heaters); - gb.GetLongArray(heaters, numH); + gb.GetIntArray(heaters, numH); // Note that M106 H-1 disables thermostatic mode. The following code implements that automatically. heatersMonitored = 0; diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp index c416d93e..9add807c 100644 --- a/src/GCodes/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer.cpp @@ -436,7 +436,7 @@ float GCodeBuffer::GetFValue() } // Get a colon-separated list of floats after a key letter -const void GCodeBuffer::GetFloatArray(float a[], size_t& returnedLength, bool doPad) +const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool doPad) { if (readPointer >= 0) { @@ -451,7 +451,7 @@ const void GCodeBuffer::GetFloatArray(float a[], size_t& returnedLength, bool do returnedLength = 0; return; } - a[length] = (float)strtod(&gcodeBuffer[readPointer + 1], 0); + arr[length] = (float)strtod(&gcodeBuffer[readPointer + 1], 0); length++; do { @@ -469,7 +469,7 @@ const void GCodeBuffer::GetFloatArray(float a[], size_t& returnedLength, bool do { for(size_t i = 1; i < returnedLength; i++) { - a[i] = a[0]; + arr[i] = arr[0]; } } else @@ -486,8 +486,8 @@ const void GCodeBuffer::GetFloatArray(float a[], size_t& returnedLength, bool do } } -// Get a :-separated list of longs after a key letter -const void GCodeBuffer::GetLongArray(long l[], size_t& returnedLength) +// Get a :-separated list of ints after a key letter +const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength) { if (readPointer >= 0) { @@ -497,12 +497,49 @@ const void GCodeBuffer::GetLongArray(long l[], size_t& returnedLength) { if (length >= returnedLength) // Array limit has been set in here { - reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode long array that is too long: %s\n", gcodeBuffer); + reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode int array that is too long: %s\n", gcodeBuffer); readPointer = -1; returnedLength = 0; return; } - l[length] = strtol(&gcodeBuffer[readPointer + 1], 0, 0); + arr[length] = strtol(&gcodeBuffer[readPointer + 1], 0, 0); + length++; + do + { + readPointer++; + } while(gcodeBuffer[readPointer] != 0 && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR)); + if (gcodeBuffer[readPointer] != LIST_SEPARATOR) + { + inList = false; + } + } + returnedLength = length; + readPointer = -1; + } + else + { + INTERNAL_ERROR; + returnedLength = 0; + } +} + +// Get a :-separated list of unsigned ints after a key letter +const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength) +{ + if (readPointer >= 0) + { + size_t length = 0; + bool inList = true; + while(inList) + { + if (length >= returnedLength) // Array limit has been set in here + { + reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode unsigned array that is too long: %s\n", gcodeBuffer); + readPointer = -1; + returnedLength = 0; + return; + } + arr[length] = strtoul(&gcodeBuffer[readPointer + 1], 0, 0); length++; do { diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h index 0846a007..54a842ab 100644 --- a/src/GCodes/GCodeBuffer.h +++ b/src/GCodes/GCodeBuffer.h @@ -39,8 +39,9 @@ public: bool GetUnprecedentedString(const StringRef& str); // Get a string with no preceding key letter bool GetQuotedString(const StringRef& str); // Get and copy a quoted string bool GetPossiblyQuotedString(const StringRef& str); // Get and copy a string which may or may not be quoted - const void GetFloatArray(float a[], size_t& length, bool doPad) __attribute__((hot)); // Get a :-separated list of floats after a key letter - const void GetLongArray(long l[], size_t& length); // Get a :-separated list of longs after a key letter + const void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a :-separated list of floats after a key letter + const void GetIntArray(int32_t arr[], size_t& length); // Get a :-separated list of ints after a key letter + const void GetUnsignedArray(uint32_t arr[], size_t& length); // Get a :-separated list of unsigned ints after a key letter void TryGetFValue(char c, float& val, bool& seen); void TryGetIValue(char c, int32_t& val, bool& seen); diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 632df2d6..23e24a4f 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -232,7 +232,8 @@ float GCodes::FractionOfFilePrinted() const return 0.0; } - return (float)(fileBeingPrinted.GetPosition() - fileInput->BytesCached()) / (float)len; + const FilePosition bytesCached = fileGCode->IsDoingFileMacro() ? 0: fileInput->BytesCached(); + return (float)(fileBeingPrinted.GetPosition() - bytesCached) / (float)len; } // Start running the config file @@ -2886,10 +2887,9 @@ void GCodes::WriteGCodeToFile(GCodeBuffer& gb) return; } - // End of file? - if (gb.Seen('M')) + if (gb.GetCommandLetter() == 'M') { - if (gb.GetIValue() == 29) + if (gb.GetCommandNumber() == 29) // end of file? { fileBeingWritten->Close(); fileBeingWritten = nullptr; @@ -2899,18 +2899,13 @@ void GCodes::WriteGCodeToFile(GCodeBuffer& gb) return; } } - - // Resend request? - if (gb.Seen('G')) + else if (gb.GetCommandLetter() == 'G' && gb.GetCommandNumber() == 998) // resend request? { - if (gb.GetIValue() == 998) + if (gb.Seen('P')) { - if (gb.Seen('P')) - { - scratchString.printf("%" PRIi32 "\n", gb.GetIValue()); - HandleReply(gb, false, scratchString.Pointer()); - return; - } + scratchString.printf("%" PRIi32 "\n", gb.GetIValue()); + HandleReply(gb, false, scratchString.Pointer()); + return; } } @@ -3147,11 +3142,11 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply) } // Check drives - long drives[MaxExtruders]; // There can never be more than we have... - size_t dCount = numExtruders; // Sets the limit and returns the count + int32_t drives[MaxExtruders]; // There can never be more than we have... + size_t dCount = numExtruders; // Sets the limit and returns the count if (gb.Seen('D')) { - gb.GetLongArray(drives, dCount); + gb.GetIntArray(drives, dCount); seen = true; } else @@ -3160,11 +3155,11 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply) } // Check heaters - long heaters[Heaters]; + int32_t heaters[Heaters]; size_t hCount = Heaters; if (gb.Seen('H')) { - gb.GetLongArray(heaters, hCount); + gb.GetIntArray(heaters, hCount); seen = true; } else @@ -3176,10 +3171,10 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply) AxesBitmap xMap; if (gb.Seen('X')) { - long xMapping[MaxAxes]; + uint32_t xMapping[MaxAxes]; size_t xCount = numVisibleAxes; - gb.GetLongArray(xMapping, xCount); - xMap = LongArrayToBitMap<AxesBitmap>(xMapping, xCount) & LowestNBits<AxesBitmap>(numVisibleAxes); + gb.GetUnsignedArray(xMapping, xCount); + xMap = UnsignedArrayToBitMap<AxesBitmap>(xMapping, xCount) & LowestNBits<AxesBitmap>(numVisibleAxes); seen = true; } else @@ -3191,10 +3186,10 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply) AxesBitmap yMap; if (gb.Seen('Y')) { - long yMapping[MaxAxes]; + uint32_t yMapping[MaxAxes]; size_t yCount = numVisibleAxes; - gb.GetLongArray(yMapping, yCount); - yMap = LongArrayToBitMap<AxesBitmap>(yMapping, yCount) & LowestNBits<AxesBitmap>(numVisibleAxes); + gb.GetUnsignedArray(yMapping, yCount); + yMap = UnsignedArrayToBitMap<AxesBitmap>(yMapping, yCount) & LowestNBits<AxesBitmap>(numVisibleAxes); seen = true; } else @@ -3212,10 +3207,10 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply) FansBitmap fanMap; if (gb.Seen('F')) { - long fanMapping[NUM_FANS]; + uint32_t fanMapping[NUM_FANS]; size_t fanCount = NUM_FANS; - gb.GetLongArray(fanMapping, fanCount); - fanMap = LongArrayToBitMap<FansBitmap>(fanMapping, fanCount) & LowestNBits<FansBitmap>(NUM_FANS); + gb.GetUnsignedArray(fanMapping, fanCount); + fanMap = UnsignedArrayToBitMap<FansBitmap>(fanMapping, fanCount) & LowestNBits<FansBitmap>(NUM_FANS); seen = true; } else @@ -3260,7 +3255,7 @@ void GCodes::DisableDrives() SetAllAxesNotHomed(); } -bool GCodes::ChangeMicrostepping(size_t drive, int microsteps, int mode) const +bool GCodes::ChangeMicrostepping(size_t drive, unsigned int microsteps, int mode) const { bool dummy; const unsigned int oldSteps = platform.GetMicrostepping(drive, mode, dummy); @@ -3335,11 +3330,11 @@ void GCodes::HandleReply(GCodeBuffer& gb, bool error, const char* reply) case marlin: // We don't need to handle M20 here because we always allocate an output buffer for that one - if (gb.Seen('M') && gb.GetIValue() == 28) + if (gb.GetCommandLetter() == 'M' && gb.GetCommandNumber() == 28) { platform.MessageF(type, "%s\n%s\n", response, reply); } - else if ((gb.Seen('M') && gb.GetIValue() == 105) || (gb.Seen('M') && gb.GetIValue() == 998)) + else if (gb.GetCommandLetter() == 'M' && (gb.GetCommandNumber() == 105 || gb.GetCommandNumber() == 998)) { platform.MessageF(type, "%s %s\n", response, reply); } @@ -3393,7 +3388,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, bool error, OutputBuffer *reply) const Compatibility c = (&gb == serialGCode || &gb == telnetGCode) ? platform.Emulating() : me; const MessageType type = gb.GetResponseMessageType(); - const char* const response = (gb.Seen('M') && gb.GetIValue() == 998) ? "rs " : "ok"; + const char* const response = (gb.GetCommandLetter() == 'M' && gb.GetCommandNumber() == 998) ? "rs " : "ok"; const char* emulationType = nullptr; switch (c) @@ -3408,7 +3403,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, bool error, OutputBuffer *reply) return; case marlin: - if (gb.Seen('M') && gb.GetIValue() == 20) + if (gb.GetCommandLetter() =='M' && gb.GetCommandNumber() == 20) { platform.Message(type, "Begin file list\n"); platform.Message(type, reply); @@ -3418,7 +3413,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, bool error, OutputBuffer *reply) return; } - if (gb.Seen('M') && gb.GetIValue() == 28) + if (gb.GetCommandLetter() == 'M' && gb.GetCommandNumber() == 28) { platform.Message(type, response); platform.Message(type, "\n"); @@ -3426,7 +3421,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, bool error, OutputBuffer *reply) return; } - if ((gb.Seen('M') && gb.GetIValue() == 105) || (gb.Seen('M') && gb.GetIValue() == 998)) + if (gb.GetCommandLetter() =='M' && (gb.GetCommandNumber() == 105 || gb.GetCommandNumber() == 998)) { platform.Message(type, response); platform.Message(type, " "); diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 9debf727..86d5c94a 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -283,7 +283,7 @@ private: GCodeResult RetractFilament(GCodeBuffer& gb, bool retract); // Retract or un-retract filaments GCodeResult LoadFilament(GCodeBuffer& gb, StringRef& reply); // Load the specified filament into a tool GCodeResult UnloadFilament(GCodeBuffer& gb, StringRef& reply); // Unload the current filament from a tool - bool ChangeMicrostepping(size_t drive, int microsteps, int mode) const; // Change microstepping on the specified drive + bool ChangeMicrostepping(size_t drive, unsigned int microsteps, int mode) const; // Change microstepping on the specified drive void ListTriggers(StringRef reply, TriggerInputsBitmap mask); // Append a list of trigger inputs to a message void CheckTriggers(); // Check for and execute triggers void CheckFilament(); // Check for and respond to filament errors diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 474a05ee..b19010b8 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -396,15 +396,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) if (gb.Seen(extrudeLetter)) { - long int eDrive[MaxExtruders]; + uint32_t eDrive[MaxExtruders]; size_t eCount = numExtruders; - gb.GetLongArray(eDrive, eCount); + gb.GetUnsignedArray(eDrive, eCount); for (size_t i = 0; i < eCount; i++) { seen = true; - if (eDrive[i] < 0 || (size_t)eDrive[i] >= numExtruders) + if (eDrive[i] >= numExtruders) { - reply.printf("Invalid extruder number specified: %ld", eDrive[i]); + reply.printf("Invalid extruder number specified: %" PRIu32, eDrive[i]); result = GCodeResult::error; break; } @@ -1279,9 +1279,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) if (!cancelWait && gb.Seen('H')) { // Wait for specified heaters to be ready - long heaters[Heaters]; + int32_t heaters[Heaters]; size_t heaterCount = Heaters; - gb.GetLongArray(heaters, heaterCount); + gb.GetIntArray(heaters, heaterCount); for (size_t i = 0; i < heaterCount; i++) { @@ -1298,9 +1298,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) if (!cancelWait && gb.Seen('C')) { // Wait for specified chamber(s) to be ready - long chamberIndices[NumChamberHeaters]; + int32_t chamberIndices[NumChamberHeaters]; size_t chamberCount = NumChamberHeaters; - gb.GetLongArray(chamberIndices, chamberCount); + gb.GetIntArray(chamberIndices, chamberCount); if (chamberCount == 0) { @@ -2034,7 +2034,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) { reply.copy("Bad heater number in M303 command"); } - else if (reprap.GetHeat().CheckHeater(heater)) + else if (!reprap.GetHeat().CheckHeater(heater)) { reply.copy("Heater is not ready to perform PID auto-tuning"); } @@ -2104,7 +2104,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) if (seen) { const bool inverseTemperatureControl = (inversionParameter == 1 || inversionParameter == 3); - if (!reprap.GetHeat().SetHeaterModel(heater, gain, tc, td, maxPwm, voltage, dontUsePid == 0, inverseTemperatureControl, (uint16_t)min<uint32_t>(freq, 65536u))) + if (!reprap.GetHeat().SetHeaterModel(heater, gain, tc, td, maxPwm, voltage, + dontUsePid == 0, inverseTemperatureControl, (uint16_t)min<uint32_t>(freq, MaxHeaterPwmFrequency))) { reply.copy("Error: bad model parameters"); } @@ -2152,7 +2153,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) case 350: // Set/report microstepping { // interp is currently an int not a bool, because we use special values of interp to set the chopper control register - int32_t mode = 0; // this is usually the interpolation rwquested (0 = off, 1 = on) + int32_t mode = 0; // this is usually the interpolation requested (0 = off, 1 = on) bool dummy; gb.TryGetIValue('I', mode, dummy); @@ -2166,14 +2167,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) return false; } seen = true; - const int microsteps = gb.GetIValue(); + const unsigned int microsteps = gb.GetUIValue(); if (ChangeMicrostepping(axis, microsteps, mode)) { SetAxisNotHomed(axis); } else { - reply.printf("Drive %c does not support %dx microstepping%s", axisLetters[axis], microsteps, ((mode) ? " with interpolation" : "")); + reply.printf("Drive %c does not support %ux microstepping%s", axisLetters[axis], microsteps, ((mode) ? " with interpolation" : "")); result = GCodeResult::error; } } @@ -2186,14 +2187,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) return false; } seen = true; - long eVals[MaxExtruders]; + uint32_t eVals[MaxExtruders]; size_t eCount = numExtruders; - gb.GetLongArray(eVals, eCount); + gb.GetUnsignedArray(eVals, eCount); for (size_t e = 0; e < eCount; e++) { if (!ChangeMicrostepping(numTotalAxes + e, (int)eVals[e], mode)) { - reply.printf("Drive E%u does not support %dx microstepping%s", e, (int)eVals[e], ((mode) ? " with interpolation" : "")); + reply.printf("Drive E%u does not support %ux microstepping%s", e, (unsigned int)eVals[e], ((mode) ? " with interpolation" : "")); result = GCodeResult::error; } } @@ -2205,15 +2206,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) for (size_t axis = 0; axis < numTotalAxes; ++axis) { bool interp; - const int microsteps = platform.GetMicrostepping(axis, mode, interp); - reply.catf("%c:%d%s, ", axisLetters[axis], microsteps, (interp) ? "(on)" : ""); + const unsigned int microsteps = platform.GetMicrostepping(axis, mode, interp); + reply.catf("%c:%u%s, ", axisLetters[axis], microsteps, (interp) ? "(on)" : ""); } reply.cat("E"); for (size_t extruder = 0; extruder < numExtruders; extruder++) { bool interp; - const int microsteps = platform.GetMicrostepping(extruder + numTotalAxes, mode, interp); - reply.catf(":%d%s", microsteps, (interp) ? "(on)" : ""); + const unsigned int microsteps = platform.GetMicrostepping(extruder + numTotalAxes, mode, interp); + reply.catf(":%u%s", microsteps, (interp) ? "(on)" : ""); } } } @@ -2355,10 +2356,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) machineType = MachineType::cnc; if (gb.Seen('P')) { - int32_t pins[2] = { NoLogicalPin, NoLogicalPin }; + uint32_t pins[2] = { NoLogicalPin, NoLogicalPin }; size_t numPins = 2; - gb.GetLongArray(pins, numPins); - if (pins[0] < 0 || pins[0] > 65535) + gb.GetUnsignedArray(pins, numPins); + if (pins[0] > 65535) { pins[0] = NoLogicalPin; } @@ -3003,14 +3004,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) const float advance = gb.GetFValue(); if (gb.Seen('D')) { - long int eDrive[MaxExtruders]; + uint32_t eDrive[MaxExtruders]; size_t eCount = MaxExtruders; - gb.GetLongArray(eDrive, eCount); + gb.GetUnsignedArray(eDrive, eCount); for (size_t i = 0; i < eCount; i++) { - if (eDrive[i] < 0 || (size_t)eDrive[i] >= numExtruders) + if (eDrive[i] >= numExtruders) { - reply.printf("Invalid extruder number '%ld'", eDrive[i]); + reply.printf("Invalid extruder number '%" PRIu32 "'", eDrive[i]); result = GCodeResult::error; break; } @@ -3161,12 +3162,12 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) } // Extruder drives - size_t eDriveCount = MaxExtruders; - long eDrives[MaxExtruders]; if (gb.Seen(extrudeLetter)) { - gb.GetLongArray(eDrives, eDriveCount); - for(size_t extruder = 0; extruder < eDriveCount; extruder++) + size_t eDriveCount = MaxExtruders; + uint32_t eDrives[MaxExtruders]; + gb.GetUnsignedArray(eDrives, eDriveCount); + for (size_t extruder = 0; extruder < eDriveCount; extruder++) { const size_t eDrive = eDrives[extruder]; if (eDrive >= MaxExtruders) diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 581796e4..349c2742 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -341,12 +341,12 @@ GCodeResult GCodes::CheckOrConfigureTrigger(GCodeBuffer& gb, StringRef& reply, i } if (gb.Seen(extrudeLetter)) { - long eStops[MaxExtruders]; + uint32_t eStops[MaxExtruders]; size_t numEntries = MaxExtruders; - gb.GetLongArray(eStops, numEntries); + gb.GetUnsignedArray(eStops, numEntries); for (size_t i = 0; i < numEntries; ++i) { - if (eStops[i] >= 0 && (unsigned long)eStops[i] < MaxExtruders) + if (eStops[i] < MaxExtruders) { SetBit(triggerMask, eStops[i] + E0_AXIS); } @@ -422,15 +422,15 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, StringRef& reply) // Found an axis letter. Get the drivers to assign to this axis. seen = true; size_t numValues = MaxDriversPerAxis; - long drivers[MaxDriversPerAxis]; - gb.GetLongArray(drivers, numValues); + uint32_t drivers[MaxDriversPerAxis]; + gb.GetUnsignedArray(drivers, numValues); // Check all the driver numbers are in range AxisDriversConfig config; config.numDrivers = numValues; for (size_t i = 0; i < numValues; ++i) { - if ((unsigned long)drivers[i] >= DRIVES) + if (drivers[i] >= DRIVES) { badDrive = true; } @@ -476,12 +476,12 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, StringRef& reply) { seen = true; size_t numValues = DRIVES - numTotalAxes; - long drivers[MaxExtruders]; - gb.GetLongArray(drivers, numValues); + uint32_t drivers[MaxExtruders]; + gb.GetUnsignedArray(drivers, numValues); numExtruders = numValues; for (size_t i = 0; i < numValues; ++i) { - if ((unsigned long)drivers[i] >= DRIVES) + if (drivers[i] >= DRIVES) { badDrive = true; } @@ -701,20 +701,20 @@ GCodeResult GCodes::UpdateFirmware(GCodeBuffer& gb, StringRef &reply) // Find out which modules we have been asked to update if (gb.Seen('S')) { - long modulesToUpdate[3]; + uint32_t modulesToUpdate[3]; size_t numUpdateModules = ARRAY_SIZE(modulesToUpdate); - gb.GetLongArray(modulesToUpdate, numUpdateModules); + gb.GetUnsignedArray(modulesToUpdate, numUpdateModules); for (size_t i = 0; i < numUpdateModules; ++i) { - long t = modulesToUpdate[i]; - if (t < 0 || (unsigned long)t >= NumFirmwareUpdateModules) + uint32_t t = modulesToUpdate[i]; + if (t >= NumFirmwareUpdateModules) { - reply.printf("Invalid module number '%ld'\n", t); + reply.printf("Invalid module number '%" PRIu32 "'\n", t); firmwareUpdateModuleMap = 0; return GCodeResult::error; break; } - firmwareUpdateModuleMap |= (1u << (unsigned int)t); + firmwareUpdateModuleMap |= (1u << t); } } else diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index b1a514c5..01f2111d 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -53,7 +53,7 @@ void Heat::ResetHeaterModels() { if (pids[heater]->IsHeaterEnabled()) { - if (IsBedHeater(heater) || IsChamberHeater(heater)) + if (IsBedOrChamberHeater(heater)) { pids[heater]->SetModel(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime, 1.0, 0.0, false, false, 0); } @@ -70,9 +70,9 @@ void Heat::Init() // Initialise the heater protection items first for (size_t index : ARRAY_INDICES(heaterProtections)) { - HeaterProtection *prot = heaterProtections[index]; + HeaterProtection * const prot = heaterProtections[index]; - const float tempLimit = (IsBedHeater(index) || IsChamberHeater(index)) ? DefaultBedTemperatureLimit : DefaultExtruderTemperatureLimit; + const float tempLimit = (IsBedOrChamberHeater(index)) ? DefaultBedTemperatureLimit : DefaultExtruderTemperatureLimit; prot->Init(tempLimit); if (index < Heaters) @@ -85,7 +85,7 @@ void Heat::Init() for (size_t heater : ARRAY_INDICES(pids)) { heaterSensors[heater] = nullptr; // no temperature sensor assigned yet - if (IsBedHeater(heater) || IsChamberHeater(heater)) + if (IsBedOrChamberHeater(heater)) { pids[heater]->Init(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime, false, false); } @@ -612,7 +612,7 @@ void Heat::UpdateHeaterProtection() } } -// Check if the heater is able to operate +// Check if the heater is able to operate returning true if everything is OK bool Heat::CheckHeater(size_t heater) { return !pids[heater]->FaultOccurred() && pids[heater]->CheckProtection(); @@ -621,7 +621,7 @@ bool Heat::CheckHeater(size_t heater) // Get the temperature of a real or virtual heater float Heat::GetTemperature(size_t heater, TemperatureError& err) { - TemperatureSensor ** const spp = GetSensor(heater); + TemperatureSensor * const * const spp = GetSensor(heater); if (spp == nullptr) { err = TemperatureError::unknownHeater; diff --git a/src/Heating/HeaterProtection.cpp b/src/Heating/HeaterProtection.cpp index e7704e57..e8d4a9a5 100644 --- a/src/Heating/HeaterProtection.cpp +++ b/src/Heating/HeaterProtection.cpp @@ -12,7 +12,7 @@ #include "Heat.h" -HeaterProtection::HeaterProtection(size_t index) +HeaterProtection::HeaterProtection(size_t index) : next(nullptr) { // By default each heater protection element is mapped to its corresponding heater. // All other heater protection elements are unused and can be optionally assigned. @@ -32,33 +32,33 @@ void HeaterProtection::Init(float tempLimit) // Check if any action needs to be taken. Returns true if everything is OK bool HeaterProtection::Check() { - TemperatureError err; - const float temperature = reprap.GetHeat().GetTemperature(supervisedHeater, err); - - if (err != TemperatureError::success) + if (supervisedHeater >= 0) { - badTemperatureCount++; + TemperatureError err; + const float temperature = reprap.GetHeat().GetTemperature(supervisedHeater, err); - if (badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT) + if (err != TemperatureError::success) { - reprap.GetPlatform().MessageF(ErrorMessage, "Temperature reading error on heater %d\n", supervisedHeater); - return false; + badTemperatureCount++; + if (badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT) + { + reprap.GetPlatform().MessageF(ErrorMessage, "Temperature reading error on heater %d\n", supervisedHeater); + return false; + } } - } - else - { - badTemperatureCount = 0; - - switch (trigger) + else { - case HeaterProtectionTrigger::TemperatureExceeded: - return (temperature < limit); + badTemperatureCount = 0; + switch (trigger) + { + case HeaterProtectionTrigger::TemperatureExceeded: + return (temperature <= limit); - case HeaterProtectionTrigger::TemperatureTooLow: - return (temperature > limit); + case HeaterProtectionTrigger::TemperatureTooLow: + return (temperature >= limit); + } } } - return true; } diff --git a/src/Heating/HeaterProtection.h b/src/Heating/HeaterProtection.h index 99f90468..4373fb51 100644 --- a/src/Heating/HeaterProtection.h +++ b/src/Heating/HeaterProtection.h @@ -12,7 +12,7 @@ // Condition of a heater protection event -enum class HeaterProtectionTrigger +enum class HeaterProtectionTrigger : uint8_t { TemperatureExceeded, TemperatureTooLow @@ -21,7 +21,7 @@ enum class HeaterProtectionTrigger const HeaterProtectionTrigger MaxHeaterProtectionTrigger = HeaterProtectionTrigger::TemperatureTooLow; // The action to trigger when the target condition is met -enum class HeaterProtectionAction +enum class HeaterProtectionAction : uint8_t { GenerateFault = 0, PermanentSwitchOff, @@ -64,8 +64,8 @@ public: private: HeaterProtection *next; - int8_t heater, supervisedHeater; float limit; + int8_t heater, supervisedHeater; HeaterProtectionAction action; HeaterProtectionTrigger trigger; diff --git a/src/Heating/Pid.cpp b/src/Heating/Pid.cpp index 41ec78d0..e64d382a 100644 --- a/src/Heating/Pid.cpp +++ b/src/Heating/Pid.cpp @@ -39,7 +39,7 @@ float tuningVoltageAccumulator; // sum of the voltage readings we take during // Member functions and constructors -PID::PID(Platform& p, int8_t h) : platform(p), heater(h), mode(HeaterMode::off), invertPwmSignal(false) +PID::PID(Platform& p, int8_t h) : platform(p), heaterProtection(nullptr), heater(h), mode(HeaterMode::off), invertPwmSignal(false) { } @@ -726,7 +726,7 @@ void PID::DoTuningStep() case HeaterMode::tuning1: // Heating up { - const bool isBedOrChamberHeater = (reprap.GetHeat().IsBedHeater(heater) || reprap.GetHeat().IsChamberHeater(heater)); + const bool isBedOrChamberHeater = reprap.GetHeat().IsBedOrChamberHeater(heater); const uint32_t heatingTime = millis() - tuningPhaseStartTime; const float extraTimeAllowed = (isBedOrChamberHeater) ? 60.0 : 30.0; if (heatingTime > (uint32_t)((model.GetDeadTime() + extraTimeAllowed) * SecondsToMillis) && (temperature - tuningStartTemp) < 3.0) diff --git a/src/Heating/Sensors/TemperatureSensor.cpp b/src/Heating/Sensors/TemperatureSensor.cpp index 0634fa4c..f97492e1 100644 --- a/src/Heating/Sensors/TemperatureSensor.cpp +++ b/src/Heating/Sensors/TemperatureSensor.cpp @@ -35,7 +35,7 @@ void TemperatureSensor::SetHeaterName(const char *newName) heaterName = nullptr; delete oldName; - if (newName != nullptr) + if (newName != nullptr && strlen(newName) != 0) { char * const temp = new char[strlen(newName) + 1]; strcpy(temp, newName); diff --git a/src/Movement/BedProbing/Grid.cpp b/src/Movement/BedProbing/Grid.cpp index 5b56c518..ad3f11d1 100644 --- a/src/Movement/BedProbing/Grid.cpp +++ b/src/Movement/BedProbing/Grid.cpp @@ -165,7 +165,7 @@ void GridDefinition::PrintError(float originalXrange, float originalYrange, Stri } // Increase the version number in the following string whenever we change the format of the height map file. -const char *HeightMap::HeightMapComment = "RepRapFirmware height map file v2"; +const char * const HeightMap::HeightMapComment = "RepRapFirmware height map file v2"; HeightMap::HeightMap() : useMap(false) { } diff --git a/src/Movement/BedProbing/Grid.h b/src/Movement/BedProbing/Grid.h index 7054ec35..d76346a9 100644 --- a/src/Movement/BedProbing/Grid.h +++ b/src/Movement/BedProbing/Grid.h @@ -83,7 +83,7 @@ public: void ExtrapolateMissing(); // Extrapolate missing points to ensure consistency private: - static const char *HeightMapComment; // The start of the comment we write at the start of the height map file + static const char * const HeightMapComment; // The start of the comment we write at the start of the height map file GridDefinition def; float gridHeights[MaxGridProbePoints]; // The Z coordinates of the points on the bed that were probed diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index 35ee63aa..d75e422f 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -47,6 +47,13 @@ struct MoveParameters (double)accelDistance, (double)steadyDistance, (double)decelDistance, (double)requestedSpeed, (double)startSpeed, (double)topSpeed, (double)endSpeed, (double)targetNextSpeed, endstopChecks, flags); } + + static void PrintHeading() + { + reprap.GetPlatform().Message(DebugMessage, + "accelDistance,steadyDistance,decelDistance,requestedSpeed,startSpeed,topSpeed,endSpeed," + "targetNextSpeed,endstopChecks,flags\n"); + } }; const size_t NumSavedMoves = 128; @@ -58,6 +65,7 @@ static size_t savedMovePointer = 0; /*static*/ void DDA::PrintMoves() { // Print the saved moved in CSV format + MoveParameters::PrintHeading(); for (size_t i = 0; i < NumSavedMoves; ++i) { savedMoves[savedMovePointer].DebugPrint(); @@ -445,7 +453,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) { // Try to meld this move to the previous move to avoid stop/start // Assuming that this move ends with zero speed, calculate the maximum possible starting speed: u^2 = v^2 - 2as - prev->targetNextSpeed = sqrtf(acceleration * totalDistance * 2.0); + prev->targetNextSpeed = min<float>(sqrtf(acceleration * totalDistance * 2.0), requestedSpeed); DoLookahead(prev); startSpeed = prev->targetNextSpeed; } @@ -1003,7 +1011,7 @@ void DDA::Prepare(uint8_t simMode) for (size_t drive = 0; drive < DRIVES; ++drive) { DriveMovement* const pdm = pddm[drive]; - if (pddm != nullptr && pdm->state == DMState::moving) + if (pdm != nullptr && pdm->state == DMState::moving) { if (isLeadscrewAdjustmentMove) { @@ -1324,7 +1332,7 @@ pre(state == frozen) const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); for (size_t i = 0; i < DRIVES; ++i) { - DriveMovement* const pdm = pddm[i]; + DriveMovement* const pdm = FindDM(i); if (pdm != nullptr && pdm->state == DMState::moving) { const size_t drive = pdm->drive; @@ -1498,7 +1506,7 @@ bool DDA::Step() // For extruder drivers, we need to be able to calculate how much of the extrusion was completed after calling this. void DDA::StopDrive(size_t drive) { - DriveMovement* const pdm = pddm[drive]; + DriveMovement* const pdm = FindDM(drive); if (pdm != nullptr && pdm->state == DMState::moving) { pdm->state = DMState::idle; @@ -1547,7 +1555,7 @@ float DDA::GetProportionDone(bool moveWasAborted) const int32_t taken = 0, left = 0; for (size_t drive = reprap.GetGCodes().GetTotalAxes(); drive < DRIVES; ++drive) { - const DriveMovement* const pdm = pddm[drive]; + const DriveMovement* const pdm = FindDM(drive); if (pdm != nullptr) // if this extruder is active { taken += pdm->GetNetStepsTaken(); @@ -1588,7 +1596,7 @@ void DDA::ReduceHomingSpeed() // Adjust the speed in the DMs for (size_t drive = 0; drive < DRIVES; ++drive) { - DriveMovement* const pdm = pddm[drive]; + DriveMovement* const pdm = FindDM(drive); if (pdm != nullptr && pdm->state == DMState::moving) { pdm->ReduceSpeed(*this, ProbingSpeedReductionFactor); @@ -1601,7 +1609,7 @@ bool DDA::HasStepError() const { for (size_t drive = 0; drive < DRIVES; ++drive) { - const DriveMovement* const pdm = pddm[drive]; + const DriveMovement* const pdm = FindDM(drive); if (pdm != nullptr && pdm->state == DMState::stepError) { return true; @@ -1621,7 +1629,7 @@ bool DDA::Free() // Return the number of net steps already taken in this move by a particular drive int32_t DDA::GetStepsTaken(size_t drive) const { - const DriveMovement * const dmp = pddm[drive]; + const DriveMovement * const dmp = FindDM(drive); return (dmp != nullptr) ? dmp->GetNetStepsTaken() : 0; } diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index 2475dfa9..6644f5ea 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -128,6 +128,7 @@ public: static uint32_t maxReps; private: + DriveMovement *FindDM(size_t drive) const; void RecalculateMove() __attribute__ ((hot)); void CalcNewSpeeds() __attribute__ ((hot)); void ReduceHomingSpeed(); // called to reduce homing speed when a near-endstop is triggered @@ -221,6 +222,12 @@ private: DriveMovement *pddm[DRIVES]; // These describe the state of each drive movement }; +// Find the DriveMovement record for a given drive, or return nullptr if there isn't one +inline DriveMovement *DDA::FindDM(size_t drive) const +{ + return pddm[drive]; +} + // Force an end point inline void DDA::SetDriveCoordinate(int32_t a, size_t drive) { @@ -233,7 +240,7 @@ inline void DDA::SetDriveCoordinate(int32_t a, size_t drive) // Get the current full step interval for this axis or extruder inline uint32_t DDA::GetStepInterval(size_t axis, uint32_t microstepShift) const { - const DriveMovement * const dm = pddm[axis]; + const DriveMovement * const dm = FindDM(axis); return (dm != nullptr) ? dm->GetStepInterval(microstepShift) : 0; } diff --git a/src/Movement/DriveMovement.h b/src/Movement/DriveMovement.h index 9a1c535a..1d71931e 100644 --- a/src/Movement/DriveMovement.h +++ b/src/Movement/DriveMovement.h @@ -156,20 +156,20 @@ private: DMState state; // whether this is active or not uint8_t drive; // the drive that this DM controls - uint8_t microstepShift : 4, // log2 of the microstepping factor + uint8_t microstepShift : 4, // log2 of the microstepping factor (for when we use dynamic microstepping adjustment) direction : 1, // true=forwards, false=backwards fullCurrent : 1; // true if the drivers are set to the full current, false if they are set to the standstill current uint8_t stepsTillRecalc; // how soon we need to recalculate uint32_t totalSteps; // total number of steps for this move - // These values change as the step is executed + // These values change as the step is executed, except for reverseStartStep uint32_t nextStep; // number of steps already done uint32_t reverseStartStep; // the step number for which we need to reverse direction due to pressure advance or delta movement uint32_t nextStepTime; // how many clocks after the start of this move the next step is due uint32_t stepInterval; // how many clocks between steps - // The following only need to be stored per-drive if we are supporting pressure advance + // The following only needs to be stored per-drive if we are supporting pressure advance uint64_t twoDistanceToStopTimesCsquaredDivA; // Parameters unique to a style of move (Cartesian, delta or extruder). Currently, extruders and Cartesian moves use the same parameters. diff --git a/src/Movement/Kinematics/Kinematics.cpp b/src/Movement/Kinematics/Kinematics.cpp index a258a377..52ec0262 100644 --- a/src/Movement/Kinematics/Kinematics.cpp +++ b/src/Movement/Kinematics/Kinematics.cpp @@ -19,7 +19,7 @@ #include "Platform.h" #include "GCodes/GCodeBuffer.h" -const char *Kinematics::HomeAllFileName = "homeall.g"; +const char * const Kinematics::HomeAllFileName = "homeall.g"; const char * const Kinematics::StandardHomingFileNames[] = AXES_("homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g", "homea.g", "homeb.g", "homec.g"); // Constructor. Pass segsPerSecond <= 0.0 to get non-segmented kinematics. diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h index fe9d4e52..d6c59e5a 100644 --- a/src/Movement/Kinematics/Kinematics.h +++ b/src/Movement/Kinematics/Kinematics.h @@ -186,7 +186,7 @@ protected: float segmentsPerSecond; // if we are using segmentation, the target number of segments/second float minSegmentLength; // if we are using segmentation, the minimum segment size - static const char *HomeAllFileName; + static const char * const HomeAllFileName; static const char * const StandardHomingFileNames[]; private: diff --git a/src/Network2/ESP8266/Network.cpp b/src/Network2/ESP8266/Network.cpp index 79258a41..8070a417 100644 --- a/src/Network2/ESP8266/Network.cpp +++ b/src/Network2/ESP8266/Network.cpp @@ -404,77 +404,72 @@ void Network::Stop() void Network::Spin(bool full) { - // Main state machine. - switch (state) + if (full) { - case NetworkState::starting1: - if (full) + // Main state machine. + switch (state) { - // The ESP toggles CS before it has finished starting up, so don't look at the CS signal too soon - const uint32_t now = millis(); - if (now - lastTickMillis >= WiFiStartupMillis) + case NetworkState::starting1: { - lastTickMillis = now; - state = NetworkState::starting2; + // The ESP toggles CS before it has finished starting up, so don't look at the CS signal too soon + const uint32_t now = millis(); + if (now - lastTickMillis >= WiFiStartupMillis) + { + lastTickMillis = now; + state = NetworkState::starting2; + } } - } - break; + break; - case NetworkState::starting2: - if (full) - { - // See if the ESP8266 has kept its pins at their stable values for long enough - const uint32_t now = millis(); - if (digitalRead(SamCsPin) && digitalRead(EspTransferRequestPin) && !digitalRead(APIN_SPI_SCK)) + case NetworkState::starting2: { - if (now - lastTickMillis >= WiFiStableMillis) + // See if the ESP8266 has kept its pins at their stable values for long enough + const uint32_t now = millis(); + if (digitalRead(SamCsPin) && digitalRead(EspTransferRequestPin) && !digitalRead(APIN_SPI_SCK)) { - // Setup the SPI controller in slave mode and assign the CS pin to it - platform.Message(NetworkInfoMessage, "WiFi module started\n"); - SetupSpi(); // set up the SPI subsystem - - // Read the status to get the WiFi server version - Receiver<NetworkStatusResponse> status; - const int32_t rc = SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status); - if (rc > 0) + if (now - lastTickMillis >= WiFiStableMillis) { - SafeStrncpy(wiFiServerVersion, status.Value().versionText, ARRAY_SIZE(wiFiServerVersion)); + // Setup the SPI controller in slave mode and assign the CS pin to it + platform.Message(NetworkInfoMessage, "WiFi module started\n"); + SetupSpi(); // set up the SPI subsystem + + // Read the status to get the WiFi server version + Receiver<NetworkStatusResponse> status; + const int32_t rc = SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status); + if (rc > 0) + { + SafeStrncpy(wiFiServerVersion, status.Value().versionText, ARRAY_SIZE(wiFiServerVersion)); + + // Set the hostname before anything else is done + if (SendCommand(NetworkCommand::networkSetHostName, 0, 0, hostname, HostNameLength, nullptr, 0) != ResponseEmpty) + { + reprap.GetPlatform().Message(NetworkInfoMessage, "Error: Could not set WiFi hostname\n"); + } - // Set the hostname before anything else is done - if (SendCommand(NetworkCommand::networkSetHostName, 0, 0, hostname, HostNameLength, nullptr, 0) != ResponseEmpty) + state = NetworkState::active; + espStatusChanged = true; // make sure we fetch the current state and enable the ESP interrupt + } + else { - reprap.GetPlatform().Message(NetworkInfoMessage, "Error: Could not set WiFi hostname\n"); + // Something went wrong, maybe a bad firmware image was flashed + // Disable the WiFi chip again in this case + platform.MessageF(NetworkInfoMessage, "Error: Failed to initialise WiFi module, code %" PRIi32 "\n", rc); + Stop(); } - - state = NetworkState::active; - espStatusChanged = true; // make sure we fetch the current state and enable the ESP interrupt - } - else - { - // Something went wrong, maybe a bad firmware image was flashed - // Disable the WiFi chip again in this case - platform.MessageF(NetworkInfoMessage, "Error: Failed to initialise WiFi module, code %" PRIi32 "\n", rc); - Stop(); } } + else + { + lastTickMillis = now; + } } - else - { - lastTickMillis = now; - } - } - break; + break; - case NetworkState::disabled: - if (full) - { + case NetworkState::disabled: uploader->Spin(); - } - break; + break; - case NetworkState::active: - if (full) - { + case NetworkState::active: if (espStatusChanged && digitalRead(EspTransferRequestPin)) { if (reprap.Debug(moduleNetwork)) @@ -557,48 +552,48 @@ void Network::Spin(bool full) nextResponderToPoll = nr; } } - } - break; + break; - case NetworkState::changingMode: - if (full && espStatusChanged && digitalRead(EspTransferRequestPin)) - { - GetNewStatus(); - if (currentMode != WiFiState::connecting) + case NetworkState::changingMode: + if (espStatusChanged && digitalRead(EspTransferRequestPin)) { - requestedMode = currentMode; // don't keep repeating the request if it failed - state = NetworkState::active; - if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint) + GetNewStatus(); + if (currentMode != WiFiState::connecting) { - // Get our IP address, this needs to be correct for FTP to work - Receiver<NetworkStatusResponse> status; - if (SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status) > 0) + requestedMode = currentMode; // don't keep repeating the request if it failed + state = NetworkState::active; + if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint) { - uint32_t ip = status.Value().ipAddress; - for (size_t i = 0; i < 4; ++i) + // Get our IP address, this needs to be correct for FTP to work + Receiver<NetworkStatusResponse> status; + if (SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status) > 0) { - ipAddress[i] = (uint8_t)(ip & 255); - ip >>= 8; + uint32_t ip = status.Value().ipAddress; + for (size_t i = 0; i < 4; ++i) + { + ipAddress[i] = (uint8_t)(ip & 255); + ip >>= 8; + } + SafeStrncpy(actualSsid, status.Value().ssid, SsidLength); } - SafeStrncpy(actualSsid, status.Value().ssid, SsidLength); + InitSockets(); + reconnectCount = 0; + platform.MessageF(NetworkInfoMessage, "Wifi module is %s%s, IP address %s\n", + TranslateWiFiState(currentMode), + actualSsid, + IP4String(ipAddress).c_str()); + } + else + { + platform.MessageF(NetworkInfoMessage, "Wifi module is %s\n", TranslateWiFiState(currentMode)); } - InitSockets(); - reconnectCount = 0; - platform.MessageF(NetworkInfoMessage, "Wifi module is %s%s, IP address %s\n", - TranslateWiFiState(currentMode), - actualSsid, - IP4String(ipAddress).c_str()); - } - else - { - platform.MessageF(NetworkInfoMessage, "Wifi module is %s\n", TranslateWiFiState(currentMode)); } } - } - break; + break; - default: - break; + default: + break; + } } // Check for debug info received from the WiFi module diff --git a/src/Network2/ESP8266/WifiFirmwareUploader.cpp b/src/Network2/ESP8266/WifiFirmwareUploader.cpp index a14f3d6d..0e8c1800 100644 --- a/src/Network2/ESP8266/WifiFirmwareUploader.cpp +++ b/src/Network2/ESP8266/WifiFirmwareUploader.cpp @@ -5,8 +5,8 @@ * Author: David */ -#include <Network2/ESP8266/Network.h> -#include <Network2/ESP8266/WifiFirmwareUploader.h> +#include "Network.h" +#include "WifiFirmwareUploader.h" #include "Platform.h" #include "RepRap.h" #include "Storage/FileStore.h" @@ -43,7 +43,7 @@ const uint32_t ESP_FLASH_ADDR = 0x40200000; // address of start of Flash const uint32_t ESP_FLASH_READ_STUB_BEGIN = IRAM_ADDR + 0x18; // Messages corresponding to result codes, should make sense when followed by " error" -const char *resultMessages[] = +const char * const resultMessages[] = { "no", "timeout", diff --git a/src/Network2/HttpResponder.cpp b/src/Network2/HttpResponder.cpp index ca3a3bc0..7a1fe334 100644 --- a/src/Network2/HttpResponder.cpp +++ b/src/Network2/HttpResponder.cpp @@ -13,8 +13,8 @@ #define KO_START "rr_" const size_t KoFirst = 3; -const char* overflowResponse = "overflow"; -const char* badEscapeResponse = "bad escape"; +const char* const overflowResponse = "overflow"; +const char* const badEscapeResponse = "bad escape"; const uint32_t HttpReceiveTimeout = 2000; diff --git a/src/Platform.cpp b/src/Platform.cpp index 1dd6a049..7301cbae 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -317,7 +317,7 @@ Platform::Platform() : nextDriveToPoll(0), onBoardDriversFanRunning(false), offBoardDriversFanRunning(false), onBoardDriversFanStartMillis(0), offBoardDriversFanStartMillis(0), #endif - lastFanCheckTime(0), auxGCodeReply(nullptr), tickState(0), debugCode(0), lastWarningMillis(0) + lastFanCheckTime(0), auxGCodeReply(nullptr), tickState(0), debugCode(0), lastWarningMillis(0), deliberateError(false) { // Output auxOutput = new OutputStack(); @@ -918,14 +918,14 @@ bool Platform::ProgramZProbe(GCodeBuffer& gb, StringRef& reply) { if (gb.Seen('S')) { - long zProbeProgram[MaxZProbeProgramBytes]; + uint32_t zProbeProgram[MaxZProbeProgramBytes]; size_t len = MaxZProbeProgramBytes; - gb.GetLongArray(zProbeProgram, len); + gb.GetUnsignedArray(zProbeProgram, len); if (len != 0) { for (size_t i = 0; i < len; ++i) { - if (zProbeProgram[i] < 0 || zProbeProgram[i] > 255) + if (zProbeProgram[i] > 255) { reply.copy("Out of range value in program bytes"); return true; @@ -1792,6 +1792,10 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk) } reason |= (uint8_t)reprap.GetSpinningModule(); reason |= (softwareResetDebugInfo & 0x07) << 5; + if (deliberateError) + { + reason |= (uint16_t)SoftwareResetReason::deliberate; + } // Record the reason for the software reset // First find a free slot (wear levelling) @@ -1823,6 +1827,7 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk) } srdBuf[slot].magic = SoftwareResetData::magicValue; srdBuf[slot].resetReason = reason; + srdBuf[slot].when = realTime; GetStackUsage(nullptr, nullptr, &srdBuf[slot].neverUsedRam); srdBuf[slot].hfsr = SCB->HFSR; srdBuf[slot].cfsr = SCB->CFSR; @@ -2147,14 +2152,14 @@ void Platform::Diagnostics(MessageType mtype) #endif { // Find the last slot written - slot = SoftwareResetData::numberOfSlots - 1; - while (slot >= 0 && srdBuf[slot].magic == 0xFFFF) + slot = SoftwareResetData::numberOfSlots; + do { --slot; } + while (slot >= 0 && srdBuf[slot].magic == 0xFFFF); } - Message(mtype, "Last software reset reason: "); if (slot >= 0 && srdBuf[slot].magic == SoftwareResetData::magicValue) { const uint32_t reason = srdBuf[slot].resetReason & 0xF0; @@ -2165,10 +2170,23 @@ void Platform::Diagnostics(MessageType mtype) : (reason == (uint32_t)SoftwareResetReason::wdtFault) ? "Watchdog timeout" : (reason == (uint32_t)SoftwareResetReason::otherFault) ? "Other fault" : "Unknown"; - MessageF(mtype, "%s, spinning module %s, available RAM %" PRIu32 " bytes (slot %d)\n", - reasonText, moduleName[srdBuf[slot].resetReason & 0x0F], srdBuf[slot].neverUsedRam, slot); + if (srdBuf[slot].when != 0) + { + const struct tm * const timeInfo = gmtime(&srdBuf[slot].when); + scratchString.printf("at %04u-%02u-%02u %02u:%02u", + timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min); + } + else + { + scratchString.copy("time unknown"); + } + + MessageF(mtype, "Last software reset %s, reason: %s%s, spinning module %s, available RAM %" PRIu32 " bytes (slot %d)\n", + scratchString.Pointer(), + (srdBuf[slot].resetReason & (uint32_t)SoftwareResetReason::deliberate) ? "deliberate " : "", + reasonText, moduleName[srdBuf[slot].resetReason & 0x0F], srdBuf[slot].neverUsedRam, slot); // Our format buffer is only 256 characters long, so the next 2 lines must be written separately - MessageF(mtype, "Software reset code 0x%04x, HFSR 0x%08" PRIx32 ", CFSR 0x%08" PRIx32 ", ICSR 0x%08" PRIx32 ", BFAR 0x%08" PRIx32 ", SP 0x%08" PRIx32 "\n", + MessageF(mtype, "Software reset code 0x%04x HFSR 0x%08" PRIx32 ", CFSR 0x%08" PRIx32 ", ICSR 0x%08" PRIx32 ", BFAR 0x%08" PRIx32 ", SP 0x%08" PRIx32 "\n", srdBuf[slot].resetReason, srdBuf[slot].hfsr, srdBuf[slot].cfsr, srdBuf[slot].icsr, srdBuf[slot].bfar, srdBuf[slot].sp); if (srdBuf[slot].sp != 0xFFFFFFFF) { @@ -2183,7 +2201,7 @@ void Platform::Diagnostics(MessageType mtype) } else { - Message(mtype, "not available\n"); + Message(mtype, "Last software reset details not available\n"); } } @@ -2412,27 +2430,33 @@ bool Platform::DiagnosticTest(GCodeBuffer& gb, StringRef& reply, int d) break; case (int)DiagnosticTestType::TestWatchdog: + deliberateError = true; SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk); // disable the system tick interrupt so that we get a watchdog timeout reset break; case (int)DiagnosticTestType::TestSpinLockup: + deliberateError = true; debugCode = d; // tell the Spin function to loop break; case (int)DiagnosticTestType::TestSerialBlock: // write an arbitrary message via debugPrintf() + deliberateError = true; debugPrintf("Diagnostic Test\n"); break; case (int)DiagnosticTestType::DivideByZero: // do an integer divide by zero to test exception handling + deliberateError = true; (void)RepRap::DoDivide(1, 0); // call function in another module so it can't be optimised away break; case (int)DiagnosticTestType::UnalignedMemoryAccess: // do an unaligned memory access to test exception handling + deliberateError = true; SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk; // by default, unaligned memory accesses are allowed, so change that (void)RepRap::ReadDword(reinterpret_cast<const char*>(dummy) + 1); // call function in another module so it can't be optimised away break; case (int)DiagnosticTestType::BusFault: + deliberateError = true; // Read from the "Undefined (Abort)" area #if SAME70 // FIXME: The SAME70 provides an MPU, maybe we should configure it as well? @@ -2605,84 +2629,81 @@ void Platform::UpdateConfiguredHeaters() EndStopHit Platform::Stopped(size_t drive) const { - if (drive < DRIVES) + if (drive < reprap.GetGCodes().GetTotalAxes()) { - if (drive >= reprap.GetGCodes().GetTotalAxes()) + switch (endStopInputType[drive]) { - // Endstop not used for an axis, so no configuration data available. - // To allow us to see its status in DWC, pretend it is configured as a high-end active high endstop. - return (endStopPins[drive] != NoPin && IoPort::ReadPin(endStopPins[drive])) ? EndStopHit::highHit : EndStopHit::noStop; - } - else - { - switch (endStopInputType[drive]) + case EndStopInputType::zProbe: { - case EndStopInputType::zProbe: - { - const EndStopHit rslt = GetZProbeResult(); - return (rslt == EndStopHit::lowHit && endStopPos[drive] == EndStopPosition::highEndStop) - ? EndStopHit::highHit - : rslt; - } + const EndStopHit rslt = GetZProbeResult(); + return (rslt == EndStopHit::lowHit && endStopPos[drive] == EndStopPosition::highEndStop) + ? EndStopHit::highHit + : rslt; + } #if HAS_SMART_DRIVERS - case EndStopInputType::motorStall: + case EndStopInputType::motorStall: + { + bool motorIsStalled; + switch (reprap.GetMove().GetKinematics().GetKinematicsType()) { - bool motorIsStalled; - switch (reprap.GetMove().GetKinematics().GetKinematicsType()) - { - case KinematicsType::coreXY: - // Both X and Y motors are involved in homing X or Y - motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) - ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS) - : AnyMotorStalled(drive); - break; - - case KinematicsType::coreXYU: - // Both X and Y motors are involved in homing X or Y, and both U and V motors are involved in homing U - motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) - ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS) - : (drive == U_AXIS) - ? AnyMotorStalled(U_AXIS) || AnyMotorStalled(V_AXIS) - : AnyMotorStalled(drive); - break; - - case KinematicsType::coreXZ: - // Both X and Z motors are involved in homing X or Z - motorIsStalled = (drive == X_AXIS || drive == Z_AXIS) - ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Z_AXIS) - : AnyMotorStalled(drive); - break; - - default: - motorIsStalled = AnyMotorStalled(drive); - break; - } - return (!motorIsStalled) ? EndStopHit::noStop - : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit - : EndStopHit::lowHit; + case KinematicsType::coreXY: + // Both X and Y motors are involved in homing X or Y + motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) + ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS) + : AnyMotorStalled(drive); + break; + + case KinematicsType::coreXYU: + // Both X and Y motors are involved in homing X or Y, and both U and V motors are involved in homing U + motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) + ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS) + : (drive == U_AXIS) + ? AnyMotorStalled(U_AXIS) || AnyMotorStalled(V_AXIS) + : AnyMotorStalled(drive); + break; + + case KinematicsType::coreXZ: + // Both X and Z motors are involved in homing X or Z + motorIsStalled = (drive == X_AXIS || drive == Z_AXIS) + ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Z_AXIS) + : AnyMotorStalled(drive); + break; + + default: + motorIsStalled = AnyMotorStalled(drive); + break; } - break; + return (!motorIsStalled) ? EndStopHit::noStop + : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit + : EndStopHit::lowHit; + } + break; #endif - case EndStopInputType::activeLow: - case EndStopInputType::activeHigh: - if (endStopPins[drive] != NoPin) + case EndStopInputType::activeLow: + case EndStopInputType::activeHigh: + if (endStopPins[drive] != NoPin) + { + bool b = IoPort::ReadPin(endStopPins[drive]); + if (endStopInputType[drive] == EndStopInputType::activeHigh) { - bool b = IoPort::ReadPin(endStopPins[drive]); - if (endStopInputType[drive] == EndStopInputType::activeHigh) - { - b = !b; - } - return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; + b = !b; } - break; - - default: - break; + return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } + break; + + default: + break; } } + else if (drive < DRIVES) + { + // Endstop not used for an axis, so no configuration data available. + // To allow us to see its status in DWC, pretend it is configured as a high-end active high endstop. + return (endStopPins[drive] != NoPin && IoPort::ReadPin(endStopPins[drive])) ? EndStopHit::highHit : EndStopHit::noStop; + } return EndStopHit::noStop; } @@ -3053,7 +3074,7 @@ void Platform::SetIdleCurrentFactor(float f) } // Set the microstepping for a driver, returning true if successful -bool Platform::SetDriverMicrostepping(size_t driver, int microsteps, int mode) +bool Platform::SetDriverMicrostepping(size_t driver, unsigned int microsteps, int mode) { if (driver < DRIVES) { @@ -4170,14 +4191,14 @@ bool Platform::ConfigureStallDetection(GCodeBuffer& gb, StringRef& reply) DriversBitmap drivers = 0; if (gb.Seen('P')) { - long int drives[DRIVES]; + uint32_t drives[DRIVES]; size_t dCount = DRIVES; - gb.GetLongArray(drives, dCount); + gb.GetUnsignedArray(drives, dCount); for (size_t i = 0; i < dCount; i++) { - if (drives[i] < 0 || (size_t)drives[i] >= numSmartDrivers) + if (drives[i] >= numSmartDrivers) { - reply.printf("Invalid drive number '%ld'", drives[i]); + reply.printf("Invalid drive number '%" PRIu32 "'", drives[i]); return true; } SetBit(drivers, drives[i]); diff --git a/src/Platform.h b/src/Platform.h index 4c2699e0..6fcd96b2 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -155,7 +155,8 @@ enum class SoftwareResetReason : uint16_t otherFault = 0x70, inAuxOutput = 0x0800, // this bit is or'ed in if we were in aux output at the time inLwipSpin = 0x2000, // we got stuck in a call to LWIP for too long - inUsbOutput = 0x4000 // this bit is or'ed in if we were in USB output at the time + inUsbOutput = 0x4000, // this bit is or'ed in if we were in USB output at the time + deliberate = 0x8000 // this but it or'ed in if we deliberately caused a fault }; // Enumeration to describe various tests we do in response to the M122 command @@ -392,7 +393,7 @@ public: void SetIdleCurrentFactor(float f); float GetIdleCurrentFactor() const { return idleCurrentFactor; } - bool SetDriverMicrostepping(size_t driver, int microsteps, int mode); + bool SetDriverMicrostepping(size_t driver, unsigned int microsteps, int mode); unsigned int GetDriverMicrostepping(size_t drive, int mode, bool& interpolation) const; bool SetMicrostepping(size_t drive, int microsteps, int mode); unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation) const; @@ -606,12 +607,12 @@ private: // directly from/to flash memory. struct SoftwareResetData { - static const uint16_t versionValue = 7; // increment this whenever this struct changes + static const uint16_t versionValue = 8; // increment this whenever this struct changes static const uint16_t magicValue = 0x7D00 | versionValue; // value we use to recognise that all the flash data has been written #if SAM3XA static const uint32_t nvAddress = 0; // must be 4-byte aligned #endif - static const size_t numberOfSlots = 5; // number of storage slots used to implement wear levelling - must fit in 512 bytes + static const size_t numberOfSlots = 4; // number of storage slots used to implement wear levelling - must fit in 512 bytes uint16_t magic; // the magic number, including the version uint16_t resetReason; // this records why we did a software reset, for diagnostic purposes @@ -621,7 +622,8 @@ private: uint32_t icsr; // interrupt control and state register uint32_t bfar; // bus fault address register uint32_t sp; // stack pointer - uint32_t stack[18]; // stack when the exception occurred, with the program counter at the bottom + time_t when; // value of the RTC when the software reset occurred + uint32_t stack[24]; // stack when the exception occurred, with the program counter at the bottom bool isVacant() const // return true if this struct can be written without erasing it first { @@ -734,7 +736,6 @@ private: #endif // Z probe - Pin zProbePin; Pin zProbeModulationPin; ZProbeProgrammer zProbeProg; @@ -756,7 +757,6 @@ private: void UpdateNetworkAddress(byte dst[4], const byte src[4]); // Axes and endstops - float axisMaxima[MaxAxes]; float axisMinima[MaxAxes]; AxesBitmap axisMinimaProbed, axisMaximaProbed; @@ -766,7 +766,6 @@ private: static bool WriteAxisLimits(FileStore *f, AxesBitmap axesProbed, const float limits[MaxAxes], int sParam); // Heaters - bed is assumed to be the first - Pin tempSensePins[Heaters]; Pin heatOnPins[Heaters]; Pin spiTempSenseCsPins[MaxSpiTempSensors]; @@ -774,7 +773,6 @@ private: uint32_t heatSampleTicks; // Fans - Fan fans[NUM_FANS]; Pin coolingFanRpmPin; // we currently support only one fan RPM input uint32_t lastFanCheckTime; @@ -782,7 +780,6 @@ private: bool FansHardwareInverted(size_t fanNumber) const; // Serial/USB - uint32_t baudRates[NUM_SERIAL_CHANNELS]; uint8_t commsParams[NUM_SERIAL_CHANNELS]; OutputStack *auxOutput; @@ -795,7 +792,6 @@ private: uint32_t auxSeq; // Sequence number for AUX devices // Files - MassStorage* massStorage; // Data used by the tick interrupt handler @@ -875,6 +871,9 @@ private: // Direct pin manipulation int8_t logicalPinModes[HighestLogicalPin + 1]; // what mode each logical pin is set to - would ideally be class PinMode not int8_t + + // Misc + bool deliberateError; // true if we deliberately caused an exception for testing purposes }; // Where the htm etc files are diff --git a/src/PortControl.cpp b/src/PortControl.cpp index 44cbdbdd..7c8a595a 100644 --- a/src/PortControl.cpp +++ b/src/PortControl.cpp @@ -73,13 +73,13 @@ bool PortControl::Configure(GCodeBuffer& gb, StringRef& reply) seen = true; UpdatePorts(0); numConfiguredPorts = 0; - long portNumbers[MaxPorts]; + uint32_t portNumbers[MaxPorts]; size_t numPorts = MaxPorts; - gb.GetLongArray(portNumbers, numPorts); + gb.GetUnsignedArray(portNumbers, numPorts); for (size_t i = 0; i < numPorts; ++i) { - const long pnum = portNumbers[i]; - if (pnum < 0 || pnum > HighestLogicalPin) + const uint32_t pnum = portNumbers[i]; + if (pnum > HighestLogicalPin) { reply.printf("Port number %ld out of range", pnum); return true; diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 8c564247..e8f88066 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -1034,6 +1034,9 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) } response->cat("]]"); + // Fan mapping + response->catf(",\"fans\":%lu", tool->GetFanMapping()); + // Filament (if any) if (tool->GetFilament() != nullptr) { @@ -1042,8 +1045,15 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) response->EncodeString(filamentName, strlen(filamentName), false); } - // Do we have any more tools? - response->cat((tool->Next() != nullptr) ? "}," : "}"); + // Offsets + response->cat(",\"offsets\":["); + for (size_t i = 0; i < numAxes; i++) + { + response->catf((i == 0) ? "%.2f" : ",%.2f", (double)tool->GetOffset(i)); + } + + // Do we have any more tools? + response->cat((tool->Next() != nullptr) ? "]}," : "]}"); } response->cat("]"); } diff --git a/src/RepRapFirmware.cpp b/src/RepRapFirmware.cpp index 8093866a..1e193f5e 100644 --- a/src/RepRapFirmware.cpp +++ b/src/RepRapFirmware.cpp @@ -169,7 +169,7 @@ Licence: GPL RepRap reprap; -const char *moduleName[] = +const char * const moduleName[] = { "Platform", "Network", @@ -193,7 +193,7 @@ const char *moduleName[] = // Utilities and storage not part of any class -static char scratchStringBuffer[170]; // this needs to be long enough to print delta parameters and 18 words of stack (162 bytes) +static char scratchStringBuffer[220]; // this needs to be long enough to print delta parameters and 24 words of stack (217 bytes) StringRef scratchString(scratchStringBuffer, ARRAY_SIZE(scratchStringBuffer)); // For debug use diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h index f37e0231..23022eda 100644 --- a/src/RepRapFirmware.h +++ b/src/RepRapFirmware.h @@ -59,7 +59,7 @@ enum Module : uint8_t noModule = 15 }; -extern const char *moduleName[]; +extern const char * const moduleName[]; // Warn of what's to come, so we can use pointers to classes without including the entire header files class Network; @@ -182,15 +182,15 @@ template<typename BitmapType> inline void ClearBit(BitmapType &b, unsigned int n } // Convert an array of longs to a bit map with overflow checking -template<typename BitmapType> BitmapType LongArrayToBitMap(const long *arr, size_t numEntries) +template<typename BitmapType> BitmapType UnsignedArrayToBitMap(const uint32_t *arr, size_t numEntries) { BitmapType res = 0; for (size_t i = 0; i < numEntries; ++i) { - const long f = arr[i]; - if (f >= 0 && (unsigned long)f < sizeof(BitmapType) * CHAR_BIT) + const uint32_t f = arr[i]; + if (f < sizeof(BitmapType) * CHAR_BIT) { - SetBit(res, (unsigned int)f); + SetBit(res, f); } } return res; diff --git a/src/Scanner.cpp b/src/Scanner.cpp index 7f849fbc..8afa2099 100644 --- a/src/Scanner.cpp +++ b/src/Scanner.cpp @@ -13,12 +13,12 @@ #include "Platform.h" -const char* ALIGN_ON_G = "align_on.g"; -const char* ALIGN_OFF_G = "align_off.g"; -const char* SCAN_PRE_G = "scan_pre.g"; -const char* SCAN_POST_G = "scan_post.g"; -const char* CALIBRATE_PRE_G = "calibrate_pre.g"; -const char* CALIBRATE_POST_G = "calibrate_post.g"; +const char* const ALIGN_ON_G = "align_on.g"; +const char* const ALIGN_OFF_G = "align_off.g"; +const char* const SCAN_PRE_G = "scan_pre.g"; +const char* const SCAN_POST_G = "scan_post.g"; +const char* const CALIBRATE_PRE_G = "calibrate_pre.g"; +const char* const CALIBRATE_POST_G = "calibrate_post.g"; void Scanner::Init() diff --git a/src/Storage/FileStore.cpp b/src/Storage/FileStore.cpp index 1ed6d654..c47bcce9 100644 --- a/src/Storage/FileStore.cpp +++ b/src/Storage/FileStore.cpp @@ -89,7 +89,10 @@ bool FileStore::Open(const char* directory, const char* fileName, OpenMode mode) } // Also try to allocate a write buffer so we can perform faster writes - writeBuffer = reprap.GetPlatform().GetMassStorage()->AllocateWriteBuffer(); + // We only do this if the mode is write, not append, because we don't want to use up a large buffer to append messages to the log file, + // especially as we need to flush messages to SD card regularly. + // Currently, append mode is used only for the log file. + writeBuffer = (mode == OpenMode::write) ? reprap.GetPlatform().GetMassStorage()->AllocateWriteBuffer() : nullptr; } const FRESULT openReturn = f_open(&file, location, diff --git a/src/Storage/FileWriteBuffer.h b/src/Storage/FileWriteBuffer.h index c7a04116..d5198e8c 100644 --- a/src/Storage/FileWriteBuffer.h +++ b/src/Storage/FileWriteBuffer.h @@ -10,7 +10,6 @@ #include "RepRapFirmware.h" - #if SAM4E || SAM4S || SAME70 const size_t NumFileWriteBuffers = 2; // Number of write buffers const size_t FileWriteBufLen = 8192; // Size of each write buffer @@ -19,7 +18,6 @@ const size_t NumFileWriteBuffers = 1; const size_t FileWriteBufLen = 4096; #endif - // Class to cache data that is about to be written to the SD card. This is NOT a ring buffer, // instead it just provides simple interfaces to cache a certain amount of data so that fewer // f_write() calls are needed. This effectively improves upload speeds. @@ -36,14 +34,14 @@ public: const size_t BytesStored() const { return index; } const size_t BytesLeft() const { return FileWriteBufLen - index; } - size_t Store(const char *data, size_t length); // Stores some data and returns how much could be stored - void DataTaken() { index = 0; } // Called to indicate that the buffer has been written + size_t Store(const char *data, size_t length); // Stores some data and returns how much could be stored + void DataTaken() { index = 0; } // Called to indicate that the buffer has been written private: FileWriteBuffer *next; size_t index; - int32_t data32[FileWriteBufLen / sizeof(int32_t)]; // 32-bit aligned buffer for better HSMCI performance + uint32_t data32[FileWriteBufLen / sizeof(uint32_t)]; // 32-bit aligned buffer for better HSMCI performance }; inline size_t FileWriteBuffer::Store(const char *data, size_t length) diff --git a/src/Tools/Filament.cpp b/src/Tools/Filament.cpp index 2efb50a4..13113bc3 100644 --- a/src/Tools/Filament.cpp +++ b/src/Tools/Filament.cpp @@ -13,8 +13,8 @@ #include <ctime> -const char *Filament::FilamentAssignmentFile = "filaments.csv"; -const char *Filament::FilamentAssignmentFileComment = "RepRapFirmware filament assignment file v1"; +const char * const Filament::FilamentAssignmentFile = "filaments.csv"; +const char * const Filament::FilamentAssignmentFileComment = "RepRapFirmware filament assignment file v1"; Filament *Filament::filamentList = nullptr; diff --git a/src/Tools/Filament.h b/src/Tools/Filament.h index bdccf8a6..58ebd1a7 100644 --- a/src/Tools/Filament.h +++ b/src/Tools/Filament.h @@ -35,8 +35,8 @@ public: static Filament *GetFilamentByExtruder(const int extruder); // Retrieve the Filament instance assigned to the given extruder drive private: - static const char *FilamentAssignmentFile; // In which file the extruder <-> filament assignments are stored - static const char *FilamentAssignmentFileComment; // The comment we write at the start of this file to ensure its integrity + static const char * const FilamentAssignmentFile; // In which file the extruder <-> filament assignments are stored + static const char * const FilamentAssignmentFileComment; // The comment we write at the start of this file to ensure its integrity static Filament *filamentList; Filament *next; diff --git a/src/Tools/Tool.cpp b/src/Tools/Tool.cpp index cbda3524..8047ac60 100644 --- a/src/Tools/Tool.cpp +++ b/src/Tools/Tool.cpp @@ -81,7 +81,7 @@ Tool * Tool::freelist = nullptr; if (dCount == 1) { // Create only one Filament instance per extruder drive, and only if this tool is assigned to exactly one extruder - Filament *filament = Filament::GetFilamentByExtruder(d[0]); + Filament * const filament = Filament::GetFilamentByExtruder(d[0]); t->filament = (filament == nullptr) ? new Filament(d[0]) : filament; } else @@ -90,9 +90,19 @@ Tool * Tool::freelist = nullptr; t->filament = nullptr; } - t->myNumber = toolNumber; - SafeStrncpy(t->name, name, ToolNameLength); + const size_t nameLength = strlen(name); + if (nameLength != 0) + { + t->name = new char[nameLength + 1]; + SafeStrncpy(t->name, name, nameLength + 1); + } + else + { + t->name = nullptr; + } + t->next = nullptr; + t->myNumber = toolNumber; t->state = ToolState::off; t->driveCount = dCount; t->heaterCount = hCount; @@ -111,7 +121,7 @@ Tool * Tool::freelist = nullptr; for (size_t drive = 0; drive < t->driveCount; drive++) { t->drives[drive] = d[drive]; - t->mix[drive] = (drive == 0) ? 1.0 : 0.0; // initial mix ratio is 1:1:0 + t->mix[drive] = (drive == 0) ? 1.0 : 0.0; // initial mix ratio is 1:0:0 } for (size_t heater = 0; heater < t->heaterCount; heater++) @@ -133,6 +143,8 @@ Tool * Tool::freelist = nullptr; { if (t != nullptr) { + delete t->name; + t->name = nullptr; t->filament = nullptr; t->next = freelist; freelist = t; @@ -142,7 +154,7 @@ Tool * Tool::freelist = nullptr; void Tool::Print(StringRef& reply) const { reply.printf("Tool %d - ", myNumber); - if (!StringEquals(name, "")) + if (name != nullptr) { reply.catf("name: %s; ", name); } @@ -392,7 +404,7 @@ void Tool::UpdateExtruderAndHeaterCount(uint16_t &numExtruders, uint16_t &numHea for (size_t heater = 0; heater < heaterCount; heater++) { - if (!reprap.GetHeat().IsBedHeater(heaters[heater]) && !reprap.GetHeat().IsChamberHeater(heaters[heater]) && heaters[heater] >= numHeaters) + if (!reprap.GetHeat().IsBedOrChamberHeater(heaters[heater]) && heaters[heater] >= numHeaters) { numHeaters = heaters[heater] + 1; } diff --git a/src/Tools/Tool.h b/src/Tools/Tool.h index 5e56b1d0..b5d5063f 100644 --- a/src/Tools/Tool.h +++ b/src/Tools/Tool.h @@ -28,9 +28,9 @@ Licence: GPL #include "RepRapFirmware.h" -const size_t ToolNameLength = 32; // maximum allowed length for tool names -const AxesBitmap DefaultXAxisMapping = 1u << X_AXIS; // by default, X is mapped to X -const AxesBitmap DefaultYAxisMapping = 1u << Y_AXIS; // by default, Y is mapped to Y +constexpr size_t ToolNameLength = 32; // maximum allowed length for tool names +constexpr AxesBitmap DefaultXAxisMapping = 1u << X_AXIS; // by default, X is mapped to X +constexpr AxesBitmap DefaultYAxisMapping = 1u << Y_AXIS; // by default, Y is mapped to Y enum class ToolState : uint8_t { @@ -40,6 +40,7 @@ enum class ToolState : uint8_t }; class Filament; + class Tool { public: @@ -85,25 +86,27 @@ protected: private: static Tool *freelist; + Tool() : next(nullptr), filament(nullptr), name(nullptr) { } + void SetTemperatureFault(int8_t dudHeater); void ResetTemperatureFault(int8_t wasDudHeater); bool AllHeatersAtHighTemperature(bool forExtrusion) const; - int myNumber; - char name[ToolNameLength]; - int drives[MaxExtruders]; + Tool* next; + Filament *filament; + char *name; + float offset[MaxAxes]; float mix[MaxExtruders]; - size_t driveCount; - int heaters[Heaters]; float activeTemperatures[Heaters]; float standbyTemperatures[Heaters]; + size_t driveCount; size_t heaterCount; - float offset[MaxAxes]; - AxesBitmap axisOffsetsProbed; + int myNumber; AxesBitmap xMapping, yMapping; + AxesBitmap axisOffsetsProbed; FansBitmap fanMapping; - Filament *filament; - Tool* next; + uint8_t drives[MaxExtruders]; + int8_t heaters[Heaters]; ToolState state; bool heaterFault; @@ -127,7 +130,7 @@ inline int Tool::Heater(size_t heaterNumber) const inline const char *Tool::GetName() const { - return name; + return (name == nullptr) ? "" : name; } inline int Tool::Number() const diff --git a/src/Version.h b/src/Version.h index 29703760..0a3ebf75 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.20RC1" +# define VERSION "1.20RC2" #endif #ifndef DATE -# define DATE "2017-12-08" +# define DATE "2017-12-13" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" diff --git a/src/ZProbeProgrammer.cpp b/src/ZProbeProgrammer.cpp index 5eb63789..d6a12f7b 100644 --- a/src/ZProbeProgrammer.cpp +++ b/src/ZProbeProgrammer.cpp @@ -19,7 +19,7 @@ ZProbeProgrammer::ZProbeProgrammer() } // Kick off sending some program bytes -void ZProbeProgrammer::SendProgram(const long zProbeProgram[], size_t len) +void ZProbeProgrammer::SendProgram(const uint32_t zProbeProgram[], size_t len) { timer.CancelCallback(); // make quite certain that this timer isn't already pending diff --git a/src/ZProbeProgrammer.h b/src/ZProbeProgrammer.h index ab0bf478..02e37973 100644 --- a/src/ZProbeProgrammer.h +++ b/src/ZProbeProgrammer.h @@ -15,7 +15,7 @@ class ZProbeProgrammer public: ZProbeProgrammer(); - void SendProgram(const long zProbeProgram[], size_t len); + void SendProgram(const uint32_t zProbeProgram[], size_t len); private: static bool TimerInterrupt(void *param, uint32_t& when); |