diff options
author | David Crocker <dcrocker@eschertech.com> | 2018-03-11 14:16:57 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2018-03-11 14:16:57 +0300 |
commit | b1369644379aa9c6a1dd8f84d20210f32ded6dd5 (patch) | |
tree | 0d5e376cc33d1344e6d007540127b2746f1803be | |
parent | afd7e327ec71865a2ecf0243265ef6f84387becb (diff) |
Version 1.21RC4(11b1)
New features:
- On CoreXZ machines we no longer require Z to be homed before bed
probing with G30
- M589 now checks that the password is either empty or 8 characters
minimum
- G10 L2 is supported as an alternative way to set tool offsets
- G10 L20 is supported as an alternative way to set workspace
coordinates
- Heater fault detection is suppressed when heaters are suspended during
bed probing
- DuetWiFiServer/bin uses a new SDK version, which seems to resolve some
issues
- On boards with a W5500 Ethernet interface, the Ethernet PHY is now
programmed to auto negotiate
- Added M564 H0 command to allow axis movement before homing on
Cartesian/CoreXY printers
- The filament length comment proposed to be generated by the next
version of Cura when using more than one filament is supported
Bug fixes:
- I parameter on M452, M453 and M573 didn't work
- If a homing file contained an illegal movement command then homing was
not cancelled
- Corrected Z probe input pin in RADDS build
- Possible fix to Duet 06/085 failure to start when using DHCP
44 files changed, 681 insertions, 394 deletions
diff --git a/src/BugList.txt b/src/BugList.txt new file mode 100644 index 00000000..0afe7b67 --- /dev/null +++ b/src/BugList.txt @@ -0,0 +1,160 @@ +RRF 1.20 work list + +Done in 1.21RC1: +- [done, reported ok] nonlinear extrusion bug, see https://www.duet3d.com/forum/thread.php?pid=34811#p34811 (not updating netSteps?) +- [done, ok] M574 reported active low switches as "unknown type" +- [done, ok] If no temp sensor configured, M305 Px should say so instead of allocating a thermistor +- [done] "Warning: Error: short to ground on driver(s) 3" +- [done, ok] Bug: M350 E32 affects only 1st extruder +- [done, ok] FTP listen failed problem, \bin\curl\curl -vvv ftp://192.168.1.98/sys/bed.g +- [done, test] M304 bug fix +- [done, test] Support M260 I2C code +- [done, test] Support M261 I2C code +- [done, test] absolute babystepping mode +- [done, test] Missing check on valid pin number in attachInterrupt, causes reset if you try to use a filament monitor on a DueX endstop input +- [don't do, instead consider new GCode to set pause point + G92 R option] add G92 Z command to resurrect.g +- [done, ok] Jerky curves with pressure advance, see https://www.duet3d.com/forum/thread.php?pid=35688#p35688 also see Ian's blog. Need to reduce extruder jerk speed due to the need to jerk steps. +- [done, test] Endstops 5-10 when no DueX board present +- [done, ok] Show board revision as 1.02 if VSSA sense present +- [done] Disabled cache +- [done, ok] Double probe touch + +Done in 1.21RC2: +- [done, ok] Unified wifi/Ethernet firmware +- [done, working] Support Ideamaker filament used, see https://github.com/dc42/RepRapFirmware/issues/151 +- [done, working] bltouch separate probe type +- [done, working] option to disable heaters when probing, B1 in M558 +- [done, working] constant time password compare +- [done, ok judging from M671 readback] M671 to allow 1 pair of XY coordinates to clear settings +- [done, SCARA looks OK] SCARA and polar continuous rotation +- [done, ok] start.g file +- [done, ok] M0/M1 from PanelDue etc. no longer cancels a non-paused print +- [done, ok] when Z probe readings are out of tolerance, use the average in G32 bed probing +- [done, test] count and report I2C errors in diagnostics +- [done, working] G29 fixes (square delta height map and multi touch) +- [done, working] M207 retract hop changed while retracted +- [done, all working] Test expansion connector endstop inputs +- [done, working] Test 404 page when no files present, change it to give a useful message instead of blank screen + +1.21RC3: +- [done, ok] Duet Ethernet/M DHCP fixes +- [done, ok] prohibit movement until homed +- [done, ok] recovery time before all taps, not just the first +- [done, ok] https://www.duet3d.com/forum/thread.php?pid=37605#p37605 (rotating magnet filament monitor) +- [done, ok] During simulation, send status 'M' +- [done, ok] M39 result to include cluster size +- [done, ok] No error message if you try to turn off a non existent bed or chamber heater +- [done, ok] Implement G60 +- [done, ok] bug fix for M556 S0 +- [done, ok] check G2/G3 against axis limits +- [done, ok] M671 to allow correction factor 'F' +- [done, ok] can set standstill current fraction on Duet M +- [done, ok] https://www.duet3d.com/forum/thread.php?pid=37629#p37629 (issues getting info from large files) +- [done, ok] https://www.duet3d.com/forum/thread.php?pid=39637#p39637 (ftp doesn't work with 1.21RC2 DWS) +- [done, no test] added M118 support from chrishamm +- [done, no test] when using any external drivers, don't change DIR before end of STEP pulse +- [done] bug fix for multi tap with M558 P9 +- [done, test] M452, M453 and M573 option to invert laser/spindle/extrusion signal (I1 parameter) +- [done, test?] endstops 5-9 allowed for simple filament sensors +- [done, believed fixed] https://www.duet3d.com/forum/thread.php?pid=40154#p40154 (incorrect resume point after pause) +- [done, should be better] https://www.duet3d.com/forum/thread.php?pid=40183#p40183, https://www.duet3d.com/forum/thread.php?pid=39509#p39509 (not starting up correctly in access point mode) +- [done] Attempted movements outside limits or when not homed cause current print file to be aborted + +Remaining: +- [done] for CoreXZ require just X and Y to be homed before probing (so that G30 can be used to home Z axis) +- [done, test] Check min. 8 character password in M589, see https://www.duet3d.com/forum/thread.php?pid=40914#p40914 +- [done] G10 L2 +- [done] G10 L20 +- [done, test] Suppress heater fault detection when heaters are suspended +- [done] DuetWiFiServer: new SDK version +- [problem gone away with latest DuetWiFiServer] Duet WiFi (Kossel): disconnects every time after I upload file xyzCalibration_cube s3d.gcode due to incomplete json reply, but can reconnect afterwards +- [done] Ethernet: set W5500 to auto negotiate +- [done, test] I parameter on M452, M453 and M573 didn't work +- [done, test] M564 H0 to allow axis movement before homing on Cartesian/CoreXY printers +- [done, test] Filament length comment generated by Cura, see https://www.duet3d.com/forum/thread.php?pid=40913#p40913 +- [done, test] Doesn't cancel homeall.g if there is an illegal Z move at the start, https://www.duet3d.com/forum/thread.php?pid=41082#p41082 + +- How should we lift X on a CoreXZ printer before homing? +- Multi tap on G30? + +- if a homing command in an SD print file is aborted due to e.g. G1 Z5 in the homing file, error message should be written to both DWC and PanelDue +- M116 issue +- [made a change, but try to reproduce it] Duet 0.8/0.8.5 DHCP issue, https://www.duet3d.com/forum/thread.php?pid=34605#p34605 +- stall detect on Z axis +- Files generated by Cura doesn't detect layer changes, see https://www.duet3d.com/forum/thread.php?pid=40865#p40865 +- [re-test using new DuetWiFiServer] "Failed to change mode" messages after M552 S2/S0/S1 cycle +- [can't reproduce] "Attempt to seek on a non-open file", https://www.duet3d.com/forum/thread.php?pid=41175#p41175 +- Test smart effector sensitivity programming + +- min/max RSSI display? + +- [hopefully this is fixed by the DHCP fixes] https://www.duet3d.com/forum/thread.php?pid=37797#p37797 (Duet Ethernet long delays between moves) +- [no idea, bus fault in pbuf_cat] Look at https://www.duet3d.com/forum/thread.php?pid=37551#p37551 + +- save theta, phi in move and then in DDA? +- report RSSI in M552? + +- When Z probe readings are out of tolerance, display the lowest difference seen between consecutive readings + +- laser control, https://www.duet3d.com/forum/thread.php?pid=37891#p37891 +- slow DWC but fast FTP, https://www.duet3d.com/forum/thread.php?pid=38345#p38345 +- no stall detect on Z axis, https://www.duet3d.com/forum/thread.php?pid=38504#p38504, https://www.duet3d.com/forum/thread.php?pid=39484#p39484 +- Pressure advance, see https://www.duet3d.com/forum/thread.php?pid=38036#p38036 +- check that we never enable the drivers before we set vsense + +- [don't do] Don't report the motor current for a non-existent extruder +- SD card read error handling? +- dual extrusion layer counting, see https://www.duet3d.com/forum/thread.php?pid=34816#p34816 +- M140/M190 with no P parameter sets all bed heater temperatures (same for M141/M191) +- M291 to lock movement and wait for it to finish? +- Add timeout to hsmci_send_cmd_execute, see https://www.duet3d.com/forum/thread.php?pid=35654#p35654 +- Bug: pressure advance attempts high speed or acceleration extruder movements on bench setup (was it caused by hitting limits?) +- Bug: https://www.duet3d.com/forum/thread.php?pid=34772#p34772 (needs RRF fix too?) +- When VIN power too low, flag axes as not homed? +- M40 to run eject.g [don't do, not NIST standard] +- configurable minimum extrusion temperature (per extruder?) +- M81: don't give low voltage warnings when main power is off +- case-insensitive http headers + +Remaining: +- Send reduce power command to PanelDue when main power turned off? +- Document multiple bed and chamber heaters +- Check all classes for correct initialisation +- sd_mmc_spi doesn't acquire/release the SPI bus. Need to change this for RTOS. +- If wifi module gets stuck in starting state, reset it again + +Bug investigations: +- [done] step errors, https://www.duet3d.com/forum/thread.php?pid=33741#p33741 + +Investigations: + +[done, waiting forever for SD card] Investigate https://www.duet3d.com/forum/thread.php?pid=32237#p32237 +[done] https://www.duet3d.com/forum/thread.php?pid=30414#p30414 (watchdog reset) +[can't reproduce] https://www.duet3d.com/forum/thread.php?pid=28210#p28210 (pressure advance causes over extrusion) +[done] https://www.duet3d.com/forum/thread.php?pid=28255#p28255 (tool change problem) +[done] https://www.duet3d.com/forum/thread.php?pid=30431#p30431 (bed probing inaccurate) +[can't reproduce] https://www.duet3d.com/forum/thread.php?pid=30799#p30799 (step errors at high E steps/mm) +[no fault] https://www.duet3d.com/forum/thread.php?pid=30851#p30851 (split axis motor goes the wrong way) +[done BUT still wrong in lwip 2] inconsistend oversize vs. len +p->ref == 1 in WiFi + +Later versions: + +- Multiple bed heaters, https://www.duet3d.com/forum/thread.php?pid=33903#p33903 +- Use M140H1:2:3 to set multiple bed heater numbers +- Check https://www.duet3d.com/forum/thread.php?pid=33951#p33951 + +- Option to not broadcast SSID? +- On file read error during SD card print, treat like a temperature fault +- Support faster homing by using interrupts to check homing switch states +- Allow manual bed probing to be aborted +- Implement G1 S4? (like S2 but always relative) +- Add work coordinates? https://www.duet3d.com/forum/thread.php?pid=27128#p27128 +- Don't do pressure advance during accel/decel of sequences of short segments +- Axis limits on arc moves +- Arc move with same finish and start coordinates to do complete circle +- Add T parameter to M207 +- look at supporting SIZE in FTP +- Make mp.delta.hmz0sK, hmz0scK and dsk 64-bit in SAM4E versions, to increase movement limit - also increase K2? + +- SAME7 boot loader - could base on SAM-BA, see http://hobbygenius.co.uk/blog/1633 diff --git a/src/Display/Display.cpp b/src/Display/Display.cpp index 91ba42f4..28643dc0 100644 --- a/src/Display/Display.cpp +++ b/src/Display/Display.cpp @@ -6,7 +6,9 @@ */ #include "Display.h" + #include "GCodes/GCodes.h" +#include "GCodes/GCodeBuffer.h" #include "IoPort.h" #include "Pins.h" diff --git a/src/Duet/Network.cpp b/src/Duet/Network.cpp index 7d20cedb..3d2a8d3b 100644 --- a/src/Duet/Network.cpp +++ b/src/Duet/Network.cpp @@ -461,31 +461,33 @@ void Network::Spin(bool full) return; } } - - NetworkTransaction *transaction = writingTransactions; - if (transaction != nullptr && sendingConnection == nullptr) + else if (state == NetworkActive) { - if (transaction->next != nullptr) + NetworkTransaction *transaction = writingTransactions; + if (transaction != nullptr && sendingConnection == nullptr) { - // Data is supposed to be sent and the last packet has been acknowledged. - // Rotate the transactions so every client is served even while multiple files are sent - NetworkTransaction *next = transaction->next; - writingTransactions = next; - AppendTransaction(&writingTransactions, transaction); - transaction = next; - } - - if (transaction->Send()) - { - // This transaction can be released, do this here - writingTransactions = transaction->next; - PrependTransaction(&freeTransactions, transaction); + if (transaction->next != nullptr) + { + // Data is supposed to be sent and the last packet has been acknowledged. + // Rotate the transactions so every client is served even while multiple files are sent + NetworkTransaction *next = transaction->next; + writingTransactions = next; + AppendTransaction(&writingTransactions, transaction); + transaction = next; + } - // If there is more data to write on this connection, do it sometime soon - NetworkTransaction *nextWrite = transaction->nextWrite; - if (nextWrite != nullptr) + if (transaction->Send()) { - PrependTransaction(&writingTransactions, nextWrite); + // This transaction can be released, do this here + writingTransactions = transaction->next; + PrependTransaction(&freeTransactions, transaction); + + // If there is more data to write on this connection, do it sometime soon + NetworkTransaction *nextWrite = transaction->nextWrite; + if (nextWrite != nullptr) + { + PrependTransaction(&writingTransactions, nextWrite); + } } } } @@ -530,7 +532,7 @@ void Network::Diagnostics(MessageType mtype) platform.Message(mtype, "=== Network ===\n"); size_t numFreeConnections = 0; - ConnectionState *freeConn = freeConnections; + const ConnectionState *freeConn = freeConnections; while (freeConn != nullptr) { numFreeConnections++; @@ -539,7 +541,7 @@ void Network::Diagnostics(MessageType mtype) platform.MessageF(mtype, "Free connections: %d of %d\n", numFreeConnections, MEMP_NUM_TCP_PCB); size_t numFreeTransactions = 0; - NetworkTransaction *freeTrans = freeTransactions; + const NetworkTransaction *freeTrans = freeTransactions; while (freeTrans != nullptr) { numFreeTransactions++; @@ -567,7 +569,7 @@ void Network::ResetCallback() // Called when data has been received. Return false if we cannot process it bool Network::ReceiveInput(pbuf *pb, ConnectionState* cs) { - NetworkTransaction* r = freeTransactions; + NetworkTransaction* const r = freeTransactions; if (r == nullptr) { platform.Message(UsbMessage, "Network::ReceiveInput() - no free transactions!\n"); @@ -586,14 +588,14 @@ bool Network::ReceiveInput(pbuf *pb, ConnectionState* cs) // or NULL if no more items are available. This would reset the connection immediately ConnectionState *Network::ConnectionAccepted(tcp_pcb *pcb) { - ConnectionState *cs = freeConnections; + ConnectionState * const cs = freeConnections; if (cs == nullptr) { platform.Message(UsbMessage, "Network::ConnectionAccepted() - no free ConnectionStates!\n"); return nullptr; } - NetworkTransaction* transaction = freeTransactions; + NetworkTransaction* const transaction = freeTransactions; if (transaction == nullptr) { platform.Message(UsbMessage, "Network::ConnectionAccepted() - no free transactions!\n"); diff --git a/src/Duet/Webserver.cpp b/src/Duet/Webserver.cpp index f378b39a..1756e324 100644 --- a/src/Duet/Webserver.cpp +++ b/src/Duet/Webserver.cpp @@ -1065,7 +1065,6 @@ void Webserver::HttpInterpreter::ConnectionLost(Connection conn) // Make sure deferred requests are cancelled if (deferredRequestConnection == conn) { - reprap.GetPrintMonitor().StopParsing(filenameBeingProcessed); deferredRequestConnection = NoConnection; } diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp index 36fe9e95..ccb20d82 100644 --- a/src/GCodes/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer.cpp @@ -8,6 +8,8 @@ //************************************************************************************* #include "GCodeBuffer.h" + +#include "GCodeInput.h" #include "Platform.h" #include "RepRap.h" @@ -950,11 +952,17 @@ bool GCodeBuffer::PopState() return true; } -// Abort execution of any files or macros being executed -void GCodeBuffer::AbortFile() +// Abort execution of any files or macros being executed, returning true if any files were closed +void GCodeBuffer::AbortFile(FileGCodeInput* fileInput) { - while (PopState()) { } // abandon any macros - machineState->fileState.Close(); // if we are executing a file, abandon it + do + { + if (machineState->fileState.IsLive()) + { + fileInput->Reset(machineState->fileState); + machineState->fileState.Close(); + } + } while (PopState()); // abandon any macros } // Return true if this source is executing a file macro diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h index fb64ff6f..69c2bf69 100644 --- a/src/GCodes/GCodeBuffer.h +++ b/src/GCodes/GCodeBuffer.h @@ -67,7 +67,7 @@ public: GCodeMachineState& OriginalMachineState() const; bool PushState(); // Push state returning true if successful (i.e. stack not overflowed) bool PopState(); // Pop state returning true if successful (i.e. no stack underrun) - void AbortFile(); // Abort execution of any files or macros being executed + void AbortFile(FileGCodeInput* fileInput); // Abort execution of any files or macros being executed bool IsDoingFileMacro() const; // Return true if this source is executing a file macro GCodeState GetState() const; @@ -210,7 +210,7 @@ inline void GCodeBuffer::SetState(GCodeState newState) inline void GCodeBuffer::SetState(GCodeState newState, const char *err) { machineState->state = newState; - machineState->err = err; + machineState->errorMessage = err; } inline void GCodeBuffer::AdvanceState() diff --git a/src/GCodes/GCodeInput.cpp b/src/GCodes/GCodeInput.cpp index 2ba77c9b..d414396e 100644 --- a/src/GCodes/GCodeInput.cpp +++ b/src/GCodes/GCodeInput.cpp @@ -9,7 +9,7 @@ #include "RepRap.h" #include "GCodes.h" - +#include "GCodeBuffer.h" bool GCodeInput::FillBuffer(GCodeBuffer *gb) { diff --git a/src/GCodes/GCodeInput.h b/src/GCodes/GCodeInput.h index 11c900d3..d421f567 100644 --- a/src/GCodes/GCodeInput.h +++ b/src/GCodes/GCodeInput.h @@ -9,10 +9,8 @@ #define GCODEINPUT_H #include "RepRapFirmware.h" - -#include "GCodeBuffer.h" -#include "Storage/FileStore.h" - +#include "Storage/FileData.h" +#include "MessageType.h" const size_t GCodeInputBufferSize = 256; // How many bytes can we cache per input source? const size_t GCodeInputFileReadThreshold = 128; // How many free bytes must be available before data is read from the SD card? @@ -96,7 +94,7 @@ public: FileGCodeInput() : RegularGCodeInput(), lastFile(nullptr) { } void Reset() override; // This should be called when the associated file is being closed - void Reset(const FileData &file); // Should be called when a specific G-code or macro file is closed outside the reading context + void Reset(const FileData &file); // Should be called when a specific G-code or macro file is closed or re-opened outside the reading context bool ReadFromFile(FileData &file); // Read another chunk of G-codes from the file and return true if more data is available diff --git a/src/GCodes/GCodeMachineState.cpp b/src/GCodes/GCodeMachineState.cpp index a0f49eaf..dc396a3d 100644 --- a/src/GCodes/GCodeMachineState.cpp +++ b/src/GCodes/GCodeMachineState.cpp @@ -12,7 +12,7 @@ unsigned int GCodeMachineState::numAllocated = 0; // Create a default initialised GCodeMachineState GCodeMachineState::GCodeMachineState() - : previous(nullptr), feedrate(DefaultFeedrate * SecondsToMinutes), fileState(), lockedResources(0), err(nullptr), state(GCodeState::normal), + : previous(nullptr), feedrate(DefaultFeedrate * SecondsToMinutes), fileState(), lockedResources(0), errorMessage(nullptr), state(GCodeState::normal), drivesRelative(false), axesRelative(false), doingFileMacro(false), runningM501(false), runningM502(false), volumetricExtrusion(false), waitingForAcknowledgement(false), messageAcknowledged(false) { } @@ -25,7 +25,7 @@ GCodeMachineState::GCodeMachineState() { freeList = ms->previous; ms->lockedResources = 0; - ms->err = nullptr; + ms->errorMessage = nullptr; ms->state = GCodeState::normal; } else diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h index bacd9aac..9ac29a64 100644 --- a/src/GCodes/GCodeMachineState.h +++ b/src/GCodes/GCodeMachineState.h @@ -92,7 +92,7 @@ public: float feedrate; FileData fileState; ResourceBitmap lockedResources; - const char *err; + const char *errorMessage; GCodeState state; uint8_t toolChangeParam; int16_t newToolNumber; diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index cb1e5a29..ac9d9c0c 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -100,7 +100,7 @@ void GCodes::Init() active = true; fileSize = 0; longWait = millis(); - limitAxes = true; + limitAxes = noMovesBeforeHoming = true; SetAllAxesNotHomed(); for (size_t i = 0; i < NUM_FANS; ++i) { @@ -280,6 +280,14 @@ void GCodes::CopyConfigFinalValues(GCodeBuffer& gb) } } +// Set up to do the first of a possibly multi-tap probe +void GCodes::InitialiseTaps() +{ + tapsDone = 0; + g30zHeightErrorSum = 0.0; + g30zHeightErrorLowestDiff = 1000.0; +} + void GCodes::Spin() { if (!active) @@ -318,7 +326,7 @@ void GCodes::Spin() { if (gb.MachineState().previous == nullptr) { - StopPrint(false); + StopPrint(StopPrintReason::userCancelled); } else { @@ -1004,15 +1012,14 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) totalSegments = 1; segmentsLeft = 1; - tapsDone = 0; - g30zHeightErrorSum = 0.0; - g30zHeightErrorLowestDiff = 1000.0; - + InitialiseTaps(); gb.AdvanceState(); } break; case GCodeState::probingAtPoint2a: // note we return to this state when doing the second and subsequent taps + // Executing G30 with a P parameter. The move to put the head at the specified XY coordinates has been commanded. + // OR initial state when executing G30 with no P parameter (must call InitialiseTaps first) if (LockMovementAndWaitForStandstill(gb)) { gb.AdvanceState(); @@ -1024,8 +1031,6 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) break; case GCodeState::probingAtPoint2b: - // Executing G30 with a P parameter. The move to put the head at the specified XY coordinates has been commanded. - // OR initial state when executing G30 with no P parameter if (LockMovementAndWaitForStandstill(gb)) { // Head has finished moving to the correct XY position @@ -1126,58 +1131,54 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) } } - if (g30ProbePointIndex < 0) + if (g30ProbePointIndex < 0) // if no P parameter { // Simple G30 probing move - gb.SetState(GCodeState::normal); // usually nothing more to do except perhaps retract the probe - if (!hadProbingError) + if (g30SValue == -1 || g30SValue == -2) { - if (g30SValue == -1 || g30SValue == -2) - { - // G30 S-1 or S-2 command - gb.SetState(GCodeState::probingAtPoint7); // special state for reporting the stopped height at the end - } - else + // G30 S-1 or S-2 command taps once and reports the height + gb.SetState(GCodeState::probingAtPoint7); // special state for reporting the stopped height at the end + if (platform.GetZProbeType() != ZProbeType::none && !probeIsDeployed) { - // Reset the Z axis origin according to the height error - moveBuffer.coords[Z_AXIS] -= g30zHeightError; - reprap.GetMove().SetNewPosition(moveBuffer.coords, false); - ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); - SetAxisIsHomed(Z_AXIS); //TODO this is only correct if the Z axis is Cartesian-like! + DoFileMacro(gb, RETRACTPROBE_G, false); // retract the probe before moving to the new state } + break; } - if (platform.GetZProbeType() != ZProbeType::none && !probeIsDeployed) + if (tapsDone == 1 && !hadProbingError) { - DoFileMacro(gb, RETRACTPROBE_G, false); // retract the probe before moving to the new state + // Reset the Z axis origin according to the height error so that we can move back up to the dive height + moveBuffer.coords[Z_AXIS] -= g30zHeightError; + g30zHeightError = 0; // there is no zero height error form this probe + reprap.GetMove().SetNewPosition(moveBuffer.coords, false); + ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); + SetAxisIsHomed(Z_AXIS); // this is only correct if the Z axis is Cartesian-like, but other architectures must be homed before probing anyway } } - else - { - // Move back up to the dive height before we change anything, in particular before we adjust leadscrews - moveBuffer.moveType = 0; - moveBuffer.isCoordinated = false; - moveBuffer.endStopsToCheck = 0; - moveBuffer.usePressureAdvance = false; - moveBuffer.filePos = noFilePosition; - moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); - moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); - moveBuffer.xAxes = DefaultXAxisMapping; - moveBuffer.yAxes = DefaultYAxisMapping; - totalSegments = 1; - segmentsLeft = 1; - gb.AdvanceState(); - if (platform.GetZProbeType() == ZProbeType::blTouch) - { - DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers - } + // Move back up to the dive height before we change anything, in particular before we adjust leadscrews + moveBuffer.moveType = 0; + moveBuffer.isCoordinated = false; + moveBuffer.endStopsToCheck = 0; + moveBuffer.usePressureAdvance = false; + moveBuffer.filePos = noFilePosition; + moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); + moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); + moveBuffer.xAxes = DefaultXAxisMapping; + moveBuffer.yAxes = DefaultYAxisMapping; + totalSegments = 1; + segmentsLeft = 1; + gb.AdvanceState(); + + if (platform.GetZProbeType() == ZProbeType::blTouch) + { + DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers } } break; case GCodeState::probingAtPoint5: - // Here when we were probing at a numbered point and we have moved the head back up to the dive height + // Here when we have moved the head back up to the dive height if (LockMovementAndWaitForStandstill(gb)) { // See whether we need to do any more taps @@ -1210,7 +1211,17 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) g30zHeightError = g30zHeightErrorSum/tapsDone; } - reprap.GetMove().SetZBedProbePoint(g30ProbePointIndex, g30zHeightError, true, hadProbingError); + if (g30ProbePointIndex >= 0) + { + reprap.GetMove().SetZBedProbePoint(g30ProbePointIndex, g30zHeightError, true, hadProbingError); + } + else + { + // Setting the Z height with G30 + moveBuffer.coords[Z_AXIS] -= g30zHeightError; + reprap.GetMove().SetNewPosition(moveBuffer.coords, false); + ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); + } gb.AdvanceState(); if (platform.GetZProbeType() != ZProbeType::none && !probeIsDeployed) { @@ -1382,12 +1393,12 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) UnlockAll(gb); if (error) { - gb.MachineState().err = nullptr; // we can't report more than one error here, so clear the original one + gb.MachineState().errorMessage = nullptr; // we can't report more than one error here, so clear the original one } - else if (gb.MachineState().err != nullptr) + else if (gb.MachineState().errorMessage != nullptr) { - reply.copy(gb.MachineState().err); - gb.MachineState().err = nullptr; + reply.copy(gb.MachineState().errorMessage); + gb.MachineState().errorMessage = nullptr; error = true; } HandleReply(gb, error, reply.Pointer()); @@ -1483,13 +1494,13 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) && IsCodeQueueIdle() // must also wait until deferred command queue has caught up ) { - StopPrint(true); + StopPrint(StopPrintReason::normalCompletion); } } else { // Finished a macro or finished processing config.g - fileInput->Reset(); + fileInput->Reset(fd); fd.Close(); if (runningConfigFile) { @@ -1666,8 +1677,8 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg) FileData& fdata = fileGCode->MachineState().fileState; if (fdata.IsLive() && pauseRestorePoint.filePos != noFilePosition) { + fileInput->Reset(fdata); // clear the buffered data fdata.Seek(pauseRestorePoint.filePos); // replay the abandoned instructions when we resume - fileInput->Reset(); // clear the buffered data fileGCode->Init(); // clear the next move UnlockAll(*fileGCode); // release any locks it had } @@ -2223,60 +2234,10 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType) return true; } -// Check that enough axes have been homed +// Check that enough axes have been homed, returning true if insufficient axes homed bool GCodes::CheckEnoughAxesHomed(AxesBitmap axesMoved) { - // Regular move. If it's a delta or SCARA printer, the XYZ axes must be homed first. - constexpr AxesBitmap xyAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS); - constexpr AxesBitmap xyzAxes = xyAxes | MakeBitmap<AxesBitmap>(Z_AXIS); - constexpr AxesBitmap xzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); - constexpr AxesBitmap uvAxes = MakeBitmap<AxesBitmap>(U_AXIS) | MakeBitmap<AxesBitmap>(V_AXIS); - - switch (reprap.GetMove().GetKinematics().GetKinematicsType()) - { - case KinematicsType::cartesian: - break; - - case KinematicsType::coreXY: - case KinematicsType::coreXYU: - if ((axesMoved & xyAxes) != 0) - { - axesMoved |= xyAxes; - } - break; - - case KinematicsType::coreXZ: - if ((axesMoved & xzAxes) != 0) - { - axesMoved |= xzAxes; - } - break; - - case KinematicsType::coreXYUV: - if ((axesMoved & xyAxes) != 0) - { - axesMoved |= xyAxes; - } - if ((axesMoved & uvAxes) != 0) - { - axesMoved |= uvAxes; - } - break; - - case KinematicsType::linearDelta: - case KinematicsType::polar: - case KinematicsType::scara: - case KinematicsType::hangprinter: - default: - // For these printers we require all of XYZ to be homed before any normal movements are made - if ((axesMoved & xyzAxes) != 0) - { - axesMoved |= xyzAxes; - } - break; - } - - return (axesMoved & ~axesHomed) != 0; + return (reprap.GetMove().GetKinematics().MustBeHomedAxes(axesMoved, noMovesBeforeHoming) & ~axesHomed) != 0; } // Execute a straight move returning true if an error was written to 'reply' @@ -2739,23 +2700,10 @@ void GCodes::ClearMove() // Cancel any macro or print in progress void GCodes::AbortPrint(GCodeBuffer& gb) { - gb.AbortFile(); // stop executing any files that this GCodeBuffer is running + gb.AbortFile(fileInput); // stop executing any files or macros that this GCodeBuffer is running if (&gb == fileGCode) // if the current command came from a file being printed { - reprap.GetHeat().SwitchOffAll(true); // turn all heaters off - switch (machineType) - { - case MachineType::cnc: - platform.SetSpindlePwm(0); - break; - - case MachineType::laser: - platform.SetLaserPwm(0); - break; - - default: - break; - } + StopPrint(StopPrintReason::abort); } } @@ -2780,6 +2728,7 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi return true; } gb.MachineState().fileState.Set(f); + fileInput->Reset(gb.MachineState().fileState); gb.MachineState().doingFileMacro = true; gb.MachineState().runningM501 = (codeRunning == 501); gb.MachineState().runningM502 = (codeRunning == 502); @@ -2898,6 +2847,7 @@ GCodeResult GCodes::ExecuteG30(GCodeBuffer& gb, const StringRef& reply) { // G30 without P parameter. This probes the current location starting from the current position. // If S=-1 it just reports the stopped height, else it resets the Z origin. + InitialiseTaps(); gb.SetState(GCodeState::probingAtPoint2a); if (platform.GetZProbeType() != ZProbeType::none && !probeIsDeployed) { @@ -3215,7 +3165,7 @@ bool GCodes::QueueFileToPrint(const char* fileName, const StringRef& reply) void GCodes::StartPrinting(bool fromStart) { fileGCode->OriginalMachineState().fileState.MoveFrom(fileToPrint); - fileInput->Reset(); + fileInput->Reset(fileGCode->OriginalMachineState().fileState); lastFilamentError = FilamentSensorStatus::ok; reprap.GetPrintMonitor().StartedPrint(); platform.MessageF(LogMessage, @@ -4175,7 +4125,7 @@ bool GCodes::IsCodeQueueIdle() const // Cancel the current SD card print. // This is called from Pid.cpp when there is a heater fault, and from elsewhere in this module. -void GCodes::StopPrint(bool normalCompletion) +void GCodes::StopPrint(StopPrintReason reason) { segmentsLeft = 0; isPaused = pausePending = false; @@ -4208,11 +4158,37 @@ void GCodes::StopPrint(bool normalCompletion) reprap.GetMove().Simulate(simulationMode); EndSimulation(nullptr); const uint32_t simMinutes = lrintf((reprap.GetMove().GetSimulationTime() + simulationTime)/60.0); - platform.MessageF(LoggedGenericMessage, "File %s will print in %" PRIu32 "h %" PRIu32 "m plus heating time\n", - printingFilename, simMinutes/60u, simMinutes % 60u); + if (reason == StopPrintReason::normalCompletion) + { + platform.MessageF(LoggedGenericMessage, "File %s will print in %" PRIu32 "h %" PRIu32 "m plus heating time\n", + printingFilename, simMinutes/60u, simMinutes % 60u); + } + else + { + platform.MessageF(LoggedGenericMessage, "Cancelled simulating file %s after %" PRIu32 "h %" PRIu32 "m simulated time\n", + printingFilename, simMinutes/60u, simMinutes % 60u); + } } else if (reprap.GetPrintMonitor().IsPrinting()) { + if (reason == StopPrintReason::abort) + { + reprap.GetHeat().SwitchOffAll(true); // turn all heaters off + switch (machineType) + { + case MachineType::cnc: + platform.SetSpindlePwm(0); + break; + + case MachineType::laser: + platform.SetLaserPwm(0); + break; + + default: + break; + } + } + if (platform.Emulating() == Compatibility::marlin) { // Pronterface expects a "Done printing" message @@ -4220,15 +4196,15 @@ void GCodes::StopPrint(bool normalCompletion) } const uint32_t printMinutes = lrintf(reprap.GetPrintMonitor().GetPrintDuration()/60.0); platform.MessageF(LoggedGenericMessage, "%s printing file %s, print time was %" PRIu32 "h %" PRIu32 "m\n", - (normalCompletion) ? "Finished" : "Cancelled", + (reason == StopPrintReason::normalCompletion) ? "Finished" : "Cancelled", printingFilename, printMinutes/60u, printMinutes % 60u); + if (reason == StopPrintReason::normalCompletion && simulationMode == 0) + { + platform.GetMassStorage()->Delete(platform.GetSysDir(), RESUME_AFTER_POWER_FAIL_G, true); + } } reprap.GetPrintMonitor().StoppedPrint(); // must do this after printing the simulation details because it clears the filename - if (normalCompletion && simulationMode == 0) - { - platform.GetMassStorage()->Delete(platform.GetSysDir(), RESUME_AFTER_POWER_FAIL_G, true); - } } // Return true if all the heaters for the specified tool are at their set temperatures @@ -4803,7 +4779,7 @@ void GCodes::CheckHeaterFault() case HeaterFaultState::timing: if (millis() - heaterFaultTime >= heaterFaultTimeout) { - StopPrint(false); + StopPrint(StopPrintReason::abort); reprap.GetHeat().SwitchOffAll(true); platform.MessageF(ErrorMessage, "Shutting down due to un-cleared heater fault after %lu seconds\n", heaterFaultTimeout/1000); heaterFaultState = HeaterFaultState::stopping; diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index be3074f6..ba312f2c 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -93,6 +93,13 @@ enum class PauseReason #endif }; +enum class StopPrintReason +{ + normalCompletion, + userCancelled, + abort +}; + //**************************************************************************************************** // The GCode interpreter @@ -172,7 +179,7 @@ public: bool AllAxesAreHomed() const; // Return true if all axes are homed - void StopPrint(bool normalCompletion); // Stop the current print + void StopPrint(StopPrintReason reason); // Stop the current print void MoveStoppedByZProbe() { zProbeTriggered = true; } // Called from the step ISR when the Z probe is triggered, causing the move to be aborted @@ -251,6 +258,7 @@ private: GCodeResult DoDwellTime(GCodeBuffer& gb, uint32_t dwellMillis); // Really wait for a bit GCodeResult DoHome(GCodeBuffer& gb, const StringRef& reply); // Home some axes GCodeResult ExecuteG30(GCodeBuffer& gb, const StringRef& reply); // Probes at a given position - see the comment at the head of the function itself + void InitialiseTaps(); // Set up to do the first of a possibly multi-tap probe void SetBedEquationWithProbe(int sParam, const StringRef& reply); // Probes a series of points and sets the bed equation GCodeResult SetPrintZProbe(GCodeBuffer& gb, const StringRef& reply); // Either return the probe value, or set its threshold GCodeResult SetOrReportOffsets(GCodeBuffer& gb, const StringRef& reply); // Deal with a G10 @@ -273,7 +281,7 @@ private: GCodeResult OffsetAxes(GCodeBuffer& gb); // Set offsets #if SUPPORT_WORKPLACE_COORDINATES - GCodeResult GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply); // Set workspace coordinates + GCodeResult GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply, bool compute); // Set workspace coordinates #endif bool SetHeaterProtection(GCodeBuffer &gb, const StringRef &reply); // Configure heater protection (M143). Returns true if an error occurred @@ -440,7 +448,8 @@ private: uint8_t eofStringLength; // ... EoF string as we read. char axisLetters[MaxAxes + 1]; // The names of the axes, with a null terminator - bool limitAxes; // Don't think outside the box. + bool limitAxes; // Don't think outside the box + bool noMovesBeforeHoming; // Don't allow movement prior to homing the associates axes AxesBitmap toBeHomed; // Bitmap of axes still to be homed AxesBitmap axesHomed; // Bitmap of which axes have been homed diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index c1226920..dea916c1 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -114,11 +114,8 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) const char* err = DoStraightMove(gb, code == 1); if (err != nullptr) { + AbortPrint(gb); gb.SetState(GCodeState::waitingForSpecialMoveToComplete, err); // force the user position to be restored - if (&gb == fileGCode) - { - AbortPrint(gb); - } } } break; @@ -138,11 +135,8 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) const char* err = DoArcMove(gb, code == 2); if (err != nullptr) { + AbortPrint(gb); gb.SetState(GCodeState::waitingForSpecialMoveToComplete, err); // force the user position to be restored - if (&gb == fileGCode) - { - AbortPrint(gb); - } } } break; @@ -156,13 +150,24 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) #if SUPPORT_WORKPLACE_COORDINATES if (gb.Seen('L')) { - if (gb.GetUIValue() == 2) - { - result = GetSetWorkplaceCoordinates(gb, reply); - } - else + const uint32_t ival = gb.GetUIValue(); + switch (ival) { + case 1: + result = SetOrReportOffsets(gb, reply); // same as G10 with offsets and no L parameter + break; + + case 2: + result = GetSetWorkplaceCoordinates(gb, reply, false); + break; + + case 20: + result = GetSetWorkplaceCoordinates(gb, reply, true); + break; + + default: result = GCodeResult::badOrMissingParameter; + break; } } else @@ -357,7 +362,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) const bool wasPaused = isPaused; // isPaused gets cleared by CancelPrint const bool wasSimulating = IsSimulating(); // simulationMode may get cleared by CancelPrint - StopPrint(&gb == fileGCode); // if this is normal end-of-print commanded by the file, delete the resurrect.g file + StopPrint((&gb == fileGCode) ? StopPrintReason::normalCompletion : StopPrintReason::userCancelled); if (!wasSimulating) // don't run any macro files or turn heaters off etc. if we were simulating before we stopped the print { @@ -2915,13 +2920,22 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) break; case 564: // Think outside the box? - if (gb.Seen('S')) - { - limitAxes = (gb.GetIValue() != 0); - } - else { - reply.printf("Movement outside the bed is %spermitted", (limitAxes) ? "not " : ""); + bool seen = false; + if (gb.Seen('S')) + { + seen = true; + limitAxes = (gb.GetIValue() > 0); + } + if (gb.Seen('H')) + { + seen = true; + noMovesBeforeHoming = (gb.GetIValue() > 0); + } + if (!seen) + { + reply.printf("Movement outside the bed is %spermitted, movement before homing is %spermitted", (limitAxes) ? "not " : "", (noMovesBeforeHoming) ? "not " : ""); + } } break; diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 4fee02ae..9ab7291b 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -193,7 +193,7 @@ GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb) #if SUPPORT_WORKPLACE_COORDINATES // Set workspace coordinates -GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply) +GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply, bool compute) { if (gb.Seen('P')) { @@ -205,11 +205,26 @@ GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& { if (gb.Seen(axisLetters[axis])) { - workplaceCoordinates[cs][axis] = gb.GetFValue() * distanceScale; - seen = true; + const float coord = gb.GetFValue() * distanceScale; + if (!seen) + { + if (!LockMovementAndWaitForStandstill(gb)) // make sure the user coordinates are stable and up to date + { + return GCodeResult::notFinished; + } + seen = true; + } + workplaceCoordinates[cs][axis] = (compute) + ? coord - currentUserPosition[axis] + workplaceCoordinates[currentCoordinateSystem][axis] + : coord; } } - if (!seen) + + if (seen) + { + ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // update user coordinates in case we are using the workspace we just changed + } + else { reply.printf("Coordinates of workplace %" PRIu32 ":", cs); for (size_t axis = 0; axis < numVisibleAxes; axis++) diff --git a/src/Heating/Pid.cpp b/src/Heating/Pid.cpp index 4b254680..56d5b68b 100644 --- a/src/Heating/Pid.cpp +++ b/src/Heating/Pid.cpp @@ -79,7 +79,6 @@ void PID::Reset() averagePWM = lastPwm = 0.0; heatingFaultCount = 0; temperature = BAD_ERROR_TEMPERATURE; - suspended = false; } // Set the process model @@ -202,17 +201,11 @@ void PID::Spin() // Read the temperature even if the heater is suspended const TemperatureError err = ReadTemperature(); - if (suspended) - { - SetHeater(0.0); - return; - } - // Handle any temperature reading error and calculate the temperature rate of change, if possible if (err != TemperatureError::success) { previousTemperaturesGood <<= 1; // this reading isn't a good one - if (mode > HeaterMode::off) // don't worry about errors when reading heaters that are switched off or flagged as having faults + if (mode > HeaterMode::suspended) // don't worry about errors when reading heaters that are switched off or flagged as having faults { // Error may be a temporary error and may correct itself after a few additional reads badTemperatureCount++; @@ -330,12 +323,12 @@ void PID::Spin() } break; - default: // this covers off, fault, and the auto tuning states + default: // this covers off, fault, suspended, and the auto tuning states break; } // Calculate the PWM - if (mode <= HeaterMode::off) + if (mode <= HeaterMode::suspended) { lastPwm = 0.0; } @@ -367,14 +360,7 @@ void PID::Spin() } else { -#if 1 // try normal PWM instead, because it looks like the modified PWM may be causing undershoot on initial heating const float errorToUse = error; -#else - // In the following we use a modified PID when the temperature is a long way off target. - // During initial heating or cooling, the D term represents expected overshoot, which we don't want to add to the I accumulator. - // When we are in load mode, the I term is much larger and the D term doesn't represent overshoot, so use normal PID. - const float errorToUse = (inLoadMode || model.ArePidParametersOverridden()) ? error : errorMinusDterm; -#endif iAccumulator = constrain<float> (iAccumulator + (errorToUse * params.kP * params.recipTi * platform.HeatSampleInterval() * MillisToSeconds), 0.0, model.GetMaxPwm()); @@ -468,7 +454,7 @@ void PID::SetActiveTemperature(float t) else { activeTemperature = t; - if (mode > HeaterMode::off && active) + if (mode > HeaterMode::suspended && active) { SwitchOn(); } @@ -488,7 +474,7 @@ void PID::SetStandbyTemperature(float t) else { standbyTemperature = t; - if (mode > HeaterMode::off && !active) + if (mode > HeaterMode::suspended && !active) { SwitchOn(); } @@ -964,10 +950,18 @@ void PID::DisplayBuffer(const char *intro) // Suspend the heater, or resume it void PID::Suspend(bool sus) { - suspended = sus; - if (sus && model.IsEnabled()) + if (sus) { - SetHeater(0.0); + if (mode == HeaterMode::stable || mode == HeaterMode::heating || mode == HeaterMode::cooling) + { + mode = HeaterMode::suspended; + SetHeater(0.0); + lastPwm = 0.0; + } + } + else if (mode == HeaterMode::suspended) + { + SwitchOn(); } } diff --git a/src/Heating/Pid.h b/src/Heating/Pid.h index 9eea4dbb..83a37f63 100644 --- a/src/Heating/Pid.h +++ b/src/Heating/Pid.h @@ -22,9 +22,11 @@ class PID { enum class HeaterMode : uint8_t { - // The order of these is important because we test "mode > HeatingMode::off" to determine whether the heater is active + // The order of these is important because we test "mode > HeatingMode::suspended" to determine whether the heater is active + // and "mode >= HeatingMode::off" to determine whether the heater is eitehr active or suspended fault, off, + suspended, heating, cooling, stable, @@ -129,7 +131,6 @@ private: bool invertPwmSignal; // Invert the final PWM output signal (same behaviour as with HEAT_ON in earlier firmware versions) bool active; // Are we active or standby? bool tuned; // True if tuning was successful - bool suspended; // True if suspended to save power uint8_t badTemperatureCount; // Count of sequential dud readings static_assert(sizeof(previousTemperaturesGood) * 8 >= NumPreviousTemperatures, "too few bits in previousTemperaturesGood"); diff --git a/src/IoPorts.cpp b/src/IoPorts.cpp index 5ec57499..0fb1605d 100644 --- a/src/IoPorts.cpp +++ b/src/IoPorts.cpp @@ -29,16 +29,21 @@ void IoPort::Clear() bool IoPort::Set(LogicalPin lp, PinAccess access, bool pInvert) { - invert = pInvert; const bool ret = reprap.GetPlatform().GetFirmwarePin(lp, access, pin, invert); - if (!ret) + if (ret) + { + if (pInvert) + { + invert = !invert; + } + } + else { Clear(); } return ret; } - /*static*/ void IoPort::SetPinMode(Pin pin, PinMode mode) { #ifdef DUET_NG @@ -114,4 +119,12 @@ void PwmPort::SetFrequency(float freq) frequency = (uint16_t)constrain<float>(freq, 1.0, 65535); } +void PwmPort::WriteAnalog(float pwm) const +{ + if (pin != NoPin) + { + IoPort::WriteAnalog(pin, ((invert) ? 1.0 - pwm : pwm), frequency); + } +} + // End diff --git a/src/IoPorts.h b/src/IoPorts.h index f4e5eb20..67d90b45 100644 --- a/src/IoPorts.h +++ b/src/IoPorts.h @@ -54,7 +54,7 @@ public: PwmPort(); void SetFrequency(float freq); float GetFrequency() const { return (float)frequency; } - void WriteAnalog(float pwm) const { if (pin != NoPin) { IoPort::WriteAnalog(pin, ((invert) ? 1.0 - pwm : pwm), frequency); } } + void WriteAnalog(float pwm) const; private: uint16_t frequency; diff --git a/src/Libraries/General/StringRef.h b/src/Libraries/General/StringRef.h index d144cb1a..44d6c4df 100644 --- a/src/Libraries/General/StringRef.h +++ b/src/Libraries/General/StringRef.h @@ -29,6 +29,7 @@ public: bool IsEmpty() const { return p[0] == 0; } char *Pointer() { return p; } const char *Pointer() const { return p; } + const char *c_str() const { return p; } char& operator[](size_t index) { return p[index]; } char operator[](size_t index) const { return p[index]; } diff --git a/src/Movement/Kinematics/CoreBaseKinematics.cpp b/src/Movement/Kinematics/CoreBaseKinematics.cpp index 75055e6e..9d356fff 100644 --- a/src/Movement/Kinematics/CoreBaseKinematics.cpp +++ b/src/Movement/Kinematics/CoreBaseKinematics.cpp @@ -6,7 +6,9 @@ */ #include "CoreBaseKinematics.h" + #include "GCodes/GCodes.h" +#include "GCodes/GCodeBuffer.h" #include "Movement/DDA.h" CoreBaseKinematics::CoreBaseKinematics(KinematicsType t) : ZLeadscrewKinematics(t) diff --git a/src/Movement/Kinematics/CoreXYUKinematics.cpp b/src/Movement/Kinematics/CoreXYUKinematics.cpp index fa7ea41d..0b2f3981 100644 --- a/src/Movement/Kinematics/CoreXYUKinematics.cpp +++ b/src/Movement/Kinematics/CoreXYUKinematics.cpp @@ -6,7 +6,9 @@ */ #include "CoreXYUKinematics.h" + #include "GCodes/GCodes.h" +#include "GCodes/GCodeBuffer.h" #include "Movement/DDA.h" CoreXYUKinematics::CoreXYUKinematics() : CoreBaseKinematics(KinematicsType::coreXYU) diff --git a/src/Movement/Kinematics/CoreXYUVKinematics.cpp b/src/Movement/Kinematics/CoreXYUVKinematics.cpp index 9db86238..6d2ea68c 100644 --- a/src/Movement/Kinematics/CoreXYUVKinematics.cpp +++ b/src/Movement/Kinematics/CoreXYUVKinematics.cpp @@ -8,6 +8,7 @@ #include "CoreXYUVKinematics.h" #include "GCodes/GCodes.h" +#include "GCodes/GCodeBuffer.h" #include "Movement/DDA.h" CoreXYUVKinematics::CoreXYUVKinematics() : CoreBaseKinematics(KinematicsType::coreXYUV) diff --git a/src/Movement/Kinematics/CoreXZKinematics.h b/src/Movement/Kinematics/CoreXZKinematics.h index 9f9078ef..cd8f02b9 100644 --- a/src/Movement/Kinematics/CoreXZKinematics.h +++ b/src/Movement/Kinematics/CoreXZKinematics.h @@ -19,7 +19,6 @@ public: const char *GetName(bool forStatusReport) const override; bool CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const override; void MotorStepsToCartesian(const int32_t motorPos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, float machinePos[]) const override; - AxesBitmap AxesToHomeBeforeProbing() const override { return MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); } bool DriveIsShared(size_t drive) const override; bool SupportsAutoCalibration() const override { return false; } void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector) const override; diff --git a/src/Movement/Kinematics/HangprinterKinematics.cpp b/src/Movement/Kinematics/HangprinterKinematics.cpp index ec0798f1..2ffb2706 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.cpp +++ b/src/Movement/Kinematics/HangprinterKinematics.cpp @@ -259,6 +259,17 @@ uint32_t HangprinterKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const return g92Axes; } +// Return the set of axes that must be homed prior to regular movement of the specified axes +AxesBitmap HangprinterKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const +{ + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((axesMoving & xyzAxes) != 0) + { + axesMoving |= xyzAxes; + } + return axesMoving; +} + // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. void HangprinterKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector) const diff --git a/src/Movement/Kinematics/HangprinterKinematics.h b/src/Movement/Kinematics/HangprinterKinematics.h index 533a59ee..cf858370 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.h +++ b/src/Movement/Kinematics/HangprinterKinematics.h @@ -32,6 +32,7 @@ public: const char* HomingButtonNames() const override { return "ABCD"; } HomingMode GetHomingMode() const override { return homeIndividualMotors; } AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const override; + AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const override; const char* GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h index b6bd0c5e..5c386f68 100644 --- a/src/Movement/Kinematics/Kinematics.h +++ b/src/Movement/Kinematics/Kinematics.h @@ -149,6 +149,10 @@ public: // This default is good for Cartesian and Core printers, but not deltas or SCARA virtual AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const { return g92Axes; } + // Return the set of axes that must be homed prior to regular movement of the specified axes + // This default is good for Cartesian and Core printers, but not deltas or SCARA + virtual AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const { return (disallowMovesBeforeHoming) ? axesMoving : 0; } + // Write any calibration data that we need to resume a print after power fail, returning true if successful. Override where necessary. virtual bool WriteResumeSettings(FileStore *f) const { return true; } diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.cpp b/src/Movement/Kinematics/LinearDeltaKinematics.cpp index 5b5cb644..4704b191 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.cpp +++ b/src/Movement/Kinematics/LinearDeltaKinematics.cpp @@ -6,11 +6,12 @@ */ #include "LinearDeltaKinematics.h" -#include "Pins.h" -#include "Configuration.h" + #include "Movement/Move.h" #include "RepRap.h" #include "Storage/FileStore.h" +#include "GCodes/GCodeBuffer.h" + LinearDeltaKinematics::LinearDeltaKinematics() : Kinematics(KinematicsType::linearDelta, -1.0, 0.0, true) { @@ -679,10 +680,10 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const } // Return the axes that we can assume are homed after executing a G92 command to set the specified axis coordinates -uint32_t LinearDeltaKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const +AxesBitmap LinearDeltaKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const { // If all of X, Y and Z have been specified then we know the positions of all 3 tower motors, otherwise we don't - const uint32_t xyzAxes = (1u << X_AXIS) | (1u << Y_AXIS) | (1u << Z_AXIS); + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); if ((g92Axes & xyzAxes) != xyzAxes) { g92Axes &= ~xyzAxes; @@ -690,6 +691,17 @@ uint32_t LinearDeltaKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const return g92Axes; } +// Return the set of axes that must be homed prior to regular movement of the specified axes +AxesBitmap LinearDeltaKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const +{ + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((axesMoving & xyzAxes) != 0) + { + axesMoving |= xyzAxes; + } + return axesMoving; +} + // This function is called when a request is made to home the axes in 'toBeHomed' and the axes in 'alreadyHomed' have already been homed. // If we can proceed with homing some axes, return the name of the homing file to be called. // If we can't proceed because other axes need to be homed first, return nullptr and pass those axes back in 'mustBeHomedFirst'. diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.h b/src/Movement/Kinematics/LinearDeltaKinematics.h index efee53bd..0e696e60 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.h +++ b/src/Movement/Kinematics/LinearDeltaKinematics.h @@ -41,6 +41,7 @@ public: size_t NumHomingButtons(size_t numVisibleAxes) const override { return 0; } HomingMode GetHomingMode() const override { return homeIndividualMotors; } AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const override; + AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const override; const char* GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; diff --git a/src/Movement/Kinematics/PolarKinematics.cpp b/src/Movement/Kinematics/PolarKinematics.cpp index c9781ada..03f35bb9 100644 --- a/src/Movement/Kinematics/PolarKinematics.cpp +++ b/src/Movement/Kinematics/PolarKinematics.cpp @@ -190,6 +190,17 @@ AxesBitmap PolarKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const return g92Axes; } +// Return the set of axes that must be homed prior to regular movement of the specified axes +AxesBitmap PolarKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const +{ + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((axesMoving & xyzAxes) != 0) + { + axesMoving |= xyzAxes; + } + return axesMoving; +} + // This function is called when a request is made to home the axes in 'toBeHomed' and the axes in 'alreadyHomed' have already been homed. // If we can proceed with homing some axes, return the name of the homing file to be called. Optionally, update 'alreadyHomed' to indicate // that some additional axes should be considered not homed. diff --git a/src/Movement/Kinematics/PolarKinematics.h b/src/Movement/Kinematics/PolarKinematics.h index fa5c670c..cb1a4c87 100644 --- a/src/Movement/Kinematics/PolarKinematics.h +++ b/src/Movement/Kinematics/PolarKinematics.h @@ -26,6 +26,7 @@ public: const char* HomingButtonNames() const override { return "RTZUVWABC"; } HomingMode GetHomingMode() const override { return homeIndividualMotors; } AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const override; + AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const override; const char* GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; diff --git a/src/Movement/Kinematics/ScaraKinematics.cpp b/src/Movement/Kinematics/ScaraKinematics.cpp index 34634891..aa3946f7 100644 --- a/src/Movement/Kinematics/ScaraKinematics.cpp +++ b/src/Movement/Kinematics/ScaraKinematics.cpp @@ -322,6 +322,17 @@ AxesBitmap ScaraKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const return g92Axes; } +// Return the set of axes that must be homed prior to regular movement of the specified axes +AxesBitmap ScaraKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const +{ + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((axesMoving & xyzAxes) != 0) + { + axesMoving |= xyzAxes; + } + return axesMoving; +} + size_t ScaraKinematics::NumHomingButtons(size_t numVisibleAxes) const { const MassStorage *storage = reprap.GetPlatform().GetMassStorage(); diff --git a/src/Movement/Kinematics/ScaraKinematics.h b/src/Movement/Kinematics/ScaraKinematics.h index b6193b6a..56506121 100644 --- a/src/Movement/Kinematics/ScaraKinematics.h +++ b/src/Movement/Kinematics/ScaraKinematics.h @@ -37,6 +37,7 @@ public: const char* HomingButtonNames() const override { return "PDZUVWABC"; } HomingMode GetHomingMode() const override { return homeIndividualMotors; } AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const override; + AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const override; const char* GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; diff --git a/src/Movement/Kinematics/ZLeadscrewKinematics.cpp b/src/Movement/Kinematics/ZLeadscrewKinematics.cpp index 9be14ec1..44478df1 100644 --- a/src/Movement/Kinematics/ZLeadscrewKinematics.cpp +++ b/src/Movement/Kinematics/ZLeadscrewKinematics.cpp @@ -6,9 +6,12 @@ */ #include "ZLeadscrewKinematics.h" + #include "RepRap.h" #include "Platform.h" #include "Movement/Move.h" +#include "GCodes/GCodeBuffer.h" + const float M3ScrewPitch = 0.5; diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp index 3b8bfaa1..235f7a83 100644 --- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp +++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp @@ -24,23 +24,25 @@ static_assert(SsidLength == SsidBufferLength, "SSID lengths in NetworkDefs.h and #if defined(DUET_NG) // The PDC seems to be too slow to work reliably without getting transmit underruns, so we use the DMAC now. -# define USE_PDC 0 // use peripheral DMA controller -# define USE_DMAC 1 // use general DMA controller -# define USE_XDMAC 0 // use XDMA controller +# define USE_PDC 0 // use peripheral DMA controller +# define USE_DMAC 1 // use general DMA controller +# define USE_XDMAC 0 // use XDMA controller -# define ESP_SPI SPI -# define ESP_SPI_ID ID_SPI -# define ESP_SPI_IRQn SPI_IRQn +# define ESP_SPI SPI +# define ESP_SPI_ID ID_SPI +# define ESP_SPI_IRQn SPI_IRQn +# define ESP_SPI_HANDLER SPI_Handler #elif defined(SAME70_TEST_BOARD) -# define USE_PDC 0 // use peripheral DMA controller -# define USE_DMAC 0 // use general DMA controller -# define USE_XDMAC 1 // use XDMA controller +# define USE_PDC 0 // use peripheral DMA controller +# define USE_DMAC 0 // use general DMA controller +# define USE_XDMAC 1 // use XDMA controller -# define ESP_SPI SPI0 -# define ESP_SPI_ID ID_SPI0 -# define ESP_SPI_IRQn SPI0_IRQn +# define ESP_SPI SPI0 +# define ESP_SPI_ID ID_SPI0 +# define ESP_SPI_IRQn SPI0_IRQn +# define ESP_SPI_HANDLER SPI0_Handler #else # error Unknown board @@ -630,14 +632,14 @@ void WiFiInterface::Spin(bool full) } InitSockets(); reconnectCount = 0; - platform.MessageF(NetworkInfoMessage, "Wifi module is %s%s, IP address %s\n", + 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)); + platform.MessageF(NetworkInfoMessage, "WiFi module is %s\n", TranslateWiFiState(currentMode)); } } } @@ -1020,6 +1022,12 @@ GCodeResult WiFiInterface::HandleWiFiCode(int mcode, GCodeBuffer &gb, const Stri if (ok) { SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password)); + if (password.strlen() < 8 && password.strlen() != 0) // WPA2 passwords must be at least 8 characters + { + reply.copy("WiFi password must be at least 8 characters"); + return GCodeResult::error; + } + SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password)); if (gb.Seen('I')) { ok = gb.GetIPAddress(config.ip); @@ -1540,7 +1548,7 @@ int32_t WiFiInterface::SendCommand(NetworkCommand cmd, SocketNumber socketNum, u // Wait for the ESP to be ready, with timeout { const uint32_t now = millis(); - while (!digitalRead(EspDataReadyPin)) + while (!digitalRead(EspDataReadyPin) || !digitalRead(SamCsPin)) { if (millis() - now > WiFiWaitReadyMillis) { @@ -1586,11 +1594,12 @@ int32_t WiFiInterface::SendCommand(NetworkCommand cmd, SocketNumber socketNum, u digitalWrite(SamTfrReadyPin, HIGH); // Wait for the DMA complete interrupt, with timeout + // When we use RTOS we should allow other tasks to run here { const uint32_t now = millis(); while (transferPending || !spi_dma_check_rx_complete()) { - if (millis() - now > WifiResponseTimeoutMillis) + if (digitalRead(SamCsPin) && millis() - now > WifiResponseTimeoutMillis) // if no transfer in progress and timed out { if (reprap.Debug(moduleNetwork)) { @@ -1605,39 +1614,33 @@ int32_t WiFiInterface::SendCommand(NetworkCommand cmd, SocketNumber socketNum, u } // Look at the response - int32_t response; if (bufferIn.hdr.formatVersion != MyFormatVersion) { - response = ResponseBadReplyFormatVersion; + if (reprap.Debug(moduleNetwork)) + { + debugPrintf("bad format version %02x\n", bufferIn.hdr.formatVersion); + } + return ResponseBadReplyFormatVersion; } - else - { - if ( (bufferIn.hdr.state == WiFiState::autoReconnecting || bufferIn.hdr.state == WiFiState::reconnecting) + + if ( (bufferIn.hdr.state == WiFiState::autoReconnecting || bufferIn.hdr.state == WiFiState::reconnecting) && currentMode != WiFiState::autoReconnecting && currentMode != WiFiState::reconnecting ) - { - ++reconnectCount; - } - currentMode = bufferIn.hdr.state; - response = bufferIn.hdr.response; - if (response > 0 && dataIn != nullptr) - { - memcpy(dataIn, bufferIn.data, min<size_t>(dataInLength, (size_t)response)); - } + { + ++reconnectCount; } - if (response < 0 && reprap.Debug(moduleNetwork)) + currentMode = bufferIn.hdr.state; + const int32_t response = bufferIn.hdr.response; + if (response > 0 && dataIn != nullptr) { - debugPrintf("Network command %d socket %u returned error %" PRIi32 "\n", (int)cmd, socketNum, response); + memcpy(dataIn, bufferIn.data, min<size_t>(dataInLength, (size_t)response)); } -#if 0 - //***TEMP debug - if (cmd != NetworkCommand::connGetStatus) + if (response < 0 && reprap.Debug(moduleNetwork)) { - debugPrintBuffer("Recv", &bufferIn, (dataIn == nullptr) ? 0 : (size_t)max<int>(0, response)); + debugPrintf("Network command %d socket %u returned error: %s\n", (int)cmd, socketNum, TranslateWiFiResponse(response)); } -#endif return response; } @@ -1674,7 +1677,7 @@ void WiFiInterface::GetNewStatus() rcvr.Value().messageBuffer[ARRAY_UPB(rcvr.Value().messageBuffer)] = 0; if (rslt < 0) { - platform.Message(NetworkInfoMessage, "Error retrieving WiFi status message\n"); + platform.MessageF(NetworkInfoMessage, "Error retrieving WiFi status message: %s\n", TranslateWiFiResponse(rslt)); } else if (rslt > 0 && rcvr.Value().messageBuffer[0] != 0) { @@ -1682,23 +1685,36 @@ void WiFiInterface::GetNewStatus() } } -// SPI interrupt handlers, called when NSS goes high -#if SAME70 -void SPI0_Handler(void) +/*static*/ const char* WiFiInterface::TranslateWiFiResponse(int32_t response) { - wifiInterface->SpiInterrupt(); + switch (response) + { + case ResponseUnknownCommand: return "unknown command"; + case ResponseBadRequestFormatVersion: return "bad request format version"; + case ResponseTooManySsids: return "too many stored SSIDs"; + case ResponseWrongState: return "wrong WiFi module state"; + case ResponseBadDataLength: return "bad data length"; + case ResponseNetworkDisabled: return "WiFi module is disabled"; + case ResponseTimeout: return "SPI timeout"; + case ResponseBusy: return "another SPI transfer is pending"; + case ResponseBufferTooSmall: return "response buffer too small"; + case ResponseBadReplyFormatVersion: return "bad reply format version"; + case ResponseBadParameter: return "bad parameter in request"; + case ResponseUnknownError: return "unknown error"; + default: return "unknown response code"; + } } -#else -void SPI_Handler(void) + +// SPI interrupt handlers, called when NSS goes high +void ESP_SPI_HANDLER(void) { wifiInterface->SpiInterrupt(); } -#endif void WiFiInterface::SpiInterrupt() { - const uint32_t status = ESP_SPI->SPI_SR; // read status and clear interrupt - ESP_SPI->SPI_IDR = SPI_IER_NSSR; // disable the interrupt + const uint32_t status = ESP_SPI->SPI_SR; // read status and clear interrupt + ESP_SPI->SPI_IDR = SPI_IER_NSSR; // disable the interrupt if ((status & SPI_SR_NSSR) != 0) { #if USE_PDC @@ -1707,7 +1723,7 @@ void WiFiInterface::SpiInterrupt() #if USE_DMAC spi_tx_dma_disable(); - dmac_channel_suspend(DMAC, CONF_SPI_DMAC_RX_CH); // suspend the receive channel, don't disable it because the FIFO needs to empty first + dmac_channel_suspend(DMAC, CONF_SPI_DMAC_RX_CH); // suspend the receive channel, don't disable it because the FIFO needs to empty first #endif #if USE_XDMAC diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.h b/src/Networking/ESP8266WiFi/WiFiInterface.h index a77573a2..2dc85fe9 100644 --- a/src/Networking/ESP8266WiFi/WiFiInterface.h +++ b/src/Networking/ESP8266WiFi/WiFiInterface.h @@ -116,6 +116,7 @@ private: void SendListenCommand(Port port, NetworkProtocol protocol, unsigned int maxConnections); void GetNewStatus(); + static const char* TranslateWiFiResponse(int32_t response); static const char* TranslateEspResetReason(uint32_t reason); @@ -157,7 +158,7 @@ private: // For processing debug messages from the WiFi module bool serialRunning; bool debugPrintPending; - String<100> debugMessageBuffer; + String<150> debugMessageBuffer; }; #endif diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp index 7cb191b0..6b946e79 100644 --- a/src/Networking/W5500Ethernet/W5500Interface.cpp +++ b/src/Networking/W5500Ethernet/W5500Interface.cpp @@ -234,13 +234,16 @@ void W5500Interface::Start() static const uint8_t bufSizes[8] = { 2, 2, 2, 2, 2, 2, 2, 2 }; // 2K buffers for everything #endif - wizchip_init(bufSizes, bufSizes); + setPHYCFGR(PHYCFGR_OPMD | PHYCFGR_OPMDC_ALLA); // set auto negotiation and reset the PHY + wizchip_init(bufSizes, bufSizes); setSHAR(macAddress); setSIPR(ipAddress); setGAR(gateway); setSUBR(netmask); + setPHYCFGR(PHYCFGR_OPMD | PHYCFGR_OPMDC_ALLA | ~PHYCFGR_RST); // remove the reset + state = NetworkState::establishingLink; } diff --git a/src/OutputMemory.cpp b/src/OutputMemory.cpp index 8cb71fc5..6bbcbf5e 100644 --- a/src/OutputMemory.cpp +++ b/src/OutputMemory.cpp @@ -287,6 +287,11 @@ size_t OutputBuffer::EncodeString(const char *src, size_t srcLength, bool allowC return bytesWritten; } +size_t OutputBuffer::EncodeString(const StringRef& str, bool allowControlChars, bool encapsulateString) +{ + return EncodeString(str.Pointer(), str.Length(), encapsulateString); +} + size_t OutputBuffer::EncodeReply(OutputBuffer *src, bool allowControlChars) { size_t bytesWritten = cat('"'); diff --git a/src/OutputMemory.h b/src/OutputMemory.h index 87137bf1..a027b059 100644 --- a/src/OutputMemory.h +++ b/src/OutputMemory.h @@ -54,6 +54,7 @@ class OutputBuffer size_t cat(StringRef &str); size_t EncodeString(const char *src, size_t srcLength, bool allowControlChars, bool encapsulateString = true); + size_t EncodeString(const StringRef& str, bool allowControlChars, bool encapsulateString = true); size_t EncodeReply(OutputBuffer *src, bool allowControlChars); uint32_t GetAge() const; diff --git a/src/Platform.cpp b/src/Platform.cpp index 75f2f517..aee8b7c6 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -4000,6 +4000,7 @@ bool Platform::IsDuetWiFi() const #endif // User I/O and servo support +// Translate a logical pin to a firmware pin and also return whether the output of that pin is normally inverted bool Platform::GetFirmwarePin(LogicalPin logicalPin, PinAccess access, Pin& firmwarePin, bool& invert) { firmwarePin = NoPin; // assume failure diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp index 6e857748..216f27ed 100644 --- a/src/PrintMonitor.cpp +++ b/src/PrintMonitor.cpp @@ -45,7 +45,7 @@ void PrintMonitor::Spin() // File information about the file being printed must be available before layer estimations can be made if (filenameBeingPrinted[0] != 0 && !printingFileParsed) { - printingFileParsed = GetFileInfo(platform.GetGCodeDir(), filenameBeingPrinted, printingFileInfo); + printingFileParsed = GetFileInfo(platform.GetGCodeDir(), filenameBeingPrinted.c_str(), printingFileInfo); if (!printingFileParsed) { platform.ClassReport(longWait); @@ -111,24 +111,22 @@ void PrintMonitor::Spin() currentLayer = 1; } } - // Print is in progress and filament is being extruded else if (!gCodes.DoingFileMacro() && reprap.GetMove().IsExtruding()) { + // Print is in progress and filament is being extruded float liveCoordinates[DRIVES]; reprap.GetMove().LiveCoordinates(liveCoordinates, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes()); - // See if we need to determine the first layer height (usually smaller than the nozzle diameter) - if (printingFileInfo.firstLayerHeight == 0.0) + if (currentLayer == 1) { - if (liveCoordinates[Z_AXIS] < platform.GetNozzleDiameter() * 1.5) + // See if we need to determine the first layer height (usually smaller than the nozzle diameter) + if (printingFileInfo.firstLayerHeight == 0.0 && liveCoordinates[Z_AXIS] < platform.GetNozzleDiameter() * 1.5) { // This shouldn't be needed because we parse the first layer height anyway, but it won't harm printingFileInfo.firstLayerHeight = liveCoordinates[Z_AXIS]; } - } - // Check if we've finished the first layer - else if (currentLayer == 1) - { + + // Check if we've finished the first layer if (liveCoordinates[Z_AXIS] > printingFileInfo.firstLayerHeight + LAYER_HEIGHT_TOLERANCE) { FirstLayerComplete(); @@ -169,7 +167,7 @@ float PrintMonitor::GetWarmUpDuration() const void PrintMonitor::StartingPrint(const char* filename) { printingFileParsed = GetFileInfo(platform.GetGCodeDir(), filename, printingFileInfo); - SafeStrncpy(filenameBeingPrinted, filename, ARRAY_SIZE(filenameBeingPrinted)); + filenameBeingPrinted.copy(filename); } // Tell this class that the file set for printing is now actually processed @@ -195,9 +193,9 @@ void PrintMonitor::FirstLayerComplete() // Update layer-based estimation time (if the object and layer heights are known) // This won't be very accurate, but at least something can be sent the web interface and to PanelDue - if (printingFileInfo.objectHeight > 0.0 && printingFileInfo.layerHeight > 0.0) + if (printingFileInfo.layerHeight > 0.0 && printingFileInfo.objectHeight > printingFileInfo.layerHeight) { - unsigned int layersToPrint = round((printingFileInfo.objectHeight - printingFileInfo.firstLayerHeight) / printingFileInfo.layerHeight) + 1; + unsigned int layersToPrint = lrintf((printingFileInfo.objectHeight - printingFileInfo.firstLayerHeight) / printingFileInfo.layerHeight) + 1; layerEstimatedTimeLeft = firstLayerDuration * FIRST_LAYER_SPEED_FACTOR * (layersToPrint - 1); } } @@ -238,7 +236,7 @@ void PrintMonitor::LayerComplete() lastLayerFilament = extrRawTotal; // Update layer-based estimation time (if the object and layer heights are known) - if (printingFileInfo.objectHeight > 0.0 && printingFileInfo.layerHeight > 0.0) + if (printingFileInfo.layerHeight > 0.0 && printingFileInfo.objectHeight > printingFileInfo.layerHeight) { // Calculate the average layer time and include the first layer if possible float avgLayerTime = (numLayerSamples < MAX_LAYER_SAMPLES) @@ -251,8 +249,7 @@ void PrintMonitor::LayerComplete() avgLayerTime /= (numLayerSamples < MAX_LAYER_SAMPLES) ? numLayerSamples + 1 : numLayerSamples; // Estimate the layer-based time left - unsigned int totalLayers; - totalLayers = round((printingFileInfo.objectHeight - printingFileInfo.firstLayerHeight) / printingFileInfo.layerHeight) + 1; + const unsigned int totalLayers = lrintf((printingFileInfo.objectHeight - printingFileInfo.firstLayerHeight) / printingFileInfo.layerHeight) + 1; if (currentLayer < totalLayers) { // Current layer is within reasonable boundaries, so an estimation can be made @@ -278,6 +275,19 @@ void PrintMonitor::StoppedPrint() bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCodeFileInfo& info) { + if (parseState != notParsing && !StringEquals(fileName, filenameBeingParsed.c_str())) + { + // We are already parsing a different file + if (millis() - lastFileParseTime < MaxFileParseInterval) + { + return false; // try again later + } + + // Time this client out because it has probably disconnected + fileBeingParsed->Close(); + parseState = notParsing; + } + if (parseState == notParsing) { // See if we can access the file @@ -297,7 +307,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod } // File has been opened, let's start now - SafeStrncpy(filenameBeingParsed, fileName, ARRAY_SIZE(filenameBeingParsed)); + filenameBeingParsed.copy(fileName); fileOverlapLength = 0; // Set up the info struct @@ -331,11 +341,6 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod } parseState = parsingHeader; } - else if (!StringEquals(fileName, filenameBeingParsed)) - { - // We are already parsing a different file. Try again later. - return false; - } // Getting file information take a few runs. Speed it up when we are not printing by calling it several times. const uint32_t loopStartTime = millis(); @@ -400,58 +405,10 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod } // Look for slicer program - if (parsedFileInfo.generatedBy[0] == 0) + if (parsedFileInfo.generatedBy.IsEmpty()) { - static const char * const GeneratedByStrings[] = - { - "generated by ", // slic3r and S3D - ";Sliced by ", // ideaMaker - "; KISSlicer", // KISSlicer - ";Sliced at: ", // Cura (old) - ";Generated with " // Cura (new) - }; - - size_t index = 0; - const char* pos; - do - { - pos = strstr(buf, GeneratedByStrings[index]); - if (pos != nullptr) - { - break; - } - ++index; - } while (index < ARRAY_SIZE(GeneratedByStrings)); - - if (pos != nullptr) - { - const char* introString = ""; - switch (index) - { - default: - pos += strlen(GeneratedByStrings[index]); - break; - - case 2: // KISSlicer - pos += 2; - break; - - case 3: // Cura (old) - introString = "Cura at "; - pos += strlen(GeneratedByStrings[index]); - break; - } - - strcpy(parsedFileInfo.generatedBy, introString); - size_t i = strlen(introString); - while (i < ARRAY_SIZE(parsedFileInfo.generatedBy) - 1 && *pos >= ' ') - { - parsedFileInfo.generatedBy[i++] = *pos++; - } - parsedFileInfo.generatedBy[i] = 0; - } + headerInfoComplete &= FindSlicerInfo(buf, sizeToScan, parsedFileInfo.generatedBy.GetRef()); } - headerInfoComplete &= (parsedFileInfo.generatedBy[0] != 0); // Keep track of the time stats accumulatedParseTime += millis() - startTime; @@ -496,7 +453,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod // Seek at most 512 clusters at a time const FilePosition maxSeekDistance = 512 * (FilePosition)clsize; - const bool doFullSeek = (nextSeekPos <= currentPos) || (nextSeekPos - currentPos <= maxSeekDistance); + const bool doFullSeek = (nextSeekPos <= currentPos + maxSeekDistance); const FilePosition thisSeekPos = (doFullSeek) ? nextSeekPos : currentPos + maxSeekDistance; const uint32_t startTime = millis(); @@ -519,8 +476,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod case parsingFooter: { // Processing the footer. See how many bytes we need to read and if we can reuse the overlap - FilePosition pos = fileBeingParsed->Position(); - sizeToRead = (size_t)min<FilePosition>(fileBeingParsed->Length() - pos, GCODE_READ_SIZE); + sizeToRead = (size_t)min<FilePosition>(fileBeingParsed->Length() - nextSeekPos, GCODE_READ_SIZE); if (fileOverlapLength > 0) { memcpy(&buf[sizeToRead], fileOverlap, fileOverlapLength); @@ -583,7 +539,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod accumulatedParseTime += millis() - startTime; // If we've collected all details, scanned the last 192K of the file or if we cannot go any further, stop here. - if (footerInfoComplete || pos == 0 || fileBeingParsed->Length() - pos >= GCODE_FOOTER_SIZE) + if (footerInfoComplete || nextSeekPos == 0 || fileBeingParsed->Length() - nextSeekPos >= GCODE_FOOTER_SIZE) { if (reprap.Debug(modulePrintMonitor)) { @@ -600,7 +556,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod // Else go back further fileOverlapLength = (size_t)min<FilePosition>(sizeToScan, GCODE_OVERLAP_SIZE); memcpy(fileOverlap, buf, fileOverlapLength); - nextSeekPos = (pos <= GCODE_READ_SIZE) ? 0 : pos - GCODE_READ_SIZE; + nextSeekPos = (nextSeekPos <= GCODE_READ_SIZE) ? 0 : nextSeekPos - GCODE_READ_SIZE; parseState = seeking; } break; @@ -609,7 +565,8 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod info = parsedFileInfo; return true; } - } while (!isPrinting && millis() - loopStartTime < MAX_FILEINFO_PROCESS_TIME); + lastFileParseTime = millis(); + } while (!isPrinting && lastFileParseTime - loopStartTime < MAX_FILEINFO_PROCESS_TIME); return false; } @@ -659,7 +616,7 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp } } response->cat("],\"generatedBy\":"); - response->EncodeString(info.generatedBy, ARRAY_SIZE(info.generatedBy), false); + response->EncodeString(info.generatedBy.c_str(), info.generatedBy.MaxLength(), false); response->cat("}"); } else @@ -699,9 +656,9 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp } } response->cat("],\"generatedBy\":"); - response->EncodeString(printingFileInfo.generatedBy, ARRAY_SIZE(printingFileInfo.generatedBy), false); + response->EncodeString(printingFileInfo.generatedBy.GetRef(), false); response->catf(",\"printDuration\":%d,\"fileName\":", (int)GetPrintDuration()); - response->EncodeString(filenameBeingPrinted, ARRAY_SIZE(filenameBeingPrinted), false); + response->EncodeString(filenameBeingPrinted.GetRef(), false); response->cat('}'); } else @@ -717,22 +674,6 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp return true; } -// May be called from ISR -void PrintMonitor::StopParsing(const char *filename) -{ - if (parseState != notParsing && StringEquals(filenameBeingParsed, filename)) - { - if (filenameBeingPrinted[0] != 0 && !printingFileParsed) - { - // If this is the file we're parsing for internal purposes, don't bother with this request - return; - } - - parseState = notParsing; - fileBeingParsed->Close(); - } -} - // Estimate the print time left in seconds on a preset estimation method float PrintMonitor::EstimateTimeLeft(PrintEstimationMethod method) const { @@ -1085,6 +1026,58 @@ bool PrintMonitor::FindLayerHeight(const char *buf, size_t len, float& layerHeig return false; } +bool PrintMonitor::FindSlicerInfo(const char* buf, size_t len, const StringRef& generatedBy) const +{ + static const char * const GeneratedByStrings[] = + { + "generated by ", // slic3r and S3D + ";Sliced by ", // ideaMaker + "; KISSlicer", // KISSlicer + ";Sliced at: ", // Cura (old) + ";Generated with " // Cura (new) + }; + + size_t index = 0; + const char* pos; + do + { + pos = strstr(buf, GeneratedByStrings[index]); + if (pos != nullptr) + { + break; + } + ++index; + } while (index < ARRAY_SIZE(GeneratedByStrings)); + + if (pos != nullptr) + { + const char* introString = ""; + switch (index) + { + default: + pos += strlen(GeneratedByStrings[index]); + break; + + case 2: // KISSlicer + pos += 2; + break; + + case 3: // Cura (old) + introString = "Cura at "; + pos += strlen(GeneratedByStrings[index]); + break; + } + + generatedBy.copy(introString); + while (*pos >= ' ') + { + generatedBy.cat(*pos++); + } + return true; + } + return false; +} + // Scan the buffer for the filament used. The buffer is null-terminated. // Returns the number of filaments found. unsigned int PrintMonitor::FindFilamentUsed(const char* buf, size_t len, float *filamentUsed, size_t maxFilaments) const @@ -1092,7 +1085,7 @@ unsigned int PrintMonitor::FindFilamentUsed(const char* buf, size_t len, float * unsigned int filamentsFound = 0; // Look for filament usage as generated by Slic3r and Cura - const char* filamentUsedStr1 = "ilament used"; // comment string used by slic3r and Cura, followed by filament used and "mm" + const char* const filamentUsedStr1 = "ilament used"; // comment string used by slic3r and Cura, followed by filament used and "mm" const char* p = buf; while (filamentsFound < maxFilaments && (p = strstr(p, filamentUsedStr1)) != nullptr) { @@ -1101,20 +1094,33 @@ unsigned int PrintMonitor::FindFilamentUsed(const char* buf, size_t len, float * { ++p; // this allows for " = " from default slic3r comment and ": " from default Cura comment } - if (isDigit(*p)) + while (isDigit(*p)) { char* q; filamentUsed[filamentsFound] = strtod(p, &q); - if (*q == 'm' && *(q + 1) != 'm') + p = q; + if (*p == 'm') { - filamentUsed[filamentsFound] *= 1000.0; // Cura outputs filament used in metres not mm + ++p; + if (*p == 'm') + { + ++p; + } + else + { + filamentUsed[filamentsFound] *= 1000.0; // Cura outputs filament used in metres not mm + } } ++filamentsFound; + while (strchr(", \t", *p) != nullptr) + { + ++p; + } } } // Look for filament usage string generated by Ideamaker - const char* filamentUsedStr2 = ";Material#"; // comment string used by Ideamaker, e.g. ";Material#1 Used: 868.0" + const char* const filamentUsedStr2 = ";Material#"; // comment string used by Ideamaker, e.g. ";Material#1 Used: 868.0" p = buf; while (filamentsFound < maxFilaments && (p = strstr(p, filamentUsedStr2)) != nullptr) { @@ -1146,7 +1152,7 @@ unsigned int PrintMonitor::FindFilamentUsed(const char* buf, size_t len, float * p += strlen(filamentLengthStr); while(strchr(" :=\t", *p) != nullptr) { - ++p; // this allows for " = " from default slic3r comment and ": " from default Cura comment + ++p; } if (isDigit(*p)) { diff --git a/src/PrintMonitor.h b/src/PrintMonitor.h index 4f1cb56d..78348514 100644 --- a/src/PrintMonitor.h +++ b/src/PrintMonitor.h @@ -25,8 +25,8 @@ Licence: GPL const FilePosition GCODE_HEADER_SIZE = 20000uL; // How many bytes to read from the header - I (DC) have a Kisslicer file with a layer height comment 14Kb from the start const FilePosition GCODE_FOOTER_SIZE = 400000uL; // How many bytes to read from the footer -#if SAM4E || SAM4S -const size_t GCODE_READ_SIZE = 4096; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) +#if SAM4E || SAM4S || SAME70 +const size_t GCODE_READ_SIZE = 2048; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) #else const size_t GCODE_READ_SIZE = 1024; // How many bytes to read in one go in GetFileInfo() (should be a multiple of 512 for read efficiency) #endif @@ -42,6 +42,7 @@ const float FIRST_LAYER_SPEED_FACTOR = 0.25; // First layer speed factor compar const uint32_t PRINTMONITOR_UPDATE_INTERVAL = 200; // Update interval in milliseconds const uint32_t MAX_FILEINFO_PROCESS_TIME = 200; // Maximum time to spend polling for file info in each call +const uint32_t MaxFileParseInterval = 4000; // Maximum interval between repeat requests to parse a file enum PrintEstimationMethod { @@ -61,7 +62,7 @@ struct GCodeFileInfo float filamentNeeded[MaxExtruders]; unsigned int numFilaments; float layerHeight; - char generatedBy[50]; + String<50> generatedBy; }; enum FileParseState @@ -87,7 +88,6 @@ class PrintMonitor // The following two methods need to be called until they return true - this may take a few runs bool GetFileInfo(const char *directory, const char *fileName, GCodeFileInfo& info); bool GetFileInfoResponse(const char *filename, OutputBuffer *&response); - void StopParsing(const char *filename); // Return an estimate in seconds based on a specific estimation method float EstimateTimeLeft(PrintEstimationMethod method) const; @@ -100,13 +100,14 @@ class PrintMonitor float GetFirstLayerDuration() const; float GetFirstLayerHeight() const; - const char *GetPrintingFilename() const { return (isPrinting) ? filenameBeingPrinted : nullptr; } + const char *GetPrintingFilename() const { return (isPrinting) ? filenameBeingPrinted.c_str() : nullptr; } private: Platform& platform; GCodes& gCodes; uint32_t longWait; uint32_t lastUpdateTime; + uint32_t lastFileParseTime; // Information/Events concerning the file being printed void WarmUpComplete(); @@ -131,7 +132,7 @@ class PrintMonitor // We parse G-Code files in multiple stages. These variables hold the required information FileParseState parseState; - char filenameBeingParsed[MaxFilenameLength]; + String<MaxFilenameLength> filenameBeingParsed; FileStore *fileBeingParsed; FilePosition nextSeekPos; GCodeFileInfo parsedFileInfo; @@ -141,12 +142,13 @@ class PrintMonitor bool printingFileParsed; GCodeFileInfo printingFileInfo; - char filenameBeingPrinted[MaxFilenameLength]; + String<MaxFilenameLength> filenameBeingPrinted; // G-Code parser methods bool FindHeight(const char* buf, size_t len, float& height) const; bool FindFirstLayerHeight(const char* buf, size_t len, float& layerHeight) const; bool FindLayerHeight(const char* buf, size_t len, float& layerHeight) const; + bool FindSlicerInfo(const char* buf, size_t len, const StringRef& generatedBy) const; unsigned int FindFilamentUsed(const char* buf, size_t len, float *filamentUsed, size_t maxFilaments) const; uint32_t accumulatedParseTime, accumulatedReadTime, accumulatedSeekTime; diff --git a/src/RADDS/Pins_RADDS.h b/src/RADDS/Pins_RADDS.h index 2c0ce4ad..79076303 100644 --- a/src/RADDS/Pins_RADDS.h +++ b/src/RADDS/Pins_RADDS.h @@ -118,7 +118,7 @@ const Pin ATX_POWER_PIN = 40; // Z Probe pin // Must be an ADC capable pin. Can be any of the ARM's A/D capable // pins even a non-Arduino pin. -const Pin Z_PROBE_PIN = 5; // RADDS "ADC" pin +const Pin Z_PROBE_PIN = A5; // RADDS "ADC" pin // Digital pin number to turn the IR LED on (high) or off (low) // D34 -- unused X-max on RADDS diff --git a/src/Storage/FileStore.cpp b/src/Storage/FileStore.cpp index 652c78d4..86c24893 100644 --- a/src/Storage/FileStore.cpp +++ b/src/Storage/FileStore.cpp @@ -184,7 +184,7 @@ bool FileStore::ForceClose() writeBuffer = nullptr; } - FRESULT fr = f_close(&file); + const FRESULT fr = f_close(&file); inUse = false; writing = false; closeRequested = false; diff --git a/src/Version.h b/src/Version.h index 53dc216f..d90862b8 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.21RC3" +# define VERSION "1.21RC4" #endif #ifndef DATE -# define DATE "2018-02-28 build 4" +# define DATE "2018-03-11 build 1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" |