diff options
author | David Crocker <dcrocker@eschertech.com> | 2021-06-13 01:21:27 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2021-06-13 01:21:27 +0300 |
commit | a7fde45b618c76c03516696d670dd665282873da (patch) | |
tree | 250ec090839017aeac12e7cefa9d1f19dea35835 | |
parent | 92b7d130d974b6b62780e68d32717a7c6567db6e (diff) |
Various
Support layer counting in GCode files generated by SuperSlicer
When reporting a bad command, display any non-printing characters in hex
Support measuring fan RPMs down to 160 instead of down to 320
After turning a remote heater on, if it was previously off then set its
status to 'heating' pending receiving updated status for it, to make
sure that M116 waits for it
-rw-r--r-- | src/CAN/CanInterface.cpp | 40 | ||||
-rw-r--r-- | src/CAN/CanInterface.h | 3 | ||||
-rw-r--r-- | src/CAN/CanMotion.cpp | 10 | ||||
-rw-r--r-- | src/Fans/LocalFan.h | 2 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.cpp | 16 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.h | 2 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 28 | ||||
-rw-r--r-- | src/Heating/RemoteHeater.cpp | 9 | ||||
-rw-r--r-- | src/Movement/DDA.cpp | 2 | ||||
-rw-r--r-- | src/Movement/DDA.h | 10 | ||||
-rw-r--r-- | src/Movement/DDARing.cpp | 7 | ||||
-rw-r--r-- | src/Platform/TaskPriorities.h | 4 | ||||
-rw-r--r-- | src/PrintMonitor/PrintMonitor.cpp | 8 | ||||
-rw-r--r-- | src/PrintMonitor/PrintMonitor.h | 1 | ||||
-rw-r--r-- | src/Version.h | 2 |
15 files changed, 105 insertions, 39 deletions
diff --git a/src/CAN/CanInterface.cpp b/src/CAN/CanInterface.cpp index 764a73c2..710f14e9 100644 --- a/src/CAN/CanInterface.cpp +++ b/src/CAN/CanInterface.cpp @@ -179,8 +179,12 @@ static Task<CanReceiverTaskStackWords> canReceiverTask; constexpr size_t CanClockTaskStackWords = 400; // used to be 300 but RD had a stack overflow static Task<CanSenderTaskStackWords> canClockTask; -static CanMessageBuffer * volatile pendingBuffers; -static CanMessageBuffer * volatile lastBuffer; // only valid when pendingBuffers != nullptr +static CanMessageBuffer * volatile pendingMotionBuffers = nullptr; +static CanMessageBuffer * volatile lastMotionBuffer; // only valid when pendingBuffers != nullptr + +#if 0 //unused +static unsigned int numPendingMotionBuffers = 0; +#endif extern "C" [[noreturn]] void CanSenderLoop(void *) noexcept; extern "C" [[noreturn]] void CanClockLoop(void *) noexcept; @@ -239,7 +243,7 @@ void TxCallback(uint8_t marker, CanId id, uint16_t timeStamp) noexcept void CanInterface::Init() noexcept { CanMessageBuffer::Init(NumCanBuffers); - pendingBuffers = nullptr; + pendingMotionBuffers = nullptr; transactionMutex.Create("CanTrans"); @@ -369,13 +373,16 @@ extern "C" [[noreturn]] void CanSenderLoop(void *) noexcept { can0dev->SendMessage(TxBufferIndexUrgent, MaxUrgentSendWait, urgentMessage); } - else if (pendingBuffers != nullptr) + else if (pendingMotionBuffers != nullptr) { CanMessageBuffer *buf; { TaskCriticalSectionLocker lock; - buf = pendingBuffers; - pendingBuffers = buf->next; + buf = pendingMotionBuffers; + pendingMotionBuffers = buf->next; +#if 0 //unused + --numPendingMotionBuffers; +#endif } // Send the message @@ -617,20 +624,33 @@ void CanInterface::SendMotion(CanMessageBuffer *buf) noexcept { TaskCriticalSectionLocker lock; - if (pendingBuffers == nullptr) + if (pendingMotionBuffers == nullptr) { - pendingBuffers = buf; + pendingMotionBuffers = buf; } else { - lastBuffer->next = buf; + lastMotionBuffer->next = buf; } - lastBuffer = buf; + lastMotionBuffer = buf; +#if 0 //unused + ++numPendingMotionBuffers; +#endif } canSenderTask.Give(); } +#if 0 // not currently used + +// Get the number of motion messages waiting to be sent through the Tx fifo +unsigned int CanInterface::GetNumPendingMotionMessages() noexcept +{ + return can0dev->NumTxMessagesPending(TxBufferIndexMotion) + numPendingMotionBuffers; +} + +#endif + // Send a request to an expansion board and append the response to 'reply' GCodeResult CanInterface::SendRequestAndGetStandardReply(CanMessageBuffer *buf, CanRequestId rid, const StringRef& reply, uint8_t *extra) noexcept { diff --git a/src/CAN/CanInterface.h b/src/CAN/CanInterface.h index 50aecfd7..8ee3b0b1 100644 --- a/src/CAN/CanInterface.h +++ b/src/CAN/CanInterface.h @@ -106,6 +106,9 @@ namespace CanInterface GCodeResult SetRemoteDriverStepsPerMmAndMicrostepping(const CanDriversData<StepsPerUnitAndMicrostepping>& data, const StringRef& reply) noexcept; GCodeResult ConfigureRemoteDriver(DriverId driver, GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException); GCodeResult GetSetRemoteDriverStallParameters(const CanDriversList& drivers, GCodeBuffer& gb, const StringRef& reply, OutputBuffer *& buf) THROWS(GCodeException); +#if 0 // not currently used + unsigned int GetNumPendingMotionMessages() noexcept; +#endif void WakeAsyncSenderFromIsr() noexcept; // Remote handle functions diff --git a/src/CAN/CanMotion.cpp b/src/CAN/CanMotion.cpp index 6c8e72b6..c1c82dc2 100644 --- a/src/CAN/CanMotion.cpp +++ b/src/CAN/CanMotion.cpp @@ -17,6 +17,10 @@ static CanMessageBuffer *movementBufferList = nullptr; static CanMessageBuffer *urgentMessageBuffer = nullptr; static uint32_t currentMoveClocks; +#if 0 +static unsigned int numMotionMessagesSentLast = 0; +#endif + static volatile uint32_t hiccupToInsert = 0; static CanDriversList driversToStop[2]; static size_t driversToStopIndexBeingFilled = 0; @@ -128,6 +132,9 @@ uint32_t CanMotion::FinishMovement(uint32_t moveStartTime) noexcept return 0; } +#if 0 + numMotionMessagesSentLast = 0; +#endif do { boardsActiveInLastMove.SetBit(buf->id.Dst()); //TODO should we set this if there were no steps for drives on the board, just drives to be enabled? @@ -138,6 +145,9 @@ uint32_t CanMotion::FinishMovement(uint32_t moveStartTime) noexcept buf->dataLength = buf->msg.moveLinear.GetActualDataLength(); CanMessageBuffer * const nextBuffer = buf->next; // must get this before sending the buffer, because sending the buffer releases it CanInterface::SendMotion(buf); // queues the buffer for sending and frees it when done +#if 0 + ++numMotionMessagesSentLast; +#endif buf = nextBuffer; } while (buf != nullptr); diff --git a/src/Fans/LocalFan.h b/src/Fans/LocalFan.h index 469053a7..7178833f 100644 --- a/src/Fans/LocalFan.h +++ b/src/Fans/LocalFan.h @@ -46,7 +46,7 @@ private: float lastVal; // the last PWM value we sent to the fan, not allowing for blipping, or -1 if we don't know it // Variables used to read the tacho - static constexpr uint32_t fanMaxInterruptCount = 32; // number of fan interrupts that we average over + static constexpr uint32_t fanMaxInterruptCount = 16; // number of fan interrupts that we average over. We time out after 3 seconds, so a count of 16 allows us to read rpm down to (16/3) * (60/2) = 160. uint32_t fanInterruptCount; // accessed only in ISR, so no need to declare it volatile volatile uint32_t fanLastResetTime; // time (in step clocks) at which we last reset the interrupt count, accessed inside and outside ISR volatile uint32_t fanInterval; // written by ISR, read outside the ISR diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp index abf822e5..8b4df0f0 100644 --- a/src/GCodes/GCodeBuffer/StringParser.cpp +++ b/src/GCodes/GCodeBuffer/StringParser.cpp @@ -266,7 +266,7 @@ bool StringParser::Put(char c) noexcept // This is called when we are fed a null, CR or LF character. // Return true if there is a completed command ready to be executed. -bool StringParser::LineFinished() +bool StringParser::LineFinished() noexcept { if (hadLineNumber) { @@ -1486,9 +1486,21 @@ void StringParser::PrintCommand(const StringRef& s) const noexcept } // Append the full command content to a string +// This is called when we report a "Bad command" error, so make sure we display any control characters. void StringParser::AppendFullCommand(const StringRef &s) const noexcept { - s.cat(gb.buffer); + for (size_t i = commandStart; i < commandEnd; ++i) + { + const char c = gb.buffer[i]; + if (c < 0x20) + { + s.catf("[0x%02x]", (unsigned int)c); + } + else + { + s.cat(c); + } + } } // Called when we start a new file diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h index a4b828fe..3e7c515b 100644 --- a/src/GCodes/GCodeBuffer/StringParser.h +++ b/src/GCodes/GCodeBuffer/StringParser.h @@ -92,7 +92,7 @@ private: void AddToChecksum(char c) noexcept; void StoreAndAddToChecksum(char c) noexcept; - bool LineFinished() THROWS(GCodeException); // Deal with receiving end-of-line and return true if we have a command + bool LineFinished() noexcept; // Deal with receiving end-of-line and return true if we have a command void InternalGetQuotedString(const StringRef& str) THROWS(GCodeException) pre (readPointer >= 0; gb.buffer[readPointer] == '"'; str.IsEmpty()); void InternalGetPossiblyQuotedString(const StringRef& str) THROWS(GCodeException) diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index ed140fb7..b48ae06b 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -38,9 +38,11 @@ #endif #ifdef I2C_IFACE -# include "Wire.h" +# include <Wire.h> #endif +#include <cctype> + // Deal with G60 GCodeResult GCodes::SavePosition(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) { @@ -1650,29 +1652,29 @@ bool GCodes::ProcessWholeLineComment(GCodeBuffer& gb, const StringRef& reply) TH "BEGIN_LAYER_OBJECT z=", // KISSlicer (followed by Z height) "HEIGHT", // Ideamaker "PRINTING", // Ideamaker - "REMAINING_TIME" // Ideamaker + "REMAINING_TIME", // Ideamaker + "LAYER_CHANGE" // SuperSlicer }; String<StringLength100> comment; gb.GetCompleteParameters(comment.GetRef()); - const char *text = comment.c_str(); - while (*text == ' ') + const char *fullText = comment.c_str(); + while (*fullText == ' ') { - ++text; + ++fullText; } for (size_t i = 0; i < ARRAY_SIZE(StartStrings); ++i) { - if (StringStartsWith(text, StartStrings[i])) + if (StringStartsWith(fullText, StartStrings[i])) { - text += strlen(StartStrings[i]); - if (*text == ' ' || *text == ':') // need this test to avoid recognising "processName" as "process" + const char *text = fullText + strlen(StartStrings[i]); + if (!isalpha(*text) && *text != '_') // need this test to avoid recognising "processName" as "process" { - do + while (*text == ' ' || *text == ':') { ++text; } - while (*text == ' ' || *text == ':'); switch (i) { @@ -1717,7 +1719,7 @@ bool GCodes::ProcessWholeLineComment(GCodeBuffer& gb, const StringRef& reply) TH case 4: // layer (counting from 1) case 5: // layer (counting from 0) - case 6: // later (counting from 0) + case 6: // layer (counting from 0) { const char *endptr; const int32_t layer = StrToI32(text, &endptr); // IdeaMaker uses negative layer numbers for the raft, so read a signed number here @@ -1756,6 +1758,10 @@ bool GCodes::ProcessWholeLineComment(GCodeBuffer& gb, const StringRef& reply) TH } } break; + + case 11: // LAYER_CHANGE (SuperSlicer). No layer number provided. + reprap.GetPrintMonitor().LayerChange(); + break; } break; } diff --git a/src/Heating/RemoteHeater.cpp b/src/Heating/RemoteHeater.cpp index e4cf368d..8bdfe5f3 100644 --- a/src/Heating/RemoteHeater.cpp +++ b/src/Heating/RemoteHeater.cpp @@ -385,7 +385,14 @@ GCodeResult RemoteHeater::SwitchOn(const StringRef& reply) noexcept msg->heaterNumber = GetHeaterNumber(); msg->setPoint = GetTargetTemperature(); msg->command = CanMessageSetHeaterTemperature::commandOn; - return CanInterface::SendRequestAndGetStandardReply(buf, rid, reply); + const GCodeResult rslt = CanInterface::SendRequestAndGetStandardReply(buf, rid, reply); + if (lastMode == HeaterMode::off && rslt <= GCodeResult::warning) + { + // If the heater was previously off then we need to change lastMode, otherwise if M116 is executed before we get an update from the expansion board + // then it will treat the heater as inactive and not wait for it to reach temperature + lastMode = HeaterMode::heating; + } + return rslt; } // This is called when the heater model has been updated diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index 5870f59c..89959ee0 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -1576,7 +1576,7 @@ void DDA::Prepare(uint8_t simMode, float extrusionPending[]) noexcept const DDAState st = prev->state; afterPrepare.moveStartTime = (st == DDAState::executing || st == DDAState::frozen) ? prev->afterPrepare.moveStartTime + prev->clocksNeeded // this move will follow the previous one, so calculate the start time assuming no more hiccups - : StepTimer::GetTimerTicks() + MovementStartDelayClocks; // else this move is the first so start it after a short delay + : StepTimer::GetTimerTicks() + AbsoluteMinimumPreparedTime; // else this move is the first so start it after a short delay if (flags.checkEndstops) { diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index 22c65780..3db44ded 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -113,6 +113,7 @@ public: #if SUPPORT_LASER || SUPPORT_IOBITS LaserPwmOrIoBits GetLaserPwmOrIoBits() const noexcept { return laserPwmOrIoBits; } + bool ControlLaser() const noexcept { return flags.controlLaser; } #endif #if SUPPORT_LASER @@ -135,6 +136,8 @@ public: void DebugPrint(const char *tag) const noexcept; // print the DDA only void DebugPrintAll(const char *tag) const noexcept; // print the DDA and active DMs + static void PrintMoves() noexcept; // print saved moves for debugging + // Note on the following constant: // If we calculate the step interval on every clock, we reach a point where the calculation time exceeds the step interval. // The worst case is pure Z movement on a delta. On a Mini Kossel with 80 steps/mm with this firmware running on a Duet (84MHx SAM3X8 processor), @@ -163,7 +166,8 @@ public: static constexpr uint32_t WakeupTime = (100 * StepTimer::StepClockRate)/1000000; // stop resting 100us before the move is due to end static constexpr uint32_t HiccupIncrement = HiccupTime/2; // how much we increase the hiccup time by on each attempt - static void PrintMoves() noexcept; // print saved moves for debugging + static constexpr uint32_t UsualMinimumPreparedTime = StepTimer::StepClockRate/10; // 100ms + static constexpr uint32_t AbsoluteMinimumPreparedTime = StepTimer::StepClockRate/20; // 50ms #if DDA_LOG_PROBE_CHANGES static const size_t MaxLoggedProbePositions = 40; @@ -171,10 +175,6 @@ public: static int32_t loggedProbePositions[XYZ_AXES * MaxLoggedProbePositions]; #endif -#if SUPPORT_LASER || SUPPORT_IOBITS - bool ControlLaser() const noexcept { return flags.controlLaser; } -#endif - static uint32_t lastStepLowTime; // when we last completed a step pulse to a slow driver static uint32_t lastDirChangeTime; // when we last change the DIR signal to a slow driver diff --git a/src/Movement/DDARing.cpp b/src/Movement/DDARing.cpp index cb765e53..11108208 100644 --- a/src/Movement/DDARing.cpp +++ b/src/Movement/DDARing.cpp @@ -15,9 +15,6 @@ # include "CAN/CanMotion.h" #endif -constexpr uint32_t UsualMinimumPreparedTime = StepTimer::StepClockRate/10; // 100ms -constexpr uint32_t AbsoluteMinimumPreparedTime = StepTimer::StepClockRate/20; // 50ms - // Object model table and functions // Note: if using GCC version 7.3.1 20180622 and lambda functions are used in this table, you must compile this file with option -std=gnu++17. // Otherwise the table will be allocated in RAM instead of flash, which wastes too much RAM. @@ -357,9 +354,9 @@ void DDARing::PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, unsig // If the number of prepared moves will execute in less than the minimum time, prepare another move. // Try to avoid preparing deceleration-only moves too early while ( firstUnpreparedMove->GetState() == DDA::provisional - && moveTimeLeft < (int32_t)UsualMinimumPreparedTime // prepare moves one eighth of a second ahead of when they will be needed + && moveTimeLeft < (int32_t)DDA::UsualMinimumPreparedTime // prepare moves one tenth of a second ahead of when they will be needed && alreadyPrepared * 2 < numDdasInRing // but don't prepare more than half the ring - && (firstUnpreparedMove->IsGoodToPrepare() || moveTimeLeft < (int32_t)AbsoluteMinimumPreparedTime) + && (firstUnpreparedMove->IsGoodToPrepare() || moveTimeLeft < (int32_t)DDA::AbsoluteMinimumPreparedTime) #if SUPPORT_CAN_EXPANSION && CanMotion::CanPrepareMove() #endif diff --git a/src/Platform/TaskPriorities.h b/src/Platform/TaskPriorities.h index b65f1568..36545a55 100644 --- a/src/Platform/TaskPriorities.h +++ b/src/Platform/TaskPriorities.h @@ -14,7 +14,7 @@ namespace TaskPriority constexpr int IdlePriority = 0; constexpr int SpinPriority = 1; // priority for tasks that rarely block #if HAS_LINUX_INTERFACE - constexpr int SbcPriority = 1; // priority for SBC task + constexpr int SbcPriority = 1; // priority for SBC task. TODO increase this when we are certain that it never spins. #endif #if defined(LPC_NETWORKING) constexpr int TcpPriority = 2; @@ -26,7 +26,9 @@ namespace TaskPriority constexpr int TmcPriority = 4; constexpr int AinPriority = 4; constexpr int HeightFollowingPriority = 4; +#ifdef DUET_NG constexpr int DueXPriority = 5; +#endif constexpr int LaserPriority = 5; constexpr int CanSenderPriority = 5; constexpr int CanReceiverPriority = 5; diff --git a/src/PrintMonitor/PrintMonitor.cpp b/src/PrintMonitor/PrintMonitor.cpp index 64661cb9..4cf8f2ed 100644 --- a/src/PrintMonitor/PrintMonitor.cpp +++ b/src/PrintMonitor/PrintMonitor.cpp @@ -346,6 +346,14 @@ void PrintMonitor::SetLayerZ(float layerZ) noexcept // Currently we don't use the layerZ value } +// Report that a new layer has started +void PrintMonitor::LayerChange() noexcept +{ + ++currentLayer; + lastLayerChangeTime = millis64(); + lastLayerChangeNonPrintingTime = GetWarmUpDuration() + GetPauseDuration(); +} + float PrintMonitor::FractionOfFilePrinted() const noexcept { ReadLocker locker(printMonitorLock); diff --git a/src/PrintMonitor/PrintMonitor.h b/src/PrintMonitor/PrintMonitor.h index 16ae6b62..5ff5406f 100644 --- a/src/PrintMonitor/PrintMonitor.h +++ b/src/PrintMonitor/PrintMonitor.h @@ -44,6 +44,7 @@ public: void StoppedPrint() noexcept; // Called whenever a file print has stopped void SetLayerNumber(uint32_t layerNumber) noexcept; // Set the current layer number void SetLayerZ(float layerZ) noexcept; // Set the printing height of the new layer + void LayerChange() noexcept; // Report that a new layer has started float FractionOfFilePrinted() const noexcept; // Return the fraction printed (0..1) // Return an estimate in seconds based on a specific estimation method diff --git a/src/Version.h b/src/Version.h index f31ac080..f1076245 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,7 +9,7 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define MAIN_VERSION "3.3RC3+6" +# define MAIN_VERSION "3.3RC3+7" # ifdef USE_CAN0 # define VERSION_SUFFIX " (CAN0)" # else |