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:
-rw-r--r--.cproject14
-rw-r--r--src/Fan.cpp2
-rw-r--r--src/FilamentMonitors/Duet3DFilamentMonitor.cpp207
-rw-r--r--src/FilamentMonitors/Duet3DFilamentMonitor.h56
-rw-r--r--src/FilamentMonitors/FilamentMonitor.cpp (renamed from src/FilamentSensors/FilamentSensor.cpp)58
-rw-r--r--src/FilamentMonitors/FilamentMonitor.h (renamed from src/FilamentSensors/FilamentSensor.h)22
-rw-r--r--src/FilamentMonitors/LaserFilamentMonitor.cpp356
-rw-r--r--src/FilamentMonitors/LaserFilamentMonitor.h81
-rw-r--r--src/FilamentMonitors/PulsedFilamentMonitor.cpp251
-rw-r--r--src/FilamentMonitors/PulsedFilamentMonitor.h60
-rw-r--r--src/FilamentMonitors/RotatingMagnetFilamentMonitor.cpp300
-rw-r--r--src/FilamentMonitors/RotatingMagnetFilamentMonitor.h69
-rw-r--r--src/FilamentMonitors/SimpleFilamentMonitor.cpp (renamed from src/FilamentSensors/SimpleFilamentSensor.cpp)20
-rw-r--r--src/FilamentMonitors/SimpleFilamentMonitor.h (renamed from src/FilamentSensors/SimpleFilamentSensor.h)14
-rw-r--r--src/FilamentSensors/Duet3DFilamentSensor.cpp434
-rw-r--r--src/FilamentSensors/Duet3DFilamentSensor.h83
-rw-r--r--src/GCodes/GCodeBuffer.cpp36
-rw-r--r--src/GCodes/GCodeBuffer.h4
-rw-r--r--src/GCodes/GCodes.cpp67
-rw-r--r--src/GCodes/GCodes.h2
-rw-r--r--src/GCodes/GCodes2.cpp36
-rw-r--r--src/GCodes/GCodes3.cpp8
-rw-r--r--src/Movement/DDA.cpp26
-rw-r--r--src/Movement/DDA.h19
-rw-r--r--src/Movement/DriveMovement.cpp12
-rw-r--r--src/Movement/Move.cpp26
-rw-r--r--src/Movement/Move.h3
-rw-r--r--src/Network2/ESP8266/Network.cpp2
-rw-r--r--src/Network2/W5500/Network.cpp3
-rw-r--r--src/Network2/W5500/Wiznet/Ethernet/WizSpi.cpp9
-rw-r--r--src/Platform.cpp71
-rw-r--r--src/Platform.h5
-rw-r--r--src/PortControl.cpp2
-rw-r--r--src/PrintMonitor.cpp62
-rw-r--r--src/RepRap.cpp6
-rw-r--r--src/RepRapFirmware.h2
-rw-r--r--src/Version.h4
37 files changed, 1699 insertions, 733 deletions
diff --git a/.cproject b/.cproject
index 1b3e2d88..d6267e54 100644
--- a/.cproject
+++ b/.cproject
@@ -110,7 +110,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/Network2|src/Alligator|src/Duet/Lwip/lwip/src/core/ipv6|src/Duet/Lwip/lwip/test|src/DuetNG|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Network2|src/Alligator|src/Duet/Lwip/lwip/src/core/ipv6|src/Duet/Lwip/lwip/test|src/SAME70_TEST|src/DuetNG|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -228,7 +228,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/Network2/W5500|src/Alligator|src/Duet|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Network2/W5500|src/Alligator|src/SAME70_TEST|src/Duet|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -338,7 +338,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/Network2|src/Alligator|src/Duet|src/DuetNG|src/DuetM" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Network2|src/Alligator|src/SAME70_TEST|src/Duet|src/DuetNG|src/DuetM" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -461,7 +461,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/Alligator|src/Duet|src/DuetM|src/Network2/ESP8266|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Alligator|src/SAME70_TEST|src/Duet|src/DuetM|src/Network2/ESP8266|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -582,7 +582,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/Network2|src/Duet/Lwip/lwip/src/core/ipv6|src/Duet/Lwip/lwip/test|src/DuetNG|src/DuetM|src/Alligator/Lwip/lwip/src/include/ipv6|src/Alligator/Lwip/lwip/test|src/Duet/MCP4461|src/Alligator/Lwip/lwip/src/core/ipv6|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Network2|src/Duet/Lwip/lwip/src/core/ipv6|src/Duet/Lwip/lwip/test|src/SAME70_TEST|src/DuetNG|src/DuetM|src/Alligator/Lwip/lwip/src/include/ipv6|src/Alligator/Lwip/lwip/test|src/Duet/MCP4461|src/Alligator/Lwip/lwip/src/core/ipv6|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -703,7 +703,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/SAME70_TEST|src/DuetNG/DuetEthernet/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Ethernet3|src/DuetNG/DuetWiFi|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPServer|src/Duet|src/NetworkW5500/Wiznet/Internet/SNMP|src/DuetNG/DuetEthernet/Wiznet/Internet/SNTP|src/DuetNG/DuetEthernet/Ethernet3/examples|src/DuetNG|src/DuetNG/DuetEthernet/Wiznet/Internet/DNS|src/NetworkW5500/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Wiznet/Application|src/DuetNG/DuetEthernet/Wiznet/Internet/MQTT|src/Alligator|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPClient|src/DuetNG/DuetEthernet/Wiznet/Internet/httpServer|src/NetworkW5500/Wiznet/Internet/SNTP|src/NetworkW5500/Wiznet/Internet/DNS|src/DuetNG/DuetEthernet/Wiznet/Internet/SNMP|src/NetworkESP8266|src/Network2/ESP8266|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/DuetNG/DuetEthernet/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Ethernet3|src/DuetNG/DuetWiFi|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPServer|src/Duet|src/NetworkW5500/Wiznet/Internet/SNMP|src/DuetNG/DuetEthernet/Wiznet/Internet/SNTP|src/DuetNG/DuetEthernet/Ethernet3/examples|src/DuetNG|src/DuetNG/DuetEthernet/Wiznet/Internet/DNS|src/NetworkW5500/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Wiznet/Application|src/DuetNG/DuetEthernet/Wiznet/Internet/MQTT|src/Alligator|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPClient|src/SAME70_TEST|src/DuetNG/DuetEthernet/Wiznet/Internet/httpServer|src/NetworkW5500/Wiznet/Internet/SNTP|src/NetworkW5500/Wiznet/Internet/DNS|src/DuetNG/DuetEthernet/Wiznet/Internet/SNMP|src/NetworkESP8266|src/Network2/ESP8266|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@@ -847,7 +847,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="src/DuetM|src/Network2/W5500|src/Network2|src/DuetNG/DuetWiFi|src/Duet|src/DuetNG/DuetEthernet/Wiznet/Internet/SNTP|src/DuetNG|src/DuetNG/DuetEthernet/Wiznet/Internet/DNS|src/DuetNG/DuetEthernet/Wiznet/Application|src/DuetNG/DuetEthernet/Wiznet/Internet/MQTT|src/Alligator|src/SAME70_TEST/Lwip/src/apps/mqtt|src/DuetNG/DuetEthernet/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Ethernet3|src/SAME70_TEST/Lwip/src/apps/snmp|src/SAME70_TEST/Lwip/src/apps/httpd|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPServer|src/SAME70_TEST/Lwip/src/apps/tftp|src/DuetNG/DuetEthernet/Ethernet3/examples|src/SAME70_TEST/Lwip/test|src/SAME70_TEST/Lwip/src/netif/ppp|src/SAME70_TEST/Lwip/src/apps/lwiperf|src/SAME70_TEST/Lwip/src/apps/sntp|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPClient|src/DuetNG/DuetEthernet/Wiznet/Internet/httpServer|src/DuetNG/DuetEthernet/Wiznet/Internet/SNMP|src/Network2/ESP8266|src/RADDS|src/SAME70_TEST/Lwip/doc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ <entry excluding="src/Network2/W5500|src/Network2|src/SAME70_TEST/Lwip/src/netif/ppp|src/DuetNG/DuetWiFi|src/Duet|src/SAME70_TEST/Lwip/doc|src/DuetNG/DuetEthernet/Wiznet/Internet/SNTP|src/DuetNG|src/DuetNG/DuetEthernet/Wiznet/Internet/DNS|src/DuetNG/DuetEthernet/Wiznet/Application|src/DuetNG/DuetEthernet/Wiznet/Internet/MQTT|src/Alligator|src/SAME70_TEST/Lwip/test|src/SAME70_TEST/Lwip/src/apps/snmp|src/SAME70_TEST/Lwip/src/apps/httpd|src/SAME70_TEST/Lwip/src/apps/tftp|src/DuetNG/DuetEthernet/Wiznet/Internet/TFTP|src/DuetNG/DuetEthernet/Ethernet3|src/SAME70_TEST/Lwip/src/apps/lwiperf|src/SAME70_TEST/Lwip/src/apps/sntp|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPServer|src/DuetNG/DuetEthernet/Ethernet3/examples|src/SAME70_TEST/Lwip/src/apps/mqtt|src/DuetNG/DuetEthernet/Wiznet/Internet/FTPClient|src/DuetNG/DuetEthernet/Wiznet/Internet/httpServer|src/DuetNG/DuetEthernet/Wiznet/Internet/SNMP|src/DuetM|src/Network2/ESP8266|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
diff --git a/src/Fan.cpp b/src/Fan.cpp
index d704abbe..efd73200 100644
--- a/src/Fan.cpp
+++ b/src/Fan.cpp
@@ -97,7 +97,7 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, StringRef&
seen = true;
int32_t heaters[Heaters + MaxVirtualHeaters]; // signed because we use H-1 to disable thermostatic mode
size_t numH = ARRAY_SIZE(heaters);
- gb.GetIntArray(heaters, numH);
+ gb.GetIntArray(heaters, numH, false);
// Note that M106 H-1 disables thermostatic mode. The following code implements that automatically.
heatersMonitored = 0;
diff --git a/src/FilamentMonitors/Duet3DFilamentMonitor.cpp b/src/FilamentMonitors/Duet3DFilamentMonitor.cpp
new file mode 100644
index 00000000..051fefa1
--- /dev/null
+++ b/src/FilamentMonitors/Duet3DFilamentMonitor.cpp
@@ -0,0 +1,207 @@
+/*
+ * Duet3DFilamentSensor.cpp
+ *
+ * Created on: 20 Jul 2017
+ * Author: David
+ */
+
+#include "Duet3DFilamentMonitor.h"
+#include "GCodes/GCodeBuffer.h"
+#include "Platform.h"
+#include "Movement/DDA.h" // for stepClockRate
+
+// Constructors
+Duet3DFilamentMonitor::Duet3DFilamentMonitor(int type)
+ : FilamentMonitor(type)
+{
+ InitReceiveBuffer();
+}
+
+void Duet3DFilamentMonitor::InitReceiveBuffer()
+{
+ edgeCaptureReadPointer = edgeCaptureWritePointer = 1;
+ edgeCaptures[0] = Platform::GetInterruptClocks(); // pretend we just had a high-to-low transition
+ state = RxdState::waitingForStartBit;
+}
+
+// ISR for when the pin state changes
+void Duet3DFilamentMonitor::Interrupt()
+{
+ uint32_t now = Platform::GetInterruptClocks();
+ const size_t writePointer = edgeCaptureWritePointer; // capture volatile variable
+ if ((writePointer + 1) % EdgeCaptureBufferSize != edgeCaptureReadPointer)
+ {
+ if (IoPort::ReadPin(GetPin()))
+ {
+ if ((writePointer & 1) == 0) // low-to-high transitions should occur on odd indices
+ {
+ return;
+ }
+ }
+ else
+ {
+ if ((writePointer & 1) != 0) // high-to-low transitions should occur on even indices
+ {
+ return;
+ }
+ now -= 40; // partial correction for skew caused by debounce filter on Duet endstop inputs (measured skew = 74)
+ }
+ }
+
+ edgeCaptures[writePointer] = now; // record the time at which this edge was detected
+ edgeCaptureWritePointer = (writePointer + 1) % EdgeCaptureBufferSize;
+}
+
+// Call the following regularly to keep the status up to date
+void Duet3DFilamentMonitor::PollReceiveBuffer()
+{
+ // For the Duet3D sensors we need to decode the received data from the transition times recorded in the edgeCaptures array
+ static constexpr uint32_t BitsPerSecond = 1000; // the nominal bit rate that the data is transmitted at
+ static constexpr uint32_t NominalBitLength = DDA::stepClockRate/BitsPerSecond; // the nominal bit length in step clocks
+ static constexpr uint32_t MinBitLength = (NominalBitLength * 10)/13; // allow 30% clock speed tolerance
+ static constexpr uint32_t MaxBitLength = (NominalBitLength * 13)/10; // allow 30% clock speed tolerance
+ static constexpr uint32_t ErrorRecoveryDelayBits = 8; // before a start bit we want the line to be low for this long
+ static constexpr uint32_t ErrorRecoveryTime = NominalBitLength * ErrorRecoveryDelayBits;
+
+ bool again;
+ do
+ {
+ again = false;
+ const size_t writePointer = edgeCaptureWritePointer; // capture volatile variable
+ const uint32_t now = Platform::GetInterruptClocks();
+ switch (state)
+ {
+ case RxdState::waitingForStartBit:
+ if (writePointer != edgeCaptureReadPointer) // if we have recorded any new edges
+ {
+ if ((edgeCaptureReadPointer & 1u) == 0) // if we are out of sync (this is normal when the last stuffing bit was a 1)
+ {
+ edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
+ again = true;
+ }
+ else
+ {
+ if (edgeCaptures[edgeCaptureReadPointer] - edgeCaptures[(edgeCaptureReadPointer - 1) % EdgeCaptureBufferSize] < ErrorRecoveryTime)
+ {
+ // The input line has not been idle for long enough before the start bit
+ edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize; // ignore this start bit
+ state = RxdState::errorRecovery1;
+ again = true;
+ }
+ else
+ {
+ OnStartBitReceived();
+ state = RxdState::waitingForEndOfStartBit;
+ again = true;
+ }
+ }
+ }
+ break;
+
+ case RxdState::waitingForEndOfStartBit:
+ // This state must time out because while we are in it, comparison of filament extruded is suspended
+ if ((writePointer - edgeCaptureReadPointer) % EdgeCaptureBufferSize >= 2)
+ {
+ // Check for a valid start bit
+ lastBitChangeIndex = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
+ startBitLength = edgeCaptures[lastBitChangeIndex] - edgeCaptures[edgeCaptureReadPointer];
+ edgeCaptureReadPointer = lastBitChangeIndex;
+ if (startBitLength >= MinBitLength && startBitLength <= MaxBitLength)
+ {
+ valueBeingAssembled = 0;
+ nibblesAssembled = 0;
+ state = RxdState::waitingForNibble;
+ again = true;
+ //debugPrintf("sb %u\n", startBitLength);
+ }
+ else
+ {
+ // Start bit too long or too short
+ state = RxdState::errorRecovery2;
+ again = true;
+ }
+ }
+ else if (now - edgeCaptures[edgeCaptureReadPointer] > MaxBitLength) // check for timeout
+ {
+ edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
+ state = RxdState::errorRecovery2;
+ again = true;
+ }
+ break;
+
+ case RxdState::waitingForNibble:
+ // This state must time out because while we are in it, comparison of filament extruded is suspended
+ {
+ const uint32_t nibbleStartTime = edgeCaptures[lastBitChangeIndex];
+ if (now - nibbleStartTime > (13 * startBitLength)/2)
+ {
+ // 6.5 bit times have passed since the start of the bit that preceded the current nibble, so we should have a complete nibble and the following stuffing bit
+ uint32_t samplePoint = (startBitLength * 3)/2; // sampling time after the end of the start bit for bit 7 (MSB)
+ uint8_t currentNibble = 0;
+ size_t nextBitChangeIndex = (lastBitChangeIndex + 1u) % EdgeCaptureBufferSize;
+ for (uint8_t numBits = 0; numBits < 5; ++numBits)
+ {
+ if (nextBitChangeIndex != edgeCaptureWritePointer && edgeCaptures[nextBitChangeIndex] - nibbleStartTime < samplePoint)
+ {
+ lastBitChangeIndex = nextBitChangeIndex;
+ nextBitChangeIndex = (lastBitChangeIndex + 1u) % EdgeCaptureBufferSize;
+ if (nextBitChangeIndex != writePointer && edgeCaptures[nextBitChangeIndex] - nibbleStartTime < samplePoint)
+ {
+ edgeCaptureReadPointer = nextBitChangeIndex;
+ state = RxdState::errorRecovery3;
+ again = true;
+ break;
+ }
+ }
+ currentNibble <<= 1;
+ currentNibble |= (uint8_t)(lastBitChangeIndex & 1u);
+ samplePoint += startBitLength;
+ }
+
+ if (state != RxdState::waitingForNibble)
+ {
+ break;
+ }
+
+ // The 5th bit we received should be the inverse of the 4th bit
+ if ((((currentNibble >> 1u) ^ currentNibble) & 0x01u) == 0)
+ {
+ edgeCaptureReadPointer = nextBitChangeIndex;
+ state = RxdState::errorRecovery4;
+ again = true;
+ break;
+ }
+
+ currentNibble >>= 1;
+ valueBeingAssembled = (valueBeingAssembled << 4) | currentNibble;
+ ++nibblesAssembled;
+ if (nibblesAssembled == 4) // if we have a complete 16-bit word
+ {
+ edgeCaptureReadPointer = nextBitChangeIndex; // ready for a new word
+ ProcessReceivedWord(valueBeingAssembled);
+ state = RxdState::waitingForStartBit;
+ }
+ again = true;
+ }
+ }
+ break;
+
+ default: // error recovery states
+ if (reprap.Debug(moduleFilamentSensors))
+ {
+ debugPrintf("Fil err %u\n", (unsigned int)state);
+ }
+ state = RxdState::waitingForStartBit;
+ again = true;
+ break;
+ }
+ } while (again);
+}
+
+// Return true if we are on the process of receiving data form the filament monitor
+bool Duet3DFilamentMonitor::IsReceiving() const
+{
+ return state == RxdState::waitingForEndOfStartBit || state == RxdState::waitingForNibble;
+}
+
+// End
diff --git a/src/FilamentMonitors/Duet3DFilamentMonitor.h b/src/FilamentMonitors/Duet3DFilamentMonitor.h
new file mode 100644
index 00000000..837093e4
--- /dev/null
+++ b/src/FilamentMonitors/Duet3DFilamentMonitor.h
@@ -0,0 +1,56 @@
+/*
+ * Duet3DFilamentSensor.h
+ *
+ * Created on: 20 Jul 2017
+ * Author: David
+ *
+ * This is the base class for filament monitors that use the Duet3D protocol for sending 16-bit words to the Duet.
+ */
+
+#ifndef SRC_FILAMENTSENSORS_DUET3DFILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_DUET3DFILAMENTMONITOR_H_
+
+#include "FilamentMonitor.h"
+
+class Duet3DFilamentMonitor : public FilamentMonitor
+{
+public:
+ Duet3DFilamentMonitor(int type);
+
+ void Interrupt() override;
+
+protected:
+ virtual void OnStartBitReceived() = 0;
+ virtual void ProcessReceivedWord(uint16_t val) = 0;
+ void InitReceiveBuffer();
+ void PollReceiveBuffer();
+ bool IsReceiving() const;
+
+private:
+ static constexpr size_t EdgeCaptureBufferSize = 64; // must be a power of 2
+
+ // Buffer used to capture received data, and associated info
+ uint32_t edgeCaptures[EdgeCaptureBufferSize];
+ size_t edgeCaptureReadPointer;
+ volatile size_t edgeCaptureWritePointer;
+
+ enum class RxdState : uint8_t
+ {
+ waitingForStartBit,
+ waitingForEndOfStartBit,
+ waitingForNibble,
+ errorRecovery1,
+ errorRecovery2,
+ errorRecovery3,
+ errorRecovery4
+ };
+
+ RxdState state;
+ uint32_t startBitLength;
+ uint32_t errorRecoveryStartTime;
+ size_t lastBitChangeIndex;
+ uint16_t valueBeingAssembled;
+ uint8_t nibblesAssembled;
+};
+
+#endif /* SRC_FILAMENTSENSORS_DUET3DFILAMENTMONITOR_H_ */
diff --git a/src/FilamentSensors/FilamentSensor.cpp b/src/FilamentMonitors/FilamentMonitor.cpp
index b7a9c9a9..4d370bea 100644
--- a/src/FilamentSensors/FilamentSensor.cpp
+++ b/src/FilamentMonitors/FilamentMonitor.cpp
@@ -5,9 +5,11 @@
* Author: David
*/
-#include "FilamentSensor.h"
-#include "SimpleFilamentSensor.h"
-#include "Duet3DFilamentSensor.h"
+#include "FilamentMonitor.h"
+#include "SimpleFilamentMonitor.h"
+#include "RotatingMagnetFilamentMonitor.h"
+#include "LaserFilamentMonitor.h"
+#include "PulsedFilamentMonitor.h"
#include "RepRap.h"
#include "Platform.h"
#include "GCodes/GCodeBuffer.h"
@@ -15,10 +17,10 @@
#include "PrintMonitor.h"
// Static data
-FilamentSensor *FilamentSensor::filamentSensors[MaxExtruders] = { 0 };
+FilamentMonitor *FilamentMonitor::filamentSensors[MaxExtruders] = { 0 };
// Default destructor
-FilamentSensor::~FilamentSensor()
+FilamentMonitor::~FilamentMonitor()
{
if (pin != NoPin)
{
@@ -28,7 +30,7 @@ FilamentSensor::~FilamentSensor()
// Try to get the pin number from the GCode command in the buffer, setting Seen if a pin number was provided and returning true if error.
// Also attaches the ISR.
-bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
+bool FilamentMonitor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, uint32_t interruptMode, bool& seen)
{
if (gb.Seen('C'))
{
@@ -43,7 +45,7 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
endstopNumber = endstop;
pin = p;
- attachInterrupt(pin, InterruptEntry, CHANGE, this);
+ attachInterrupt(pin, InterruptEntry, interruptMode, this);
}
else if (seen)
{
@@ -55,18 +57,25 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
// Factory function
-/*static*/ FilamentSensor *FilamentSensor::Create(int type)
+/*static*/ FilamentMonitor *FilamentMonitor::Create(int type)
{
switch (type)
{
case 1: // active high switch
case 2: // active low switch
- return new SimpleFilamentSensor(type);
+ return new SimpleFilamentMonitor(type);
break;
- case 3: // duet3d, no switch
- case 4: // duet3d + switch
- return new Duet3DFilamentSensor(type);
+ case 3: // duet3d rotating magnet, no switch
+ case 4: // duet3d rotating magnet + switch
+ return new RotatingMagnetFilamentMonitor(type);
+
+ case 5: // duet3d laser, no switch
+ case 6: // duet3d laser + switch
+ return new LaserFilamentMonitor(type);
+
+ case 7: // simple pulse output sensor
+ return new PulsedFilamentMonitor(type);
break;
default: // no sensor, or unknown sensor
@@ -75,7 +84,7 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
// Return an error message corresponding to a status code
-/*static*/ const char *FilamentSensor::GetErrorMessage(FilamentSensorStatus f)
+/*static*/ const char *FilamentMonitor::GetErrorMessage(FilamentSensorStatus f)
{
switch(f)
{
@@ -89,12 +98,12 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
// ISR
-/*static*/ void FilamentSensor::InterruptEntry(CallbackParameter param)
+/*static*/ void FilamentMonitor::InterruptEntry(CallbackParameter param)
{
- static_cast<FilamentSensor*>(param.vp)->Interrupt();
+ static_cast<FilamentMonitor*>(param.vp)->Interrupt();
}
-/*static*/ void FilamentSensor::Spin(bool full)
+/*static*/ void FilamentMonitor::Spin(bool full)
{
// Filament sensors
for (size_t extruder = 0; extruder < MaxExtruders; ++extruder)
@@ -102,16 +111,17 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
if (filamentSensors[extruder] != nullptr)
{
GCodes& gCodes = reprap.GetGCodes();
- const float extrusionCommanded = (float)reprap.GetMove().GetAccumulatedExtrusion(extruder)/reprap.GetPlatform().DriveStepsPerUnit(extruder + gCodes.GetTotalAxes());
- // get and clear the Move extrusion commanded
+ bool wasNonPrinting;
+ const int32_t extruderStepsCommanded = reprap.GetMove().GetAccumulatedExtrusion(extruder, wasNonPrinting); // get and clear the net extrusion commanded
if (gCodes.IsReallyPrinting() && !gCodes.IsSimulating())
{
- const FilamentSensorStatus fstat = filamentSensors[extruder]->Check(full, extrusionCommanded);
+ const float extrusionCommanded = (float)extruderStepsCommanded/reprap.GetPlatform().DriveStepsPerUnit(extruder + gCodes.GetTotalAxes());
+ const FilamentSensorStatus fstat = filamentSensors[extruder]->Check(full, wasNonPrinting, extrusionCommanded);
if (full && fstat != FilamentSensorStatus::ok && extrusionCommanded > 0.0)
{
if (reprap.Debug(moduleFilamentSensors))
{
- debugPrintf("Filament error: extruder %u reports %s\n", extruder, FilamentSensor::GetErrorMessage(fstat));
+ debugPrintf("Filament error: extruder %u reports %s\n", extruder, FilamentMonitor::GetErrorMessage(fstat));
}
else
{
@@ -128,17 +138,17 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
// Return the filament sensor associated with a particular extruder
-/*static*/ FilamentSensor *FilamentSensor::GetFilamentSensor(unsigned int extruder)
+/*static*/ FilamentMonitor *FilamentMonitor::GetFilamentSensor(unsigned int extruder)
{
return (extruder < MaxExtruders) ? filamentSensors[extruder] : nullptr;
}
// Set the filament sensor associated with a particular extruder
-/*static*/ bool FilamentSensor::SetFilamentSensorType(unsigned int extruder, int newSensorType)
+/*static*/ bool FilamentMonitor::SetFilamentSensorType(unsigned int extruder, int newSensorType)
{
if (extruder < MaxExtruders)
{
- FilamentSensor*& sensor = filamentSensors[extruder];
+ FilamentMonitor*& sensor = filamentSensors[extruder];
const int oldSensorType = (sensor == nullptr) ? 0 : sensor->GetType();
if (newSensorType != oldSensorType)
{
@@ -152,7 +162,7 @@ bool FilamentSensor::ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen)
}
// Send diagnostics info
-/*static*/ void FilamentSensor::Diagnostics(MessageType mtype)
+/*static*/ void FilamentMonitor::Diagnostics(MessageType mtype)
{
bool first = true;
for (size_t i = 0; i < MaxExtruders; ++i)
diff --git a/src/FilamentSensors/FilamentSensor.h b/src/FilamentMonitors/FilamentMonitor.h
index 2483cec3..373295d5 100644
--- a/src/FilamentSensors/FilamentSensor.h
+++ b/src/FilamentMonitors/FilamentMonitor.h
@@ -5,8 +5,8 @@
* Author: David
*/
-#ifndef SRC_FILAMENTSENSORS_FILAMENTSENSOR_H_
-#define SRC_FILAMENTSENSORS_FILAMENTSENSOR_H_
+#ifndef SRC_FILAMENTSENSORS_FILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_FILAMENTMONITOR_H_
#include "RepRapFirmware.h"
#include "MessageType.h"
@@ -20,7 +20,7 @@ enum class FilamentSensorStatus : uint8_t
sensorError
};
-class FilamentSensor
+class FilamentMonitor
{
public:
// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
@@ -28,7 +28,7 @@ public:
// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
- virtual FilamentSensorStatus Check(bool full, float filamentConsumed) = 0;
+ virtual FilamentSensorStatus Check(bool full, bool hadNonPrintingMove, float filamentConsumed) = 0;
// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
virtual FilamentSensorStatus Clear(bool full) = 0;
@@ -40,7 +40,7 @@ public:
virtual void Interrupt() = 0;
// Override the virtual destructor if your derived class allocates any dynamic memory
- virtual ~FilamentSensor();
+ virtual ~FilamentMonitor();
// Return the type of this sensor
int GetType() const { return type; }
@@ -52,7 +52,7 @@ public:
static void Spin(bool full);
// Return the filament sensor associated with a particular extruder
- static FilamentSensor *GetFilamentSensor(unsigned int extruder);
+ static FilamentMonitor *GetFilamentSensor(unsigned int extruder);
// Set the filament sensor associated with a particular extruder
static bool SetFilamentSensorType(unsigned int extruder, int newSensorType);
@@ -61,9 +61,9 @@ public:
static void Diagnostics(MessageType mtype);
protected:
- FilamentSensor(int t) : type(t), pin(NoPin) { }
+ FilamentMonitor(int t) : type(t), pin(NoPin) { }
- bool ConfigurePin(GCodeBuffer& gb, StringRef& reply, bool& seen);
+ bool ConfigurePin(GCodeBuffer& gb, StringRef& reply, uint32_t interruptMode, bool& seen);
int GetEndstopNumber() const { return endstopNumber; }
@@ -71,15 +71,15 @@ protected:
private:
// Create a filament sensor returning null if not a valid sensor type
- static FilamentSensor *Create(int type);
+ static FilamentMonitor *Create(int type);
static void InterruptEntry(CallbackParameter param);
- static FilamentSensor *filamentSensors[MaxExtruders];
+ static FilamentMonitor *filamentSensors[MaxExtruders];
int type;
int endstopNumber;
Pin pin;
};
-#endif /* SRC_FILAMENTSENSORS_FILAMENTSENSOR_H_ */
+#endif /* SRC_FILAMENTSENSORS_FILAMENTMONITOR_H_ */
diff --git a/src/FilamentMonitors/LaserFilamentMonitor.cpp b/src/FilamentMonitors/LaserFilamentMonitor.cpp
new file mode 100644
index 00000000..cd23311d
--- /dev/null
+++ b/src/FilamentMonitors/LaserFilamentMonitor.cpp
@@ -0,0 +1,356 @@
+/*
+ * LaserFilamentMonitor.cpp
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#include "LaserFilamentMonitor.h"
+#include "GCodes/GCodeBuffer.h"
+#include "Platform.h"
+#include "RepRap.h"
+
+LaserFilamentMonitor::LaserFilamentMonitor(int type)
+ : Duet3DFilamentMonitor(type),
+ minMovementAllowed(DefaultMinMovementAllowed), maxMovementAllowed(DefaultMaxMovementAllowed),
+ minimumExtrusionCheckLength(DefaultMinimumExtrusionCheckLength), comparisonEnabled(false)
+{
+ switchOpenMask = (type == 6) ? TypeLaserSwitchOpenMask : 0;
+ Init();
+}
+
+void LaserFilamentMonitor::Init()
+{
+ sensorValue = 0;
+ parityErrorCount = 0;
+ lastMeasurementTime = 0;
+ backwards = false;
+ InitReceiveBuffer();
+ Reset();
+}
+
+void LaserFilamentMonitor::Reset()
+{
+ extrusionCommanded = movementMeasured = extrusionCommandedAtLastMeasurement = extrusionCommandedAtStartBit = movementMeasuredAtLastCheck = 0.0;
+ samplesReceived = 0;
+ laserMonitorState = LaserMonitorState::idle;
+}
+
+// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
+bool LaserFilamentMonitor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
+{
+ if (ConfigurePin(gb, reply, CHANGE, seen))
+ {
+ return true;
+ }
+
+ gb.TryGetFValue('E', minimumExtrusionCheckLength, seen);
+
+ if (gb.Seen('R'))
+ {
+ seen = true;
+ size_t numValues = 2;
+ uint32_t minMax[2];
+ gb.GetUnsignedArray(minMax, numValues, false);
+ if (numValues > 0)
+ {
+ minMovementAllowed = (float)minMax[0] * 0.01;
+ }
+ if (numValues > 1)
+ {
+ maxMovementAllowed = (float)minMax[1] * 0.01;
+ }
+ }
+
+ if (gb.Seen('S'))
+ {
+ seen = true;
+ comparisonEnabled = (gb.GetIValue() > 0);
+ }
+
+ if (seen)
+ {
+ Init();
+ }
+ else
+ {
+ reply.printf("Duet3D laser filament monitor%s on endstop input %u, %s, allowed movement %ld%% to %ld%%, check every %.1fmm, ",
+ (switchOpenMask != 0) ? " with microswitch" : "",
+ GetEndstopNumber(),
+ (comparisonEnabled) ? "enabled" : "disabled",
+ lrintf(minMovementAllowed * 100.0),
+ lrintf(maxMovementAllowed * 100.0),
+ (double)minimumExtrusionCheckLength);
+
+ if (!dataReceived)
+ {
+ reply.cat("no data received");
+ }
+ else if ((sensorValue & TypeLaserErrorMask) != 0)
+ {
+ reply.cat("error");
+ }
+ else
+ {
+ reply.catf("current position %.1f, brightness %u, shutter %u, ", (double)GetCurrentPosition(), qualityWord & 0x00FF, (qualityWord >> 8) & 0x3F);
+ if (laserMonitorState != LaserMonitorState::calibrating && totalExtrusionCommanded > 10.0)
+ {
+ reply.catf("measured minimum %ld%%, average %ld%%, maximum %ld%% over %.1fmm",
+ lrintf(100 * minMovementRatio),
+ lrintf((100 * totalMovementMeasured)/totalExtrusionCommanded),
+ lrintf(100 * maxMovementRatio),
+ (double)totalExtrusionCommanded);
+ }
+ else
+ {
+ reply.cat("no calibration data");
+ }
+ }
+ }
+
+ return false;
+}
+
+// This is called from the poll function when we receive what could be a start bit
+void LaserFilamentMonitor::OnStartBitReceived() /*override*/
+{
+ extrusionCommandedAtStartBit = extrusionCommanded; // record the extrusion
+}
+
+// This is called from the poll function when we have received a complete word of data
+void LaserFilamentMonitor::ProcessReceivedWord(uint16_t val) /*override*/
+{
+ // Check the parity
+ uint8_t data8 = (uint8_t)((val >> 8) ^ val);
+ data8 ^= (data8 >> 4);
+ data8 ^= (data8 >> 2);
+ data8 ^= (data8 >> 1);
+ if ((data8 & 1) != 0)
+ {
+ ++parityErrorCount;
+ return; // parity error, so ignore the data
+ }
+
+ // Check whether this is a quality report
+ if ((val & TypeLaserQualityMask) != 0)
+ {
+ qualityWord = val & ~(TypeLaserQualityMask | TypeLaserParityMask); // record the quality report
+ return;
+ }
+
+ // We received a position report
+ if (samplesReceived == 0)
+ {
+ dataReceived = true;
+ extrusionCommanded -= extrusionCommandedAtStartBit;
+ extrusionCommandedAtStartBit = 0;
+ movementMeasured = 0.0; // use the first measurement sample as a baseline
+ }
+ else
+ {
+ const uint16_t positionChange = (val - sensorValue) & TypeLaserPositionMask; // position change in range 0..1023
+ const int32_t movement = (positionChange <= 512) ? (int32_t)positionChange : (int32_t)positionChange - 1024;
+ movementMeasured += (float)movement * 0.02;
+ }
+
+ lastMeasurementTime = millis();
+ extrusionCommandedAtLastMeasurement = extrusionCommandedAtStartBit;
+ sensorValue = val;
+ if (samplesReceived < 100)
+ {
+ ++samplesReceived;
+ }
+}
+
+// Return the current wheel angle
+float LaserFilamentMonitor::GetCurrentPosition() const
+{
+ int32_t pos = (int32_t)(sensorValue & TypeLaserPositionMask);
+ if (pos > 512)
+ {
+ pos -= 1024;
+ }
+ return (float)pos * 0.02; // each count is nominally 0.02mm of filament motion @ 5 * 254 cpi
+}
+
+// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
+// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
+// 'hadNonPrintingMove' is called if filamentConsumed includes extruder movement form non-printing moves.
+FilamentSensorStatus LaserFilamentMonitor::Check(bool full, bool hadNonPrintingMove, float filamentConsumed)
+{
+ PollReceiveBuffer(); // this may update movementMeasured
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (hadNonPrintingMove)
+ {
+ // We have had a non-printing move recently and we are configured to not check non-printing moves. Reset the counters.
+ movementMeasured = movementMeasuredAtLastCheck; // ignore measured extrusion since last check
+ }
+ else
+ {
+ extrusionCommanded += filamentConsumed; // include the extrusion we have just been told about
+
+ if (full)
+ {
+ if ((sensorValue & TypeLaserErrorMask) != 0)
+ {
+ ret = FilamentSensorStatus::sensorError;
+ }
+ else if ((sensorValue & switchOpenMask) != 0)
+ {
+ ret = FilamentSensorStatus::noFilament;
+ }
+ else if (samplesReceived >= 10 && !IsReceiving())
+ {
+ if (extrusionCommandedAtLastMeasurement >= minimumExtrusionCheckLength)
+ {
+ ret = CheckFilament(extrusionCommandedAtLastMeasurement, movementMeasured, false);
+ extrusionCommanded -= extrusionCommandedAtLastMeasurement;
+ extrusionCommandedAtLastMeasurement = 0.0;
+ movementMeasured = 0.0;
+ }
+ else if (extrusionCommanded >= minimumExtrusionCheckLength * 1.1 && millis() - lastMeasurementTime > 110)
+ {
+ ret = CheckFilament(extrusionCommanded, movementMeasured, true);
+ extrusionCommanded = 0.0;
+ extrusionCommandedAtLastMeasurement = 0.0;
+ movementMeasured = 0.0;
+ }
+ }
+ }
+ movementMeasuredAtLastCheck = movementMeasured; // save for next time
+ }
+
+ return ret;
+}
+
+// Compare the amount commanded with the amount of extrusion measured, and set up for the next comparison
+FilamentSensorStatus LaserFilamentMonitor::CheckFilament(float amountCommanded, float amountMeasured, bool overdue)
+{
+ if (reprap.Debug(moduleFilamentSensors))
+ {
+ debugPrintf("Extr req %.3f meas %.3f rem %.3f %s\n", (double)amountCommanded, (double)amountMeasured, (double)(extrusionCommanded - amountCommanded),
+ (overdue) ? " overdue" : "");
+ }
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+
+ switch (laserMonitorState)
+ {
+ case LaserMonitorState::idle:
+ laserMonitorState = LaserMonitorState::calibrating;
+ totalExtrusionCommanded = amountCommanded;
+ totalMovementMeasured = amountMeasured;
+ break;
+
+ case LaserMonitorState::calibrating:
+ totalExtrusionCommanded += amountCommanded;
+ totalMovementMeasured += amountMeasured;
+ if (totalExtrusionCommanded >= 10.0)
+ {
+ backwards = (totalMovementMeasured < 0.0);
+ if (backwards)
+ {
+ totalMovementMeasured = -totalMovementMeasured;
+ amountMeasured = -amountMeasured;
+ }
+ minMovementRatio = maxMovementRatio = amountMeasured/amountCommanded;
+ if (comparisonEnabled)
+ {
+ if (minMovementRatio < minMovementAllowed)
+ {
+ ret = FilamentSensorStatus::tooLittleMovement;
+ }
+ else if (maxMovementRatio > maxMovementAllowed)
+ {
+ ret = FilamentSensorStatus::tooMuchMovement;
+ }
+ }
+ laserMonitorState = LaserMonitorState::comparing;
+ }
+ break;
+
+ case LaserMonitorState::comparing:
+ {
+ totalExtrusionCommanded += amountCommanded;
+ if (backwards)
+ {
+ amountMeasured = -amountMeasured;
+ }
+ totalMovementMeasured += amountMeasured;
+ const float ratio = amountMeasured/amountCommanded;
+ if (ratio > maxMovementRatio)
+ {
+ maxMovementRatio = ratio;
+ }
+ if (ratio < minMovementRatio)
+ {
+ minMovementRatio = ratio;
+ }
+ if (comparisonEnabled)
+ {
+ if (ratio < minMovementAllowed)
+ {
+ ret = FilamentSensorStatus::tooLittleMovement;
+ }
+ else if (ratio > maxMovementAllowed)
+ {
+ ret = FilamentSensorStatus::tooMuchMovement;
+ }
+ }
+ }
+ break;
+ }
+
+ return ret;
+}
+
+// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
+FilamentSensorStatus LaserFilamentMonitor::Clear(bool full)
+{
+ PollReceiveBuffer(); // to keep the diagnostics up to date
+ Reset();
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (full)
+ {
+ if ((sensorValue & TypeLaserErrorMask) != 0)
+ {
+ ret = FilamentSensorStatus::sensorError;
+ }
+ else if ((sensorValue & switchOpenMask) != 0)
+ {
+ ret = FilamentSensorStatus::noFilament;
+ }
+ }
+ return ret;
+}
+
+// Print diagnostic info for this sensor
+void LaserFilamentMonitor::Diagnostics(MessageType mtype, unsigned int extruder)
+{
+ PollReceiveBuffer();
+ const char* const statusText = (!dataReceived) ? "no data received"
+ : ((sensorValue & TypeLaserErrorMask) != 0) ? "error"
+ : ((sensorValue & switchOpenMask) != 0) ? "no filament"
+ : "ok";
+ reprap.GetPlatform().MessageF(mtype, "Extruder %u sensor: position %.2f, %s, ", extruder, (double)GetCurrentPosition(), statusText);
+ if (dataReceived)
+ {
+ reprap.GetPlatform().MessageF(mtype, "%" PRIu32 " parity errors, ", parityErrorCount);
+ }
+ if (laserMonitorState != LaserMonitorState::calibrating && totalExtrusionCommanded > 10.0)
+ {
+ reprap.GetPlatform().MessageF(mtype, "measured minimum %ld%%, average %ld%%, maximum %ld%% over %.1fmm\n",
+ lrintf(100 * minMovementRatio),
+ lrintf((100 * totalMovementMeasured)/totalExtrusionCommanded),
+ lrintf(100 * maxMovementRatio),
+ (double)totalExtrusionCommanded);
+ }
+ else
+ {
+ reprap.GetPlatform().Message(mtype, "no calibration data\n");
+ }
+}
+
+// End
diff --git a/src/FilamentMonitors/LaserFilamentMonitor.h b/src/FilamentMonitors/LaserFilamentMonitor.h
new file mode 100644
index 00000000..e3db56e5
--- /dev/null
+++ b/src/FilamentMonitors/LaserFilamentMonitor.h
@@ -0,0 +1,81 @@
+/*
+ * LaserFilamentMonitor.h
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#ifndef SRC_FILAMENTSENSORS_LASERFILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_LASERFILAMENTMONITOR_H_
+
+#include "Duet3DFilamentMonitor.h"
+
+class LaserFilamentMonitor : public Duet3DFilamentMonitor
+{
+public:
+ LaserFilamentMonitor(int type);
+
+ bool Configure(GCodeBuffer& gb, StringRef& reply, bool& seen) override;
+ FilamentSensorStatus Check(bool full, bool hadNonPrintingMove, float filamentConsumed) override;
+ FilamentSensorStatus Clear(bool full) override;
+ void Diagnostics(MessageType mtype, unsigned int extruder) override;
+
+protected:
+ void OnStartBitReceived();
+ void ProcessReceivedWord(uint16_t val);
+
+private:
+ static constexpr float DefaultMinMovementAllowed = 0.6;
+ static constexpr float DefaultMaxMovementAllowed = 1.6;
+ static constexpr float DefaultMinimumExtrusionCheckLength = 3.0;
+
+ static constexpr uint16_t TypeLaserParityMask = 0x8000u;
+ static constexpr uint16_t TypeLaserQualityMask = 0x4000u;
+ static constexpr uint16_t TypeLaserErrorMask = 0x2000u;
+ static constexpr uint16_t TypeLaserSwitchOpenMask = 0x1000u;
+ static constexpr uint16_t TypeLaserPositionMask = 0x03FF; // we use a 10-bit sensor position
+
+ static constexpr size_t EdgeCaptureBufferSize = 64; // must be a power of 2
+
+ void Init();
+ void Reset();
+ float GetCurrentPosition() const;
+ FilamentSensorStatus CheckFilament(float amountCommanded, float amountMeasured, bool overdue);
+
+ // Configuration parameters
+ float minMovementAllowed, maxMovementAllowed;
+ float minimumExtrusionCheckLength;
+
+ // Other data
+ uint16_t sensorValue; // last known filament position (10 bits)
+ uint16_t qualityWord; // last received quality data
+ uint32_t lastMeasurementTime; // the last time we received a value
+ uint16_t switchOpenMask; // mask to isolate the switch open bit(s) from the sensor value
+ uint32_t parityErrorCount; // the number of words with bad parity we received
+
+ float extrusionCommanded; // the amount of extrusion commanded since we last did a comparison
+ float extrusionCommandedAtStartBit; // the amount of extrusion commanded since the previous comparison when we received the start bit
+ float extrusionCommandedAtLastMeasurement; // the amount of extrusion commanded up to the start but of the last received measurement
+ float movementMeasured; // the accumulated revs (magnet), position (laser), or pulses since the previous comparison
+ float movementMeasuredAtLastCheck; // the accumulated movement measured before non-printing moves
+
+ // Values measured for calibration
+ float minMovementRatio, maxMovementRatio;
+ float totalExtrusionCommanded;
+ float totalMovementMeasured;
+
+ uint8_t samplesReceived;
+ bool dataReceived;
+ bool backwards;
+ bool comparisonEnabled;
+
+ enum class LaserMonitorState : uint8_t
+ {
+ idle,
+ calibrating,
+ comparing
+ };
+ LaserMonitorState laserMonitorState;
+};
+
+#endif /* SRC_FILAMENTSENSORS_LASERFILAMENTMONITOR_H_ */
diff --git a/src/FilamentMonitors/PulsedFilamentMonitor.cpp b/src/FilamentMonitors/PulsedFilamentMonitor.cpp
new file mode 100644
index 00000000..d1e2522a
--- /dev/null
+++ b/src/FilamentMonitors/PulsedFilamentMonitor.cpp
@@ -0,0 +1,251 @@
+/*
+ * PulsedFilamentSensor.cpp
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#include "PulsedFilamentMonitor.h"
+#include "GCodes/GCodeBuffer.h"
+#include "Platform.h"
+#include "RepRap.h"
+
+PulsedFilamentMonitor::PulsedFilamentMonitor(int type)
+ : FilamentMonitor(type),
+ mmPerPulse(DefaultMmPerPulse), tolerance(DefaultTolerance), minimumExtrusionCheckLength(DefaultMinimumExtrusionCheckLength)
+{
+ Init();
+}
+
+void PulsedFilamentMonitor::Init()
+{
+ sensorValue = 0;
+ calibrationStarted = dataReceived = false;
+ Reset();
+}
+
+void PulsedFilamentMonitor::Reset()
+{
+ extrusionCommanded = movementMeasured = extrusionCommandedAtLastMeasurement = movementMeasuredAtLastCheck = 0.0;
+ samplesReceived = 0;
+ comparisonStarted = false;
+}
+
+// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
+bool PulsedFilamentMonitor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
+{
+ if (ConfigurePin(gb, reply, RISING, seen))
+ {
+ return true;
+ }
+
+ gb.TryGetFValue('S', mmPerPulse, seen); // this is mm per rev for Duet3D sensors, mm per pulse for pulsed sensors
+ gb.TryGetFValue('E', minimumExtrusionCheckLength, seen);
+
+ if (gb.Seen('R'))
+ {
+ seen = true;
+ tolerance = gb.GetFValue() * 0.01;
+ }
+
+ if (seen)
+ {
+ Init();
+ }
+ else
+ {
+ reply.printf("Pulse-type filament monitor on endstop input %u, sensitivity %.2fmm/pulse, check every %.1fmm, tolerance %.1f%%, ",
+ GetEndstopNumber(),
+ (double)mmPerPulse,
+ (double)minimumExtrusionCheckLength,
+ (double)(tolerance * 100.0));
+
+ if (!dataReceived)
+ {
+ reply.cat("no data received");
+ }
+ else
+ {
+ reply.catf("current position %.1f, ", (double)GetCurrentPosition());
+ if (calibrationStarted && fabsf(totalMovementMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
+ {
+ const float measuredCalibration = totalExtrusionCommanded/totalMovementMeasured;
+ const float normalRatio = 1.0/measuredCalibration;
+ const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
+ const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
+ reply.catf("measured sensitivity %.2fmm/pulse over %.1fmm, tolerance +%d%% -%d%%",
+ (double)measuredCalibration,
+ (double)totalExtrusionCommanded,
+ measuredPosTolerance,
+ measuredNegTolerance);
+ }
+ else
+ {
+ reply.cat("no calibration data");
+ }
+ }
+ }
+
+ return false;
+}
+
+// ISR for when the pin state changes
+void PulsedFilamentMonitor::Interrupt()
+{
+ ++sensorValue;
+ extrusionCommandedAtLastMeasurement = extrusionCommanded;
+ if (samplesReceived < 100)
+ {
+ ++samplesReceived;
+ }
+}
+
+// Call the following regularly to keep the status up to date
+void PulsedFilamentMonitor::Poll()
+{
+ cpu_irq_disable();
+ const uint16_t locSensorVal = sensorValue;
+ sensorValue = 0;
+ cpu_irq_enable();
+ movementMeasured += (float)locSensorVal;
+ extrusionCommandedAtLastMeasurement = extrusionCommanded;
+}
+
+// Return the current wheel angle
+float PulsedFilamentMonitor::GetCurrentPosition() const
+{
+ return (float)sensorValue;
+}
+
+// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
+// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
+// 'hadNonPrintingMove' is called if filamentConsumed includes extruder movement form non-printing moves.
+FilamentSensorStatus PulsedFilamentMonitor::Check(bool full, bool hadNonPrintingMove, float filamentConsumed)
+{
+ Poll(); // this may update movementMeasured
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (!hadNonPrintingMove)
+ {
+ // We have had a non-printing move recently and we are configured to not check non-printing moves. Reset the counters.
+ movementMeasured = movementMeasuredAtLastCheck; // ignore measured extrusion since last check
+ }
+ else
+ {
+ extrusionCommanded += filamentConsumed; // include the extrusion we have just been told about
+ movementMeasuredAtLastCheck = movementMeasured; // save for next time
+
+ if (full)
+ {
+ if (extrusionCommandedAtLastMeasurement >= minimumExtrusionCheckLength)
+ {
+ ret = CheckFilament(extrusionCommandedAtLastMeasurement, false);
+ }
+ else if (extrusionCommanded >= minimumExtrusionCheckLength * 1.1 && millis() - lastMeasurementTime > 110)
+ {
+ ret = CheckFilament(extrusionCommanded, true);
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Compare the amount commanded with the amount of extrusion measured, and set up for the next comparison
+FilamentSensorStatus PulsedFilamentMonitor::CheckFilament(float amountCommanded, bool overdue)
+{
+ const float extrusionMeasured = movementMeasured * mmPerPulse;
+ if (reprap.Debug(moduleFilamentSensors))
+ {
+ debugPrintf("Extr req %.3f meas %.3f rem %.3f %s\n", (double)amountCommanded, (double)extrusionMeasured, (double)(extrusionCommanded - amountCommanded),
+ (overdue) ? " overdue" : "");
+ }
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (!comparisonStarted)
+ {
+ // The first measurement after we start extruding is often a long way out, so discard it
+ comparisonStarted = true;
+ calibrationStarted = false;
+ }
+ else if (tolerance >= 0.0)
+ {
+ const float minExtrusionExpected = (amountCommanded >= 0.0)
+ ? amountCommanded * (1.0 - tolerance)
+ : amountCommanded * (1.0 + tolerance);
+ if (extrusionMeasured < minExtrusionExpected)
+ {
+ ret = FilamentSensorStatus::tooLittleMovement;
+ }
+ else
+ {
+ const float maxExtrusionExpected = (amountCommanded >= 0.0)
+ ? amountCommanded * (1.0 + tolerance)
+ : amountCommanded * (1.0 - tolerance);
+ if (extrusionMeasured > maxExtrusionExpected)
+ {
+ ret = FilamentSensorStatus::tooMuchMovement;
+ }
+ }
+ }
+
+ // Update the calibration accumulators, even if the user hasn't asked to do calibration
+ const float ratio = movementMeasured/amountCommanded;
+ if (calibrationStarted)
+ {
+ if (ratio < minMovementRatio)
+ {
+ minMovementRatio = ratio;
+ }
+ if (ratio > maxMovementRatio)
+ {
+ maxMovementRatio = ratio;
+ }
+ totalExtrusionCommanded += amountCommanded;
+ totalMovementMeasured += movementMeasured;
+ }
+ else
+ {
+ minMovementRatio = maxMovementRatio = ratio;
+ totalExtrusionCommanded = amountCommanded;
+ totalMovementMeasured = movementMeasured;
+ calibrationStarted = true;
+ }
+
+ extrusionCommanded -= amountCommanded;
+ extrusionCommandedAtLastMeasurement = movementMeasured = 0.0;
+
+ return ret;
+}
+
+// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
+FilamentSensorStatus PulsedFilamentMonitor::Clear(bool full)
+{
+ Poll(); // to keep the diagnostics up to date
+ Reset();
+
+ return FilamentSensorStatus::ok;
+}
+
+// Print diagnostic info for this sensor
+void PulsedFilamentMonitor::Diagnostics(MessageType mtype, unsigned int extruder)
+{
+ Poll();
+ const char* const statusText = (!dataReceived) ? "no data received" : "ok";
+ reprap.GetPlatform().MessageF(mtype, "Extruder %u sensor: position %.2f, %s, ", extruder, (double)GetCurrentPosition(), statusText);
+ if (calibrationStarted && fabsf(totalMovementMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
+ {
+ const float measuredMmPerRev = totalExtrusionCommanded/totalMovementMeasured;
+ const float normalRatio = 1.0/measuredMmPerRev;
+ const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
+ const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
+ reprap.GetPlatform().MessageF(mtype,"measured sensitivity %.2fmm/pulse +%d%% -%d%%\n",
+ (double)measuredMmPerRev, measuredPosTolerance, measuredNegTolerance);
+ }
+ else
+ {
+ reprap.GetPlatform().Message(mtype, "no calibration data\n");
+ }
+}
+
+// End
diff --git a/src/FilamentMonitors/PulsedFilamentMonitor.h b/src/FilamentMonitors/PulsedFilamentMonitor.h
new file mode 100644
index 00000000..93999e5e
--- /dev/null
+++ b/src/FilamentMonitors/PulsedFilamentMonitor.h
@@ -0,0 +1,60 @@
+/*
+ * PulsedFilamentSensor.h
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#ifndef SRC_FILAMENTSENSORS_PULSEDFILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_PULSEDFILAMENTMONITOR_H_
+
+#include "FilamentMonitor.h"
+
+class PulsedFilamentMonitor : public FilamentMonitor
+{
+public:
+ PulsedFilamentMonitor(int type);
+
+ bool Configure(GCodeBuffer& gb, StringRef& reply, bool& seen) override;
+ FilamentSensorStatus Check(bool full, bool hadNonPrintingMove, float filamentConsumed) override;
+ FilamentSensorStatus Clear(bool full) override;
+ void Diagnostics(MessageType mtype, unsigned int extruder) override;
+ void Interrupt() override;
+
+private:
+ static constexpr float DefaultMmPerPulse = 28.8;
+ static constexpr float DefaultTolerance = 0.25;
+ static constexpr float DefaultMinimumExtrusionCheckLength = 3.0;
+
+ void Init();
+ void Reset();
+ void Poll();
+ float GetCurrentPosition() const;
+ FilamentSensorStatus CheckFilament(float amountCommanded, bool overdue);
+
+ // Configuration parameters
+ float mmPerPulse;
+ float tolerance;
+ float minimumExtrusionCheckLength;
+
+ // Other data
+ uint16_t sensorValue; // last known pulses received (10 bits)
+ uint32_t lastMeasurementTime; // the last time we received a value
+
+ float extrusionCommanded; // the amount of extrusion commanded since we last did a comparison
+ float extrusionCommandedAtLastMeasurement; // the amount of extrusion commanded up to the start but of the last received measurement
+ float movementMeasured; // the accumulated revs (magnet), position (laser), or pulses since the previous comparison
+ float movementMeasuredAtLastCheck; // the accumulated movement measured before non-printing moves
+
+ // Values measured for calibration
+ float minMovementRatio, maxMovementRatio;
+ float totalExtrusionCommanded;
+ float totalMovementMeasured;
+
+ uint8_t samplesReceived;
+ bool dataReceived;
+ bool comparisonStarted;
+ bool calibrationStarted;
+};
+
+#endif /* SRC_FILAMENTSENSORS_PULSEDFILAMENTMONITOR_H_ */
diff --git a/src/FilamentMonitors/RotatingMagnetFilamentMonitor.cpp b/src/FilamentMonitors/RotatingMagnetFilamentMonitor.cpp
new file mode 100644
index 00000000..97db41b1
--- /dev/null
+++ b/src/FilamentMonitors/RotatingMagnetFilamentMonitor.cpp
@@ -0,0 +1,300 @@
+/*
+ * RotatingMagnetFilamentMonitor.cpp
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#include "RotatingMagnetFilamentMonitor.h"
+#include "GCodes/GCodeBuffer.h"
+#include "Platform.h"
+#include "RepRap.h"
+
+RotatingMagnetFilamentMonitor::RotatingMagnetFilamentMonitor(int type)
+ : Duet3DFilamentMonitor(type),
+ mmPerRev(DefaultMmPerRev), tolerance(DefaultTolerance), minimumExtrusionCheckLength(DefaultMinimumExtrusionCheckLength), checkNonPrintingMoves(true)
+{
+ switchOpenMask = (type == 4) ? TypeMagnetSwitchOpenMask : 0;
+ Init();
+}
+
+void RotatingMagnetFilamentMonitor::Init()
+{
+ sensorValue = 0;
+ calibrationStarted = dataReceived = false;
+ lastMeasurementTime = 0;
+ InitReceiveBuffer();
+ Reset();
+}
+
+void RotatingMagnetFilamentMonitor::Reset()
+{
+ extrusionCommanded = movementMeasured = extrusionCommandedAtLastMeasurement = extrusionCommandedAtStartBit = movementMeasuredAtLastCheck = 0.0;
+ samplesReceived = 0;
+ comparisonStarted = false;
+}
+
+// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
+bool RotatingMagnetFilamentMonitor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
+{
+ if (ConfigurePin(gb, reply, CHANGE, seen))
+ {
+ return true;
+ }
+
+ gb.TryGetFValue('S', mmPerRev, seen); // this is mm per rev for Duet3D sensors, mm per pulse for pulsed sensors
+ gb.TryGetFValue('E', minimumExtrusionCheckLength, seen);
+
+ if (gb.Seen('R'))
+ {
+ seen = true;
+ tolerance = gb.GetFValue() * 0.01;
+ }
+
+ if (seen)
+ {
+ Init();
+ }
+ else
+ {
+ reply.printf("Duet3D rotating magnet filament monitor%s on endstop input %u, sensitivity %.2fmm/rev, check every %.1fmm, tolerance %.1f%%, ",
+ (switchOpenMask != 0) ? " with microswitch" : "",
+ GetEndstopNumber(),
+ (double)mmPerRev,
+ (double)minimumExtrusionCheckLength,
+ (double)(tolerance * 100.0));
+ if (!dataReceived)
+ {
+ reply.cat("no data received");
+ }
+ else if ((sensorValue & TypeMagnetErrorMask) != 0)
+ {
+ reply.cat("error");
+ }
+ else
+ {
+ reply.catf("current position %.1f, ", (double)GetCurrentPosition());
+ if (calibrationStarted && fabsf(totalMovementMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
+ {
+ const float measuredCalibration = totalExtrusionCommanded/totalMovementMeasured;
+ const float normalRatio = 1.0/measuredCalibration;
+ const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
+ const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
+ reply.catf("measured sensitivity %.2fmm/rev over %.1fmm, tolerance +%d%% -%d%%",
+ (double)measuredCalibration,
+ (double)totalExtrusionCommanded,
+ measuredPosTolerance,
+ measuredNegTolerance);
+ }
+ else
+ {
+ reply.cat("no calibration data");
+ }
+ }
+ }
+
+ return false;
+}
+
+// This is called from the poll function when we receive what could be a start bit
+void RotatingMagnetFilamentMonitor::OnStartBitReceived() /*override*/
+{
+ extrusionCommandedAtStartBit = extrusionCommanded; // record the extrusion
+}
+
+// This is called from the poll function when we have received a complete word of data
+void RotatingMagnetFilamentMonitor::ProcessReceivedWord(uint16_t val)
+{
+ // We received a position report
+ if (samplesReceived == 0)
+ {
+ dataReceived = true;
+ extrusionCommanded -= extrusionCommandedAtStartBit;
+ extrusionCommandedAtStartBit = 0;
+ movementMeasured = 0.0; // use the first measurement sample as a baseline
+ }
+ else
+ {
+ const uint16_t angleChange = (val - sensorValue) & TypeMagnetAngleMask; // angle change in range 0..1023
+ const int32_t movement = (angleChange <= 512) ? (int32_t)angleChange : (int32_t)angleChange - 1024;
+ movementMeasured += (float)movement/1024;
+ }
+
+ lastMeasurementTime = millis();
+ extrusionCommandedAtLastMeasurement = extrusionCommandedAtStartBit;
+ sensorValue = val;
+ if (samplesReceived < 100)
+ {
+ ++samplesReceived;
+ }
+}
+
+// Return the current wheel angle
+float RotatingMagnetFilamentMonitor::GetCurrentPosition() const
+{
+ return (sensorValue & TypeMagnetAngleMask) * (360.0/1024.0);
+}
+
+// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
+// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
+// 'hadNonPrintingMove' is called if filamentConsumed includes extruder movement form non-printing moves.
+FilamentSensorStatus RotatingMagnetFilamentMonitor::Check(bool full, bool hadNonPrintingMove, float filamentConsumed)
+{
+ const bool useThisMeasurement = checkNonPrintingMoves || !hadNonPrintingMove;
+
+ PollReceiveBuffer(); // this may update movementMeasured
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (!useThisMeasurement)
+ {
+ // We have had a non-printing move recently and we are configured to not check non-printing moves. Reset the counters.
+ movementMeasured = movementMeasuredAtLastCheck; // ignore measured extrusion since last check
+ }
+ else
+ {
+ extrusionCommanded += filamentConsumed; // include the extrusion we have just been told about
+ movementMeasuredAtLastCheck = movementMeasured; // save for next time
+
+ if (full)
+ {
+ if ((sensorValue & TypeMagnetErrorMask) != 0)
+ {
+ ret = FilamentSensorStatus::sensorError;
+ }
+ else if ((sensorValue & switchOpenMask) != 0)
+ {
+ ret = FilamentSensorStatus::noFilament;
+ }
+ else if (samplesReceived >= 10 && !IsReceiving())
+ {
+ if (extrusionCommandedAtLastMeasurement >= minimumExtrusionCheckLength)
+ {
+ ret = CheckFilament(extrusionCommandedAtLastMeasurement, movementMeasured, false);
+ extrusionCommanded -= extrusionCommandedAtLastMeasurement;
+ extrusionCommandedAtLastMeasurement = 0.0;
+ movementMeasured = 0.0;
+ }
+ else if (extrusionCommanded >= minimumExtrusionCheckLength * 1.1 && millis() - lastMeasurementTime > 110)
+ {
+ ret = CheckFilament(extrusionCommanded, movementMeasured, true);
+ extrusionCommanded = 0.0;
+ extrusionCommandedAtLastMeasurement = 0.0;
+ movementMeasured = 0.0;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Compare the amount commanded with the amount of extrusion measured, and set up for the next comparison
+FilamentSensorStatus RotatingMagnetFilamentMonitor::CheckFilament(float amountCommanded, float amountMeasured, bool overdue)
+{
+ if (reprap.Debug(moduleFilamentSensors))
+ {
+ debugPrintf("Extr req %.3f meas %.3f rem %.3f %s\n", (double)amountCommanded, (double)amountMeasured, (double)(extrusionCommanded - amountCommanded),
+ (overdue) ? " overdue" : "");
+ }
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (!comparisonStarted)
+ {
+ // The first measurement after we start extruding is often a long way out, so discard it
+ comparisonStarted = true;
+ calibrationStarted = false;
+ }
+ else if (tolerance >= 0.0)
+ {
+ const float minExtrusionExpected = (amountCommanded >= 0.0)
+ ? amountCommanded * (1.0 - tolerance)
+ : amountCommanded * (1.0 + tolerance);
+ const float extrusionMeasured = amountMeasured * mmPerRev;
+ if (extrusionMeasured < minExtrusionExpected)
+ {
+ ret = FilamentSensorStatus::tooLittleMovement;
+ }
+ else
+ {
+ const float maxExtrusionExpected = (amountCommanded >= 0.0)
+ ? amountCommanded * (1.0 + tolerance)
+ : amountCommanded * (1.0 - tolerance);
+ if (extrusionMeasured > maxExtrusionExpected)
+ {
+ ret = FilamentSensorStatus::tooMuchMovement;
+ }
+ }
+ }
+
+ // Update the calibration accumulators, even if the user hasn't asked to do calibration
+ const float ratio = amountMeasured/amountCommanded;
+ if (calibrationStarted)
+ {
+ if (ratio < minMovementRatio)
+ {
+ minMovementRatio = ratio;
+ }
+ if (ratio > maxMovementRatio)
+ {
+ maxMovementRatio = ratio;
+ }
+ totalExtrusionCommanded += amountCommanded;
+ totalMovementMeasured += amountMeasured;
+ }
+ else
+ {
+ minMovementRatio = maxMovementRatio = ratio;
+ totalExtrusionCommanded = amountCommanded;
+ totalMovementMeasured = amountMeasured;
+ calibrationStarted = true;
+ }
+
+ return ret;
+}
+
+// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
+FilamentSensorStatus RotatingMagnetFilamentMonitor::Clear(bool full)
+{
+ PollReceiveBuffer(); // to keep the diagnostics up to date
+ Reset();
+
+ FilamentSensorStatus ret = FilamentSensorStatus::ok;
+ if (full)
+ {
+ if ((sensorValue & TypeMagnetErrorMask) != 0)
+ {
+ ret = FilamentSensorStatus::sensorError;
+ }
+ else if ((sensorValue & switchOpenMask) != 0)
+ {
+ ret = FilamentSensorStatus::noFilament;
+ }
+ }
+ return ret;
+}
+
+// Print diagnostic info for this sensor
+void RotatingMagnetFilamentMonitor::Diagnostics(MessageType mtype, unsigned int extruder)
+{
+ PollReceiveBuffer();
+ const char* const statusText = (!dataReceived) ? "no data received"
+ : ((sensorValue & TypeMagnetErrorMask) != 0) ? "error"
+ : ((sensorValue & switchOpenMask) != 0) ? "no filament"
+ : "ok";
+ reprap.GetPlatform().MessageF(mtype, "Extruder %u sensor: position %.2f, %s, ", extruder, (double)GetCurrentPosition(), statusText);
+ if (calibrationStarted && fabsf(totalMovementMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
+ {
+ const float measuredMmPerRev = totalExtrusionCommanded/totalMovementMeasured;
+ const float normalRatio = 1.0/measuredMmPerRev;
+ const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
+ const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
+ reprap.GetPlatform().MessageF(mtype,"measured sensitivity %.2fmm/rev +%d%% -%d%%\n",
+ (double)measuredMmPerRev, measuredPosTolerance, measuredNegTolerance);
+ }
+ else
+ {
+ reprap.GetPlatform().Message(mtype, "no calibration data\n");
+ }
+}
+
+// End
diff --git a/src/FilamentMonitors/RotatingMagnetFilamentMonitor.h b/src/FilamentMonitors/RotatingMagnetFilamentMonitor.h
new file mode 100644
index 00000000..7156e5f2
--- /dev/null
+++ b/src/FilamentMonitors/RotatingMagnetFilamentMonitor.h
@@ -0,0 +1,69 @@
+/*
+ * RotatingMagnetFilamentMonitor.h
+ *
+ * Created on: 9 Jan 2018
+ * Author: David
+ */
+
+#ifndef SRC_FILAMENTSENSORS_ROTATINGMAGNETFILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_ROTATINGMAGNETFILAMENTMONITOR_H_
+
+#include "Duet3DFilamentMonitor.h"
+
+class RotatingMagnetFilamentMonitor : public Duet3DFilamentMonitor
+{
+public:
+ RotatingMagnetFilamentMonitor(int type);
+
+ bool Configure(GCodeBuffer& gb, StringRef& reply, bool& seen) override;
+ FilamentSensorStatus Check(bool full, bool hadNonPrintingMove, float filamentConsumed) override;
+ FilamentSensorStatus Clear(bool full) override;
+ void Diagnostics(MessageType mtype, unsigned int extruder) override;
+
+protected:
+ void OnStartBitReceived();
+ void ProcessReceivedWord(uint16_t val);
+
+private:
+ static constexpr float DefaultMmPerRev = 28.8;
+ static constexpr float DefaultTolerance = 0.25;
+ static constexpr float DefaultMinimumExtrusionCheckLength = 3.0;
+
+ static constexpr uint16_t TypeMagnetErrorMask = 0x8000u;
+ static constexpr uint16_t TypeMagnetSwitchOpenMask = 0x4000u;
+ static constexpr uint16_t TypeMagnetAngleMask = 0x03FF; // we use a 10-bit sensor angle
+
+ void Init();
+ void Reset();
+ float GetCurrentPosition() const;
+ FilamentSensorStatus CheckFilament(float amountCommanded, float amountMeasured, bool overdue);
+
+ // Configuration parameters
+ float mmPerRev;
+ float tolerance;
+ float minimumExtrusionCheckLength;
+ bool checkNonPrintingMoves;
+
+ // Other data
+ uint16_t sensorValue; // last known filament position (10 bits)
+ uint32_t lastMeasurementTime; // the last time we received a value
+ uint16_t switchOpenMask; // mask to isolate the switch open bit(s) from the sensor value
+
+ float extrusionCommanded; // the amount of extrusion commanded since we last did a comparison
+ float extrusionCommandedAtStartBit; // the amount of extrusion commanded since the previous comparison when we received the start bit
+ float extrusionCommandedAtLastMeasurement; // the amount of extrusion commanded up to the start but of the last received measurement
+ float movementMeasured; // the accumulated revs (magnet), position (laser), or pulses since the previous comparison
+ float movementMeasuredAtLastCheck; // the accumulated movement measured before non-printing moves
+
+ // Values measured for calibration
+ float minMovementRatio, maxMovementRatio;
+ float totalExtrusionCommanded;
+ float totalMovementMeasured;
+
+ uint8_t samplesReceived;
+ bool dataReceived;
+ bool comparisonStarted;
+ bool calibrationStarted;
+};
+
+#endif /* SRC_FILAMENTSENSORS_ROTATINGMAGNETFILAMENTMONITOR_H_ */
diff --git a/src/FilamentSensors/SimpleFilamentSensor.cpp b/src/FilamentMonitors/SimpleFilamentMonitor.cpp
index 793169a3..04a354e2 100644
--- a/src/FilamentSensors/SimpleFilamentSensor.cpp
+++ b/src/FilamentMonitors/SimpleFilamentMonitor.cpp
@@ -5,25 +5,25 @@
* Author: David
*/
-#include "SimpleFilamentSensor.h"
+#include "SimpleFilamentMonitor.h"
#include "RepRap.h"
#include "Platform.h"
-SimpleFilamentSensor::SimpleFilamentSensor(int type) : FilamentSensor(type), highWhenNoFilament(type == 2), filamentPresent(false)
+SimpleFilamentMonitor::SimpleFilamentMonitor(int type) : FilamentMonitor(type), highWhenNoFilament(type == 2), filamentPresent(false)
{
}
// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
-bool SimpleFilamentSensor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
+bool SimpleFilamentMonitor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
{
- if (ConfigurePin(gb, reply, seen))
+ if (ConfigurePin(gb, reply, CHANGE, seen))
{
return true;
}
if (seen)
{
- Check(true, 0.0);
+ Check(true, false, 0.0);
}
else
{
@@ -34,14 +34,14 @@ bool SimpleFilamentSensor::Configure(GCodeBuffer& gb, StringRef& reply, bool& se
}
// ISR for when the pin state changes
-void SimpleFilamentSensor::Interrupt()
+void SimpleFilamentMonitor::Interrupt()
{
// Nothing needed here
detachInterrupt(GetPin());
}
// Call the following regularly to keep the status up to date
-void SimpleFilamentSensor::Poll()
+void SimpleFilamentMonitor::Poll()
{
const bool b = IoPort::ReadPin(GetPin());
filamentPresent = (highWhenNoFilament) ? !b : b;
@@ -49,21 +49,21 @@ void SimpleFilamentSensor::Poll()
// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
-FilamentSensorStatus SimpleFilamentSensor::Check(bool full, float filamentConsumed)
+FilamentSensorStatus SimpleFilamentMonitor::Check(bool full, bool hadNonPrintingMove, float filamentConsumed)
{
Poll();
return (filamentPresent) ? FilamentSensorStatus::ok : FilamentSensorStatus::noFilament;
}
// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
-FilamentSensorStatus SimpleFilamentSensor::Clear(bool full)
+FilamentSensorStatus SimpleFilamentMonitor::Clear(bool full)
{
Poll();
return (filamentPresent) ? FilamentSensorStatus::ok : FilamentSensorStatus::noFilament;
}
// Print diagnostic info for this sensor
-void SimpleFilamentSensor::Diagnostics(MessageType mtype, unsigned int extruder)
+void SimpleFilamentMonitor::Diagnostics(MessageType mtype, unsigned int extruder)
{
reprap.GetPlatform().MessageF(mtype, "Extruder %u sensor: %s\n", extruder, (filamentPresent) ? "ok" : "no filament");
}
diff --git a/src/FilamentSensors/SimpleFilamentSensor.h b/src/FilamentMonitors/SimpleFilamentMonitor.h
index 05122005..74badf32 100644
--- a/src/FilamentSensors/SimpleFilamentSensor.h
+++ b/src/FilamentMonitors/SimpleFilamentMonitor.h
@@ -5,18 +5,18 @@
* Author: David
*/
-#ifndef SRC_FILAMENTSENSORS_SIMPLEFILAMENTSENSOR_H_
-#define SRC_FILAMENTSENSORS_SIMPLEFILAMENTSENSOR_H_
+#ifndef SRC_FILAMENTSENSORS_SIMPLEFILAMENTMONITOR_H_
+#define SRC_FILAMENTSENSORS_SIMPLEFILAMENTMONITOR_H_
-#include "FilamentSensor.h"
+#include "FilamentMonitor.h"
-class SimpleFilamentSensor : public FilamentSensor
+class SimpleFilamentMonitor : public FilamentMonitor
{
public:
- SimpleFilamentSensor(int type);
+ SimpleFilamentMonitor(int type);
bool Configure(GCodeBuffer& gb, StringRef& reply, bool& seen) override;
- FilamentSensorStatus Check(bool full, float filamentConsumed) override;
+ FilamentSensorStatus Check(bool full, bool hadNonPrintingMove, float filamentConsumed) override;
FilamentSensorStatus Clear(bool full) override;
void Diagnostics(MessageType mtype, unsigned int extruder) override;
void Interrupt() override;
@@ -28,4 +28,4 @@ private:
bool filamentPresent;
};
-#endif /* SRC_FILAMENTSENSORS_SIMPLEFILAMENTSENSOR_H_ */
+#endif /* SRC_FILAMENTSENSORS_SIMPLEFILAMENTMONITOR_H_ */
diff --git a/src/FilamentSensors/Duet3DFilamentSensor.cpp b/src/FilamentSensors/Duet3DFilamentSensor.cpp
deleted file mode 100644
index ceddf765..00000000
--- a/src/FilamentSensors/Duet3DFilamentSensor.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Duet3DFilamentSensor.cpp
- *
- * Created on: 20 Jul 2017
- * Author: David
- */
-
-#include "Duet3DFilamentSensor.h"
-#include "GCodes/GCodeBuffer.h"
-#include "Platform.h"
-#include "Movement/DDA.h" // for stepClockRate
-
-// Constructors
-Duet3DFilamentSensor::Duet3DFilamentSensor(int type)
- : FilamentSensor(type), mmPerRev(DefaultMmPerRev),
- tolerance(DefaultTolerance), minimumExtrusionCheckLength(DefaultMinimumExtrusionCheckLength), withSwitch(type == 4)
-{
- Init();
-}
-
-void Duet3DFilamentSensor::Init()
-{
- samplesReceived = 0;
- sensorValue = 0;
- calibrationStarted = comparisonStarted = dataReceived = false;
- edgeCaptureReadPointer = edgeCaptureWritePointer = 1;
- edgeCaptures[0] = Platform::GetInterruptClocks(); // assume we just had a high-to-low transition
- lastMeasurementTime = 0;
- accumulatedExtrusionCommanded = accumulatedRevsMeasured = extrusionCommandedAtLastMeasurement = tentativeExtrusionCommanded = 0.0;
- state = RxdState::waitingForStartBit;
-}
-
-// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
-bool Duet3DFilamentSensor::Configure(GCodeBuffer& gb, StringRef& reply, bool& seen)
-{
- if (ConfigurePin(gb, reply, seen))
- {
- return true;
- }
-
- gb.TryGetFValue('S', mmPerRev, seen);
- gb.TryGetFValue('E', minimumExtrusionCheckLength, seen);
-
- if (gb.Seen('R'))
- {
- seen = true;
- tolerance = gb.GetFValue() * 0.01;
- }
-
- if (seen)
- {
- Init();
- }
- else
- {
- reply.printf("Duet3D filament monitor on E%u, %s microswitch, %.2fmm/rev, check every %.1fmm, tolerance %.1f%%, ",
- GetEndstopNumber(), (withSwitch) ? "with" : "no", (double)mmPerRev, (double)minimumExtrusionCheckLength, (double)(tolerance * 100.0));
-
- if (!dataReceived)
- {
- reply.cat("no data received");
- }
- else if ((sensorValue & ErrorBit) != 0)
- {
- reply.cat("error");
- }
- else
- {
- reply.catf("current angle %.1f, ", (double)GetCurrentAngle());
- if (calibrationStarted && fabsf(totalRevsMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
- {
- const float measuredMmPerRev = totalExtrusionCommanded/totalRevsMeasured;
- const float normalRatio = 1.0/measuredMmPerRev;
- const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
- const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
- reply.catf("measured %.2fmm/rev +%d%% -%d%% over %.1fmm\n", (double)measuredMmPerRev, measuredPosTolerance, measuredNegTolerance, (double)totalExtrusionCommanded);
- }
- else
- {
- reply.cat("no calibration data");
- }
- }
- }
-
- return false;
-}
-
-// ISR for when the pin state changes
-void Duet3DFilamentSensor::Interrupt()
-{
- uint32_t now = Platform::GetInterruptClocks();
- const size_t writePointer = edgeCaptureWritePointer; // capture volatile variable
- if ((writePointer + 1) % EdgeCaptureBufferSize != edgeCaptureReadPointer)
- {
- if (IoPort::ReadPin(GetPin()))
- {
- if ((writePointer & 1) == 0) // low-to-high transitions should occur on odd indices
- {
- return;
- }
- }
- else
- {
- if ((writePointer & 1) != 0) // high-to-low transitions should occur on even indices
- {
- return;
- }
- now -= 40; // partial correction for skew caused by debounce filter on Duet endstop inputs (measured skew = 74)
- }
- }
-
- edgeCaptures[writePointer] = now; // record the time at which this edge was detected
- edgeCaptureWritePointer = (writePointer + 1) % EdgeCaptureBufferSize;
-}
-
-// Call the following regularly to keep the status up to date
-void Duet3DFilamentSensor::Poll()
-{
- static constexpr uint32_t BitsPerSecond = 1000; // the nominal bit rate that the data is transmitted at
- static constexpr uint32_t NominalBitLength = DDA::stepClockRate/BitsPerSecond;
- static constexpr uint32_t MinBitLength = (NominalBitLength * 10)/13; // allow 30% clock speed tolerance
- static constexpr uint32_t MaxBitLength = (NominalBitLength * 13)/10; // allow 30% clock speed tolerance
- static constexpr uint32_t ErrorRecoveryDelayBits = 8; // before a start bit we want the line to be low for this long
- static constexpr uint32_t ErrorRecoveryTime = NominalBitLength * ErrorRecoveryDelayBits;
-
- bool again;
- do
- {
- again = false;
- const size_t writePointer = edgeCaptureWritePointer; // capture volatile variable
- const uint32_t now = Platform::GetInterruptClocks();
- switch (state)
- {
- case RxdState::waitingForStartBit:
- if (writePointer != edgeCaptureReadPointer)
- {
- if ((edgeCaptureReadPointer & 1u) == 0) // if we are out of sync (this is normal when the last stuffing bit was a 1)
- {
- edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
- again = true;
- }
- else
- {
- if (edgeCaptures[edgeCaptureReadPointer] - edgeCaptures[(edgeCaptureReadPointer - 1) % EdgeCaptureBufferSize] < ErrorRecoveryTime)
- {
- // The input line has not been low for long enough before the start bit
- edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize; // ignore this start bit
- state = RxdState::errorRecovery1;
- again = true;
- }
- else
- {
- tentativeExtrusionCommanded = accumulatedExtrusionCommanded; // we have received what could be the beginning of a start bit
- state = RxdState::waitingForEndOfStartBit;
- again = true;
- }
- }
- }
- break;
-
- case RxdState::waitingForEndOfStartBit:
- // This state must be made to time out because while we are in it, comparison of filament extruded is suspended
- if ((writePointer - edgeCaptureReadPointer) % EdgeCaptureBufferSize >= 2)
- {
- // Check for a valid start bit
- lastBitChangeIndex = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
- startBitLength = edgeCaptures[lastBitChangeIndex] - edgeCaptures[edgeCaptureReadPointer];
- edgeCaptureReadPointer = lastBitChangeIndex;
- if (startBitLength >= MinBitLength && startBitLength <= MaxBitLength)
- {
- valueBeingAssembled = 0;
- nibblesAssembled = 0;
- state = RxdState::waitingForNibble;
- again = true;
- //debugPrintf("sb %u\n", startBitLength);
- }
- else
- {
- // Start bit too long or too short
- state = RxdState::errorRecovery2;
- again = true;
- }
- }
- else if (now - edgeCaptures[edgeCaptureReadPointer] > MaxBitLength)
- {
- edgeCaptureReadPointer = (edgeCaptureReadPointer + 1u) % EdgeCaptureBufferSize;
- state = RxdState::errorRecovery2;
- again = true;
- }
- break;
-
- case RxdState::waitingForNibble:
- // This state must time out because while we are in it, comparison of filament extruded is suspended
- {
- const uint32_t nibbleStartTime = edgeCaptures[lastBitChangeIndex];
- if (now - nibbleStartTime > (13 * startBitLength)/2)
- {
- // 6.5 bit times have passed since the start of the bit that preceded the current nibble, so we should have a complete nibble and the following stuffing bit
- uint32_t samplePoint = (startBitLength * 3)/2; // sampling time after the end of the start bit for bit 7 (MSB)
- uint8_t currentNibble = 0;
- size_t nextBitChangeIndex = (lastBitChangeIndex + 1u) % EdgeCaptureBufferSize;
- for (uint8_t numBits = 0; numBits < 5; ++numBits)
- {
- if (nextBitChangeIndex != edgeCaptureWritePointer && edgeCaptures[nextBitChangeIndex] - nibbleStartTime < samplePoint)
- {
- lastBitChangeIndex = nextBitChangeIndex;
- nextBitChangeIndex = (lastBitChangeIndex + 1u) % EdgeCaptureBufferSize;
- if (nextBitChangeIndex != writePointer && edgeCaptures[nextBitChangeIndex] - nibbleStartTime < samplePoint)
- {
- edgeCaptureReadPointer = nextBitChangeIndex;
- state = RxdState::errorRecovery3;
- again = true;
- break;
- }
- }
- currentNibble <<= 1;
- currentNibble |= (uint8_t)(lastBitChangeIndex & 1u);
- samplePoint += startBitLength;
- }
-
- if (state != RxdState::waitingForNibble)
- {
- break;
- }
-
- // The 5th bit we received should be the inverse of the 4th bit
- if ((((currentNibble >> 1u) ^ currentNibble) & 0x01u) == 0)
- {
- edgeCaptureReadPointer = nextBitChangeIndex;
- state = RxdState::errorRecovery4;
- again = true;
- break;
- }
-
- currentNibble >>= 1;
- valueBeingAssembled = (valueBeingAssembled << 4) | currentNibble;
- ++nibblesAssembled;
- if (nibblesAssembled == 4)
- {
- edgeCaptureReadPointer = nextBitChangeIndex; // ready for a new word
- if (samplesReceived == 0)
- {
- dataReceived = true;
- accumulatedExtrusionCommanded -= tentativeExtrusionCommanded;
- accumulatedRevsMeasured = 0.0; // use the first measurement sample as a baseline
- }
- else
- {
- const uint16_t angleChange = (valueBeingAssembled - sensorValue) & AngleMask; // angle change in range 0..1023
- const int32_t movement = (angleChange <= 512) ? (int32_t)angleChange : (int32_t)angleChange - 1024;
- accumulatedRevsMeasured += (float)movement/1024;
- }
-
- lastMeasurementTime = millis();
- extrusionCommandedAtLastMeasurement = tentativeExtrusionCommanded;
- sensorValue = valueBeingAssembled;
- if (samplesReceived < 100)
- {
- ++samplesReceived;
- }
- edgeCaptureReadPointer = nextBitChangeIndex;
- state = RxdState::waitingForStartBit;
- }
- again = true;
- }
- }
- break;
-
- default: // error recovery states
- if (reprap.Debug(moduleFilamentSensors))
- {
- debugPrintf("Fil err %u\n", (unsigned int)state);
- }
- state = RxdState::waitingForStartBit;
- again = true;
- break;
- }
- } while (again);
-}
-
-// Return the current wheel angle
-float Duet3DFilamentSensor::GetCurrentAngle() const
-{
- return (sensorValue & AngleMask) * (360.0/1024.0);
-}
-
-// Call the following at intervals to check the status. This is only called when extrusion is in progress or imminent.
-// 'filamentConsumed' is the net amount of extrusion since the last call to this function.
-FilamentSensorStatus Duet3DFilamentSensor::Check(bool full, float filamentConsumed)
-{
- accumulatedExtrusionCommanded += filamentConsumed;
- Poll();
-
- FilamentSensorStatus ret = FilamentSensorStatus::ok;
- if (full)
- {
- if ((sensorValue & ErrorBit) != 0)
- {
- ret = FilamentSensorStatus::sensorError;
- }
- else if (withSwitch && (sensorValue & SwitchOpenBit) != 0)
- {
- ret = FilamentSensorStatus::noFilament;
- }
- else if (samplesReceived >= 10 && state != RxdState::waitingForEndOfStartBit && state != RxdState::waitingForNibble)
- {
- if (extrusionCommandedAtLastMeasurement >= minimumExtrusionCheckLength)
- {
- ret = CheckFilament(extrusionCommandedAtLastMeasurement, false);
- }
- else if (accumulatedExtrusionCommanded >= minimumExtrusionCheckLength * 1.1 && millis() - lastMeasurementTime > 110)
- {
- ret = CheckFilament(accumulatedExtrusionCommanded, true);
- }
- }
- }
-
- return ret;
-}
-
-// Compare the amount commanded with the amount of extrusion measured, and set up for the next comparison
-FilamentSensorStatus Duet3DFilamentSensor::CheckFilament(float amountCommanded, bool overdue)
-{
- const float extrusionMeasured = accumulatedRevsMeasured * mmPerRev;
- if (reprap.Debug(moduleFilamentSensors))
- {
- debugPrintf("Extr req %.3f meas %.3f rem %.3f %s\n", (double)amountCommanded, (double)extrusionMeasured, (double)(accumulatedExtrusionCommanded - amountCommanded),
- (overdue) ? " overdue" : "");
- }
-
- FilamentSensorStatus ret = FilamentSensorStatus::ok;
- if (!comparisonStarted)
- {
- // The first measurement after we start extruding is often a long way out, so discard it
- comparisonStarted = true;
- calibrationStarted = false;
- }
- else if (tolerance >= 0.0)
- {
- const float minExtrusionExpected = (amountCommanded >= 0.0)
- ? amountCommanded * (1.0 - tolerance)
- : amountCommanded * (1.0 + tolerance);
- if (extrusionMeasured < minExtrusionExpected)
- {
- ret = FilamentSensorStatus::tooLittleMovement;
- }
- else
- {
- const float maxExtrusionExpected = (amountCommanded >= 0.0)
- ? amountCommanded * (1.0 + tolerance)
- : amountCommanded * (1.0 - tolerance);
- if (extrusionMeasured > maxExtrusionExpected)
- {
- ret = FilamentSensorStatus::tooMuchMovement;
- }
- }
- }
-
- // Update the calibration accumulators, even if the user hasn't asked to do calibration
- const float ratio = accumulatedRevsMeasured/amountCommanded;
- if (calibrationStarted)
- {
- if (ratio < minMovementRatio)
- {
- minMovementRatio = ratio;
- }
- if (ratio > maxMovementRatio)
- {
- maxMovementRatio = ratio;
- }
- totalExtrusionCommanded += amountCommanded;
- totalRevsMeasured += accumulatedRevsMeasured;
- }
- else
- {
- minMovementRatio = maxMovementRatio = ratio;
- totalExtrusionCommanded = amountCommanded;
- totalRevsMeasured = accumulatedRevsMeasured;
- calibrationStarted = true;
- }
-
- accumulatedExtrusionCommanded -= amountCommanded;
- extrusionCommandedAtLastMeasurement = accumulatedRevsMeasured = 0.0;
-
- return ret;
-}
-
-// Clear the measurement state - called when we are not printing a file. Return the present/not present status if available.
-FilamentSensorStatus Duet3DFilamentSensor::Clear(bool full)
-{
- Poll(); // to keep the diagnostics up to date
- accumulatedExtrusionCommanded = accumulatedRevsMeasured = extrusionCommandedAtLastMeasurement = tentativeExtrusionCommanded = 0.0;
- samplesReceived = 0;
- comparisonStarted = false;
-
- FilamentSensorStatus ret = FilamentSensorStatus::ok;
- if (full)
- {
- if ((sensorValue & ErrorBit) != 0)
- {
- ret = FilamentSensorStatus::sensorError;
- }
- else if (withSwitch && (sensorValue & SwitchOpenBit) != 0)
- {
- ret = FilamentSensorStatus::noFilament;
- }
- }
- return ret;
-}
-
-// Print diagnostic info for this sensor
-void Duet3DFilamentSensor::Diagnostics(MessageType mtype, unsigned int extruder)
-{
- Poll();
- const char* const statusText = (!dataReceived) ? "no data received"
- : ((sensorValue & ErrorBit) != 0) ? "error"
- : (withSwitch && (sensorValue & SwitchOpenBit) != 0) ? "no filament"
- : "ok";
- reprap.GetPlatform().MessageF(mtype, "Extruder %u sensor: angle %.1f, %s, ", extruder, (double)GetCurrentAngle(), statusText);
- if (calibrationStarted && fabsf(totalRevsMeasured) > 1.0 && totalExtrusionCommanded > 20.0)
- {
- const float measuredMmPerRev = totalExtrusionCommanded/totalRevsMeasured;
- const float normalRatio = 1.0/measuredMmPerRev;
- const int measuredPosTolerance = lrintf(100.0 * (((normalRatio > 0.0) ? maxMovementRatio : minMovementRatio) - normalRatio)/normalRatio);
- const int measuredNegTolerance = lrintf(100.0 * (normalRatio - ((normalRatio > 0.0) ? minMovementRatio : maxMovementRatio))/normalRatio);
- reprap.GetPlatform().MessageF(mtype,"%.2fmm/rev, tolerance +%d%% -%d%%\n", (double)measuredMmPerRev, measuredPosTolerance, measuredNegTolerance);
- }
- else
- {
- reprap.GetPlatform().Message(mtype, "no calibration data\n");
- }
-}
-
-// End
diff --git a/src/FilamentSensors/Duet3DFilamentSensor.h b/src/FilamentSensors/Duet3DFilamentSensor.h
deleted file mode 100644
index 94e0204d..00000000
--- a/src/FilamentSensors/Duet3DFilamentSensor.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Duet3DFilamentSensor.h
- *
- * Created on: 20 Jul 2017
- * Author: David
- */
-
-#ifndef SRC_FILAMENTSENSORS_DUET3DFILAMENTSENSOR_H_
-#define SRC_FILAMENTSENSORS_DUET3DFILAMENTSENSOR_H_
-
-#include "FilamentSensor.h"
-
-class Duet3DFilamentSensor : public FilamentSensor
-{
-public:
- Duet3DFilamentSensor(int type);
-
- bool Configure(GCodeBuffer& gb, StringRef& reply, bool& seen) override;
- FilamentSensorStatus Check(bool full, float filamentConsumed) override;
- FilamentSensorStatus Clear(bool full) override;
- void Diagnostics(MessageType mtype, unsigned int extruder) override;
- void Interrupt() override;
-
-private:
- static constexpr float DefaultMmPerRev = 28.8;
- static constexpr float DefaultTolerance = 0.2;
- static constexpr float DefaultMinimumExtrusionCheckLength = 3.0;
-
- static constexpr uint16_t SwitchOpenBit = 0x4000u;
- static constexpr uint16_t ErrorBit = 0x8000u;
- static constexpr uint16_t AngleMask = 0x03FF; // 10-bit sensor angle
-
- static constexpr size_t EdgeCaptureBufferSize = 64; // must be a power of 2
-
- void Init();
- void Poll();
- float GetCurrentAngle() const;
- FilamentSensorStatus CheckFilament(float amountCommanded, bool overdue);
-
- // Configuration parameters
- float mmPerRev;
- float tolerance;
- float minimumExtrusionCheckLength;
- bool withSwitch;
-
- // Other data
- uint16_t sensorValue;
- float accumulatedExtrusionCommanded;
- float accumulatedRevsMeasured;
- float extrusionCommandedAtLastMeasurement;
- float tentativeExtrusionCommanded;
-
- uint32_t lastMeasurementTime;
- uint32_t edgeCaptures[EdgeCaptureBufferSize];
- size_t edgeCaptureReadPointer;
- volatile size_t edgeCaptureWritePointer;
- float minMovementRatio, maxMovementRatio;
- float totalExtrusionCommanded, totalRevsMeasured;
-
- enum class RxdState : uint8_t
- {
- waitingForStartBit,
- waitingForEndOfStartBit,
- waitingForNibble,
- errorRecovery1,
- errorRecovery2,
- errorRecovery3,
- errorRecovery4
- };
-
- RxdState state;
- uint32_t startBitLength;
- uint32_t errorRecoveryStartTime;
- size_t lastBitChangeIndex;
- uint16_t valueBeingAssembled;
- uint8_t nibblesAssembled;
- uint8_t samplesReceived;
- bool dataReceived;
- bool comparisonStarted;
- bool calibrationStarted;
-};
-
-#endif /* SRC_FILAMENTSENSORS_DUET3DFILAMENTSENSOR_H_ */
diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp
index 9add807c..5dbd1181 100644
--- a/src/GCodes/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer.cpp
@@ -463,8 +463,7 @@ const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool
}
}
- // Special case if there is one entry and returnedLength requests several.
- // Fill the array with the first entry.
+ // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
if (doPad && length == 1 && returnedLength > 1)
{
for(size_t i = 1; i < returnedLength; i++)
@@ -487,7 +486,7 @@ const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool
}
// Get a :-separated list of ints after a key letter
-const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength)
+const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength, bool doPad)
{
if (readPointer >= 0)
{
@@ -513,7 +512,19 @@ const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength)
inList = false;
}
}
- returnedLength = length;
+
+ // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
+ if (doPad && length == 1 && returnedLength > 1)
+ {
+ for (size_t i = 1; i < returnedLength; i++)
+ {
+ arr[i] = arr[0];
+ }
+ }
+ else
+ {
+ returnedLength = length;
+ }
readPointer = -1;
}
else
@@ -524,7 +535,7 @@ const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength)
}
// Get a :-separated list of unsigned ints after a key letter
-const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength)
+const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength, bool doPad)
{
if (readPointer >= 0)
{
@@ -550,7 +561,20 @@ const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength)
inList = false;
}
}
- returnedLength = length;
+
+ // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
+ if (doPad && length == 1 && returnedLength > 1)
+ {
+ for (size_t i = 1; i < returnedLength; i++)
+ {
+ arr[i] = arr[0];
+ }
+ }
+ else
+ {
+ returnedLength = length;
+ }
+
readPointer = -1;
}
else
diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h
index 54a842ab..57886c67 100644
--- a/src/GCodes/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer.h
@@ -40,8 +40,8 @@ public:
bool GetQuotedString(const StringRef& str); // Get and copy a quoted string
bool GetPossiblyQuotedString(const StringRef& str); // Get and copy a string which may or may not be quoted
const void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a :-separated list of floats after a key letter
- const void GetIntArray(int32_t arr[], size_t& length); // Get a :-separated list of ints after a key letter
- const void GetUnsignedArray(uint32_t arr[], size_t& length); // Get a :-separated list of unsigned ints after a key letter
+ const void GetIntArray(int32_t arr[], size_t& length, bool doPad); // Get a :-separated list of ints after a key letter
+ const void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad); // Get a :-separated list of unsigned ints after a key letter
void TryGetFValue(char c, float& val, bool& seen);
void TryGetIValue(char c, int32_t& val, bool& seen);
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 9a7c025b..7560db63 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -1439,7 +1439,7 @@ void GCodes::CheckFilament()
)
{
String<100> filamentErrorString;
- filamentErrorString.GetRef().printf("Extruder %u reports %s", lastFilamentErrorExtruder, FilamentSensor::GetErrorMessage(lastFilamentError));
+ filamentErrorString.GetRef().printf("Extruder %u reports %s", lastFilamentErrorExtruder, FilamentMonitor::GetErrorMessage(lastFilamentError));
DoPause(*autoPauseGCode, PauseReason::filament, filamentErrorString.Pointer());
lastFilamentError = FilamentSensorStatus::ok;
platform.Message(LogMessage, filamentErrorString.c_str());
@@ -2011,16 +2011,25 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType)
{
const int drive = tool->Drive(eDrive);
float extrusionAmount = requestedExtrusionAmount * tool->GetMix()[eDrive];
- if (gb.MachineState().volumetricExtrusion)
+ if (extrusionAmount != 0.0)
{
- extrusionAmount *= volumetricExtrusionFactors[drive];
- }
- rawExtruderTotalByDrive[drive] += extrusionAmount;
- if (!doingToolChange) // don't count extrusion done in tool change macros towards total filament consumed, it distorts the print progress
- {
- rawExtruderTotal += extrusionAmount;
+ if (gb.MachineState().volumetricExtrusion)
+ {
+ extrusionAmount *= volumetricExtrusionFactors[drive];
+ }
+ rawExtruderTotalByDrive[drive] += extrusionAmount;
+ if (!doingToolChange) // don't count extrusion done in tool change macros towards total filament consumed, it distorts the print progress
+ {
+ rawExtruderTotal += extrusionAmount;
+ }
+ moveBuffer.coords[drive + numTotalAxes] = extrusionAmount * extrusionFactors[drive];
+#if HAS_SMART_DRIVERS
+ if (moveBuffer.moveType == 1)
+ {
+ SetBit(moveBuffer.endStopsToCheck, drive + numTotalAxes);
+ }
+#endif
}
- moveBuffer.coords[drive + numTotalAxes] = extrusionAmount * extrusionFactors[drive];
}
}
else
@@ -2032,16 +2041,25 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType)
{
const int drive = tool->Drive(eDrive);
float extrusionAmount = eMovement[eDrive] * distanceScale;
- if (gb.MachineState().volumetricExtrusion)
+ if (extrusionAmount != 0.0)
{
- extrusionAmount *= volumetricExtrusionFactors[drive];
- }
- rawExtruderTotalByDrive[drive] += extrusionAmount;
- if (!doingToolChange) // don't count extrusion done in tool change macros towards total filament consumed, it distorts the print progress
- {
- rawExtruderTotal += extrusionAmount;
+ if (gb.MachineState().volumetricExtrusion)
+ {
+ extrusionAmount *= volumetricExtrusionFactors[drive];
+ }
+ rawExtruderTotalByDrive[drive] += extrusionAmount;
+ if (!doingToolChange) // don't count extrusion done in tool change macros towards total filament consumed, it distorts the print progress
+ {
+ rawExtruderTotal += extrusionAmount;
+ }
+ moveBuffer.coords[drive + numTotalAxes] = extrusionAmount * extrusionFactors[drive] * volumetricExtrusionFactors[drive];
+#if HAS_SMART_DRIVERS
+ if (moveBuffer.moveType == 1)
+ {
+ SetBit(moveBuffer.endStopsToCheck, drive + numTotalAxes);
+ }
+#endif
}
- moveBuffer.coords[drive + numTotalAxes] = extrusionAmount * extrusionFactors[drive] * volumetricExtrusionFactors[drive];
}
}
else
@@ -2068,6 +2086,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, StringRef& reply, bool isCoordinate
axesToSenseLength = 0;
// Check to see if the move is a 'homing' move that endstops are checked on.
+ // We handle S1 parameters affecting extrusion elsewhere.
if (gb.Seen('S'))
{
const int ival = gb.GetIValue();
@@ -3145,7 +3164,7 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply)
size_t dCount = numExtruders; // Sets the limit and returns the count
if (gb.Seen('D'))
{
- gb.GetIntArray(drives, dCount);
+ gb.GetIntArray(drives, dCount, false);
seen = true;
}
else
@@ -3158,7 +3177,7 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply)
size_t hCount = Heaters;
if (gb.Seen('H'))
{
- gb.GetIntArray(heaters, hCount);
+ gb.GetIntArray(heaters, hCount, false);
seen = true;
}
else
@@ -3172,7 +3191,7 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply)
{
uint32_t xMapping[MaxAxes];
size_t xCount = numVisibleAxes;
- gb.GetUnsignedArray(xMapping, xCount);
+ gb.GetUnsignedArray(xMapping, xCount, false);
xMap = UnsignedArrayToBitMap<AxesBitmap>(xMapping, xCount) & LowestNBits<AxesBitmap>(numVisibleAxes);
seen = true;
}
@@ -3187,7 +3206,7 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply)
{
uint32_t yMapping[MaxAxes];
size_t yCount = numVisibleAxes;
- gb.GetUnsignedArray(yMapping, yCount);
+ gb.GetUnsignedArray(yMapping, yCount, false);
yMap = UnsignedArrayToBitMap<AxesBitmap>(yMapping, yCount) & LowestNBits<AxesBitmap>(numVisibleAxes);
seen = true;
}
@@ -3208,7 +3227,7 @@ bool GCodes::ManageTool(GCodeBuffer& gb, StringRef& reply)
{
uint32_t fanMapping[NUM_FANS];
size_t fanCount = NUM_FANS;
- gb.GetUnsignedArray(fanMapping, fanCount);
+ gb.GetUnsignedArray(fanMapping, fanCount, false);
fanMap = UnsignedArrayToBitMap<FansBitmap>(fanMapping, fanCount) & LowestNBits<FansBitmap>(NUM_FANS);
seen = true;
}
@@ -3650,13 +3669,13 @@ GCodeResult GCodes::SetHeaterParameters(GCodeBuffer& gb, StringRef& reply)
if (!seen && oldChannel < 0)
{
// For backwards compatibility, if no sensor has been configured on this channel then assume the thermistor normally associated with the heater
- if (heater < (int)Heaters)
+ if (heater < (int)Heaters && (gb.Seen('R') || gb.Seen('T') || gb.Seen('B'))) // if it has a thermistor and we are trying to configure it
{
channel = heater;
}
else
{
- reply.printf("Virtual heater %d is not configured", heater);
+ reply.printf("heater %d is not configured", heater);
return GCodeResult::error;
}
}
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index bb2351a7..83a6e3d5 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -29,7 +29,7 @@ Licence: GPL
#include "Platform.h" // for type EndStopHit
#include "GCodeInput.h"
#include "Tools/Filament.h"
-#include "FilamentSensors/FilamentSensor.h"
+#include "FilamentMonitors/FilamentMonitor.h"
#include "RestorePoint.h"
#include "Movement/BedProbing/Grid.h"
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index 2e9d1e55..3226396f 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -18,7 +18,7 @@
#include "PrintMonitor.h"
#include "RepRap.h"
#include "Tools/Tool.h"
-#include "FilamentSensors/FilamentSensor.h"
+#include "FilamentMonitors/FilamentMonitor.h"
#include "Libraries/General/IP4String.h"
#include "Version.h"
@@ -402,7 +402,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
uint32_t eDrive[MaxExtruders];
size_t eCount = numExtruders;
- gb.GetUnsignedArray(eDrive, eCount);
+ gb.GetUnsignedArray(eDrive, eCount, false);
for (size_t i = 0; i < eCount; i++)
{
seen = true;
@@ -1330,9 +1330,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (!cancelWait && gb.Seen('H'))
{
// Wait for specified heaters to be ready
- int32_t heaters[Heaters];
+ uint32_t heaters[Heaters];
size_t heaterCount = Heaters;
- gb.GetIntArray(heaters, heaterCount);
+ gb.GetUnsignedArray(heaters, heaterCount, false);
for (size_t i = 0; i < heaterCount; i++)
{
@@ -1349,9 +1349,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (!cancelWait && gb.Seen('C'))
{
// Wait for specified chamber(s) to be ready
- int32_t chamberIndices[NumChamberHeaters];
+ uint32_t chamberIndices[NumChamberHeaters];
size_t chamberCount = NumChamberHeaters;
- gb.GetIntArray(chamberIndices, chamberCount);
+ gb.GetUnsignedArray(chamberIndices, chamberCount, false);
if (chamberCount == 0)
{
@@ -1372,7 +1372,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
// Otherwise wait only for the specified chamber heaters
for (size_t i = 0; i < chamberCount; i++)
{
- if (chamberIndices[i] >= 0 && chamberIndices[i] < (int)NumChamberHeaters)
+ if (chamberIndices[i] >= 0 && chamberIndices[i] < NumChamberHeaters)
{
const int8_t heater = reprap.GetHeat().GetChamberHeater(chamberIndices[i]);
if (heater >= 0 && !reprap.GetHeat().HeaterAtSetTemperature(heater, true))
@@ -2240,7 +2240,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
seen = true;
uint32_t eVals[MaxExtruders];
size_t eCount = numExtruders;
- gb.GetUnsignedArray(eVals, eCount);
+ gb.GetUnsignedArray(eVals, eCount, true);
for (size_t e = 0; e < eCount; e++)
{
if (!ChangeMicrostepping(numTotalAxes + e, (int)eVals[e], mode))
@@ -2378,12 +2378,12 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
machineType = MachineType::laser;
if (gb.Seen('P'))
{
- int lp = gb.GetIValue();
- if (lp < 0 || lp > 65535)
+ uint32_t lp = gb.GetUIValue();
+ if (lp > 65535)
{
lp = NoLogicalPin;
}
- if (reprap.GetPlatform().SetLaserPin(lp))
+ if (reprap.GetPlatform().SetLaserPin((LogicalPin)lp))
{
reply.copy("Laser mode selected");
}
@@ -2409,7 +2409,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
uint32_t pins[2] = { NoLogicalPin, NoLogicalPin };
size_t numPins = 2;
- gb.GetUnsignedArray(pins, numPins);
+ gb.GetUnsignedArray(pins, numPins, false);
if (pins[0] > 65535)
{
pins[0] = NoLogicalPin;
@@ -3057,7 +3057,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
uint32_t eDrive[MaxExtruders];
size_t eCount = MaxExtruders;
- gb.GetUnsignedArray(eDrive, eCount);
+ gb.GetUnsignedArray(eDrive, eCount, false);
for (size_t i = 0; i < eCount; i++)
{
if (eDrive[i] >= numExtruders)
@@ -3129,7 +3129,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
reply.catf(" %s,",
(inputType == EndStopInputType::activeHigh) ? "active high switch"
- : (inputType == EndStopInputType::activeHigh) ? "active low switch"
+ : (inputType == EndStopInputType::activeLow) ? "active low switch"
: (inputType == EndStopInputType::zProbe) ? "Z probe"
: (inputType == EndStopInputType::motorStall) ? "motor stall"
: "unknown type"
@@ -3217,7 +3217,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
size_t eDriveCount = MaxExtruders;
uint32_t eDrives[MaxExtruders];
- gb.GetUnsignedArray(eDrives, eDriveCount);
+ gb.GetUnsignedArray(eDrives, eDriveCount, false);
for (size_t extruder = 0; extruder < eDriveCount; extruder++)
{
const size_t eDrive = eDrives[extruder];
@@ -3396,10 +3396,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
gb.TryGetIValue('P', sensorType, seen);
if (seen)
{
- FilamentSensor::SetFilamentSensorType(extruder, sensorType);
+ FilamentMonitor::SetFilamentSensorType(extruder, sensorType);
}
- FilamentSensor *sensor = FilamentSensor::GetFilamentSensor(extruder);
+ FilamentMonitor *sensor = FilamentMonitor::GetFilamentSensor(extruder);
if (sensor != nullptr)
{
// Configure the sensor
@@ -3407,7 +3407,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
result = GetGCodeResultFromError(error);
if (error)
{
- FilamentSensor::SetFilamentSensorType(extruder, 0); // delete the sensor
+ FilamentMonitor::SetFilamentSensorType(extruder, 0); // delete the sensor
}
}
else if (!seen)
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 349c2742..7a2a6a35 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -343,7 +343,7 @@ GCodeResult GCodes::CheckOrConfigureTrigger(GCodeBuffer& gb, StringRef& reply, i
{
uint32_t eStops[MaxExtruders];
size_t numEntries = MaxExtruders;
- gb.GetUnsignedArray(eStops, numEntries);
+ gb.GetUnsignedArray(eStops, numEntries, false);
for (size_t i = 0; i < numEntries; ++i)
{
if (eStops[i] < MaxExtruders)
@@ -423,7 +423,7 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, StringRef& reply)
seen = true;
size_t numValues = MaxDriversPerAxis;
uint32_t drivers[MaxDriversPerAxis];
- gb.GetUnsignedArray(drivers, numValues);
+ gb.GetUnsignedArray(drivers, numValues, false);
// Check all the driver numbers are in range
AxisDriversConfig config;
@@ -477,7 +477,7 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, StringRef& reply)
seen = true;
size_t numValues = DRIVES - numTotalAxes;
uint32_t drivers[MaxExtruders];
- gb.GetUnsignedArray(drivers, numValues);
+ gb.GetUnsignedArray(drivers, numValues, false);
numExtruders = numValues;
for (size_t i = 0; i < numValues; ++i)
{
@@ -703,7 +703,7 @@ GCodeResult GCodes::UpdateFirmware(GCodeBuffer& gb, StringRef &reply)
{
uint32_t modulesToUpdate[3];
size_t numUpdateModules = ARRAY_SIZE(modulesToUpdate);
- gb.GetUnsignedArray(modulesToUpdate, numUpdateModules);
+ gb.GetUnsignedArray(modulesToUpdate, numUpdateModules, false);
for (size_t i = 0; i < numUpdateModules; ++i)
{
uint32_t t = modulesToUpdate[i];
diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp
index 258f174d..6afa6f44 100644
--- a/src/Movement/DDA.cpp
+++ b/src/Movement/DDA.cpp
@@ -1264,7 +1264,13 @@ void DDA::CheckEndstops(Platform& platform)
#endif
const size_t numAxes = reprap.GetGCodes().GetTotalAxes();
- for (size_t drive = 0; drive < numAxes; ++drive)
+ for (size_t drive = 0; drive <
+#if HAS_STALL_DETECT
+ DRIVES
+#else
+ numAxes
+#endif
+ ; ++drive)
{
if (IsBitSet(endStopsToCheck, drive))
{
@@ -1273,7 +1279,7 @@ void DDA::CheckEndstops(Platform& platform)
{
case EndStopHit::lowHit:
case EndStopHit::highHit:
- if ((endStopsToCheck & UseSpecialEndstop) != 0) // use only one (probably non-default) endstop while probing a tool offset
+ if ((endStopsToCheck & UseSpecialEndstop) != 0) // use only one (probably non-default) endstop while probing a tool offset
{
MoveAborted();
}
@@ -1281,7 +1287,12 @@ void DDA::CheckEndstops(Platform& platform)
{
ClearBit(endStopsToCheck, drive); // clear this check so that we can check for more
const Kinematics& kin = reprap.GetMove().GetKinematics();
- if (endStopsToCheck == 0 || kin.QueryTerminateHomingMove(drive))
+ if ( endStopsToCheck == 0 // if no endstops left to check
+#if HAS_STALL_DETECT
+ || drive >= numAxes // or we are stopping on an extruder motor stall
+#endif
+ || kin.QueryTerminateHomingMove(drive) // or this kinematics requires us to stop the move now
+ )
{
MoveAborted(); // no more endstops to check, or this axis uses shared motors, so stop the entire move
}
@@ -1289,7 +1300,7 @@ void DDA::CheckEndstops(Platform& platform)
{
StopDrive(drive); // we must stop the drive before we mess with its coordinates
}
- if (drive < reprap.GetGCodes().GetTotalAxes() && IsHomingAxes())
+ if (drive < numAxes && IsHomingAxes())
{
kin.OnHomingSwitchTriggered(drive, esh == EndStopHit::highHit, reprap.GetPlatform().GetDriveStepsPerUnit(), *this);
reprap.GetGCodes().SetAxisIsHomed(drive);
@@ -1424,7 +1435,7 @@ bool DDA::Step()
// 2. Determine which drivers are due for stepping, overdue, or will be due very shortly
DriveMovement* dm = firstDM;
- const uint32_t elapsedTime = (Platform::GetInterruptClocks() - moveStartTime) + minInterruptInterval;
+ const uint32_t elapsedTime = (Platform::GetInterruptClocks() - moveStartTime) + MinInterruptInterval;
uint32_t driversStepping = 0;
while (dm != nullptr && elapsedTime >= dm->nextStepTime) // if the next step is due
{
@@ -1638,6 +1649,11 @@ int32_t DDA::GetStepsTaken(size_t drive) const
return (dmp != nullptr) ? dmp->GetNetStepsTaken() : 0;
}
+bool DDA::IsNonPrintingExtruderMove(size_t drive) const
+{
+ return !isPrintingMove && FindDM(drive) != nullptr;
+}
+
void DDA::LimitSpeedAndAcceleration(float maxSpeed, float maxAcceleration)
{
if (requestedSpeed > maxSpeed)
diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h
index 21a9bee5..5de52e3f 100644
--- a/src/Movement/DDA.h
+++ b/src/Movement/DDA.h
@@ -74,6 +74,7 @@ public:
void LimitSpeedAndAcceleration(float maxSpeed, float maxAcceleration); // Limit the speed an acceleration of this move
int32_t GetStepsTaken(size_t drive) const;
+ bool IsNonPrintingExtruderMove(size_t drive) const;
float GetProportionDone(bool moveWasAborted) const; // Return the proportion of extrusion for the complete multi-segment move already done
@@ -105,17 +106,17 @@ public:
// Note: the above measurements were taken some time ago, before some firmware optimisations.
#if SAME70
// The system clock of the SAME70 is running at 150MHz. Use the same defaults as for the SAM4E for now.
- static constexpr int32_t MinCalcIntervalDelta = (40 * stepClockRate)/1000000; // the smallest sensible interval between calculations (40us) in step timer clocks
- static constexpr int32_t MinCalcIntervalCartesian = (40 * stepClockRate)/1000000; // same as delta for now, but could be lower
- static constexpr uint32_t minInterruptInterval = 6; // about 6us minimum interval between interrupts, in step clocks
+ static constexpr uint32_t MinCalcIntervalDelta = (40 * stepClockRate)/1000000; // the smallest sensible interval between calculations (40us) in step timer clocks
+ static constexpr uint32_t MinCalcIntervalCartesian = (40 * stepClockRate)/1000000; // same as delta for now, but could be lower
+ static constexpr uint32_t MinInterruptInterval = 6; // about 6us minimum interval between interrupts, in step clocks
#elif SAM4E || SAM4S
- static constexpr int32_t MinCalcIntervalDelta = (40 * stepClockRate)/1000000; // the smallest sensible interval between calculations (40us) in step timer clocks
- static constexpr int32_t MinCalcIntervalCartesian = (40 * stepClockRate)/1000000; // same as delta for now, but could be lower
- static constexpr uint32_t minInterruptInterval = 6; // about 6us minimum interval between interrupts, in step clocks
+ static constexpr uint32_t MinCalcIntervalDelta = (40 * stepClockRate)/1000000; // the smallest sensible interval between calculations (40us) in step timer clocks
+ static constexpr uint32_t MinCalcIntervalCartesian = (40 * stepClockRate)/1000000; // same as delta for now, but could be lower
+ static constexpr uint32_t MinInterruptInterval = 6; // about 6us minimum interval between interrupts, in step clocks
#else
- static constexpr int32_t MinCalcIntervalDelta = (60 * stepClockRate)/1000000; // the smallest sensible interval between calculations (60us) in step timer clocks
- static constexpr int32_t MinCalcIntervalCartesian = (60 * stepClockRate)/1000000; // same as delta for now, but could be lower
- static constexpr uint32_t minInterruptInterval = 4; // about 6us minimum interval between interrupts, in step clocks
+ static constexpr uint32_t MinCalcIntervalDelta = (60 * stepClockRate)/1000000; // the smallest sensible interval between calculations (60us) in step timer clocks
+ static constexpr uint32_t MinCalcIntervalCartesian = (60 * stepClockRate)/1000000; // same as delta for now, but could be lower
+ static constexpr uint32_t MinInterruptInterval = 4; // about 6us minimum interval between interrupts, in step clocks
#endif
static void PrintMoves(); // print saved moves for debugging
diff --git a/src/Movement/DriveMovement.cpp b/src/Movement/DriveMovement.cpp
index 2352cc26..8bba7802 100644
--- a/src/Movement/DriveMovement.cpp
+++ b/src/Movement/DriveMovement.cpp
@@ -182,7 +182,9 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, bo
if (reprap.GetPlatform().GetExtrusionCoefficients(extruder, a, b, limit))
{
const float averageExtrusionSpeed = (dda.totalDistance * dv * DDA::stepClockRate)/dda.clocksNeeded;
- stepsPerMm *= 1.0 + min<float>((averageExtrusionSpeed * a) + (averageExtrusionSpeed * averageExtrusionSpeed * b), limit);
+ const float factor = 1.0 + min<float>((averageExtrusionSpeed * a) + (averageExtrusionSpeed * averageExtrusionSpeed * b), limit);
+ stepsPerMm *= factor;
+ totalSteps = (uint32_t)(totalSteps * factor); // round this down to avoid step errors
}
}
#endif
@@ -293,10 +295,10 @@ pre(nextStep < totalSteps; stepsTillRecalc == 0)
uint32_t shiftFactor = 0; // assume single stepping
if (stepInterval < DDA::MinCalcIntervalCartesian)
{
- uint32_t stepsToLimit = ((nextStep <= reverseStartStep && reverseStartStep <= totalSteps)
- ? reverseStartStep
- : totalSteps
- ) - nextStep;
+ const uint32_t stepsToLimit = ((nextStep <= reverseStartStep && reverseStartStep <= totalSteps)
+ ? reverseStartStep
+ : totalSteps
+ ) - nextStep;
if (stepInterval < DDA::MinCalcIntervalCartesian/4 && stepsToLimit > 8)
{
shiftFactor = 3; // octal stepping
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index b1532c70..2a3479ae 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -65,6 +65,7 @@ void Move::Init()
for (size_t i = 0; i < MaxExtruders; ++i)
{
extrusionAccumulators[i] = 0;
+ extruderNonPrinting[i] = false;
extrusionPending[i] = 0.0;
}
@@ -968,6 +969,10 @@ void Move::CurrentMoveCompleted()
for (size_t drive = numAxes; drive < DRIVES; ++drive)
{
extrusionAccumulators[drive - numAxes] += currentDda->GetStepsTaken(drive);
+ if (currentDda->IsNonPrintingExtruderMove(drive))
+ {
+ extruderNonPrinting[drive - numAxes] = true;
+ }
}
currentDda = nullptr;
@@ -1096,7 +1101,9 @@ void Move::ResetExtruderPositions()
}
// Get the accumulated extruder motor steps taken by an extruder since the last call. Used by the filament monitoring code.
-int32_t Move::GetAccumulatedExtrusion(size_t extruder)
+// Returns the number of motor steps moves since the last call, and nonPrinting is true if we are currently executing an extruding but non-printing move
+// or we completed one since the last call.
+int32_t Move::GetAccumulatedExtrusion(size_t extruder, bool& nonPrinting)
{
const size_t drive = extruder + reprap.GetGCodes().GetTotalAxes();
if (drive < DRIVES)
@@ -1104,12 +1111,27 @@ int32_t Move::GetAccumulatedExtrusion(size_t extruder)
const irqflags_t flags = cpu_irq_save();
const int32_t ret = extrusionAccumulators[extruder];
const DDA * const cdda = currentDda; // capture volatile variable
- const int32_t adjustment = (cdda != nullptr) ? cdda->GetStepsTaken(drive) : 0;
+ const int32_t adjustment = (cdda == nullptr) ? 0 : cdda->GetStepsTaken(drive);
+ if (adjustment == 0)
+ {
+ // Either there is no current move, or we are at the very start of this move, or it doesn't involve this extruder e.g. a travel move
+ nonPrinting = extruderNonPrinting[extruder];
+ }
+ else if (cdda->IsPrintingMove())
+ {
+ nonPrinting = extruderNonPrinting[extruder];
+ extruderNonPrinting[extruder] = false;
+ }
+ else
+ {
+ nonPrinting = true;
+ }
extrusionAccumulators[extruder] = -adjustment;
cpu_irq_restore(flags);
return ret + adjustment;
}
+ nonPrinting = true;
return 0.0;
}
diff --git a/src/Movement/Move.h b/src/Movement/Move.h
index 92a64b7b..f357f29c 100644
--- a/src/Movement/Move.h
+++ b/src/Movement/Move.h
@@ -118,7 +118,7 @@ public:
void AdjustLeadscrews(const floatc_t corrections[]); // Called by some Kinematics classes to adjust the leadscrews
- int32_t GetAccumulatedExtrusion(size_t extruder); // Return ands reset the accumulated extrusion amount
+ int32_t GetAccumulatedExtrusion(size_t extruder, bool& nonPrinting); // Return and reset the accumulated extrusion amount
bool WriteResumeSettings(FileStore *f) const; // Write settings for resuming the print
@@ -170,6 +170,7 @@ private:
volatile bool liveCoordinatesValid; // True if the XYZ live coordinates are reliable (the extruder ones always are)
volatile int32_t liveEndPoints[DRIVES]; // The XYZ endpoints of the last completed move in motor coordinates
volatile int32_t extrusionAccumulators[MaxExtruders]; // Accumulated extruder motor steps
+ volatile bool extruderNonPrinting[MaxExtruders]; // Set whenever the extruder starts a non-printing move
float tangents[3]; // Axis compensation - 90 degrees + angle gives angle between axes
float& tanXY = tangents[0];
diff --git a/src/Network2/ESP8266/Network.cpp b/src/Network2/ESP8266/Network.cpp
index 8070a417..588b4873 100644
--- a/src/Network2/ESP8266/Network.cpp
+++ b/src/Network2/ESP8266/Network.cpp
@@ -669,7 +669,7 @@ const char* Network::TranslateNetworkState() const
void Network::Diagnostics(MessageType mtype)
{
- platform.MessageF(mtype, "Network state is %s\n", TranslateNetworkState());
+ platform.MessageF(mtype, "=== Network ===\nNetwork state is %s\n", TranslateNetworkState());
platform.MessageF(mtype, "WiFi module is %s\n", TranslateWiFiState(currentMode));
platform.MessageF(mtype, "Failed messages: pending %u, notready %u, noresp %u\n", transferAlreadyPendingCount, readyTimeoutCount, responseTimeoutCount);
diff --git a/src/Network2/W5500/Network.cpp b/src/Network2/W5500/Network.cpp
index 553d59f0..e135ff0e 100644
--- a/src/Network2/W5500/Network.cpp
+++ b/src/Network2/W5500/Network.cpp
@@ -404,8 +404,7 @@ void Network::Spin(bool full)
void Network::Diagnostics(MessageType mtype)
{
- platform.Message(mtype, "=== Network ===\n");
- platform.MessageF(mtype, "State: %d\n", (int)state);
+ platform.MessageF(mtype, "=== Network ===\nState: %d\n", (int)state);
HttpResponder::CommonDiagnostics(mtype);
platform.Message(mtype, "Responder states:");
for (NetworkResponder *r = responders; r != nullptr; r = r->GetNext())
diff --git a/src/Network2/W5500/Wiznet/Ethernet/WizSpi.cpp b/src/Network2/W5500/Wiznet/Ethernet/WizSpi.cpp
index 9c53d98c..9a695791 100644
--- a/src/Network2/W5500/Wiznet/Ethernet/WizSpi.cpp
+++ b/src/Network2/W5500/Wiznet/Ethernet/WizSpi.cpp
@@ -5,7 +5,7 @@
* Author: David
*/
-#include <Network2/W5500/Wiznet/Ethernet/WizSpi.h>
+#include "WizSpi.h"
#include "variant.h"
#include "Pins.h"
@@ -24,10 +24,13 @@
#include "matrix/matrix.h"
-// Functions called by the W5500 module to transfer data to/from the W5500 via SPI
-const uint32_t SpiClockFrequency = 40000000; // tried 60MHz and we got some data corruption when uploading files, so try 40MHz instead
+// SPI data rate. I tried 60MHz and we got some data corruption when uploading files, so I reduced it to 40MHz.
+// 2018-01-11: We have now received one report of data corruption at 40MHz, so reduced this to 30MHz
+const uint32_t SpiClockFrequency = 30000000;
const unsigned int SpiPeripheralChannelId = 0; // we use NPCS0 as the slave select signal
+// Functions called by the W5500 module to transfer data to/from the W5500 via SPI
+
#if USE_PDC
static Pdc *spi_pdc;
diff --git a/src/Platform.cpp b/src/Platform.cpp
index ef3baf88..5fa5aeda 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -26,7 +26,7 @@
#include "Movement/Move.h"
#include "Network.h"
#include "PrintMonitor.h"
-#include "FilamentSensors/FilamentSensor.h"
+#include "FilamentMonitors/FilamentMonitor.h"
#include "RepRap.h"
#include "Scanner.h"
#include "Version.h"
@@ -948,7 +948,7 @@ bool Platform::ProgramZProbe(GCodeBuffer& gb, StringRef& reply)
{
uint32_t zProbeProgram[MaxZProbeProgramBytes];
size_t len = MaxZProbeProgramBytes;
- gb.GetUnsignedArray(zProbeProgram, len);
+ gb.GetUnsignedArray(zProbeProgram, len, false);
if (len != 0)
{
for (size_t i = 0; i < len; ++i)
@@ -1579,8 +1579,8 @@ void Platform::Spin()
{
bool reported = false;
#if HAS_SMART_DRIVERS
- ReportDrivers(shortToGroundDrivers, "Error: Short-to-ground", reported);
- ReportDrivers(temperatureShutdownDrivers, "Error: Over temperature shutdown", reported);
+ ReportDrivers(ErrorMessage, shortToGroundDrivers, "short-to-ground", reported);
+ ReportDrivers(ErrorMessage, temperatureShutdownDrivers, "over temperature shutdown", reported);
// Don't report open load because we get too many spurious open load reports
//ReportDrivers(openLoadDrivers, "Error: Open load", reported);
@@ -1594,7 +1594,7 @@ void Platform::Spin()
|| (offBoardOtw && (!offBoardDriversFanRunning || now - offBoardDriversFanStartMillis >= DriverCoolingTimeout))
)
{
- ReportDrivers(temperatureWarningDrivers, "Warning: high temperature", reported);
+ ReportDrivers(WarningMessage, temperatureWarningDrivers, "high temperature", reported);
}
}
#endif
@@ -1702,7 +1702,7 @@ void Platform::Spin()
// Report driver status conditions that require attention.
// Sets 'reported' if we reported anything, else leaves 'reported' alone.
-void Platform::ReportDrivers(DriversBitmap whichDrivers, const char* text, bool& reported)
+void Platform::ReportDrivers(MessageType mt, DriversBitmap whichDrivers, const char* text, bool& reported)
{
if (whichDrivers != 0)
{
@@ -1715,7 +1715,7 @@ void Platform::ReportDrivers(DriversBitmap whichDrivers, const char* text, bool&
}
whichDrivers >>= 1;
}
- MessageF(WarningMessage, "%s\n", scratchString.Pointer());
+ MessageF(mt, "%s\n", scratchString.Pointer());
reported = true;
}
}
@@ -1724,8 +1724,8 @@ void Platform::ReportDrivers(DriversBitmap whichDrivers, const char* text, bool&
#if HAS_STALL_DETECT
-// Return true if any motor driving this axis or extruder is stalled
-bool Platform::AnyMotorStalled(size_t drive) const
+// Return true if any motor driving this axis is stalled
+bool Platform::AnyAxisMotorStalled(size_t drive) const
{
const size_t numAxes = reprap.GetGCodes().GetTotalAxes();
if (drive < numAxes)
@@ -1743,6 +1743,12 @@ bool Platform::AnyMotorStalled(size_t drive) const
return (SmartDrivers::GetLiveStatus(extruderDrivers[drive - numAxes]) & TMC_RR_SG) != 0;
}
+// Return true if the motor driving this extruder is stalled
+bool Platform::ExtruderMotorStalled(size_t extruder) const pre(drive < DRIVES)
+{
+ return (SmartDrivers::GetLiveStatus(extruderDrivers[extruder]) & TMC_RR_SG) != 0;
+}
+
#endif
#if HAS_VOLTAGE_MONITOR
@@ -1925,7 +1931,7 @@ static void FanInterrupt(CallbackParameter)
++fanInterruptCount;
if (fanInterruptCount == fanMaxInterruptCount)
{
- uint32_t now = micros();
+ const uint32_t now = micros();
fanInterval = now - fanLastResetTime;
fanLastResetTime = now;
fanInterruptCount = 0;
@@ -2681,7 +2687,8 @@ void Platform::UpdateConfiguredHeaters()
EndStopHit Platform::Stopped(size_t drive) const
{
- if (drive < reprap.GetGCodes().GetTotalAxes())
+ const size_t numAxes = reprap.GetGCodes().GetTotalAxes();
+ if (drive < numAxes)
{
switch (endStopInputType[drive])
{
@@ -2702,28 +2709,28 @@ EndStopHit Platform::Stopped(size_t drive) const
case KinematicsType::coreXY:
// Both X and Y motors are involved in homing X or Y
motorIsStalled = (drive == X_AXIS || drive == Y_AXIS)
- ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS)
- : AnyMotorStalled(drive);
+ ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Y_AXIS)
+ : AnyAxisMotorStalled(drive);
break;
case KinematicsType::coreXYU:
// Both X and Y motors are involved in homing X or Y, and both U and V motors are involved in homing U
motorIsStalled = (drive == X_AXIS || drive == Y_AXIS)
- ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Y_AXIS)
+ ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Y_AXIS)
: (drive == U_AXIS)
- ? AnyMotorStalled(U_AXIS) || AnyMotorStalled(V_AXIS)
- : AnyMotorStalled(drive);
+ ? AnyAxisMotorStalled(U_AXIS) || AnyAxisMotorStalled(V_AXIS)
+ : AnyAxisMotorStalled(drive);
break;
case KinematicsType::coreXZ:
// Both X and Z motors are involved in homing X or Z
motorIsStalled = (drive == X_AXIS || drive == Z_AXIS)
- ? AnyMotorStalled(X_AXIS) || AnyMotorStalled(Z_AXIS)
- : AnyMotorStalled(drive);
+ ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Z_AXIS)
+ : AnyAxisMotorStalled(drive);
break;
default:
- motorIsStalled = AnyMotorStalled(drive);
+ motorIsStalled = AnyAxisMotorStalled(drive);
break;
}
return (!motorIsStalled) ? EndStopHit::noStop
@@ -2734,14 +2741,17 @@ EndStopHit Platform::Stopped(size_t drive) const
#endif
case EndStopInputType::activeLow:
+ if (endStopPins[drive] != NoPin)
+ {
+ const bool b = IoPort::ReadPin(endStopPins[drive]);
+ return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit;
+ }
+ break;
+
case EndStopInputType::activeHigh:
if (endStopPins[drive] != NoPin)
{
- bool b = IoPort::ReadPin(endStopPins[drive]);
- if (endStopInputType[drive] == EndStopInputType::activeHigh)
- {
- b = !b;
- }
+ const bool b = !IoPort::ReadPin(endStopPins[drive]);
return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit;
}
break;
@@ -2750,12 +2760,13 @@ EndStopHit Platform::Stopped(size_t drive) const
break;
}
}
+#if HAS_STALL_DETECT
else if (drive < DRIVES)
{
- // Endstop not used for an axis, so no configuration data available.
- // To allow us to see its status in DWC, pretend it is configured as a high-end active high endstop.
- return (endStopPins[drive] != NoPin && IoPort::ReadPin(endStopPins[drive])) ? EndStopHit::highHit : EndStopHit::noStop;
+ // Endstop is for an extruder drive, so use stall detection
+ return (ExtruderMotorStalled(drive - numAxes)) ? EndStopHit::highHit : EndStopHit::noStop;
}
+#endif
return EndStopHit::noStop;
}
@@ -4269,7 +4280,7 @@ bool Platform::ConfigureStallDetection(GCodeBuffer& gb, StringRef& reply)
{
uint32_t drives[DRIVES];
size_t dCount = DRIVES;
- gb.GetUnsignedArray(drives, dCount);
+ gb.GetUnsignedArray(drives, dCount, false);
for (size_t i = 0; i < dCount; i++)
{
if (drives[i] >= numSmartDrivers)
@@ -4469,7 +4480,7 @@ void STEP_TC_HANDLER()
{
const irqflags_t flags = cpu_irq_save();
const int32_t diff = (int32_t)(tim - GetInterruptClocks()); // see how long we have to go
- if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 6us or already passed
+ if (diff < (int32_t)DDA::MinInterruptInterval) // if less than about 6us or already passed
{
cpu_irq_restore(flags);
return true; // tell the caller to simulate an interrupt instead
@@ -4502,7 +4513,7 @@ void STEP_TC_HANDLER()
{
const irqflags_t flags = cpu_irq_save();
const int32_t diff = (int32_t)(tim - GetInterruptClocks()); // see how long we have to go
- if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 6us or already passed
+ if (diff < (int32_t)DDA::MinInterruptInterval) // if less than about 6us or already passed
{
cpu_irq_restore(flags);
return true; // tell the caller to simulate an interrupt instead
diff --git a/src/Platform.h b/src/Platform.h
index 7eb03ff0..e52abb9c 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -613,10 +613,11 @@ private:
float AdcReadingToCpuTemperature(uint32_t reading) const;
#if HAS_SMART_DRIVERS
- void ReportDrivers(DriversBitmap whichDrivers, const char* text, bool& reported);
+ void ReportDrivers(MessageType mt, DriversBitmap whichDrivers, const char* text, bool& reported);
#endif
#if HAS_STALL_DETECT
- bool AnyMotorStalled(size_t drive) const pre(drive < DRIVES);
+ bool AnyAxisMotorStalled(size_t drive) const pre(drive < DRIVES);
+ bool ExtruderMotorStalled(size_t extruder) const pre(extruder < MaxExtruders);
#endif
#if SAM4E || SAM4S || SAME70
diff --git a/src/PortControl.cpp b/src/PortControl.cpp
index 7c8a595a..def53b56 100644
--- a/src/PortControl.cpp
+++ b/src/PortControl.cpp
@@ -75,7 +75,7 @@ bool PortControl::Configure(GCodeBuffer& gb, StringRef& reply)
numConfiguredPorts = 0;
uint32_t portNumbers[MaxPorts];
size_t numPorts = MaxPorts;
- gb.GetUnsignedArray(portNumbers, numPorts);
+ gb.GetUnsignedArray(portNumbers, numPorts, false);
for (size_t i = 0; i < numPorts; ++i)
{
const uint32_t pnum = portNumbers[i];
diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp
index 16b2e168..b4605fb9 100644
--- a/src/PrintMonitor.cpp
+++ b/src/PrintMonitor.cpp
@@ -400,47 +400,41 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod
// Look for slicer program
if (parsedFileInfo.generatedBy[0] == 0)
{
- // Slic3r and S3D
- const char* generatedByString = "generated by ";
- const char* introString = "";
- const char* pos = strstr(buf, generatedByString);
- if (pos != nullptr)
+ 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;
+ const char* pos = nullptr;
+ for (index = 0; pos == nullptr && index < ARRAY_SIZE(GeneratedByStrings); ++index)
{
- pos += strlen(generatedByString);
+ pos = strstr(buf, GeneratedByStrings[index]);
}
- else
+
+ if (pos != nullptr)
{
- // KISSlicer
- pos = strstr(buf, "; KISSlicer");
- 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;
}
- else
- {
- // Cura (old)
- const char* slicedAtString = ";Sliced at: ";
- pos = strstr(buf, slicedAtString);
- if (pos != nullptr)
- {
- pos += strlen(slicedAtString);
- introString = "Cura at ";
- }
- else
- {
- // Cura (new)
- const char* generatedWithString = ";Generated with ";
- pos = strstr(buf, generatedWithString);
- if (pos != nullptr)
- {
- pos += strlen(generatedWithString);
- }
- }
- }
- }
- if (pos != nullptr)
- {
strcpy(parsedFileInfo.generatedBy, introString);
size_t i = strlen(introString);
while (i < ARRAY_SIZE(parsedFileInfo.generatedBy) - 1 && *pos >= ' ')
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index 78eb9ac8..771b10c7 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -47,7 +47,7 @@ extern "C" void hsmciIdle()
if (reprap.GetSpinningModule() != moduleFilamentSensors)
{
- FilamentSensor::Spin(false);
+ FilamentMonitor::Spin(false);
}
}
@@ -223,7 +223,7 @@ void RepRap::Spin()
ticksInSpinState = 0;
spinningModule = moduleFilamentSensors;
- FilamentSensor::Spin(true);
+ FilamentMonitor::Spin(true);
ticksInSpinState = 0;
spinningModule = noModule;
@@ -272,7 +272,7 @@ void RepRap::Diagnostics(MessageType mtype)
heat->Diagnostics(mtype);
gCodes->Diagnostics(mtype);
network->Diagnostics(mtype);
- FilamentSensor::Diagnostics(mtype);
+ FilamentMonitor::Diagnostics(mtype);
}
// Turn off the heaters, disable the motors, and deactivate the Heat and Move classes. Leave everything else working.
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index 72f3a8a2..bfaac796 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -81,7 +81,7 @@ class OutputBuffer;
class OutputStack;
class GCodeBuffer;
class GCodeQueue;
-class FilamentSensor;
+class FilamentMonitor;
class RandomProbePointSet;
class Logger;
diff --git a/src/Version.h b/src/Version.h
index d2599956..a2c7704f 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -9,11 +9,11 @@
#define SRC_VERSION_H_
#ifndef VERSION
-# define VERSION "1.20.1RC2"
+# define VERSION "1.21RC0"
#endif
#ifndef DATE
-# define DATE "2018-01-01"
+# define DATE "2018-01-11"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"