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

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2018-03-11 14:16:57 +0300
committerDavid Crocker <dcrocker@eschertech.com>2018-03-11 14:16:57 +0300
commitb1369644379aa9c6a1dd8f84d20210f32ded6dd5 (patch)
tree0d5e376cc33d1344e6d007540127b2746f1803be
parentafd7e327ec71865a2ecf0243265ef6f84387becb (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
-rw-r--r--src/BugList.txt160
-rw-r--r--src/Display/Display.cpp2
-rw-r--r--src/Duet/Network.cpp54
-rw-r--r--src/Duet/Webserver.cpp1
-rw-r--r--src/GCodes/GCodeBuffer.cpp16
-rw-r--r--src/GCodes/GCodeBuffer.h4
-rw-r--r--src/GCodes/GCodeInput.cpp2
-rw-r--r--src/GCodes/GCodeInput.h8
-rw-r--r--src/GCodes/GCodeMachineState.cpp4
-rw-r--r--src/GCodes/GCodeMachineState.h2
-rw-r--r--src/GCodes/GCodes.cpp234
-rw-r--r--src/GCodes/GCodes.h15
-rw-r--r--src/GCodes/GCodes2.cpp54
-rw-r--r--src/GCodes/GCodes3.cpp23
-rw-r--r--src/Heating/Pid.cpp38
-rw-r--r--src/Heating/Pid.h5
-rw-r--r--src/IoPorts.cpp19
-rw-r--r--src/IoPorts.h2
-rw-r--r--src/Libraries/General/StringRef.h1
-rw-r--r--src/Movement/Kinematics/CoreBaseKinematics.cpp2
-rw-r--r--src/Movement/Kinematics/CoreXYUKinematics.cpp2
-rw-r--r--src/Movement/Kinematics/CoreXYUVKinematics.cpp1
-rw-r--r--src/Movement/Kinematics/CoreXZKinematics.h1
-rw-r--r--src/Movement/Kinematics/HangprinterKinematics.cpp11
-rw-r--r--src/Movement/Kinematics/HangprinterKinematics.h1
-rw-r--r--src/Movement/Kinematics/Kinematics.h4
-rw-r--r--src/Movement/Kinematics/LinearDeltaKinematics.cpp20
-rw-r--r--src/Movement/Kinematics/LinearDeltaKinematics.h1
-rw-r--r--src/Movement/Kinematics/PolarKinematics.cpp11
-rw-r--r--src/Movement/Kinematics/PolarKinematics.h1
-rw-r--r--src/Movement/Kinematics/ScaraKinematics.cpp11
-rw-r--r--src/Movement/Kinematics/ScaraKinematics.h1
-rw-r--r--src/Movement/Kinematics/ZLeadscrewKinematics.cpp3
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp112
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.h3
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.cpp5
-rw-r--r--src/OutputMemory.cpp5
-rw-r--r--src/OutputMemory.h1
-rw-r--r--src/Platform.cpp1
-rw-r--r--src/PrintMonitor.cpp210
-rw-r--r--src/PrintMonitor.h16
-rw-r--r--src/RADDS/Pins_RADDS.h2
-rw-r--r--src/Storage/FileStore.cpp2
-rw-r--r--src/Version.h4
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"