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--src/CAN/CanInterface.cpp1
-rw-r--r--src/Configuration.h3
-rw-r--r--src/DuetM/Pins_DuetM.h2
-rw-r--r--src/DuetNG/Pins_DuetNG.h2
-rw-r--r--src/Endstops/Endstop.h1
-rw-r--r--src/Endstops/EndstopsManager.cpp13
-rw-r--r--src/Endstops/EndstopsManager.h2
-rw-r--r--src/Endstops/ZProbe.h2
-rw-r--r--src/Fans/Fan.h1
-rw-r--r--src/Fans/FansManager.h2
-rw-r--r--src/FilamentMonitors/FilamentMonitor.h2
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.cpp22
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.h3
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp2
-rw-r--r--src/GCodes/GCodeException.cpp9
-rw-r--r--src/GCodes/GCodeException.h2
-rw-r--r--src/GCodes/GCodes.cpp15
-rw-r--r--src/GCodes/GCodes.h12
-rw-r--r--src/GCodes/GCodes2.cpp10
-rw-r--r--src/GPIO/GpioPorts.h7
-rw-r--r--src/Heating/FOPDT.cpp2
-rw-r--r--src/Heating/FOPDT.h2
-rw-r--r--src/Heating/Heat.cpp333
-rw-r--r--src/Heating/Heat.h21
-rw-r--r--src/Heating/Heater.cpp242
-rw-r--r--src/Heating/Heater.h39
-rw-r--r--src/Heating/HeaterMonitor.cpp99
-rw-r--r--src/Heating/HeaterMonitor.h81
-rw-r--r--src/Heating/HeaterProtection.cpp71
-rw-r--r--src/Heating/HeaterProtection.h96
-rw-r--r--src/Heating/LocalHeater.cpp76
-rw-r--r--src/Heating/LocalHeater.h37
-rw-r--r--src/Heating/RemoteHeater.cpp32
-rw-r--r--src/Heating/RemoteHeater.h3
-rw-r--r--src/Heating/Sensors/TemperatureSensor.h1
-rw-r--r--src/Networking/Network.cpp5
-rw-r--r--src/Networking/Network.h1
-rw-r--r--src/Networking/NetworkInterface.h3
-rw-r--r--src/Networking/NetworkResponder.h2
-rw-r--r--src/Networking/Socket.h2
-rw-r--r--src/OutputMemory.h210
-rw-r--r--src/Pccb/Pins_Pccb.h2
-rw-r--r--src/RepRap.cpp14
-rw-r--r--src/RepRap.h2
-rw-r--r--src/Tools/Tool.cpp39
-rw-r--r--src/Tools/Tool.h4
-rw-r--r--src/Version.h2
47 files changed, 763 insertions, 771 deletions
diff --git a/src/CAN/CanInterface.cpp b/src/CAN/CanInterface.cpp
index 9ad20b35..14b02942 100644
--- a/src/CAN/CanInterface.cpp
+++ b/src/CAN/CanInterface.cpp
@@ -719,7 +719,6 @@ GCodeResult CanInterface::SendRequestAndGetStandardReply(CanMessageBuffer *buf,
}
else
{
-// debugPrintf("Discarded msg src=%u RID=%u exp %u\n", buf->id.Src(), buf->msg.standardReply.requestId, rid);
reply.lcatf("Discarded msg src=%u typ=%u RID=%u exp %u", buf->id.Src(), (unsigned int)buf->id.MsgType(), (unsigned int)buf->msg.standardReply.requestId, rid);
}
}
diff --git a/src/Configuration.h b/src/Configuration.h
index d379c873..79286ec2 100644
--- a/src/Configuration.h
+++ b/src/Configuration.h
@@ -86,8 +86,9 @@ constexpr float HOT_ENOUGH_TO_RETRACT = 90.0; // Celsius
constexpr unsigned int MaxBadTemperatureCount = 2000/HeatSampleIntervalMillis; // Number of bad temperature samples permitted before a heater fault is reported (2 seconds)
constexpr float BadLowTemperature = -10.0; // Celsius
-constexpr float DefaultHotEndTemperatureLimit = 290.0; // Celsius - E3D say to tighten the hot end at 285C
+constexpr float DefaultHotEndTemperatureLimit = 285.0; // Celsius - E3D say to tighten the hot end at 285C
constexpr float DefaultBedTemperatureLimit = 125.0; // Celsius
+constexpr float DefaultAllowedOverTemperature = 5.0;
constexpr float DefaultHotEndFanTemperature = 45.0; // Temperature at which a thermostatic hot end fan comes on
constexpr float ThermostatHysteresis = 1.0; // How much hysteresis we use to prevent noise turning fans on/off too often
constexpr float BadErrorTemperature = 2000.0; // Must exceed any reasonable temperature limit including DEFAULT_TEMPERATURE_LIMIT
diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h
index c737ab62..5800705a 100644
--- a/src/DuetM/Pins_DuetM.h
+++ b/src/DuetM/Pins_DuetM.h
@@ -65,7 +65,7 @@ constexpr size_t MaxSmartDrivers = 7; // The maximum number of smart drivers
constexpr size_t MaxSensors = 32;
constexpr size_t MaxHeaters = 4; // The maximum number of heaters in the machine
-constexpr size_t MaxExtraHeaterProtections = 4; // The number of extra heater protection instances
+constexpr size_t MaxMonitorsPerHeater = 3; // The maximum number of monitors per heater
constexpr size_t MaxBedHeaters = 2;
constexpr size_t MaxChamberHeaters = 2;
diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h
index 44387da9..0095530a 100644
--- a/src/DuetNG/Pins_DuetNG.h
+++ b/src/DuetNG/Pins_DuetNG.h
@@ -67,7 +67,7 @@ constexpr size_t MaxSmartDrivers = 10; // The maximum number of smart drivers
constexpr size_t MaxSensors = 32;
constexpr size_t MaxHeaters = 10; // The maximum number of heaters in the machine
-constexpr size_t MaxExtraHeaterProtections = 8; // The number of extra heater protection instances
+constexpr size_t MaxMonitorsPerHeater = 3; // The maximum number of monitors per heater
constexpr size_t MaxBedHeaters = 4;
constexpr size_t MaxChamberHeaters = 4;
diff --git a/src/Endstops/Endstop.h b/src/Endstops/Endstop.h
index e0eb3a9e..8fa272a0 100644
--- a/src/Endstops/Endstop.h
+++ b/src/Endstops/Endstop.h
@@ -22,6 +22,7 @@ class EndstopOrZProbe INHERIT_OBJECT_MODEL
{
public:
EndstopOrZProbe() noexcept : next(nullptr) {}
+ EndstopOrZProbe(const EndstopOrZProbe&) = delete;
virtual ~EndstopOrZProbe() noexcept {}
virtual EndStopHit Stopped() const noexcept = 0;
diff --git a/src/Endstops/EndstopsManager.cpp b/src/Endstops/EndstopsManager.cpp
index b618c25f..052dbd3e 100644
--- a/src/Endstops/EndstopsManager.cpp
+++ b/src/Endstops/EndstopsManager.cpp
@@ -21,6 +21,7 @@
#include "GCodes/GCodes.h"
#include "Movement/Move.h"
#include <OutputMemory.h>
+#include <Heating/Heat.h>
#if SUPPORT_CAN_EXPANSION
# include "CanMessageBuffer.h"
@@ -38,6 +39,13 @@ ReadWriteLock EndstopsManager::zProbesLock;
// Macro to build a standard lambda function that includes the necessary type conversions
#define OBJECT_MODEL_FUNC(...) OBJECT_MODEL_FUNC_BODY(EndstopsManager, __VA_ARGS__)
+constexpr ObjectModelArrayDescriptor EndstopsManager::sensorsArrayDescriptor =
+{
+ &Heat::sensorsLock,
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const Heat*)self)->GetNumSensorsToReport(); },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const Heat*)self)->FindSensor(context.GetLastIndex()).Ptr()); }
+};
+
constexpr ObjectModelArrayDescriptor EndstopsManager::endstopsArrayDescriptor =
{
&endstopsLock,
@@ -55,7 +63,7 @@ constexpr ObjectModelArrayDescriptor EndstopsManager::filamentMonitorsArrayDescr
constexpr ObjectModelArrayDescriptor EndstopsManager::inputsArrayDescriptor =
{
- &endstopsLock,
+ nullptr,
[] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetPlatform().GetNumInputsToReport(); },
[] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue
{ return ExpressionValue(&reprap.GetPlatform().GetGpInPort(context.GetLastIndex())); }
@@ -73,13 +81,14 @@ constexpr ObjectModelTableEntry EndstopsManager::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. sensors members
+ { "analog", OBJECT_MODEL_FUNC_NOSELF(&sensorsArrayDescriptor), ObjectModelEntryFlags::live },
{ "endstops", OBJECT_MODEL_FUNC_NOSELF(&endstopsArrayDescriptor), ObjectModelEntryFlags::live },
{ "filamentMonitors", OBJECT_MODEL_FUNC_NOSELF(&filamentMonitorsArrayDescriptor), ObjectModelEntryFlags::live },
{ "inputs", OBJECT_MODEL_FUNC_NOSELF(&inputsArrayDescriptor), ObjectModelEntryFlags::live },
{ "probes", OBJECT_MODEL_FUNC_NOSELF(&probesArrayDescriptor), ObjectModelEntryFlags::live },
};
-constexpr uint8_t EndstopsManager::objectModelTableDescriptor[] = { 1, 4 };
+constexpr uint8_t EndstopsManager::objectModelTableDescriptor[] = { 1, 5 };
DEFINE_GET_OBJECT_MODEL_TABLE(EndstopsManager)
diff --git a/src/Endstops/EndstopsManager.h b/src/Endstops/EndstopsManager.h
index a7ce08d1..bbd453bc 100644
--- a/src/Endstops/EndstopsManager.h
+++ b/src/Endstops/EndstopsManager.h
@@ -26,6 +26,7 @@ class EndstopsManager INHERIT_OBJECT_MODEL
{
public:
EndstopsManager() noexcept;
+ EndstopsManager(const EndstopsManager&) = delete;
void Init() noexcept;
@@ -78,6 +79,7 @@ public:
protected:
DECLARE_OBJECT_MODEL
+ OBJECT_MODEL_ARRAY(sensors)
OBJECT_MODEL_ARRAY(endstops)
OBJECT_MODEL_ARRAY(filamentMonitors)
OBJECT_MODEL_ARRAY(inputs)
diff --git a/src/Endstops/ZProbe.h b/src/Endstops/ZProbe.h
index 13bb807b..bbc129bc 100644
--- a/src/Endstops/ZProbe.h
+++ b/src/Endstops/ZProbe.h
@@ -16,7 +16,7 @@ class ZProbe : public EndstopOrZProbe
public:
ZProbe(unsigned int num, ZProbeType p_type) noexcept;
- virtual void SetIREmitter(bool on) const noexcept = 0;
+ virtual void SetIREmitter(bool on) const noexcept = 0; // Caution, this is called from within the tick ISR
virtual uint16_t GetRawReading() const noexcept = 0;
virtual void SetProbing(bool isProbing) const noexcept = 0;
virtual GCodeResult AppendPinNames(const StringRef& str) const noexcept = 0;
diff --git a/src/Fans/Fan.h b/src/Fans/Fan.h
index 6f2e3ce2..c0de5e3c 100644
--- a/src/Fans/Fan.h
+++ b/src/Fans/Fan.h
@@ -23,6 +23,7 @@ class Fan INHERIT_OBJECT_MODEL
{
public:
Fan(unsigned int fanNum) noexcept;
+ Fan(const Fan&) = delete;
virtual ~Fan() noexcept { }
virtual bool Check() noexcept = 0; // update the fan PWM returning true if it is a thermostatic fan that is on
diff --git a/src/Fans/FansManager.h b/src/Fans/FansManager.h
index 32ef8034..b38986db 100644
--- a/src/Fans/FansManager.h
+++ b/src/Fans/FansManager.h
@@ -25,6 +25,8 @@ class FansManager
{
public:
FansManager() noexcept;
+ FansManager(const FansManager&) = delete;
+
void Init() noexcept;
bool CheckFans() noexcept;
GCodeResult ConfigureFanPort(uint32_t fanNum, GCodeBuffer& gb, const StringRef& reply);
diff --git a/src/FilamentMonitors/FilamentMonitor.h b/src/FilamentMonitors/FilamentMonitor.h
index 4bffb40a..a08acef8 100644
--- a/src/FilamentMonitors/FilamentMonitor.h
+++ b/src/FilamentMonitors/FilamentMonitor.h
@@ -27,6 +27,8 @@ enum class FilamentSensorStatus : uint8_t
class FilamentMonitor INHERIT_OBJECT_MODEL
{
public:
+ FilamentMonitor(const FilamentMonitor&) = delete;
+
// Configure this sensor, returning true if error and setting 'seen' if we processed any configuration parameters
virtual bool Configure(GCodeBuffer& gb, const StringRef& reply, bool& seen) = 0;
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
index 5b42ae8c..5e12c7db 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
@@ -229,6 +229,22 @@ int32_t GCodeBuffer::GetIValue()
return isBinaryBuffer ? binaryParser.GetIValue() : stringParser.GetIValue();
}
+// Get an integer with limit checking
+int32_t GCodeBuffer::GetLimitedIValue(char c, int32_t minValue, int32_t maxValue) THROWS(GCodeException)
+{
+ MustSee(c);
+ const int32_t ret = GetIValue();
+ if (ret < minValue)
+ {
+ throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too low", (uint32_t)c);
+ }
+ if (ret > maxValue)
+ {
+ throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c);
+ }
+ return ret;
+}
+
// Get an unsigned integer value
uint32_t GCodeBuffer::GetUIValue()
{
@@ -236,15 +252,15 @@ uint32_t GCodeBuffer::GetUIValue()
}
// Get an unsigned integer value, throw if >= limit
-uint32_t GCodeBuffer::GetLimitedUIValue(char c, uint32_t limit) THROWS(GCodeException)
+uint32_t GCodeBuffer::GetLimitedUIValue(char c, uint32_t maxValuePlusOne) THROWS(GCodeException)
{
MustSee(c);
const uint32_t ret = GetUIValue();
- if (ret < limit)
+ if (ret < maxValuePlusOne)
{
return ret;
}
- throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too large", (uint32_t)c);
+ throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c);
}
// Get an IP address quad after a key letter
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.h b/src/GCodes/GCodeBuffer/GCodeBuffer.h
index f25d1a73..45cb429f 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.h
@@ -71,8 +71,9 @@ public:
float GetFValue() THROWS(GCodeException) __attribute__((hot)); // Get a float after a key letter
float GetDistance() THROWS(GCodeException); // Get a distance or coordinate and convert it from inches to mm if necessary
int32_t GetIValue() THROWS(GCodeException) __attribute__((hot)); // Get an integer after a key letter
+ int32_t GetLimitedIValue(char c, int32_t minValue, int32_t maxValue) THROWS(GCodeException); // Get an integer after a key letter
uint32_t GetUIValue() THROWS(GCodeException); // Get an unsigned integer value
- uint32_t GetLimitedUIValue(char c, uint32_t limit) THROWS(GCodeException); // Get an unsigned integer value, throw if >= limit
+ uint32_t GetLimitedUIValue(char c, uint32_t maxValuePlusOne) THROWS(GCodeException); // Get an unsigned integer value, throw if >= limit
void GetIPAddress(IPAddress& returnedIp) THROWS(GCodeException); // Get an IP address quad after a key letter
void GetMacAddress(MacAddress& mac) THROWS(GCodeException); // Get a MAC address sextet after a key letter
PwmFrequency GetPwmFrequency() THROWS(GCodeException); // Get a PWM frequency
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index 3b9b98cc..c8316bff 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -611,7 +611,7 @@ void StringParser::ProcessAbortCommand(const StringRef& reply) noexcept
}
catch (const GCodeException& e)
{
- e.GetMessage(reply, gb);
+ e.GetMessage(reply, &gb);
reply.Insert(0, "invalid expression after 'abort': ");
}
}
diff --git a/src/GCodes/GCodeException.cpp b/src/GCodes/GCodeException.cpp
index 44e74a76..23108bc7 100644
--- a/src/GCodes/GCodeException.cpp
+++ b/src/GCodes/GCodeException.cpp
@@ -11,10 +11,13 @@
#include <GCodes/GCodeBuffer/GCodeBuffer.h>
// Construct the error message. This will be prefixed with "Error: " when it is returned to the user.
-void GCodeException::GetMessage(const StringRef &reply, const GCodeBuffer& gb) const noexcept
+void GCodeException::GetMessage(const StringRef &reply, const GCodeBuffer *gb) const noexcept
{
- reply.copy((gb.IsDoingFileMacro()) ? "in file macro" : (gb.IsDoingFile()) ? "in GCode file" : "while executing command");
- if (line >= 0 && column >= 0 && gb.IsDoingFile())
+ const char *context = (gb != nullptr && gb->IsDoingFileMacro()) ? "in file macro"
+ : (gb != nullptr && gb->IsDoingFile()) ? "in GCode file"
+ : "while executing command";
+ reply.copy(context);
+ if (line >= 0 && column >= 0 && gb != nullptr && gb->IsDoingFile())
{
reply.catf(", line %d column %d", line, column + 1);
}
diff --git a/src/GCodes/GCodeException.h b/src/GCodes/GCodeException.h
index f11d6e1d..d9e9228e 100644
--- a/src/GCodes/GCodeException.h
+++ b/src/GCodes/GCodeException.h
@@ -33,7 +33,7 @@ public:
param.i = iparam;
}
- void GetMessage(const StringRef& reply, const GCodeBuffer& gb) const noexcept;
+ void GetMessage(const StringRef& reply, const GCodeBuffer *gb) const noexcept;
private:
int line;
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 5e6f523b..99ae9f1b 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -28,7 +28,7 @@
#include "GCodeBuffer/GCodeBuffer.h"
#include "GCodeQueue.h"
#include "Heating/Heat.h"
-#include "Heating/HeaterProtection.h"
+//#include "Heating/HeaterProtection.h"
#include "Platform.h"
#include "Movement/Move.h"
#include "Scanner.h"
@@ -464,7 +464,7 @@ void GCodes::StartNextGCode(GCodeBuffer& gb, const StringRef& reply)
}
catch (GCodeException& e)
{
- e.GetMessage(reply, gb);
+ e.GetMessage(reply, &gb);
HandleReply(gb, GCodeResult::error, reply.c_str());
gb.Init();
return;
@@ -628,7 +628,7 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply)
}
catch (GCodeException& e)
{
- e.GetMessage(reply, gb);
+ e.GetMessage(reply, &gb);
HandleReply(gb, GCodeResult::error, reply.c_str());
gb.Init();
AbortPrint(gb);
@@ -665,7 +665,7 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply)
}
catch (GCodeException& e)
{
- e.GetMessage(reply, gb);
+ e.GetMessage(reply, &gb);
HandleReply(gb, GCodeResult::error, reply.c_str());
gb.Init();
AbortPrint(gb);
@@ -3001,7 +3001,7 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply)
gb.GetFloatArray(active, hCount, true);
for (size_t h = 0; h < hCount; ++h)
{
- tool->SetToolHeaterActiveTemperature(h, active[h]);
+ tool->SetToolHeaterActiveTemperature(h, active[h]); // may throw
}
}
}
@@ -3431,12 +3431,11 @@ void GCodes::HandleReply(GCodeBuffer& gb, OutputBuffer *reply) noexcept
}
}
-void GCodes::SetToolHeaters(Tool *tool, float temperature, bool both)
+void GCodes::SetToolHeaters(Tool *tool, float temperature, bool both) THROWS(GCodeException)
{
if (tool == nullptr)
{
- platform.Message(ErrorMessage, "Setting temperature: no tool selected\n");
- return;
+ throw GCodeException(-1, -1, "setting temperature: no tool selected\n");
}
for (size_t h = 0; h < tool->HeaterCount(); h++)
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index c02ad69e..4490b649 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -304,7 +304,7 @@ private:
bool Push(GCodeBuffer& gb, bool withinSameFile); // Push feedrate etc on the stack
void Pop(GCodeBuffer& gb, bool withinSameFile); // Pop feedrate etc
- void DisableDrives() noexcept; // Turn the motors off
+ void DisableDrives() noexcept; // Turn the motors off
// Start saving GCodes in a file
bool SendConfigToLine(); // Deal with M503
@@ -318,7 +318,7 @@ private:
#endif
GCodeResult ManageTool(GCodeBuffer& gb, const StringRef& reply); // Create a new tool definition
- void SetToolHeaters(Tool *tool, float temperature, bool both); // Set all a tool's heaters to the temperature, for M104/M109
+ void SetToolHeaters(Tool *tool, float temperature, bool both) THROWS(GCodeException); // Set all a tool's heaters to the temperature, for M104/M109
bool ToolHeatersAtSetTemperatures(const Tool *tool, bool waitWhenCooling, float tolerance) const noexcept;
// Wait for the heaters associated with the specified tool to reach their set temperatures
void GenerateTemperatureReport(const StringRef& reply) const noexcept; // Store a standard-format temperature report in reply
@@ -338,10 +338,10 @@ private:
GCodeResult LoadFilament(GCodeBuffer& gb, const StringRef& reply); // Load the specified filament into a tool
GCodeResult UnloadFilament(GCodeBuffer& gb, const StringRef& reply); // Unload the current filament from a tool
bool ChangeMicrostepping(size_t drive, unsigned int microsteps, bool interp, const StringRef& reply) const noexcept; // Change microstepping on the specified drive
- void CheckTriggers() noexcept; // Check for and execute triggers
- void CheckFilament() noexcept; // Check for and respond to filament errors
- void CheckHeaterFault() noexcept; // Check for and respond to a heater fault, returning true if we should exit
- void DoEmergencyStop() noexcept; // Execute an emergency stop
+ void CheckTriggers() noexcept; // Check for and execute triggers
+ void CheckFilament() noexcept; // Check for and respond to filament errors
+ void CheckHeaterFault() noexcept; // Check for and respond to a heater fault, returning true if we should exit
+ void DoEmergencyStop() noexcept; // Execute an emergency stop
void DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg) noexcept // Pause the print
pre(resourceOwners[movementResource] = &gb);
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index a5ce5967..2c8b7613 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -98,7 +98,7 @@ bool GCodes::ActOnCode(GCodeBuffer& gb, const StringRef& reply)
}
catch (const GCodeException& e)
{
- e.GetMessage(reply, gb);
+ e.GetMessage(reply, &gb);
HandleReply(gb, GCodeResult::error, reply.c_str());
return true;
}
@@ -1353,7 +1353,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
// because any slicer that uses M109 doesn't understand that there are separate active and standby temperatures.
if (simulationMode == 0)
{
- SetToolHeaters(applicableTool.Ptr(), temperature, true);
+ SetToolHeaters(applicableTool.Ptr(), temperature, true); // this may throw
}
Tool * const currentTool = reprap.GetCurrentTool();
@@ -1732,7 +1732,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
}
else
{
- heat.SetActiveTemperature(currentHeater, temperature);
+ heat.SetActiveTemperature(currentHeater, temperature); // may throw
result = heat.Activate(currentHeater, reply);
}
}
@@ -1769,7 +1769,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 143: // Configure heater protection
- result = reprap.GetHeat().SetHeaterProtection(gb, reply);
+ result = reprap.GetHeat().HandleM143(gb, reply);
break;
case 144: // Set bed to standby, or to active if S1 parameter given
@@ -1829,7 +1829,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break; // no target temperature given
}
- reprap.GetHeat().SetActiveTemperature(heater, temperature);
+ reprap.GetHeat().SetActiveTemperature(heater, temperature); // may throw
result = reprap.GetHeat().Activate(heater, reply);
if (cancelWait || reprap.GetHeat().HeaterAtSetTemperature(heater, waitWhenCooling, TEMPERATURE_CLOSE_ENOUGH))
{
diff --git a/src/GPIO/GpioPorts.h b/src/GPIO/GpioPorts.h
index b8290c28..30d5a074 100644
--- a/src/GPIO/GpioPorts.h
+++ b/src/GPIO/GpioPorts.h
@@ -25,6 +25,7 @@ public:
boardAddress (CanId::MasterAddress),
#endif
currentState(false) { }
+ GpInputPort(const GpInputPort&) = delete;
bool GetState() const noexcept;
bool IsUnused() const noexcept;
@@ -50,9 +51,13 @@ private:
class GpOutputPort
{
public:
+ GpOutputPort() noexcept
#if SUPPORT_CAN_EXPANSION
- GpOutputPort() noexcept { boardAddress = CanId::MasterAddress; }
+ : boardAddress(CanId::MasterAddress)
#endif
+ { }
+
+ GpOutputPort(const GpOutputPort&) = delete;
GCodeResult WriteAnalog(uint32_t gpioPortNumber, bool isServo, float pwm, const GCodeBuffer& gb, const StringRef& reply) const noexcept;
GCodeResult Configure(uint32_t gpioNumber, bool isServo, GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException);
diff --git a/src/Heating/FOPDT.cpp b/src/Heating/FOPDT.cpp
index 95f4ec54..c2347cf1 100644
--- a/src/Heating/FOPDT.cpp
+++ b/src/Heating/FOPDT.cpp
@@ -138,7 +138,7 @@ void FopDt::CalcPidConstants() noexcept
#if SUPPORT_CAN_EXPANSION
-void FopDt::SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) noexcept
+void FopDt::SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) const noexcept
{
msg.heater = heater;
msg.gain = gain;
diff --git a/src/Heating/FOPDT.h b/src/Heating/FOPDT.h
index 0a7c033e..fa911f9c 100644
--- a/src/Heating/FOPDT.h
+++ b/src/Heating/FOPDT.h
@@ -65,7 +65,7 @@ public:
#endif
#if SUPPORT_CAN_EXPANSION
- void SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) noexcept;
+ void SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) const noexcept;
#endif
private:
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index 914dbfde..f1d6e1ec 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -20,7 +20,7 @@ Licence: GPL
#include "Heat.h"
#include "LocalHeater.h"
-#include "HeaterProtection.h"
+#include "HeaterMonitor.h"
#include "Platform.h"
#include "RepRap.h"
#include "Sensors/TemperatureSensor.h"
@@ -67,13 +67,6 @@ constexpr ObjectModelArrayDescriptor Heat::heatersArrayDescriptor =
[] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const Heat*)self)->heaters[context.GetLastIndex()]); }
};
-constexpr ObjectModelArrayDescriptor Heat::sensorsArrayDescriptor =
-{
- &sensorsLock,
- [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const Heat*)self)->GetNumSensorsToReport(); },
- [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const Heat*)self)->FindSensor(context.GetLastIndex()).Ptr()); }
-};
-
// Macro to build a standard lambda function that includes the necessary type conversions
#define OBJECT_MODEL_FUNC(...) OBJECT_MODEL_FUNC_BODY(Heat, __VA_ARGS__)
@@ -84,10 +77,9 @@ constexpr ObjectModelTableEntry Heat::objectModelTable[] =
{ "coldExtrudeTemperature", OBJECT_MODEL_FUNC(self->extrusionMinTemp, 1), ObjectModelEntryFlags::none},
{ "coldRetractTemperature", OBJECT_MODEL_FUNC(self->retractionMinTemp, 1), ObjectModelEntryFlags::none},
{ "heaters", OBJECT_MODEL_FUNC_NOSELF(&heatersArrayDescriptor), ObjectModelEntryFlags::live },
- { "sensors", OBJECT_MODEL_FUNC_NOSELF(&sensorsArrayDescriptor), ObjectModelEntryFlags::live },
};
-constexpr uint8_t Heat::objectModelTableDescriptor[] = { 1, 4 };
+constexpr uint8_t Heat::objectModelTableDescriptor[] = { 1, 3 };
DEFINE_GET_OBJECT_MODEL_TABLE(Heat)
@@ -112,11 +104,6 @@ Heat::Heat() noexcept
h = -1;
}
- for (size_t index : ARRAY_INDICES(heaterProtections))
- {
- heaterProtections[index] = new HeaterProtection(index);
- }
-
for (Heater*& h : heaters)
{
h = nullptr;
@@ -142,58 +129,7 @@ GCodeResult Heat::SetOrReportHeaterModel(GCodeBuffer& gb, const StringRef& reply
const auto h = FindHeater(heater);
if (h.IsNotNull())
{
- const FopDt& model = h->GetModel();
- bool seen = false;
- float gain = model.GetGain(),
- tc = model.GetTimeConstant(),
- td = model.GetDeadTime(),
- maxPwm = model.GetMaxPwm(),
- voltage = model.GetVoltage();
- int32_t dontUsePid = model.UsePid() ? 0 : 1;
- int32_t inversionParameter = 0;
-
- gb.TryGetFValue('A', gain, seen);
- gb.TryGetFValue('C', tc, seen);
- gb.TryGetFValue('D', td, seen);
- gb.TryGetIValue('B', dontUsePid, seen);
- gb.TryGetFValue('S', maxPwm, seen);
- gb.TryGetFValue('V', voltage, seen);
- gb.TryGetIValue('I', inversionParameter, seen);
-
- if (seen)
- {
- const bool inverseTemperatureControl = (inversionParameter == 1 || inversionParameter == 3);
- const GCodeResult rslt = h->SetModel(gain, tc, td, maxPwm, voltage, dontUsePid == 0, inverseTemperatureControl, reply);
- if (rslt != GCodeResult::ok)
- {
- return rslt;
- }
- }
- else if (!model.IsEnabled())
- {
- reply.printf("Heater %u is disabled", heater);
- }
- else
- {
- const char* const mode = (!model.UsePid()) ? "bang-bang"
- : (model.ArePidParametersOverridden()) ? "custom PID"
- : "PID";
- reply.printf("Heater %u model: gain %.1f, time constant %.1f, dead time %.1f, max PWM %.2f, calibration voltage %.1f, mode %s", heater,
- (double)model.GetGain(), (double)model.GetTimeConstant(), (double)model.GetDeadTime(), (double)model.GetMaxPwm(), (double)model.GetVoltage(), mode);
- if (model.IsInverted())
- {
- reply.cat(", inverted temperature control");
- }
- if (model.UsePid())
- {
- // When reporting the PID parameters, we scale them by 255 for compatibility with older firmware and other firmware
- M301PidParameters params = model.GetM301PidParameters(false);
- reply.catf("\nComputed PID parameters for setpoint change: P%.1f, I%.3f, D%.1f", (double)params.kP, (double)params.kI, (double)params.kD);
- params = model.GetM301PidParameters(true);
- reply.catf("\nComputed PID parameters for load change: P%.1f, I%.3f, D%.1f", (double)params.kP, (double)params.kI, (double)params.kD);
- }
- }
- return GCodeResult::ok;
+ return h->SetOrReportModel(heater, gb, reply);
}
reply.printf("Heater %u not found", heater);
@@ -299,15 +235,6 @@ void Heat::ResetHeaterModels() noexcept
void Heat::Init() noexcept
{
- // Initialise the heater protection items first
- for (size_t index : ARRAY_INDICES(heaterProtections))
- {
- HeaterProtection * const prot = heaterProtections[index];
-
- const float tempLimit = (IsBedOrChamberHeater(index)) ? DefaultBedTemperatureLimit : DefaultHotEndTemperatureLimit;
- prot->Init(tempLimit);
- }
-
extrusionMinTemp = HOT_ENOUGH_TO_EXTRUDE;
retractionMinTemp = HOT_ENOUGH_TO_RETRACT;
coldExtrude = false;
@@ -635,12 +562,21 @@ HeaterStatus Heat::GetStatus(int heater) const noexcept
void Heat::SetBedHeater(size_t index, int heater) noexcept
{
- const auto h = FindHeater(bedHeaters[index]);
- if (h.IsNotNull())
{
- h->SwitchOff();
+ const auto h = FindHeater(bedHeaters[index]);
+ if (h.IsNotNull())
+ {
+ h->SwitchOff();
+ }
}
bedHeaters[index] = heater;
+ {
+ const auto h = FindHeater(bedHeaters[index]);
+ if (h.IsNotNull())
+ {
+ h->SetDefaultMonitors();
+ }
+ }
}
bool Heat::IsBedHeater(int heater) const noexcept
@@ -657,12 +593,19 @@ bool Heat::IsBedHeater(int heater) const noexcept
void Heat::SetChamberHeater(size_t index, int heater) noexcept
{
+ {
+ const auto h = FindHeater(chamberHeaters[index]);
+ if (h.IsNotNull())
+ {
+ h->SwitchOff();
+ }
+ }
+ chamberHeaters[index] = heater;
const auto h = FindHeater(chamberHeaters[index]);
if (h.IsNotNull())
{
- h->SwitchOff();
+ h->SetDefaultMonitors();
}
- chamberHeaters[index] = heater;
}
bool Heat::IsChamberHeater(int heater) const noexcept
@@ -677,12 +620,12 @@ bool Heat::IsChamberHeater(int heater) const noexcept
return false;
}
-void Heat::SetActiveTemperature(int heater, float t) noexcept
+void Heat::SetTemperature(int heater, float t, bool activeNotStandby) THROWS(GCodeException)
{
const auto h = FindHeater(heater);
if (h.IsNotNull())
{
- h->SetActiveTemperature(t);
+ h->SetTemperature(t, activeNotStandby);
}
}
@@ -692,15 +635,6 @@ float Heat::GetActiveTemperature(int heater) const noexcept
return (h.IsNull()) ? ABS_ZERO : h->GetActiveTemperature();
}
-void Heat::SetStandbyTemperature(int heater, float t) noexcept
-{
- const auto h = FindHeater(heater);
- if (h.IsNotNull())
- {
- h->SetStandbyTemperature(t);
- }
-}
-
float Heat::GetStandbyTemperature(int heater) const noexcept
{
const auto h = FindHeater(heater);
@@ -709,42 +643,14 @@ float Heat::GetStandbyTemperature(int heater) const noexcept
float Heat::GetHighestTemperatureLimit(int heater) const noexcept
{
- float limit = BadErrorTemperature;
- if (heater >= 0 && heater < (int)MaxHeaters)
- {
- for (const HeaterProtection *prot : heaterProtections)
- {
- if (prot->GetHeater() == heater && prot->GetTrigger() == HeaterProtectionTrigger::TemperatureExceeded)
- {
- const float t = prot->GetTemperatureLimit();
- if (limit == BadErrorTemperature || t > limit)
- {
- limit = t;
- }
- }
- }
- }
- return limit;
+ const auto h = FindHeater(heater);
+ return (h.IsNull()) ? BadErrorTemperature : h->GetHighestTemperatureLimit();
}
float Heat::GetLowestTemperatureLimit(int heater) const noexcept
{
- float limit = ABS_ZERO;
- if (heater >= 0 && heater < (int)MaxHeaters)
- {
- for (const HeaterProtection *prot : heaterProtections)
- {
- if (prot->GetHeater() == heater && prot->GetTrigger() == HeaterProtectionTrigger::TemperatureTooLow)
- {
- const float t = prot->GetTemperatureLimit();
- if (limit == ABS_ZERO || t < limit)
- {
- limit = t;
- }
- }
- }
- }
- return limit;
+ const auto h = FindHeater(heater);
+ return (h.IsNull()) ? ABS_ZERO : h->GetLowestTemperatureLimit();
}
// Get the current temperature of a real or virtual heater
@@ -831,14 +737,15 @@ bool Heat::IsBedOrChamberHeater(int heater) const noexcept
float Heat::GetHighestTemperatureLimit() const noexcept
{
float limit = ABS_ZERO;
- for (HeaterProtection *prot : heaterProtections)
+ ReadLocker lock(heatersLock);
+ for (const Heater *h : heaters)
{
- if (prot->GetHeater() >= 0 && prot->GetTrigger() == HeaterProtectionTrigger::TemperatureExceeded)
+ if (h != nullptr)
{
- const float t = prot->GetTemperatureLimit();
- if (t > limit)
+ const float tlimit = h->GetHighestTemperatureLimit();
+ if (tlimit > limit)
{
- limit = t;
+ limit = tlimit;
}
}
}
@@ -903,11 +810,7 @@ GCodeResult Heat::TuneHeater(GCodeBuffer& gb, const StringRef& reply) THROWS(GCo
gb.MustSee('S');
const float temperature = gb.GetFValue();
const float maxPwm = (gb.Seen('P')) ? gb.GetFValue() : h->GetModel().GetMaxPwm();
- if (!h->CheckGood())
- {
- reply.copy("Heater is not ready to perform PID auto-tuning");
- }
- else if (maxPwm < 0.1 || maxPwm > 1.0)
+ if (maxPwm < 0.1 || maxPwm > 1.0)
{
reply.copy("Invalid PWM value");
}
@@ -916,8 +819,7 @@ GCodeResult Heat::TuneHeater(GCodeBuffer& gb, const StringRef& reply) THROWS(GCo
if (heaterBeingTuned == -1)
{
heaterBeingTuned = (int8_t)heater;
- h->StartAutoTune(temperature, maxPwm, reply);
- return GCodeResult::ok;
+ return h->StartAutoTune(temperature, maxPwm, reply);
}
else
{
@@ -1042,164 +944,17 @@ const char *Heat::GetHeaterSensorName(size_t heater) const noexcept
}
// Configure heater protection (M143). Returns true if an error occurred
-GCodeResult Heat::SetHeaterProtection(GCodeBuffer& gb, const StringRef& reply)
+GCodeResult Heat::HandleM143(GCodeBuffer& gb, const StringRef& reply)
{
- WriteLocker lock(heatersLock);
-
- bool seen = false;
- int32_t heaterNumber = 1; // default to extruder 1 if no heater number provided
- gb.TryGetIValue('H', heaterNumber, seen);
- const int index = (gb.Seen('P')) ? gb.GetIValue() : heaterNumber;
-
- if ( index < 0
- || (index >= (int)MaxHeaters && index < (int)FirstExtraHeaterProtection)
- || index >= (int)(FirstExtraHeaterProtection + MaxExtraHeaterProtections)
- )
+ const size_t heaterNumber = (gb.Seen('H')) ? gb.GetLimitedUIValue('H', MaxHeaters) : 1;
+ const auto h = FindHeater(heaterNumber);
+ if (h.IsNull())
{
- reply.printf("Invalid heater protection item '%d'", index);
+ reply.printf("Heater %u does not exist", heaterNumber);
return GCodeResult::error;
}
- HeaterProtection &item = (index >= (int)FirstExtraHeaterProtection)
- ? *heaterProtections[index - FirstExtraHeaterProtection + MaxHeaters]
- : *heaterProtections[index];
- // Set heater to control
- if (seen && heaterNumber != item.GetHeater())
- {
- const int oldHeaterNumber = item.GetHeater();
- item.SetHeater(heaterNumber);
- UpdateHeaterProtection(oldHeaterNumber);
- UpdateHeaterProtection(heaterNumber);
- }
-
- // Set sensor that supervises the heater
- if (gb.Seen('X'))
- {
- item.SetSensorNumber(gb.GetIValue());
- seen = true;
- }
-
- // Set trigger action
- if (gb.Seen('A'))
- {
- const int action = gb.GetIValue();
- if (action < 0 || action > (int)MaxHeaterProtectionAction)
- {
- reply.printf("Invalid heater protection action '%d'", action);
- }
-
- seen = true;
- item.SetAction(static_cast<HeaterProtectionAction>(action));
- }
-
- // Set trigger condition
- if (gb.Seen('C'))
- {
- const int trigger = gb.GetIValue();
- if (trigger < 0 || trigger > (int)MaxHeaterProtectionTrigger)
- {
- reply.printf("Invalid heater protection trigger '%d'", trigger);
- }
-
- seen = true;
- item.SetTrigger(static_cast<HeaterProtectionTrigger>(trigger));
- }
-
- // Set temperature limit
- if (gb.Seen('S'))
- {
- const float limit = gb.GetFValue();
- if (limit <= BadLowTemperature || limit >= BadErrorTemperature)
- {
- reply.copy("Invalid temperature limit");
- return GCodeResult::error;
- }
-
- seen = true;
- item.SetTemperatureLimit(limit);
- }
-
- // Report current parameters
- if (!seen)
- {
- if (item.GetHeater() < 0)
- {
- reply.printf("Temperature protection item %d is not configured", index);
- }
- else
- {
- const char *actionString, *triggerString;
- switch (item.GetAction())
- {
- case HeaterProtectionAction::GenerateFault:
- actionString = "generate a heater fault";
- break;
- case HeaterProtectionAction::PermanentSwitchOff:
- actionString = "permanently switch off";
- break;
- case HeaterProtectionAction::TemporarySwitchOff:
- actionString = "temporarily switch off";
- break;
- default:
- actionString = "(undefined)";
- break;
- }
-
- switch (item.GetTrigger())
- {
- case HeaterProtectionTrigger::TemperatureExceeded:
- triggerString = "exceeds";
- break;
- case HeaterProtectionTrigger::TemperatureTooLow:
- triggerString = "falls below";
- break;
- default:
- triggerString = "(undefined)";
- break;
- }
-
- reply.printf("Temperature protection item %d is configured for heater %d and uses sensor %d to %s if the temperature %s %.1f" DEGREE_SYMBOL "C",
- index, item.GetHeater(), item.GetSensorNumber(), actionString, triggerString, (double)item.GetTemperatureLimit());
- }
- }
-
- return GCodeResult::ok;
-}
-
-// Updates the PIDs and HeaterProtection items after a heater change. Caller must already have a write lock on the heaters.
-void Heat::UpdateHeaterProtection(int heaterNumber) noexcept
-{
- auto h = FindHeater(heaterNumber);
- if (h.IsNotNull())
- {
- // Rebuild linked lists
- h->SetHeaterProtection(nullptr);
- HeaterProtection *firstProtectionItem = nullptr;
- HeaterProtection *lastElementInList = nullptr;
- for (HeaterProtection *prot : heaterProtections)
- {
- if (prot->GetHeater() == heaterNumber)
- {
- if (firstProtectionItem == nullptr)
- {
- firstProtectionItem = prot;
- prot->SetNext(nullptr);
- }
- else if (lastElementInList == nullptr)
- {
- firstProtectionItem->SetNext(prot);
- lastElementInList = prot;
- }
- else
- {
- lastElementInList->SetNext(prot);
- lastElementInList = prot;
- }
- }
- }
-
- h->SetHeaterProtection(firstProtectionItem);
- }
+ return h->ConfigureMonitor(gb, reply);
}
// Get the temperature of a sensor
diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h
index 6878bb8e..3789a721 100644
--- a/src/Heating/Heat.h
+++ b/src/Heating/Heat.h
@@ -34,7 +34,7 @@ Licence: GPL
#include <RTOSIface/RTOSIface.h>
class TemperatureSensor;
-class HeaterProtection;
+class HeaterMonitor;
class GCodeBuffer;
class CanMessageSensorTemperatures;
class CanMessageHeatersStatus;
@@ -43,6 +43,7 @@ class Heat INHERIT_OBJECT_MODEL
{
public:
Heat() noexcept;
+ Heat(const Heat&) = delete;
// Methods that don't relate to a particular heater
void HeaterTask() noexcept;
@@ -79,9 +80,7 @@ public:
GCodeResult TuneHeater(GCodeBuffer& gb, const StringRef& reply) THROWS_GCODE_EXCEPTION;
GCodeResult ConfigureSensor(GCodeBuffer& gb, const StringRef& reply) THROWS_GCODE_EXCEPTION; // Create a sensor or change the parameters for an existing sensor
GCodeResult SetPidParameters(unsigned int heater, GCodeBuffer& gb, const StringRef& reply) THROWS_GCODE_EXCEPTION; // Set the P/I/D parameters for a heater
- GCodeResult SetHeaterProtection(GCodeBuffer &gb, const StringRef &reply) THROWS_GCODE_EXCEPTION; // Configure heater protection (M143)
-
- void UpdateHeaterProtection(int heaterNumber) noexcept; // Updates the PIDs and HeaterProtection items when a heater is remapped
+ GCodeResult HandleM143(GCodeBuffer &gb, const StringRef &reply) THROWS_GCODE_EXCEPTION; // Configure heater protection (M143)
void SensorsTask() noexcept;
static void EnsureSensorsTask() noexcept;
@@ -119,16 +118,16 @@ public:
float GetStandbyTemperature(int heater) const noexcept;
float GetHighestTemperatureLimit(int heater) const noexcept;
float GetLowestTemperatureLimit(int heater) const noexcept;
- float GetHeaterTemperature(int heater) const noexcept; // Get the current temperature of a heater
float GetTargetTemperature(int heater) const noexcept; // Get the target temperature
+ float GetHeaterTemperature(int heater) const noexcept; // Get the current temperature of a heater
HeaterStatus GetStatus(int heater) const noexcept; // Get the off/standby/active status
bool HeaterAtSetTemperature(int heater, bool waitWhenCooling, float tolerance) const noexcept;
GCodeResult ConfigureHeater(size_t heater, GCodeBuffer& gb, const StringRef& reply);
GCodeResult ConfigureHeaterMonitoring(size_t heater, GCodeBuffer& gb, const StringRef& reply);
- void SetActiveTemperature(int heater, float t) noexcept;
- void SetStandbyTemperature(int heater, float t) noexcept;
+ void SetActiveTemperature(int heater, float t) THROWS(GCodeException) { SetTemperature(heater, t, true); }
+ void SetStandbyTemperature(int heater, float t) THROWS(GCodeException) { SetTemperature(heater, t, false); }
GCodeResult Activate(int heater, const StringRef& reply) noexcept; // Turn on a heater
void Standby(int heater, const Tool* tool) noexcept; // Set a heater to standby
void SwitchOff(int heater) noexcept; // Turn off a specific heater
@@ -143,24 +142,22 @@ public:
void ProcessRemoteHeatersReport(CanAddress src, const CanMessageHeatersStatus& msg) noexcept;
#endif
+ static ReadWriteLock sensorsLock; // needs to be public so that the OMT in EndstopsManager can lock it
+
protected:
DECLARE_OBJECT_MODEL
OBJECT_MODEL_ARRAY(heaters)
- OBJECT_MODEL_ARRAY(sensors)
private:
- Heat(const Heat&) = delete; // Private copy constructor to prevent copying
-
ReadLockedPointer<Heater> FindHeater(int heater) const noexcept;
void DeleteSensor(unsigned int sn) noexcept;
void InsertSensor(TemperatureSensor *newSensor) noexcept;
+ void SetTemperature(int heater, float t, bool activeNotStandby) THROWS(GCodeException);
static ReadWriteLock heatersLock;
- static ReadWriteLock sensorsLock;
uint8_t volatile sensorCount;
TemperatureSensor * volatile sensorsRoot; // The sensor list
- HeaterProtection *heaterProtections[MaxHeaters + MaxExtraHeaterProtections]; // Heater protection instances to guarantee legal heater temperature ranges
Heater* heaters[MaxHeaters]; // A local or remote heater
const Tool* lastStandbyTools[MaxHeaters]; // The last tool that caused the corresponding heater to be set to standby
diff --git a/src/Heating/Heater.cpp b/src/Heating/Heater.cpp
index a3a64add..24b10302 100644
--- a/src/Heating/Heater.cpp
+++ b/src/Heating/Heater.cpp
@@ -9,8 +9,10 @@
#include "RepRap.h"
#include "Platform.h"
#include "Heat.h"
-#include "HeaterProtection.h"
+#include "HeaterMonitor.h"
#include "Sensors/TemperatureSensor.h"
+#include <GCodes/GCodeBuffer/GCodeBuffer.h>
+#include <GCodes/GCodeException.h>
#if SUPPORT_OBJECT_MODEL
@@ -41,19 +43,100 @@ DEFINE_GET_OBJECT_MODEL_TABLE(Heater)
Heater::Heater(unsigned int num) noexcept
: heaterNumber(num), sensorNumber(-1), activeTemperature(0.0), standbyTemperature(0.0),
maxTempExcursion(DefaultMaxTempExcursion), maxHeatingFaultTime(DefaultMaxHeatingFaultTime),
- heaterProtection(nullptr), active(false)
+ active(false)
{
}
Heater::~Heater() noexcept
{
+ for (HeaterMonitor& h : monitors)
+ {
+ h.Disable();
+ }
+}
+
+void Heater::SetSensorNumber(int sn) noexcept
+{
+ if (sn != sensorNumber)
+ {
+ sensorNumber = sn;
+ SetDefaultMonitors();
+ }
+}
+
+void Heater::SetDefaultMonitors() noexcept
+{
+ for (HeaterMonitor& h : monitors)
+ {
+ h.Disable();
+ }
+
+ if (sensorNumber >= 0 && sensorNumber < (int)MaxSensors)
+ {
+ const float limit = (reprap.GetHeat().IsBedOrChamberHeater(heaterNumber)) ? DefaultBedTemperatureLimit : DefaultHotEndTemperatureLimit;
+ monitors[0].Set(sensorNumber, limit, HeaterMonitorAction::GenerateFault, HeaterMonitorTrigger::TemperatureExceeded);
+ }
+}
+
+GCodeResult Heater::SetOrReportModel(unsigned int heater, GCodeBuffer& gb, const StringRef& reply) noexcept
+{
+ bool seen = false;
+ float gain = model.GetGain(),
+ tc = model.GetTimeConstant(),
+ td = model.GetDeadTime(),
+ maxPwm = model.GetMaxPwm(),
+ voltage = model.GetVoltage();
+ int32_t dontUsePid = model.UsePid() ? 0 : 1;
+ int32_t inversionParameter = 0;
+
+ gb.TryGetFValue('A', gain, seen);
+ gb.TryGetFValue('C', tc, seen);
+ gb.TryGetFValue('D', td, seen);
+ gb.TryGetIValue('B', dontUsePid, seen);
+ gb.TryGetFValue('S', maxPwm, seen);
+ gb.TryGetFValue('V', voltage, seen);
+ gb.TryGetIValue('I', inversionParameter, seen);
+
+ if (seen)
+ {
+ const bool inverseTemperatureControl = (inversionParameter == 1 || inversionParameter == 3);
+ const GCodeResult rslt = SetModel(gain, tc, td, maxPwm, voltage, dontUsePid == 0, inverseTemperatureControl, reply);
+ if (rslt != GCodeResult::ok)
+ {
+ return rslt;
+ }
+ }
+ else if (!model.IsEnabled())
+ {
+ reply.printf("Heater %u is disabled", heater);
+ }
+ else
+ {
+ const char* const mode = (!model.UsePid()) ? "bang-bang"
+ : (model.ArePidParametersOverridden()) ? "custom PID"
+ : "PID";
+ reply.printf("Heater %u model: gain %.1f, time constant %.1f, dead time %.1f, max PWM %.2f, calibration voltage %.1f, mode %s", heater,
+ (double)model.GetGain(), (double)model.GetTimeConstant(), (double)model.GetDeadTime(), (double)model.GetMaxPwm(), (double)model.GetVoltage(), mode);
+ if (model.IsInverted())
+ {
+ reply.cat(", inverted temperature control");
+ }
+ if (model.UsePid())
+ {
+ // When reporting the PID parameters, we scale them by 255 for compatibility with older firmware and other firmware
+ M301PidParameters params = model.GetM301PidParameters(false);
+ reply.catf("\nComputed PID parameters for setpoint change: P%.1f, I%.3f, D%.1f", (double)params.kP, (double)params.kI, (double)params.kD);
+ params = model.GetM301PidParameters(true);
+ reply.catf("\nComputed PID parameters for load change: P%.1f, I%.3f, D%.1f", (double)params.kP, (double)params.kI, (double)params.kD);
+ }
+ }
+ return GCodeResult::ok;
}
// Set the process model returning true if successful
GCodeResult Heater::SetModel(float gain, float tc, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept
{
- const float temperatureLimit = GetHighestTemperatureLimit();
- const bool rslt = model.SetParameters(gain, tc, td, maxPwm, temperatureLimit, voltage, usePid, inverted);
+ const bool rslt = model.SetParameters(gain, tc, td, maxPwm, GetHighestTemperatureLimit(), voltage, usePid, inverted);
if (rslt)
{
if (model.IsEnabled())
@@ -64,7 +147,7 @@ GCodeResult Heater::SetModel(float gain, float tc, float td, float maxPwm, float
return rslt;
}
const float predictedMaxTemp = gain + NormalAmbientTemperature;
- const float noWarnTemp = (temperatureLimit - NormalAmbientTemperature) * 1.5 + 50.0; // allow 50% extra power plus enough for an extra 50C
+ const float noWarnTemp = (GetHighestTemperatureLimit() - NormalAmbientTemperature) * 1.5 + 50.0; // allow 50% extra power plus enough for an extra 50C
if (predictedMaxTemp > noWarnTemp)
{
reply.printf("heater %u appears to be over-powered. If left on at full power, its temperature is predicted to reach %dC.\n",
@@ -90,6 +173,88 @@ GCodeResult Heater::SetFaultDetectionParameters(float pMaxTempExcursion, float p
return UpdateFaultDetectionParameters(reply);
}
+GCodeResult Heater::ConfigureMonitor(GCodeBuffer &gb, const StringRef &reply) THROWS(GCodeException)
+{
+ // Get any parameters that have been provided
+ const bool seenP = gb.Seen('P');
+ const size_t index = (seenP) ? gb.GetLimitedUIValue('P', MaxMonitorsPerHeater) : 0;
+
+ const bool seenSensor = gb.Seen('T');
+ const int monitoringSensor = (seenSensor) ? gb.GetLimitedUIValue('T', MaxSensors) : GetSensorNumber();
+
+ const bool seenAction = gb.Seen('A');
+ const HeaterMonitorAction action = (seenAction)
+ ? static_cast<HeaterMonitorAction>(gb.GetLimitedUIValue('A', (unsigned int)MaxHeaterMonitorAction + 1))
+ : HeaterMonitorAction::GenerateFault;
+
+ const bool seenCondition = gb.Seen('C');
+ const HeaterMonitorTrigger trigger = (seenCondition)
+ ? static_cast<HeaterMonitorTrigger>(gb.GetLimitedIValue('C', -1, (int)MaxHeaterMonitorTrigger))
+ : HeaterMonitorTrigger::TemperatureExceeded;
+
+ const bool seenLimit = gb.Seen('S');
+ const float limit = (seenLimit) ? gb.GetFValue() : monitors[index].GetTemperatureLimit();
+ if (limit <= BadLowTemperature || limit >= BadErrorTemperature)
+ {
+ reply.copy("Invalid temperature limit");
+ return GCodeResult::error;
+ }
+
+ if (seenSensor || seenLimit || seenAction || seenCondition)
+ {
+ monitors[index].Set(monitoringSensor, limit, action, trigger);
+ return UpdateHeaterMonitors(reply);
+ }
+
+ // Else we are reporting on one or all of the monitors
+ if (seenP)
+ {
+ monitors[index].Report(heaterNumber, index, reply);
+ }
+ else
+ {
+ for (size_t i = 0; i < MaxMonitorsPerHeater; ++i)
+ {
+ monitors[i].Report(heaterNumber, i, reply);
+ }
+ }
+ return GCodeResult::ok;
+}
+
+float Heater::GetHighestTemperatureLimit() const noexcept
+{
+ float limit = BadErrorTemperature;
+ for (const HeaterMonitor& prot : monitors)
+ {
+ if (prot.GetTrigger() == HeaterMonitorTrigger::TemperatureExceeded)
+ {
+ const float t = prot.GetTemperatureLimit();
+ if (limit == BadErrorTemperature || t > limit)
+ {
+ limit = t;
+ }
+ }
+ }
+ return limit;
+}
+
+float Heater::GetLowestTemperatureLimit() const noexcept
+{
+ float limit = ABS_ZERO;
+ for (const HeaterMonitor& prot : monitors)
+ {
+ if (prot.GetTrigger() == HeaterMonitorTrigger::TemperatureTooLow)
+ {
+ const float t = prot.GetTemperatureLimit();
+ if (limit == ABS_ZERO || t < limit)
+ {
+ limit = t;
+ }
+ }
+ }
+ return limit;
+}
+
HeaterStatus Heater::GetStatus() const noexcept
{
const HeaterMode mode = GetMode();
@@ -128,19 +293,19 @@ void Heater::Standby() noexcept
}
}
-void Heater::SetActiveTemperature(float t) noexcept
+void Heater::SetTemperature(float t, bool activeNotStandby) THROWS(GCodeException)
{
if (t > GetHighestTemperatureLimit())
{
- reprap.GetPlatform().MessageF(ErrorMessage, "Temperature %.1f" DEGREE_SYMBOL "C too high for heater %u\n", (double)t, GetHeaterNumber());
+ throw GCodeException(-1, -1, "Temperature too high for heater %" PRIu32, (uint32_t)GetHeaterNumber());
}
else if (t < GetLowestTemperatureLimit())
{
- reprap.GetPlatform().MessageF(ErrorMessage, "Temperature %.1f" DEGREE_SYMBOL "C too low for heater %u\n", (double)t, GetHeaterNumber());
+ throw GCodeException(-1, -1, "Temperature too low for heater %" PRIu32, (uint32_t)GetHeaterNumber());
}
else
{
- activeTemperature = t;
+ ((activeNotStandby) ? activeTemperature : standbyTemperature) = t;
if (GetMode() > HeaterMode::suspended && active)
{
String<1> dummy;
@@ -149,66 +314,9 @@ void Heater::SetActiveTemperature(float t) noexcept
}
}
-void Heater::SetStandbyTemperature(float t) noexcept
-{
- if (t > GetHighestTemperatureLimit())
- {
- reprap.GetPlatform().MessageF(ErrorMessage, "Temperature %.1f" DEGREE_SYMBOL "C too high for heater %u\n", (double)t, GetHeaterNumber());
- }
- else if (t < GetLowestTemperatureLimit())
- {
- reprap.GetPlatform().MessageF(ErrorMessage, "Temperature %.1f" DEGREE_SYMBOL "C too low for heater %u\n", (double)t, GetHeaterNumber());
- }
- else
- {
- standbyTemperature = t;
- if (GetMode() > HeaterMode::suspended && !active)
- {
- String<1> dummy;
- (void)SwitchOn(dummy.GetRef());
- }
- }
-}
-
-// Get the highest temperature limit
-float Heater::GetHighestTemperatureLimit() const noexcept
-{
- return reprap.GetHeat().GetHighestTemperatureLimit(GetHeaterNumber());
-}
-
-// Get the lowest temperature limit
-float Heater::GetLowestTemperatureLimit() const noexcept
-{
- return reprap.GetHeat().GetLowestTemperatureLimit(GetHeaterNumber());
-}
-
-void Heater::SetHeaterProtection(HeaterProtection *h) noexcept
-{
- heaterProtection = h;
-}
-
-// Check heater protection elements and return true if everything is good
-bool Heater::CheckProtection() const noexcept
-{
- for (HeaterProtection *prot = heaterProtection; prot != nullptr; prot = prot->Next())
- {
- if (!prot->Check())
- {
- // Something is not right
- return false;
- }
- }
- return true;
-}
-
-bool Heater::CheckGood() const noexcept
-{
- return GetMode() != HeaterMode::fault && CheckProtection();
-}
-
void Heater::SetModelDefaults() noexcept
{
- if (reprap.GetHeat().IsBedOrChamberHeater(GetHeaterNumber()))
+ if (reprap.GetHeat().IsBedOrChamberHeater(heaterNumber))
{
model.SetParameters(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime, 1.0, DefaultBedTemperatureLimit, 0.0, false, false);
}
diff --git a/src/Heating/Heater.h b/src/Heating/Heater.h
index c237195e..5108d548 100644
--- a/src/Heating/Heater.h
+++ b/src/Heating/Heater.h
@@ -11,6 +11,7 @@
#include <RepRapFirmware.h>
#include <NamedEnum.h>
#include "FOPDT.h"
+#include "HeaterMonitor.h"
#include "GCodes/GCodeResult.h"
#include <ObjectModel/ObjectModel.h>
@@ -18,7 +19,7 @@
# include "CanId.h"
#endif
-class HeaterProtection;
+class HeaterMonitor;
struct CanHeaterReport;
// Enumeration to describe the status of a heater. Note that the web interface returns the numerical values, so don't change them.
@@ -29,6 +30,7 @@ class Heater INHERIT_OBJECT_MODEL
public:
Heater(unsigned int num) noexcept;
virtual ~Heater() noexcept;
+ Heater(const Heater&) = delete;
// Configuration methods
virtual GCodeResult ConfigurePortAndSensor(const char *portName, PwmFrequency freq, unsigned int sensorNumber, const StringRef& reply) = 0;
@@ -40,36 +42,35 @@ public:
virtual GCodeResult ResetFault(const StringRef& reply) noexcept = 0; // Reset a fault condition - only call this if you know what you are doing
virtual void SwitchOff() noexcept = 0;
virtual void Spin() noexcept = 0;
- virtual void StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept = 0; // Start an auto tune cycle for this PID
+ virtual GCodeResult StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept = 0; // Start an auto tune cycle for this PID
virtual void GetAutoTuneStatus(const StringRef& reply) const = 0; // Get the auto tune status or last result
- virtual void Suspend(bool sus) noexcept = 0; // Suspend the heater to conserve power or while doing Z probing
+ virtual void Suspend(bool sus) noexcept = 0; // Suspend the heater to conserve power or while doing Z probing
virtual float GetAccumulator() const noexcept = 0; // Get the inertial term accumulator
#if SUPPORT_CAN_EXPANSION
virtual void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept = 0;
#endif
- HeaterStatus GetStatus() const noexcept; // Get the status of the heater
+ HeaterStatus GetStatus() const noexcept; // Get the status of the heater
unsigned int GetHeaterNumber() const noexcept { return heaterNumber; }
const char *GetSensorName() const noexcept; // Get the name of the sensor for this heater, or nullptr if it hasn't been named
- void SetActiveTemperature(float t) noexcept;
+ void SetTemperature(float t, bool activeNotStandby) THROWS(GCodeException);
float GetActiveTemperature() const noexcept { return activeTemperature; }
- void SetStandbyTemperature(float t) noexcept;
float GetStandbyTemperature() const noexcept { return standbyTemperature; }
GCodeResult Activate(const StringRef& reply) noexcept; // Switch from idle to active
- void Standby() noexcept; // Switch from active to idle
+ void Standby() noexcept; // Switch from active to idle
void GetFaultDetectionParameters(float& pMaxTempExcursion, float& pMaxFaultTime) const noexcept
{ pMaxTempExcursion = maxTempExcursion; pMaxFaultTime = maxHeatingFaultTime; }
-
GCodeResult SetFaultDetectionParameters(float pMaxTempExcursion, float pMaxFaultTime, const StringRef& reply) noexcept;
- float GetHighestTemperatureLimit() const noexcept; // Get the highest temperature limit
+ GCodeResult ConfigureMonitor(GCodeBuffer &gb, const StringRef &reply) THROWS(GCodeException);
+
+ float GetHighestTemperatureLimit() const noexcept;
float GetLowestTemperatureLimit() const noexcept; // Get the lowest temperature limit
- void SetHeaterProtection(HeaterProtection *h) noexcept;
- const FopDt& GetModel() const noexcept { return model; } // Get the process model
- GCodeResult SetModel(float gain, float tc, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept; // Set the process model
+ const FopDt& GetModel() const noexcept { return model; } // Get the process model
+ GCodeResult SetOrReportModel(unsigned int heater, GCodeBuffer& gb, const StringRef& reply) noexcept;
void SetModelDefaults() noexcept;
bool IsHeaterEnabled() const noexcept // Is this heater enabled?
@@ -78,7 +79,7 @@ public:
void SetM301PidParameters(const M301PidParameters& params) noexcept
{ model.SetM301PidParameters(params); }
- bool CheckGood() const noexcept;
+ void SetDefaultMonitors() noexcept;
protected:
DECLARE_OBJECT_MODEL
@@ -102,31 +103,31 @@ protected:
lastTuningMode = tuning3
};
+protected:
virtual void ResetHeater() noexcept = 0;
virtual HeaterMode GetMode() const noexcept = 0;
virtual GCodeResult SwitchOn(const StringRef& reply) noexcept = 0;
virtual GCodeResult UpdateModel(const StringRef& reply) noexcept = 0;
virtual GCodeResult UpdateFaultDetectionParameters(const StringRef& reply) noexcept = 0;
+ virtual GCodeResult UpdateHeaterMonitors(const StringRef& reply) noexcept = 0;
int GetSensorNumber() const noexcept { return sensorNumber; }
- void SetSensorNumber(int sn) noexcept { sensorNumber = sn; }
+ void SetSensorNumber(int sn) noexcept;
float GetMaxTemperatureExcursion() const noexcept { return maxTempExcursion; }
float GetMaxHeatingFaultTime() const noexcept { return maxHeatingFaultTime; }
float GetTargetTemperature() const noexcept { return (active) ? activeTemperature : standbyTemperature; }
- HeaterProtection *GetHeaterProtections() const noexcept { return heaterProtection; }
+ GCodeResult SetModel(float gain, float tc, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept; // Set the process model
- FopDt model;
+ HeaterMonitor monitors[MaxMonitorsPerHeater]; // embedding them in the Heater uses less memory than dynamic allocation
private:
- bool CheckProtection() const noexcept; // Check heater protection elements and return true if everything is good
-
+ FopDt model;
unsigned int heaterNumber;
int sensorNumber; // the sensor number used by this heater
float activeTemperature; // The required active temperature
float standbyTemperature; // The required standby temperature
float maxTempExcursion; // The maximum temperature excursion permitted while maintaining the setpoint
float maxHeatingFaultTime; // How long a heater fault is permitted to persist before a heater fault is raised
- HeaterProtection *heaterProtection; // The first element of assigned heater protection items
bool active; // Are we active or standby?
};
diff --git a/src/Heating/HeaterMonitor.cpp b/src/Heating/HeaterMonitor.cpp
new file mode 100644
index 00000000..bb1874b3
--- /dev/null
+++ b/src/Heating/HeaterMonitor.cpp
@@ -0,0 +1,99 @@
+/*
+ * HeaterProtection.cpp
+ *
+ * Created on: 16 Nov 2017
+ * Author: Christian
+ */
+
+#include "HeaterMonitor.h"
+
+#include <Platform.h>
+#include <RepRap.h>
+#include "Heat.h"
+
+HeaterMonitor::HeaterMonitor() noexcept
+ : sensorNumber(-1), trigger(HeaterMonitorTrigger::Disabled), badTemperatureCount(0)
+{
+}
+
+// Check if any action needs to be taken. Returns true if everything is OK
+bool HeaterMonitor::Check() noexcept
+{
+ if (sensorNumber >= 0 && trigger != HeaterMonitorTrigger::Disabled)
+ {
+ TemperatureError err;
+ const float temperature = reprap.GetHeat().GetSensorTemperature(sensorNumber, err);
+
+ if (err != TemperatureError::success)
+ {
+ badTemperatureCount++;
+ if (badTemperatureCount > MaxBadTemperatureCount)
+ {
+ reprap.GetPlatform().MessageF(ErrorMessage, "Temperature reading error on sensor %d\n", sensorNumber);
+ return false;
+ }
+ }
+ else
+ {
+ badTemperatureCount = 0;
+ switch (trigger)
+ {
+ case HeaterMonitorTrigger::TemperatureExceeded:
+ return (temperature <= limit);
+
+ case HeaterMonitorTrigger::TemperatureTooLow:
+ return (temperature >= limit);
+
+ default:
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+// Append a report of this monitor to the string
+void HeaterMonitor::Report(unsigned int heater, unsigned int index, const StringRef& reply) const noexcept
+{
+ reply.lcatf("Heater %d monitor %d ", heater, index);
+ if (trigger == HeaterMonitorTrigger::Disabled)
+ {
+ reply.cat("is disabled");
+ }
+ else
+ {
+ const char *actionString, *triggerString;
+ switch (action)
+ {
+ case HeaterMonitorAction::GenerateFault:
+ actionString = "generate a heater fault";
+ break;
+ case HeaterMonitorAction::PermanentSwitchOff:
+ actionString = "permanently switch off";
+ break;
+ case HeaterMonitorAction::TemporarySwitchOff:
+ actionString = "temporarily switch off";
+ break;
+ default:
+ actionString = "(undefined)";
+ break;
+ }
+
+ switch (trigger)
+ {
+ case HeaterMonitorTrigger::TemperatureExceeded:
+ triggerString = "exceeds";
+ break;
+ case HeaterMonitorTrigger::TemperatureTooLow:
+ triggerString = "falls below";
+ break;
+ default:
+ triggerString = "(undefined)";
+ break;
+ }
+
+ reply.catf("uses sensor %d to %s if the reading %s %.1f" DEGREE_SYMBOL "C", sensorNumber, actionString, triggerString, (double)limit);
+ }
+}
+
+// End
diff --git a/src/Heating/HeaterMonitor.h b/src/Heating/HeaterMonitor.h
new file mode 100644
index 00000000..42bdac38
--- /dev/null
+++ b/src/Heating/HeaterMonitor.h
@@ -0,0 +1,81 @@
+/*
+ * HeaterMonitor.h
+ *
+ * Created on: 16 Nov 2017
+ * Author: Christian
+ */
+
+#ifndef HEATERMONITOR_H
+#define HEATERMONITOR_H
+
+#include <RepRapFirmware.h>
+#include <General/FreelistManager.h>
+
+// Condition of a heater monitor event
+enum class HeaterMonitorTrigger : int8_t
+{
+ Disabled = -1,
+ TemperatureExceeded = 0,
+ TemperatureTooLow
+};
+
+const HeaterMonitorTrigger MaxHeaterMonitorTrigger = HeaterMonitorTrigger::TemperatureTooLow;
+
+// The action to trigger when the target condition is met
+enum class HeaterMonitorAction : uint8_t
+{
+ GenerateFault = 0,
+ PermanentSwitchOff,
+ TemporarySwitchOff
+};
+
+const HeaterMonitorAction MaxHeaterMonitorAction = HeaterMonitorAction::TemporarySwitchOff;
+
+// A note about using this class. Its size is currently 8 bytes, and will be 12 bytes of object model support is added.
+// - If we allocate them statically within the heater object, then assuming 3 per heater we need 24 bytes, or 36 bytes with OM support.
+// - If we allocate them dynamically then there is an overhead of at least 8 bytes per object. All heaters have at least 2.
+// So each heater needs 12 bytes for the pointers plus 32 bytes (without OM support) or 40 bytes (with OM support). Total 44 or 52 bytes.
+// For unconfigured heaters, the cost is 24 or 36 bytes each using static allocation, or 4 bytes each using dynamic allocation.
+// Summary:
+// - Static allocation saves 20 bytes (no OM) or 16 bytes (with OM) per configured heater, if the 3rd heater monitor is not used (and more if it is used)
+// - Dynamic allocation saves 20 bytes (no OM) or 32 bytes (with OM) per unconfigured heater
+// For now we use static allocation, i.e. we embed the heater monitor in the heater object.
+class HeaterMonitor
+{
+public:
+ HeaterMonitor() noexcept;
+
+ void Set(int sn, float lim, HeaterMonitorAction act, HeaterMonitorTrigger trig) noexcept;
+ void Disable() noexcept;
+ bool Check() noexcept; // Check if any action needs to be taken
+
+ int GetSensorNumber() const noexcept { return sensorNumber; } // Get the supervisory sensor number
+ float GetTemperatureLimit() const noexcept { return limit; } // Get the temperature limit
+ HeaterMonitorAction GetAction() const noexcept { return action; } // Get the action to trigger when a temperature event occurs
+ HeaterMonitorTrigger GetTrigger() const noexcept { return trigger; } // Get the condition for a temperature event
+
+ void Report(unsigned int heater, unsigned int index, const StringRef& reply) const noexcept; // Append a report of this monitor to the string
+
+private:
+ float limit; // temperature limit
+ int8_t sensorNumber; // the sensor that we use to monitor the heater
+ HeaterMonitorAction action; // what action we take of we detect a fault
+ HeaterMonitorTrigger trigger; // what is treated a fault
+ uint8_t badTemperatureCount; // how many consecutive sensor reading faults we have had
+};
+
+inline void HeaterMonitor::Set(int sn, float lim, HeaterMonitorAction act, HeaterMonitorTrigger trig) noexcept
+{
+ sensorNumber = sn;
+ limit = lim;
+ action = act;
+ trigger = trig;
+ badTemperatureCount = 0;
+}
+
+inline void HeaterMonitor::Disable() noexcept
+{
+ trigger = HeaterMonitorTrigger::Disabled;
+}
+
+#endif
diff --git a/src/Heating/HeaterProtection.cpp b/src/Heating/HeaterProtection.cpp
deleted file mode 100644
index f13911d0..00000000
--- a/src/Heating/HeaterProtection.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * HeaterProtection.cpp
- *
- * Created on: 16 Nov 2017
- * Author: Christian
- */
-
-#include "HeaterProtection.h"
-
-#include "Platform.h"
-#include "RepRap.h"
-#include "Heat.h"
-
-
-HeaterProtection::HeaterProtection(size_t index) noexcept : next(nullptr)
-{
- // By default each heater protection element is mapped to its corresponding heater.
- // All other heater protection elements are unused and can be optionally assigned.
- heater = (index >= MaxHeaters) ? -1 : (int8_t)index;
- sensorNumber = -1;
-}
-
-void HeaterProtection::Init(float tempLimit) noexcept
-{
- next = nullptr;
- limit = tempLimit;
- action = HeaterProtectionAction::GenerateFault;
- trigger = HeaterProtectionTrigger::TemperatureExceeded;
-
- badTemperatureCount = 0;
-}
-
-// Check if any action needs to be taken. Returns true if everything is OK
-bool HeaterProtection::Check() noexcept
-{
- if (sensorNumber >= 0)
- {
- TemperatureError err;
- const float temperature = reprap.GetHeat().GetSensorTemperature(sensorNumber, err);
-
- if (err != TemperatureError::success)
- {
- badTemperatureCount++;
- if (badTemperatureCount > MaxBadTemperatureCount)
- {
- reprap.GetPlatform().MessageF(ErrorMessage, "Temperature reading error on sensor %d\n", sensorNumber);
- return false;
- }
- }
- else
- {
- badTemperatureCount = 0;
- switch (trigger)
- {
- case HeaterProtectionTrigger::TemperatureExceeded:
- return (temperature <= limit);
-
- case HeaterProtectionTrigger::TemperatureTooLow:
- return (temperature >= limit);
- }
- }
- }
- return true;
-}
-
-void HeaterProtection::SetHeater(int newHeater) noexcept
-{
- heater = newHeater;
-}
-
-// End
diff --git a/src/Heating/HeaterProtection.h b/src/Heating/HeaterProtection.h
deleted file mode 100644
index 19f5df36..00000000
--- a/src/Heating/HeaterProtection.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * HeaterProtection.h
- *
- * Created on: 16 Nov 2017
- * Author: Christian
- */
-
-#ifndef HEATERPROTECTION_H
-#define HEATERPROTECTION_H
-
-#include "RepRapFirmware.h"
-
-
-// Condition of a heater protection event
-enum class HeaterProtectionTrigger : uint8_t
-{
- TemperatureExceeded,
- TemperatureTooLow
-};
-
-const HeaterProtectionTrigger MaxHeaterProtectionTrigger = HeaterProtectionTrigger::TemperatureTooLow;
-
-// The action to trigger when the target condition is met
-enum class HeaterProtectionAction : uint8_t
-{
- GenerateFault = 0,
- PermanentSwitchOff,
- TemporarySwitchOff
-};
-
-const HeaterProtectionAction MaxHeaterProtectionAction = HeaterProtectionAction::TemporarySwitchOff;
-
-
-class Heat;
-
-class HeaterProtection
-{
-public:
- friend class Heat;
-
- HeaterProtection(size_t index) noexcept;
- void Init(float tempLimit) noexcept;
-
- HeaterProtection *Next() const noexcept { return next; }
- void SetNext(HeaterProtection *n) noexcept { next = n; }
-
- bool Check() noexcept; // Check if any action needs to be taken
-
- int GetHeater() const noexcept { return heater; }
- void SetHeater(int newHeater) noexcept; // Set the heater to control
-
- int GetSensorNumber() const noexcept { return sensorNumber; } // Get the supervisory sensor number
- void SetSensorNumber(int sn) noexcept; // Set the supervisory sensor number
-
- float GetTemperatureLimit() const noexcept { return limit; } // Get the temperature limit
- void SetTemperatureLimit(float newLimit) noexcept; // Set the temperature limit
-
- HeaterProtectionAction GetAction() const noexcept { return action; } // Get the action to trigger when a temperature event occurs
- void SetAction(HeaterProtectionAction newAction) noexcept; // Set the action to trigger when a temperature event occurs
-
- HeaterProtectionTrigger GetTrigger() const noexcept { return trigger; } // Get the condition for a temperature event
- void SetTrigger(HeaterProtectionTrigger newTrigger) noexcept; // Set the condition for a temperature event
-
-private:
- HeaterProtection *next; // link to next HeaterProtection item for the same heater
-
- float limit; // temperature limit
- int heater; // number of the heater we are protecting
- int sensorNumber; // the sensor that we use to monitor the heater
- HeaterProtectionAction action; // what action we take of we detect a fault
- HeaterProtectionTrigger trigger; // what is treated a fault
-
- size_t badTemperatureCount; // how many consecutive sensor reading faults we have had
-};
-
-inline void HeaterProtection::SetSensorNumber(int sn) noexcept
-{
- sensorNumber = sn;
-}
-
-inline void HeaterProtection::SetTemperatureLimit(float newLimit) noexcept
-{
- limit = newLimit;
-}
-
-inline void HeaterProtection::SetAction(HeaterProtectionAction newAction) noexcept
-{
- action = newAction;
-}
-
-inline void HeaterProtection::SetTrigger(HeaterProtectionTrigger newTrigger) noexcept
-{
- trigger = newTrigger;
-}
-
-#endif
diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp
index 5cb822e4..f4429f87 100644
--- a/src/Heating/LocalHeater.cpp
+++ b/src/Heating/LocalHeater.cpp
@@ -9,7 +9,7 @@
#include "GCodes/GCodes.h"
#include "GCodes/GCodeBuffer/GCodeBuffer.h"
#include "Heat.h"
-#include "HeaterProtection.h"
+#include "HeaterMonitor.h"
#include "Platform.h"
#include "RepRap.h"
@@ -395,24 +395,24 @@ void LocalHeater::Spin() noexcept
}
// Verify that everything is operating in the required temperature range
- for (HeaterProtection *prot = GetHeaterProtections(); prot != nullptr; prot = prot->Next())
+ for (HeaterMonitor& prot : monitors)
{
- if (!prot->Check())
+ if (!prot.Check())
{
lastPwm = 0.0;
- switch (prot->GetAction())
+ switch (prot.GetAction())
{
- case HeaterProtectionAction::GenerateFault:
+ case HeaterMonitorAction::GenerateFault:
mode = HeaterMode::fault;
reprap.GetGCodes().HandleHeaterFault(GetHeaterNumber());
- reprap.GetPlatform().MessageF(ErrorMessage, "Heating fault on heater %u\n", GetHeaterNumber());
+ reprap.GetPlatform().MessageF(ErrorMessage, "Heating fault on heater %u: heater monitor was triggered\n", GetHeaterNumber());
break;
- case HeaterProtectionAction::TemporarySwitchOff:
+ case HeaterMonitorAction::TemporarySwitchOff:
// Do nothing, the PWM value has already been set above
break;
- case HeaterProtectionAction::PermanentSwitchOff:
+ case HeaterMonitorAction::PermanentSwitchOff:
SwitchOff();
break;
}
@@ -474,41 +474,49 @@ float LocalHeater::GetExpectedHeatingRate() const noexcept
}
// Auto tune this PID
-void LocalHeater::StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept
+GCodeResult LocalHeater::StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept
{
// Starting an auto tune
if (!GetModel().IsEnabled())
{
- reply.printf("Error: heater %u cannot be auto tuned while it is disabled", GetHeaterNumber());
+ reply.printf("heater %u cannot be auto tuned while it is disabled", GetHeaterNumber());
+ return GCodeResult::error;
}
- else if (lastPwm > 0.0 || GetAveragePWM() > 0.02)
+
+ if (lastPwm > 0.0 || GetAveragePWM() > 0.02)
{
- reply.printf("Error: heater %u must be off and cold before auto tuning it", GetHeaterNumber());
+ reply.printf("heater %u must be off and cold before auto tuning it", GetHeaterNumber());
+ return GCodeResult::error;
}
- else
+
+ const float limit = GetHighestTemperatureLimit();
+ if (targetTemp > limit)
{
- const TemperatureError err = ReadTemperature();
- if (err != TemperatureError::success)
- {
- reply.printf("Error: heater %u reported error '%s' at start of auto tuning", GetHeaterNumber(), TemperatureErrorString(err));
- }
- else
- {
- mode = HeaterMode::tuning0;
- tuningReadingsTaken = 0;
- tuned = false; // assume failure
-
- // We don't normally allow dynamic memory allocation when running. However, auto tuning is rarely done and it
- // would be wasteful to allocate a permanent array just in case we are going to run it, so we make an exception here.
- tuningTempReadings = new float[MaxTuningTempReadings];
- tuningTempReadings[0] = temperature;
- tuningReadingInterval = HeatSampleIntervalMillis;
- tuningPwm = maxPwm;
- tuningTargetTemp = targetTemp;
- reply.printf("Auto tuning heater %u using target temperature %.1f" DEGREE_SYMBOL "C and PWM %.2f - do not leave printer unattended",
- GetHeaterNumber(), (double)targetTemp, (double)maxPwm);
- }
+ reply.printf("heater %u target temperature must be no hiher than the temperature limit for this heater (%.1fC)", GetHeaterNumber(), (double)limit);
+ return GCodeResult::error;
+ }
+
+ const TemperatureError err = ReadTemperature();
+ if (err != TemperatureError::success)
+ {
+ reply.printf("heater %u reported error '%s' at start of auto tuning", GetHeaterNumber(), TemperatureErrorString(err));
+ return GCodeResult::error;
}
+
+ mode = HeaterMode::tuning0;
+ tuningReadingsTaken = 0;
+ tuned = false; // assume failure
+
+ // We don't normally allow dynamic memory allocation when running. However, auto tuning is rarely done and it
+ // would be wasteful to allocate a permanent array just in case we are going to run it, so we make an exception here.
+ tuningTempReadings = new float[MaxTuningTempReadings];
+ tuningTempReadings[0] = temperature;
+ tuningReadingInterval = HeatSampleIntervalMillis;
+ tuningPwm = maxPwm;
+ tuningTargetTemp = targetTemp;
+ reply.printf("Auto tuning heater %u using target temperature %.1f" DEGREE_SYMBOL "C and PWM %.2f - do not leave printer unattended",
+ GetHeaterNumber(), (double)targetTemp, (double)maxPwm);
+ return GCodeResult::ok;
}
// Get the auto tune status or last result
diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h
index 3ad48f5a..c4e283ef 100644
--- a/src/Heating/LocalHeater.h
+++ b/src/Heating/LocalHeater.h
@@ -18,7 +18,7 @@
#include "Hardware/IoPorts.h"
#include "GCodes/GCodeResult.h"
-class HeaterProtection;
+class HeaterMonitor;
class LocalHeater : public Heater
{
@@ -38,7 +38,7 @@ public:
float GetTemperature() const noexcept override; // Get the current temperature
float GetAveragePWM() const noexcept override; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
float GetAccumulator() const noexcept override; // Return the integral accumulator
- void StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept override; // Start an auto tune cycle for this PID
+ GCodeResult StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept override; // Start an auto tune cycle for this PID
void GetAutoTuneStatus(const StringRef& reply) const noexcept override; // Get the auto tune status or last result
void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing
@@ -52,10 +52,11 @@ protected:
GCodeResult SwitchOn(const StringRef& reply) noexcept override; // Turn the heater on and set the mode
GCodeResult UpdateModel(const StringRef& reply) noexcept override; // Called when the heater model has been changed
GCodeResult UpdateFaultDetectionParameters(const StringRef& reply) noexcept override { return GCodeResult::ok; }
+ GCodeResult UpdateHeaterMonitors(const StringRef& reply) noexcept override { return GCodeResult::ok; }
private:
void SetHeater(float power) const noexcept; // Power is a fraction in [0,1]
- TemperatureError ReadTemperature() noexcept; // Read and store the temperature of this heater
+ TemperatureError ReadTemperature() noexcept; // Read and store the temperature of this heater
void DoTuningStep() noexcept; // Called on each temperature sample when auto tuning
static bool ReadingsStable(size_t numReadings, float maxDiff) noexcept
pre(numReadings >= 2; numReadings <= MaxTuningTempReadings);
@@ -65,27 +66,27 @@ private:
void DisplayBuffer(const char *intro) noexcept; // Debug helper
float GetExpectedHeatingRate() const noexcept; // Get the minimum heating rate we expect
- PwmPort port; // The port that drives the heater
- float temperature; // The current temperature
- float previousTemperatures[NumPreviousTemperatures]; // The temperatures of the previous NumDerivativeSamples measurements, used for calculating the derivative
- size_t previousTemperatureIndex; // Which slot in previousTemperature we fill in next
- float iAccumulator; // The integral LocalHeater component
- float lastPwm; // The last PWM value we output, before scaling by kS
- float averagePWM; // The running average of the PWM, after scaling.
- uint32_t timeSetHeating; // When we turned on the heater
- uint32_t lastSampleTime; // Time when the temperature was last sampled by Spin()
+ PwmPort port; // The port that drives the heater
+ float temperature; // The current temperature
+ float previousTemperatures[NumPreviousTemperatures]; // The temperatures of the previous NumDerivativeSamples measurements, used for calculating the derivative
+ size_t previousTemperatureIndex; // Which slot in previousTemperature we fill in next
+ float iAccumulator; // The integral LocalHeater component
+ float lastPwm; // The last PWM value we output, before scaling by kS
+ float averagePWM; // The running average of the PWM, after scaling.
+ uint32_t timeSetHeating; // When we turned on the heater
+ uint32_t lastSampleTime; // Time when the temperature was last sampled by Spin()
- uint16_t heatingFaultCount; // Count of questionable heating behaviours
+ uint16_t heatingFaultCount; // Count of questionable heating behaviours
- uint8_t previousTemperaturesGood; // Bitmap indicating which previous temperature were good readings
- HeaterMode mode; // Current state of the heater
- bool tuned; // True if tuning was successful
- uint8_t badTemperatureCount; // Count of sequential dud readings
+ uint8_t previousTemperaturesGood; // Bitmap indicating which previous temperature were good readings
+ HeaterMode mode; // Current state of the heater
+ bool tuned; // True if tuning was successful
+ uint8_t badTemperatureCount; // Count of sequential dud readings
static_assert(sizeof(previousTemperaturesGood) * 8 >= NumPreviousTemperatures, "too few bits in previousTemperaturesGood");
// Variables used during heater tuning
- static const size_t MaxTuningTempReadings = 128; // The maximum number of readings we keep. Must be an even number.
+ static const size_t MaxTuningTempReadings = 128; // The maximum number of readings we keep. Must be an even number.
static float *tuningTempReadings; // the readings from the heater being tuned
static float tuningStartTemp; // the temperature when we turned on the heater
diff --git a/src/Heating/RemoteHeater.cpp b/src/Heating/RemoteHeater.cpp
index ace55336..ba00d3e2 100644
--- a/src/Heating/RemoteHeater.cpp
+++ b/src/Heating/RemoteHeater.cpp
@@ -128,14 +128,15 @@ float RemoteHeater::GetAccumulator() const noexcept
return 0.0; // not supported
}
-void RemoteHeater::StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept
+GCodeResult RemoteHeater::StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept
{
- //TODO
+ reply.copy("remote heater auto tune not implemented");
+ return GCodeResult::error;
}
void RemoteHeater::GetAutoTuneStatus(const StringRef& reply) const noexcept
{
- //TODO
+ reply.copy("remote heater auto tune not implemented");
}
void RemoteHeater::Suspend(bool sus) noexcept
@@ -189,7 +190,7 @@ GCodeResult RemoteHeater::UpdateModel(const StringRef& reply) noexcept
{
const CanRequestId rid = CanInterface::AllocateRequestId(boardAddress);
CanMessageUpdateHeaterModel * const msg = buf->SetupRequestMessage<CanMessageUpdateHeaterModel>(rid, CanInterface::GetCanAddress(), boardAddress);
- model.SetupCanMessage(GetHeaterNumber(), *msg);
+ GetModel().SetupCanMessage(GetHeaterNumber(), *msg);
return CanInterface::SendRequestAndGetStandardReply(buf, rid, reply);
}
@@ -214,6 +215,29 @@ GCodeResult RemoteHeater::UpdateFaultDetectionParameters(const StringRef& reply)
return GCodeResult::error;
}
+GCodeResult RemoteHeater::UpdateHeaterMonitors(const StringRef& reply) noexcept
+{
+ CanMessageBuffer *buf = CanMessageBuffer::Allocate();
+ if (buf != nullptr)
+ {
+ const CanRequestId rid = CanInterface::AllocateRequestId(boardAddress);
+ CanMessageSetHeaterMonitors * const msg = buf->SetupRequestMessage<CanMessageSetHeaterMonitors>(rid, CanInterface::GetCanAddress(), boardAddress);
+ msg->heater = GetHeaterNumber();
+ msg->numMonitors = MaxMonitorsPerHeater;
+ for (size_t i = 0; i < MaxMonitorsPerHeater; ++i)
+ {
+ msg->monitors[i].limit = monitors[i].GetTemperatureLimit();
+ msg->monitors[i].sensor = monitors[i].GetSensorNumber();
+ msg->monitors[i].action = (uint8_t)monitors[i].GetAction();
+ msg->monitors[i].trigger = (int8_t)monitors[i].GetTrigger();
+ }
+ return CanInterface::SendRequestAndGetStandardReply(buf, rid, reply);
+ }
+
+ reply.copy("No CAN buffer");
+ return GCodeResult::error;
+}
+
void RemoteHeater::UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept
{
if (src == boardAddress)
diff --git a/src/Heating/RemoteHeater.h b/src/Heating/RemoteHeater.h
index dab1b70d..5801fe7e 100644
--- a/src/Heating/RemoteHeater.h
+++ b/src/Heating/RemoteHeater.h
@@ -28,7 +28,7 @@ public:
float GetTemperature() const noexcept override; // Get the current temperature
float GetAveragePWM() const noexcept override; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
float GetAccumulator() const noexcept override; // Return the integral accumulator
- void StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept override; // Start an auto tune cycle for this PID
+ GCodeResult StartAutoTune(float targetTemp, float maxPwm, const StringRef& reply) noexcept override; // Start an auto tune cycle for this PID
void GetAutoTuneStatus(const StringRef& reply) const noexcept override; // Get the auto tune status or last result
void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing
void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override;
@@ -39,6 +39,7 @@ protected:
GCodeResult SwitchOn(const StringRef& reply) noexcept override; // Turn the heater on and set the mode
GCodeResult UpdateModel(const StringRef& reply) noexcept override; // Called when the heater model has been changed
GCodeResult UpdateFaultDetectionParameters(const StringRef& reply) noexcept override;
+ GCodeResult UpdateHeaterMonitors(const StringRef& reply) noexcept override;
private:
static constexpr uint32_t RemoteStatusTimeout = 2000;
diff --git a/src/Heating/Sensors/TemperatureSensor.h b/src/Heating/Sensors/TemperatureSensor.h
index fc522974..7b561c4f 100644
--- a/src/Heating/Sensors/TemperatureSensor.h
+++ b/src/Heating/Sensors/TemperatureSensor.h
@@ -14,6 +14,7 @@ class TemperatureSensor INHERIT_OBJECT_MODEL
{
public:
TemperatureSensor(unsigned int sensorNum, const char *type) noexcept;
+ TemperatureSensor(const TemperatureSensor&) = delete;
// Virtual destructor
virtual ~TemperatureSensor() noexcept;
diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp
index 547bc7b6..05769be7 100644
--- a/src/Networking/Network.cpp
+++ b/src/Networking/Network.cpp
@@ -103,10 +103,11 @@ constexpr ObjectModelArrayDescriptor Network::interfacesArrayDescriptor =
constexpr ObjectModelTableEntry Network::objectModelTable[] =
{
// These entries must be in alphabetical order
- { "interfaces", OBJECT_MODEL_FUNC_NOSELF(&interfacesArrayDescriptor), ObjectModelEntryFlags::none }
+ { "interfaces", OBJECT_MODEL_FUNC_NOSELF(&interfacesArrayDescriptor), ObjectModelEntryFlags::none },
+ { "name", OBJECT_MODEL_FUNC_NOSELF(reprap.GetName()), ObjectModelEntryFlags::none },
};
-constexpr uint8_t Network::objectModelTableDescriptor[] = { 1, 1 };
+constexpr uint8_t Network::objectModelTableDescriptor[] = { 1, 2 };
DEFINE_GET_OBJECT_MODEL_TABLE(Network)
diff --git a/src/Networking/Network.h b/src/Networking/Network.h
index f0e0d5ae..fe7e568b 100644
--- a/src/Networking/Network.h
+++ b/src/Networking/Network.h
@@ -54,6 +54,7 @@ class Network INHERIT_OBJECT_MODEL
{
public:
Network(Platform& p) noexcept;
+ Network(const Network&) = delete;
void Init() noexcept;
void Activate() noexcept;
diff --git a/src/Networking/NetworkInterface.h b/src/Networking/NetworkInterface.h
index bfd88c86..739f19c2 100644
--- a/src/Networking/NetworkInterface.h
+++ b/src/Networking/NetworkInterface.h
@@ -14,6 +14,9 @@
class NetworkInterface INHERIT_OBJECT_MODEL
{
public:
+ NetworkInterface() { }
+ NetworkInterface(const NetworkInterface&) = delete;
+
virtual void Init() noexcept = 0;
virtual void Activate() noexcept = 0;
virtual void Exit() noexcept = 0;
diff --git a/src/Networking/NetworkResponder.h b/src/Networking/NetworkResponder.h
index 0b13089b..ee5aa26d 100644
--- a/src/Networking/NetworkResponder.h
+++ b/src/Networking/NetworkResponder.h
@@ -24,6 +24,8 @@ class Socket;
class NetworkResponder
{
public:
+ NetworkResponder(const NetworkResponder&) = delete;
+
NetworkResponder *GetNext() const noexcept { return next; }
virtual bool Spin() noexcept = 0; // do some work, returning true if we did anything significant
virtual bool Accept(Socket *s, NetworkProtocol protocol) noexcept = 0; // ask the responder to accept this connection, returns true if it did
diff --git a/src/Networking/Socket.h b/src/Networking/Socket.h
index 2cc86cf2..41774670 100644
--- a/src/Networking/Socket.h
+++ b/src/Networking/Socket.h
@@ -23,6 +23,8 @@ class Socket
{
public:
Socket(NetworkInterface *iface) noexcept : interface(iface), localPort(0), remotePort(0), remoteIPAddress(), state(SocketState::disabled) { }
+ Socket(const Socket&) = delete;
+
NetworkInterface *GetInterface() const noexcept { return interface; }
Port GetLocalPort() const noexcept { return localPort; }
diff --git a/src/OutputMemory.h b/src/OutputMemory.h
index 27d12e46..85a411df 100644
--- a/src/OutputMemory.h
+++ b/src/OutputMemory.h
@@ -23,99 +23,100 @@ class OutputStack;
// This class is used to hold data for sending (either for Serial or Network destinations)
class OutputBuffer
{
- public:
- friend class OutputStack;
+public:
+ friend class OutputStack;
- OutputBuffer(OutputBuffer *n) noexcept : next(n) { }
+ OutputBuffer(OutputBuffer *n) noexcept : next(n) { }
+ OutputBuffer(const OutputBuffer&) = delete;
- void Append(OutputBuffer *other) noexcept;
- OutputBuffer *Next() const noexcept { return next; }
- bool IsReferenced() const noexcept { return isReferenced; }
- bool HadOverflow() const noexcept { return hadOverflow; }
- void IncreaseReferences(size_t refs) noexcept;
+ void Append(OutputBuffer *other) noexcept;
+ OutputBuffer *Next() const noexcept { return next; }
+ bool IsReferenced() const noexcept { return isReferenced; }
+ bool HadOverflow() const noexcept { return hadOverflow; }
+ void IncreaseReferences(size_t refs) noexcept;
- const char *Data() const noexcept { return data; }
- const char *UnreadData() const noexcept { return data + bytesRead; }
- size_t DataLength() const noexcept { return dataLength; } // How many bytes have been written to this instance?
- size_t Length() const noexcept; // How many bytes have been written to the whole chain?
+ const char *Data() const noexcept { return data; }
+ const char *UnreadData() const noexcept { return data + bytesRead; }
+ size_t DataLength() const noexcept { return dataLength; } // How many bytes have been written to this instance?
+ size_t Length() const noexcept; // How many bytes have been written to the whole chain?
- char& operator[](size_t index) noexcept;
- char operator[](size_t index) const noexcept;
- const char *Read(size_t len) noexcept;
- void Taken(size_t len) noexcept { bytesRead += len; }
- size_t BytesLeft() const noexcept { return dataLength - bytesRead; } // How many bytes have not been sent yet?
+ char& operator[](size_t index) noexcept;
+ char operator[](size_t index) const noexcept;
+ const char *Read(size_t len) noexcept;
+ void Taken(size_t len) noexcept { bytesRead += len; }
+ size_t BytesLeft() const noexcept { return dataLength - bytesRead; } // How many bytes have not been sent yet?
- size_t printf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
- size_t vprintf(const char *fmt, va_list vargs) noexcept;
- size_t catf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
- size_t lcatf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
+ size_t printf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
+ size_t vprintf(const char *fmt, va_list vargs) noexcept;
+ size_t catf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
+ size_t lcatf(const char *fmt, ...) noexcept __attribute__ ((format (printf, 2, 3)));
- size_t copy(const char c) noexcept;
- size_t copy(const char *src) noexcept;
- size_t copy(const char *src, size_t len) noexcept;
+ size_t copy(const char c) noexcept;
+ size_t copy(const char *src) noexcept;
+ size_t copy(const char *src, size_t len) noexcept;
- size_t cat(const char c) noexcept;
- size_t cat(const char *src) noexcept;
- size_t lcat(const char *src) noexcept;
- size_t cat(const char *src, size_t len) noexcept;
- size_t lcat(const char *src, size_t len) noexcept;
- size_t cat(StringRef &str) noexcept;
+ size_t cat(const char c) noexcept;
+ size_t cat(const char *src) noexcept;
+ size_t lcat(const char *src) noexcept;
+ size_t cat(const char *src, size_t len) noexcept;
+ size_t lcat(const char *src, size_t len) noexcept;
+ size_t cat(StringRef &str) noexcept;
- size_t EncodeString(const char *src, bool allowControlChars, bool prependAsterisk = false) noexcept;
- size_t EncodeChar(char c) noexcept;
+ size_t EncodeString(const char *src, bool allowControlChars, bool prependAsterisk = false) noexcept;
+ size_t EncodeChar(char c) noexcept;
- template<size_t Len> size_t EncodeString(const String<Len>& str, bool allowControlChars, bool prependAsterisk = false) noexcept
- {
- return EncodeString(str.c_str(), allowControlChars, prependAsterisk);
- }
+ template<size_t Len> size_t EncodeString(const String<Len>& str, bool allowControlChars, bool prependAsterisk = false) noexcept
+ {
+ return EncodeString(str.c_str(), allowControlChars, prependAsterisk);
+ }
- size_t EncodeReply(OutputBuffer *src) noexcept;
+ size_t EncodeReply(OutputBuffer *src) noexcept;
- uint32_t GetAge() const noexcept;
+ uint32_t GetAge() const noexcept;
#if HAS_MASS_STORAGE
- // Write the buffer to file returning true if successful
- bool WriteToFile(FileData& f) const noexcept;
+ // Write the buffer to file returning true if successful
+ bool WriteToFile(FileData& f) const noexcept;
#endif
- // Initialise the output buffers manager
- static void Init() noexcept;
+ // Initialise the output buffers manager
+ static void Init() noexcept;
- // Allocate an unused OutputBuffer instance. Returns true on success or false if no instance could be allocated.
- static bool Allocate(OutputBuffer *&buf) noexcept;
+ // Allocate an unused OutputBuffer instance. Returns true on success or false if no instance could be allocated.
+ static bool Allocate(OutputBuffer *&buf) noexcept;
- // Get the number of bytes left for allocation. If writingBuffer is not NULL, this returns the number of free bytes for
- // continuous writes, i.e. for writes that need to allocate an extra OutputBuffer instance to finish the message.
- static size_t GetBytesLeft(const OutputBuffer *writingBuffer) noexcept;
+ // Get the number of bytes left for allocation. If writingBuffer is not NULL, this returns the number of free bytes for
+ // continuous writes, i.e. for writes that need to allocate an extra OutputBuffer instance to finish the message.
+ static size_t GetBytesLeft(const OutputBuffer *writingBuffer) noexcept;
- // Truncate an OutputBuffer instance to free up more memory. Returns the number of released bytes.
- static size_t Truncate(OutputBuffer *buffer, size_t bytesNeeded) noexcept;
+ // Truncate an OutputBuffer instance to free up more memory. Returns the number of released bytes.
+ static size_t Truncate(OutputBuffer *buffer, size_t bytesNeeded) noexcept;
- // Release one OutputBuffer instance. Returns the next item from the chain or nullptr if this was the last instance.
- static OutputBuffer *Release(OutputBuffer *buf) noexcept;
+ // Release one OutputBuffer instance. Returns the next item from the chain or nullptr if this was the last instance.
+ static OutputBuffer *Release(OutputBuffer *buf) noexcept;
- // Release all OutputBuffer objects in a chain
- static void ReleaseAll(OutputBuffer * volatile &buf) noexcept;
+ // Release all OutputBuffer objects in a chain
+ static void ReleaseAll(OutputBuffer * volatile &buf) noexcept;
- static void Diagnostics(MessageType mtype) noexcept;
+ static void Diagnostics(MessageType mtype) noexcept;
- static unsigned int GetFreeBuffers() { return OUTPUT_BUFFER_COUNT - usedOutputBuffers; }
+ static unsigned int GetFreeBuffers() { return OUTPUT_BUFFER_COUNT - usedOutputBuffers; }
- private:
- OutputBuffer *next;
- OutputBuffer *last;
+private:
+ OutputBuffer *next;
+ OutputBuffer *last;
- uint32_t whenQueued;
+ uint32_t whenQueued;
- char data[OUTPUT_BUFFER_SIZE];
- size_t dataLength, bytesRead;
+ char data[OUTPUT_BUFFER_SIZE];
+ size_t dataLength, bytesRead;
- bool isReferenced;
- bool hadOverflow;
- volatile size_t references;
+ bool isReferenced;
+ bool hadOverflow;
+ volatile size_t references;
- static OutputBuffer * volatile freeOutputBuffers; // Messages may be sent by multiple tasks
- static volatile size_t usedOutputBuffers; // so make these volatile.
- static volatile size_t maxUsedOutputBuffers;
+ static OutputBuffer * volatile freeOutputBuffers; // Messages may be sent by multiple tasks
+ static volatile size_t usedOutputBuffers; // so make these volatile.
+ static volatile size_t maxUsedOutputBuffers;
};
inline uint32_t OutputBuffer::GetAge() const noexcept
@@ -127,60 +128,61 @@ inline uint32_t OutputBuffer::GetAge() const noexcept
// Note that OutputStack objects should normally be declared volatile.
class OutputStack
{
- public:
- OutputStack() noexcept : count(0) { }
+public:
+ OutputStack() noexcept : count(0) { }
+ OutputStack(const OutputStack&) = delete;
- // Is there anything on this stack?
- bool IsEmpty() const volatile noexcept { return count == 0; }
+ // Is there anything on this stack?
+ bool IsEmpty() const volatile noexcept { return count == 0; }
- // Clear the reference list
- void Clear() volatile noexcept { count = 0; }
+ // Clear the reference list
+ void Clear() volatile noexcept { count = 0; }
- // Push an OutputBuffer chain. Return true if successful, else release the buffer and return false.
- bool Push(OutputBuffer *buffer, MessageType type = NoDestinationMessage) volatile noexcept;
+ // Push an OutputBuffer chain. Return true if successful, else release the buffer and return false.
+ bool Push(OutputBuffer *buffer, MessageType type = NoDestinationMessage) volatile noexcept;
- // Pop an OutputBuffer chain or return NULL if none is available
- OutputBuffer *Pop() volatile noexcept;
+ // Pop an OutputBuffer chain or return NULL if none is available
+ OutputBuffer *Pop() volatile noexcept;
- // Returns the first item from the stack or NULL if none is available
- OutputBuffer *GetFirstItem() const volatile noexcept;
+ // Returns the first item from the stack or NULL if none is available
+ OutputBuffer *GetFirstItem() const volatile noexcept;
- // Returns the first item's type from the stack or NoDestinationMessage if none is available
- MessageType GetFirstItemType() const volatile noexcept;
+ // Returns the first item's type from the stack or NoDestinationMessage if none is available
+ MessageType GetFirstItemType() const volatile noexcept;
#if HAS_LINUX_INTERFACE
- // Set the first item of the stack. If it's NULL, then the first item will be removed
- void SetFirstItem(OutputBuffer *buffer) volatile noexcept;
+ // Set the first item of the stack. If it's NULL, then the first item will be removed
+ void SetFirstItem(OutputBuffer *buffer) volatile noexcept;
#endif
- // Release the first item at the top of the stack
- void ReleaseFirstItem() volatile noexcept;
+ // Release the first item at the top of the stack
+ void ReleaseFirstItem() volatile noexcept;
- // Apply a timeout to the first item at the top of the stack
- bool ApplyTimeout(uint32_t ticks) volatile noexcept;
+ // Apply a timeout to the first item at the top of the stack
+ bool ApplyTimeout(uint32_t ticks) volatile noexcept;
- // Returns the last item from the stack or NULL if none is available
- OutputBuffer *GetLastItem() const volatile noexcept;
+ // Returns the last item from the stack or NULL if none is available
+ OutputBuffer *GetLastItem() const volatile noexcept;
- // Returns the type of the last item from the stack or NoDestinationMessage if none is available
- MessageType GetLastItemType() const volatile noexcept;
+ // Returns the type of the last item from the stack or NoDestinationMessage if none is available
+ MessageType GetLastItemType() const volatile noexcept;
- // Get the total length of all queued buffers
- size_t DataLength() const volatile noexcept;
+ // Get the total length of all queued buffers
+ size_t DataLength() const volatile noexcept;
- // Append another OutputStack to this instance. If no more space is available,
- // all OutputBuffers that can't be added are automatically released
- void Append(volatile OutputStack& stack) volatile noexcept;
+ // Append another OutputStack to this instance. If no more space is available,
+ // all OutputBuffers that can't be added are automatically released
+ void Append(volatile OutputStack& stack) volatile noexcept;
- // Increase the number of references for each OutputBuffer on the stack
- void IncreaseReferences(size_t num) volatile noexcept;
+ // Increase the number of references for each OutputBuffer on the stack
+ void IncreaseReferences(size_t num) volatile noexcept;
- // Release all buffers and clean up
- void ReleaseAll() volatile noexcept;
+ // Release all buffers and clean up
+ void ReleaseAll() volatile noexcept;
- private:
- size_t count;
- OutputBuffer * items[OUTPUT_STACK_DEPTH];
- MessageType types[OUTPUT_STACK_DEPTH];
+private:
+ size_t count;
+ OutputBuffer * items[OUTPUT_STACK_DEPTH];
+ MessageType types[OUTPUT_STACK_DEPTH];
};
#endif /* OUTPUTMEMORY_H_ */
diff --git a/src/Pccb/Pins_Pccb.h b/src/Pccb/Pins_Pccb.h
index d80f248c..97d29283 100644
--- a/src/Pccb/Pins_Pccb.h
+++ b/src/Pccb/Pins_Pccb.h
@@ -91,7 +91,7 @@ constexpr size_t MaxSmartDrivers = 2; // The maximum number of smart drivers
constexpr size_t MaxSensors = 32;
constexpr size_t MaxHeaters = 1; // The number of heaters in the machine. PCCB has no heaters.
-constexpr size_t MaxExtraHeaterProtections = 4; // The number of extra heater protection instances
+constexpr size_t MaxMonitorsPerHeater = 3; // The maximum number of monitors per heater
constexpr size_t MaxBedHeaters = 1;
constexpr size_t MaxChamberHeaters = 1;
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index b55244e4..365ad8e5 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -181,9 +181,18 @@ constexpr ObjectModelTableEntry RepRap::objectModelTable[] =
{ "axes", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxAxes), ObjectModelEntryFlags::verbose },
{ "axesPlusExtruders", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxAxesPlusExtruders), ObjectModelEntryFlags::verbose },
{ "bedHeaters", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxBedHeaters), ObjectModelEntryFlags::verbose },
+#if SUPPORT_CAN_EXPANSION
+ { "boards", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxCanBoards + 1), ObjectModelEntryFlags::verbose },
+#else
+ { "boards", OBJECT_MODEL_FUNC_NOSELF((int32_t)1), ObjectModelEntryFlags::verbose },
+#endif
{ "chamberHeaters", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxChamberHeaters), ObjectModelEntryFlags::verbose },
+#if SUPPORT_CAN_EXPANSION
+ { "drivers", OBJECT_MODEL_FUNC_NOSELF((int32_t)(NumDirectDrivers + MaxCanDrivers)), ObjectModelEntryFlags::verbose },
+#else
+ { "drivers", OBJECT_MODEL_FUNC_NOSELF((int32_t)NumDirectDrivers), ObjectModelEntryFlags::verbose },
+#endif
{ "driversPerAxis", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxDriversPerAxis), ObjectModelEntryFlags::verbose },
- { "extraHeaterProtections", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxExtraHeaterProtections), ObjectModelEntryFlags::verbose },
{ "extruders", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxExtruders), ObjectModelEntryFlags::verbose },
{ "extrudersPerTool", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxExtrudersPerTool), ObjectModelEntryFlags::verbose },
{ "fans", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxFans), ObjectModelEntryFlags::verbose },
@@ -191,6 +200,7 @@ constexpr ObjectModelTableEntry RepRap::objectModelTable[] =
{ "gpOutPorts", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxGpOutPorts), ObjectModelEntryFlags::verbose },
{ "heaters", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxHeaters), ObjectModelEntryFlags::verbose },
{ "heatersPerTool", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxHeatersPerTool), ObjectModelEntryFlags::verbose },
+ { "monitorsPerHeater", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxMonitorsPerHeater), ObjectModelEntryFlags::verbose },
{ "sensors", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxSensors), ObjectModelEntryFlags::verbose },
{ "spindles", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxSpindles), ObjectModelEntryFlags::verbose },
{ "triggers", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxTriggers), ObjectModelEntryFlags::verbose },
@@ -198,7 +208,7 @@ constexpr ObjectModelTableEntry RepRap::objectModelTable[] =
{ "zProbes", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxZProbes), ObjectModelEntryFlags::verbose },
};
-constexpr uint8_t RepRap::objectModelTableDescriptor[] = { 3, 10, 5, 18 };
+constexpr uint8_t RepRap::objectModelTableDescriptor[] = { 3, 10, 5, 20 };
DEFINE_GET_OBJECT_MODEL_TABLE(RepRap)
diff --git a/src/RepRap.h b/src/RepRap.h
index 85b6a63d..0561bbc9 100644
--- a/src/RepRap.h
+++ b/src/RepRap.h
@@ -61,6 +61,8 @@ class RepRap INHERIT_OBJECT_MODEL
{
public:
RepRap() noexcept;
+ RepRap(const RepRap&) = delete;
+
void EmergencyStop() noexcept;
void Init() noexcept;
void Spin() noexcept;
diff --git a/src/Tools/Tool.cpp b/src/Tools/Tool.cpp
index 0aab2ae7..36d81f2b 100644
--- a/src/Tools/Tool.cpp
+++ b/src/Tools/Tool.cpp
@@ -361,8 +361,17 @@ void Tool::Activate() noexcept
{
for (size_t heater = 0; heater < heaterCount; heater++)
{
- reprap.GetHeat().SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
- reprap.GetHeat().SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
+ try
+ {
+ reprap.GetHeat().SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
+ reprap.GetHeat().SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
+ }
+ catch (GCodeException& exc)
+ {
+ String<StringLength100> message;
+ exc.GetMessage(message.GetRef(), nullptr);
+ reprap.GetPlatform().Message(ErrorMessage, message.c_str());
+ }
String<1> dummy;
(void)reprap.GetHeat().Activate(heaters[heater], dummy.GetRef());
}
@@ -377,8 +386,17 @@ void Tool::Standby() noexcept
// Don't switch a heater to standby if the active tool is using it and is different from this tool
if (currentTool == this || currentTool == nullptr || !currentTool->UsesHeater(heater))
{
- reprap.GetHeat().SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
- reprap.GetHeat().Standby(heaters[heater], this);
+ try
+ {
+ reprap.GetHeat().SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
+ reprap.GetHeat().Standby(heaters[heater], this);
+ }
+ catch (GCodeException& exc)
+ {
+ String<StringLength100> message;
+ exc.GetMessage(message.GetRef(), nullptr);
+ reprap.GetPlatform().Message(ErrorMessage, message.c_str());
+ }
}
}
state = ToolState::standby;
@@ -494,10 +512,11 @@ float Tool::GetToolHeaterStandbyTemperature(size_t heaterNumber) const noexcept
return (heaterNumber < heaterCount) ? standbyTemperatures[heaterNumber] : 0.0;
}
-void Tool::SetToolHeaterActiveTemperature(size_t heaterNumber, float temp) noexcept
+void Tool::SetToolHeaterActiveTemperature(size_t heaterNumber, float temp) THROWS(GCodeException)
{
if (heaterNumber < heaterCount)
{
+ const int8_t heater = heaters[heaterNumber];
const Tool * const currentTool = reprap.GetCurrentTool();
const bool setHeater = (currentTool == nullptr || currentTool == this);
if (temp < NEARLY_ABS_ZERO) // temperatures close to ABS_ZERO turn off the heater
@@ -505,26 +524,26 @@ void Tool::SetToolHeaterActiveTemperature(size_t heaterNumber, float temp) noexc
activeTemperatures[heaterNumber] = 0;
if (setHeater)
{
- reprap.GetHeat().SwitchOff(heaters[heaterNumber]);
+ reprap.GetHeat().SwitchOff(heater);
}
}
else
{
- const float minTemperatureLimit = reprap.GetHeat().GetLowestTemperatureLimit(heaters[heaterNumber]);
- const float maxTemperatureLimit = reprap.GetHeat().GetHighestTemperatureLimit(heaters[heaterNumber]);
+ const float minTemperatureLimit = reprap.GetHeat().GetLowestTemperatureLimit(heater);
+ const float maxTemperatureLimit = reprap.GetHeat().GetHighestTemperatureLimit(heater);
if (temp > minTemperatureLimit && temp < maxTemperatureLimit)
{
activeTemperatures[heaterNumber] = temp;
if (setHeater)
{
- reprap.GetHeat().SetActiveTemperature(heaters[heaterNumber], activeTemperatures[heaterNumber]);
+ reprap.GetHeat().SetActiveTemperature(heater, activeTemperatures[heaterNumber]);
}
}
}
}
}
-void Tool::SetToolHeaterStandbyTemperature(size_t heaterNumber, float temp) noexcept
+void Tool::SetToolHeaterStandbyTemperature(size_t heaterNumber, float temp) THROWS(GCodeException)
{
if (heaterNumber < heaterCount)
{
diff --git a/src/Tools/Tool.h b/src/Tools/Tool.h
index d70d429f..c64388e1 100644
--- a/src/Tools/Tool.h
+++ b/src/Tools/Tool.h
@@ -83,8 +83,8 @@ public:
float GetToolHeaterActiveTemperature(size_t heaterNumber) const noexcept;
float GetToolHeaterStandbyTemperature(size_t heaterNumber) const noexcept;
- void SetToolHeaterActiveTemperature(size_t heaterNumber, float temp) noexcept;
- void SetToolHeaterStandbyTemperature(size_t heaterNumber, float temp) noexcept;
+ void SetToolHeaterActiveTemperature(size_t heaterNumber, float temp) THROWS(GCodeException);
+ void SetToolHeaterStandbyTemperature(size_t heaterNumber, float temp) THROWS(GCodeException);
bool HasTemperatureFault() const noexcept { return heaterFault; }
diff --git a/src/Version.h b/src/Version.h
index 7562c680..1ff557a7 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -19,7 +19,7 @@
#endif
#ifndef DATE
-# define DATE "2020-02-12b1"
+# define DATE "2020-02-16b1"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d"