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

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2021-12-11 18:58:29 +0300
committerDavid Crocker <dcrocker@eschertech.com>2021-12-11 18:58:29 +0300
commited0e7929e05f96c431397495e332f190f72b5915 (patch)
tree029573d68262786249b66f7cbe7a5cbd9d571872
parent289d2f286a3fdf084c325d4db87f8075c154df6a (diff)
Added most of the event handling code
-rw-r--r--src/CAN/CommandProcessor.cpp4
-rw-r--r--src/FilamentMonitors/FilamentMonitor.cpp63
-rw-r--r--src/FilamentMonitors/FilamentMonitor.h1
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.cpp2
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp2
-rw-r--r--src/GCodes/GCodeMachineState.h2
-rw-r--r--src/GCodes/GCodes.cpp20
-rw-r--r--src/GCodes/GCodes.h1
-rw-r--r--src/GCodes/GCodes3.cpp34
-rw-r--r--src/GCodes/GCodes4.cpp35
-rw-r--r--src/Heating/LocalHeater.cpp38
-rw-r--r--src/Heating/LocalHeater.h2
-rw-r--r--src/ObjectModel/Variable.h1
-rw-r--r--src/Platform/Event.cpp192
-rw-r--r--src/Platform/Event.h64
-rw-r--r--src/Platform/EventManager.cpp14
-rw-r--r--src/Platform/EventManager.h23
-rw-r--r--src/Platform/Logger.h2
-rw-r--r--src/Platform/MessageType.h3
-rw-r--r--src/Platform/Platform.h2
20 files changed, 350 insertions, 155 deletions
diff --git a/src/CAN/CommandProcessor.cpp b/src/CAN/CommandProcessor.cpp
index b4816351..43d99b58 100644
--- a/src/CAN/CommandProcessor.cpp
+++ b/src/CAN/CommandProcessor.cpp
@@ -419,6 +419,10 @@ void CommandProcessor::ProcessReceivedMessage(CanMessageBuffer *buf) noexcept
return; // no reply needed
#endif
+ case CanMessageType::acknowledgeAnnounce:
+ CanInterface::MainBoardAcknowledgedAnnounce();
+ return;
+
case CanMessageType::returnInfo:
requestId = buf->msg.getInfo.requestId;
rslt = EutGetInfo(buf->msg.getInfo, replyRef, extra);
diff --git a/src/FilamentMonitors/FilamentMonitor.cpp b/src/FilamentMonitors/FilamentMonitor.cpp
index 95e68357..9cf6b686 100644
--- a/src/FilamentMonitors/FilamentMonitor.cpp
+++ b/src/FilamentMonitors/FilamentMonitor.cpp
@@ -12,6 +12,7 @@
#include "PulsedFilamentMonitor.h"
#include <Platform/RepRap.h>
#include <Platform/Platform.h>
+#include <Platform/Event.h>
#include <GCodes/GCodeBuffer/GCodeBuffer.h>
#include <Movement/Move.h>
#include <PrintMonitor/PrintMonitor.h>
@@ -53,7 +54,7 @@ size_t FilamentMonitor::GetNumMonitorsToReport() noexcept
FilamentMonitor::FilamentMonitor(unsigned int drv, unsigned int monitorType, DriverId did) noexcept
: driveNumber(drv), type(monitorType), driverId(did), lastStatus(FilamentSensorStatus::noDataReceived)
#if SUPPORT_CAN_EXPANSION
- , hasRemote(false)
+ , lastRemoteStatus(FilamentSensorStatus::noDataReceived), hasRemote(false)
#endif
{
}
@@ -298,7 +299,6 @@ bool FilamentMonitor::IsValid(size_t extruderNumber) const noexcept
fromIsr = false;
locIsrMillis = 0;
}
-
GCodes& gCodes = reprap.GetGCodes();
if (gCodes.IsReallyPrinting() && !gCodes.IsSimulating())
{
@@ -309,28 +309,35 @@ bool FilamentMonitor::IsValid(size_t extruderNumber) const noexcept
{
fst = fs.Clear();
}
-
- if (fst != fs.lastStatus)
- {
+ }
+#if SUPPORT_CAN_EXPANSION
+ else
+ {
+ fst = fs.lastRemoteStatus;
+ }
+#endif
+ if (fst != fs.lastStatus)
+ {
#if SUPPORT_REMOTE_COMMANDS
- statusChanged = true;
+ statusChanged = true;
#endif
- fs.lastStatus = fst;
- if (fst != FilamentSensorStatus::ok
+ fs.lastStatus = fst;
+ if (fst != FilamentSensorStatus::ok
#if SUPPORT_REMOTE_COMMANDS
- && !CanInterface::InExpansionMode()
+ && !CanInterface::InExpansionMode()
#endif
- )
+ )
+ {
+ const size_t extruder = LogicalDriveToExtruder(fs.driveNumber);
+ if (reprap.Debug(moduleFilamentSensors))
+ {
+ debugPrintf("Filament error: extruder %u reports %s\n", extruder, fst.ToString());
+ }
+ else
{
- const size_t extruder = LogicalDriveToExtruder(fs.driveNumber);
- if (reprap.Debug(moduleFilamentSensors))
- {
- debugPrintf("Filament error: extruder %u reports %s\n", extruder, fst.ToString());
- }
- else
- {
- gCodes.FilamentError(extruder, fst);
- }
+ va_list dummy;
+ Event::AddEvent(EventType::filament_error, (uint16_t)fst.ToBaseType(), extruder, CanInterface::GetCanAddress(), "", dummy);
+// gCodes.FilamentError(extruder, fst);
}
}
}
@@ -367,23 +374,7 @@ bool FilamentMonitor::IsValid(size_t extruderNumber) const noexcept
FilamentMonitor& fs = *filamentSensors[extruder];
if (fs.driverId.boardAddress == src && fs.driverId.localDriver < msg.numMonitorsReported)
{
- const FilamentSensorStatus fstat(msg.data[fs.driverId.localDriver].status);
- fs.lastStatus = fstat;
- GCodes& gCodes = reprap.GetGCodes();
- if (gCodes.IsReallyPrinting() && !gCodes.IsSimulating())
- {
- if (fstat != FilamentSensorStatus::ok)
- {
- if (reprap.Debug(moduleFilamentSensors))
- {
- debugPrintf("Filament error: extruder %u reports %s\n", extruder, fstat.ToString());
- }
- else
- {
- gCodes.FilamentError(extruder, fstat);
- }
- }
- }
+ fs.lastRemoteStatus = FilamentSensorStatus(msg.data[fs.driverId.localDriver].status);
}
}
}
diff --git a/src/FilamentMonitors/FilamentMonitor.h b/src/FilamentMonitors/FilamentMonitor.h
index af7d6bea..4f0cc406 100644
--- a/src/FilamentMonitors/FilamentMonitor.h
+++ b/src/FilamentMonitors/FilamentMonitor.h
@@ -164,6 +164,7 @@ private:
bool haveIsrStepsCommanded;
FilamentSensorStatus lastStatus;
#if SUPPORT_CAN_EXPANSION
+ FilamentSensorStatus lastRemoteStatus;
bool hasRemote;
#endif
};
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp
index 954c4e29..b1e8e4fa 100644
--- a/src/GCodes/GCodeBuffer/BinaryParser.cpp
+++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp
@@ -873,7 +873,7 @@ void BinaryParser::AddParameters(VariableSet& vs, int codeRunning) noexcept
if (ev.GetType() != TypeCode::None)
{
char paramName[2] = { param->letter, 0 };
- vs.InsertNew(paramName, ev, -1);
+ vs.InsertNewParameter(paramName, ev);
}
}
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index 24a6aaa3..78669752 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -1914,7 +1914,7 @@ void StringParser::AddParameters(VariableSet& vs, int codeRunning) noexcept
ev.Set(nullptr);
}
char paramName[2] = { letter, 0 };
- vs.InsertNew(paramName, ev, -1);
+ vs.InsertNewParameter(paramName, ev);
}
}
);
diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h
index 3ea86bce..c5ec5bbb 100644
--- a/src/GCodes/GCodeMachineState.h
+++ b/src/GCodes/GCodeMachineState.h
@@ -109,6 +109,8 @@ enum class GCodeState : uint8_t
unloadingFilament,
checkError, // go to this state after doing a macro when we need to check for a stored error message
+ processingEvent,
+ finishedProcessingEvent,
#if HAS_MASS_STORAGE
timingSDwrite,
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 902c0ac0..01291c3f 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -34,6 +34,7 @@
#include <PrintMonitor/PrintMonitor.h>
#include <Platform/RepRap.h>
#include <Platform/Tasks.h>
+#include <Platform/Event.h>
#include <Tools/Tool.h>
#include <Endstops/ZProbe.h>
#include <ObjectModel/Variable.h>
@@ -573,6 +574,13 @@ bool GCodes::StartNextGCode(GCodeBuffer& gb, const StringRef& reply) noexcept
{
return DoFilePrint(gb, reply);
}
+ else if (&gb == autoPauseGCode)
+ {
+ if (Event::StartProcessing())
+ {
+ ProcessEvent(gb); // call out to separate function to avoid increasing stack usage of this function
+ }
+ }
else if (&gb == daemonGCode
#if SUPPORT_REMOTE_COMMANDS
&& !CanInterface::InExpansionMode() // looking for the daemon.g file increases the loop time too much
@@ -967,8 +975,8 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint1
FileData& fdata = fileGCode->LatestMachineState().fileState;
if (fdata.IsLive())
{
- fileGCode->RestartFrom(pauseRestorePoint.filePos); // TODO we ought to restore the line number too, but currently we don't save it
- UnlockAll(*fileGCode); // release any locks it had
+ fileGCode->RestartFrom(pauseRestorePoint.filePos); // TODO we ought to restore the line number too, but currently we don't save it
+ UnlockAll(*fileGCode); // release any locks it had
}
}
#endif
@@ -1317,7 +1325,7 @@ bool GCodes::ReHomeOnStall(DriversBitmap stalledDrivers) noexcept
if (cfg.driverNumbers[i].IsLocal() && stalledDrivers.IsBitSet(cfg.driverNumbers[i].localDriver))
{
char str[2] = { axisLetters[axis], 0 };
- vars.InsertNew(str, ExpressionValue((int32_t)1), -1); // create a parameter with value 1 for the axis
+ vars.InsertNewParameter(str, ExpressionValue((int32_t)1)); // create a parameter with value 1 for the axis
break;
}
}
@@ -3357,7 +3365,7 @@ GCodeResult GCodes::DoDwell(GCodeBuffer& gb) THROWS(GCodeException)
}
#endif
- if ( IsSimulating() // if we are simulating then simulate the G4...
+ if ( IsSimulating() // if we are simulating then simulate the G4...
&& &gb != daemonGCode // ...unless it comes from the daemon...
&& &gb != triggerGCode // ...or a trigger...
&& (&gb == fileGCode || !exitSimulationWhenFileComplete) // ...or we are simulating a file and this command doesn't come from the file
@@ -4689,7 +4697,7 @@ void GCodes::CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const noexc
// Send a standard status response for PanelDue
OutputBuffer * const statusBuf =
(lastAuxStatusReportType == ObjectModelAuxStatusReportType) // PanelDueFirmware v3.2 or later, using M409 to retrieve object model
- ? reprap.GetModelResponse("", "d99f")
+ ? reprap.GetModelResponse("", "d99fi")
: GenerateJsonStatusResponse(lastAuxStatusReportType, -1, ResponseSource::AUX); // older PanelDueFirmware using M408
if (statusBuf != nullptr)
{
@@ -4891,7 +4899,7 @@ void GCodes::HandleHeaterFault() noexcept
}
}
-// Check for and respond to a heater fault, returning true if we should exit
+// Check for and respond to a heater fault
void GCodes::CheckHeaterFault() noexcept
{
switch (heaterFaultState)
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index e504f742..3cbddcaa 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -462,6 +462,7 @@ private:
void DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint16_t param = 0) noexcept // Pause the print
pre(resourceOwners[movementResource] == &gb);
void CheckForDeferredPause(GCodeBuffer& gb) noexcept; // Check if a pause is pending, action it if so
+ void ProcessEvent(GCodeBuffer& gb) noexcept; // Start processing a new event
#if HAS_VOLTAGE_MONITOR || HAS_SMART_DRIVERS
bool DoEmergencyPause() noexcept; // Do an emergency pause following loss of power or a motor stall
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 0a13640b..f321cf0d 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -12,6 +12,7 @@
#include <Heating/Heat.h>
#include <Movement/Move.h>
#include <Platform/RepRap.h>
+#include <Platform/Event.h>
#include <Tools/Tool.h>
#include <Endstops/ZProbe.h>
#include <PrintMonitor/PrintMonitor.h>
@@ -1863,6 +1864,37 @@ bool GCodes::ProcessWholeLineComment(GCodeBuffer& gb, const StringRef& reply) TH
return true;
}
+// Process and event. The autoPauseGCode buffer calls this when there is a new event to be processed.
+// This is a separate function because it allocates strings on the stack.
+void GCodes::ProcessEvent(GCodeBuffer& gb) noexcept
+{
+ // Get the event message
+ String<StringLength100> eventText;
+ const MessageType mt = Event::GetTextDescription(eventText.GetRef());
+ platform.Message(mt, eventText.c_str()); // tell the user about the event and log it
+
+ // Get the name of the macro file that we should look for
+ String<StringLength50> macroName;
+ Event::GetMacroFileName(macroName.GetRef());
+ if (platform.SysFileExists(macroName.c_str()))
+ {
+ // Set up the macro parameters
+ VariableSet vars;
+ Event::GetParameters(vars);
+ vars.InsertNewParameter("S", ExpressionValue(StringHandle(eventText.c_str())));
+
+ // Run the macro
+ gb.SetState(GCodeState::finishedProcessingEvent); // cancel the event when we have finished processing it
+ if (DoFileMacro(gb, macroName.c_str(), false, AsyncSystemMacroCode, vars))
+ {
+ return;
+ }
+ }
+
+ // We didn't execute the macro, so do the default action. It may need to wait for the movement lock, so do it in a new state.
+ gb.SetState(GCodeState::processingEvent);
+}
+
#if !HAS_MASS_STORAGE && !HAS_EMBEDDED_FILES && defined(DUET_NG)
// Function called by RepRap.cpp to enable PanelDue by default in the Duet 2 SBC build
@@ -1873,4 +1905,4 @@ void GCodes::SetAux0CommsProperties(uint32_t mode) const noexcept
#endif
- // End
+// End
diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp
index f2ccb6b5..961728f9 100644
--- a/src/GCodes/GCodes4.cpp
+++ b/src/GCodes/GCodes4.cpp
@@ -3,6 +3,7 @@
#include "GCodes.h"
#include "GCodeBuffer/GCodeBuffer.h"
#include <Platform/RepRap.h>
+#include <Platform/Event.h>
#include <Movement/Move.h>
#include <Tools/Tool.h>
#include <Heating/Heat.h>
@@ -1482,6 +1483,40 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept
gb.SetState(GCodeState::normal);
break;
+ // Here when we need to execute the default action for an event because the macro file was not found. We have already sent a message and logged the event.
+ case GCodeState::processingEvent:
+ {
+ const Event::DefaultAction action = Event::GetDefaultAction();
+ if (action == Event::DefaultAction::none)
+ {
+ // Nothing more to do
+ gb.SetState(GCodeState::finishedProcessingEvent);
+ }
+ else
+ {
+ // We are going to pause
+ if (pauseState != PauseState::resuming) // if we are resuming, wait for the resume to complete
+ {
+ if (pauseState != PauseState::notPaused)
+ {
+ gb.SetState(GCodeState::finishedProcessingEvent); // already paused
+ }
+ else if (LockMovementAndWaitForStandstill(gb))
+ {
+ gb.SetState(GCodeState::finishedProcessingEvent);
+ DoPause(gb, qq);
+ }
+ }
+ }
+ }
+ break;
+
+ // Here when we have finished processing an event
+ case GCodeState::finishedProcessingEvent:
+ Event::FinishedProcessing();
+ gb.SetState(GCodeState::normal);
+ break;
+
default: // should not happen
gb.LatestMachineState().SetError("Undefined GCodeState");
gb.SetState(GCodeState::normal);
diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp
index b105d6ea..4f21b246 100644
--- a/src/Heating/LocalHeater.cpp
+++ b/src/Heating/LocalHeater.cpp
@@ -12,6 +12,7 @@
#include "HeaterMonitor.h"
#include <Platform/Platform.h>
#include <Platform/RepRap.h>
+#include <Platform/Event.h>
#include <Tools/Tool.h>
#if SUPPORT_REMOTE_COMMANDS
@@ -252,7 +253,7 @@ void LocalHeater::Spin() noexcept
badTemperatureCount++;
if (badTemperatureCount > MaxBadTemperatureCount)
{
- RaiseHeaterFault("Temperature reading fault on heater %u: %s\n", GetHeaterNumber(), TemperatureErrorString(err));
+ RaiseHeaterFault(HeaterFaultType::failedToReadSensor, "%s", TemperatureErrorString(err));
}
}
// We leave lastPWM alone if we have a temporary temperature reading error
@@ -297,7 +298,7 @@ void LocalHeater::Spin() noexcept
else
{
const uint32_t now = millis();
- if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 1.5)
+ if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 2) // wait for twice the dead time before we start looking at the temperature rise
{
// Record the temperature for when we are past the dead time
lastTemperatureValue = temperature;
@@ -313,13 +314,14 @@ void LocalHeater::Spin() noexcept
// Check that we are heating fast enough, and if so, take another sample
const float expectedTemperatureRise = expectedRate * actualInterval;
const float actualTemperatureRise = temperature - lastTemperatureValue;
- if (actualTemperatureRise < expectedTemperatureRise * 0.7)
+ if (actualTemperatureRise < expectedTemperatureRise * 0.5)
{
++heatingFaultCount;
if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis)
{
- RaiseHeaterFault("Heater %u fault: at %.1f" DEGREE_SYMBOL "C temperature is rising at %.1f" DEGREE_SYMBOL "C/sec, well below the expected %.1f" DEGREE_SYMBOL "C/sec\n",
- GetHeaterNumber(), (double)temperature, (double)(actualTemperatureRise/actualInterval), (double)expectedRate);
+ RaiseHeaterFault(HeaterFaultType::temperatureRisingTooSlowly,
+ "expected %.2f" DEGREE_SYMBOL "C/sec measured %.2f" DEGREE_SYMBOL "C/sec",
+ (double)expectedRate, (double)(actualTemperatureRise/actualInterval));
}
}
else
@@ -343,8 +345,9 @@ void LocalHeater::Spin() noexcept
++heatingFaultCount;
if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis)
{
- RaiseHeaterFault("Heater %u fault: temperature excursion exceeded %.1f" DEGREE_SYMBOL "C (target %.1f" DEGREE_SYMBOL "C, actual %.1f" DEGREE_SYMBOL "C)\n",
- GetHeaterNumber(), (double)GetMaxTemperatureExcursion(), (double)targetTemperature, (double)temperature);
+ RaiseHeaterFault(HeaterFaultType::exceededAllowedExcursion,
+ "target %.1f" DEGREE_SYMBOL "C actual %.1f" DEGREE_SYMBOL "C",
+ (double)targetTemperature, (double)temperature);
}
}
else if (heatingFaultCount != 0)
@@ -450,7 +453,7 @@ void LocalHeater::Spin() noexcept
break;
case HeaterMonitorAction::GenerateFault:
- RaiseHeaterFault("Heater %u fault: heater monitor %u was triggered\n", GetHeaterNumber(), i);
+ RaiseHeaterFault(HeaterFaultType::monitorTriggered, "monitor %u was triggered", i);
break;
case HeaterMonitorAction::TemporarySwitchOff:
@@ -910,20 +913,31 @@ void LocalHeater::Suspend(bool sus) noexcept
}
}
-void LocalHeater::RaiseHeaterFault(const char *format, ...) noexcept
+void LocalHeater::RaiseHeaterFault(HeaterFaultType type, const char *_ecv_array format, ...) noexcept
{
lastPwm = 0.0;
SetHeater(0.0);
if (mode != HeaterMode::fault)
{
mode = HeaterMode::fault;
+ reprap.FlagTemperatureFault(GetHeaterNumber());
+
va_list vargs;
va_start(vargs, format);
- reprap.GetPlatform().MessageV(ErrorMessage, format, vargs);
+
+#if SUPPORT_REMOTE_COMMANDS
+ if (CanInterface::InExpansionMode())
+ {
+ CanInterface::RaiseEvent(EventType::heater_fault, (uint16_t)type, GetHeaterNumber(), format, vargs);
+ }
+ else
+#endif
+ {
+ Event::AddEvent(EventType::heater_fault, (uint16_t)type, GetHeaterNumber(), CanInterface::GetCanAddress(), format, vargs);
+ }
va_end(vargs);
+// reprap.GetGCodes().HandleHeaterFault();
}
- reprap.GetGCodes().HandleHeaterFault();
- reprap.FlagTemperatureFault(GetHeaterNumber());
}
#if SUPPORT_REMOTE_COMMANDS
diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h
index fd31dde9..cf0840c5 100644
--- a/src/Heating/LocalHeater.h
+++ b/src/Heating/LocalHeater.h
@@ -66,7 +66,7 @@ private:
TemperatureError ReadTemperature() noexcept; // Read and store the temperature of this heater
void DoTuningStep() noexcept; // Called on each temperature sample when auto tuning
float GetExpectedHeatingRate() const noexcept; // Get the minimum heating rate we expect
- void RaiseHeaterFault(const char *format, ...) noexcept;
+ void RaiseHeaterFault(HeaterFaultType type, const char *_ecv_array format, ...) noexcept;
PwmPort ports[MaxPortsPerHeater]; // The port(s) that drive the heater
float temperature; // The current temperature
diff --git a/src/ObjectModel/Variable.h b/src/ObjectModel/Variable.h
index e107faaa..2b104608 100644
--- a/src/ObjectModel/Variable.h
+++ b/src/ObjectModel/Variable.h
@@ -47,6 +47,7 @@ public:
Variable *Lookup(const char *_ecv_array str) noexcept;
const Variable *Lookup(const char *_ecv_array str) const noexcept;
void InsertNew(const char *str, ExpressionValue pVal, int8_t pScope) noexcept;
+ void InsertNewParameter(const char *str, ExpressionValue pVal) noexcept { InsertNew(str, pVal, -1); }
void EndScope(uint8_t blockNesting) noexcept;
void Delete(const char *str) noexcept;
void Clear() noexcept;
diff --git a/src/Platform/Event.cpp b/src/Platform/Event.cpp
index ddc17eb6..5cf95a67 100644
--- a/src/Platform/Event.cpp
+++ b/src/Platform/Event.cpp
@@ -7,78 +7,176 @@
#include <Platform/Event.h>
#include <RepRapFirmware.h>
+#include <ObjectModel/ObjectModel.h>
+#include <ObjectModel/Variable.h>
-Event::Event(Event *p_next, EventType et, EventParameter p_param, CanAddress p_ba, uint8_t devNum) noexcept
- : next(p_next), param(p_param), type(et), boardAddress(p_ba), deviceNumber(devNum)
+Event *_ecv_null Event::eventsPending = nullptr;
+
+inline Event::Event(Event *_ecv_null pnext, EventType et, uint16_t p_param, uint8_t devNum, CanAddress p_ba, const char *_ecv_array format, va_list vargs) noexcept
+ : next(pnext), param(p_param), type(et), boardAddress(p_ba), deviceNumber(devNum), isBeingProcessed(false)
{
+ text.vprintf(format, vargs);
}
-void Event::AppendText(const StringRef &str) const noexcept
+// Queue an event unless we have a similar event pending already. Returns true if the event was added.
+// The event list is held in priority order, lowest numbered (highest priority) events first.
+/*static*/ bool Event::AddEvent(EventType et, uint16_t p_param, uint8_t devNum, CanAddress p_ba, const char *_ecv_array format, va_list vargs) noexcept
{
- // First append the event type with underscores changed to spaces
- const char *p = type.ToString();
- while (*p != 0)
- {
- str.cat((*p == '_') ? ' ' : *p);
- ++p;
- }
+ // Search for similar events already pending or being processed.
+ // An event is 'similar' if it has the same type, device number and parameter even if the text is different.
+ TaskCriticalSectionLocker lock;
- // Now append further details of the event
- switch (type.ToBaseType())
+ Event** pe = &eventsPending;
+ while (*pe != nullptr && (et >= (*pe)->type || (*pe)->isBeingProcessed)) // while the next event in the list has same or higher priority than the new one
{
- case EventType::Heater_fault:
- str.catf("on heater %u: %s", deviceNumber, HeaterFaultType(param.heaterFaultStatus).ToString());
- break;
-
- case EventType::Driver_error:
- case EventType::Driver_warning:
+ if (et == (*pe)->type && devNum == (*pe)->deviceNumber
#if SUPPORT_CAN_EXPANSION
- str.catf(" on %u.%u", boardAddress, deviceNumber);
-#else
- str.catf(" on %u", deviceNumber);
+ && p_ba == (*pe)->boardAddress
#endif
- param.driverStatus.AppendText(str, (type == EventType::Driver_error) ? 2 : 1);
- break;
+ )
+ {
+ return false; // there is a similar event already in the queue
+ }
+ pe = &((*pe)->next);
+ }
+
+ // We didn't find a similar event, so add the new one
+ *pe = new Event(*pe, et, p_param, p_ba, devNum, format, vargs);
+ return true;
+}
- case EventType::Filament_error:
- str.catf(" on extruder %u: %s", deviceNumber, FilamentSensorStatus(param.filamentStatus).ToString());
- break;
+// Get the highest priority event and mark it as being serviced
+/*static*/ bool Event::StartProcessing() noexcept
+{
+ TaskCriticalSectionLocker lock;
- case EventType::Main_board_power_failure:
- break;
+ Event * const ev = eventsPending;
+ if (ev == nullptr)
+ {
+ return false;
+ }
+ ev->isBeingProcessed = true;
+ return true;
+}
- case EventType::Trigger:
- str.catf(" %u activated", deviceNumber);
- break;
+// Get the name of the macro that we run when this event occurs
+/*static*/ void Event::GetMacroFileName(const StringRef& fname) noexcept
+{
+ const Event * const ep = eventsPending;
+ if (ep != nullptr && ep->isBeingProcessed)
+ {
+ fname.copy(ep->type.ToString());
+ fname.cat(".g");
+ }
+}
- case EventType::Mcu_temperature_warning:
+// Get the macro parameters for the current event, excluding the S parameter which the caller will add
+/*static*/ void Event::GetParameters(VariableSet& vars) noexcept
+{
+ const Event * const ep = eventsPending;
+ if (ep != nullptr && ep->isBeingProcessed)
+ {
+ vars.InsertNewParameter("D", ExpressionValue((int32_t)(ep->deviceNumber)));
#if SUPPORT_CAN_EXPANSION
- str.catf("on board %u: temperature %.1fC", boardAddress, (double)param.fVal);
-#else
- str.catf(": temperature %.1fC", (double)param.fVal);
+ vars.InsertNewParameter("B", ExpressionValue((int32_t)(ep->boardAddress)));
#endif
- break;
+ vars.InsertNewParameter("P", ExpressionValue((int32_t)(ep->param)));
}
}
-// Append the name of the macro that we run when this event occurs
-void Event::GetMacroFileName(const StringRef& fname) const noexcept
+// Get the default action for the current event
+/*static*/ Event::DefaultAction Event::GetDefaultAction() noexcept
{
- const char *p = type.ToString();
- fname.cat((char)tolower(*p++));
- while (*p != 0)
+ const Event * const ep = eventsPending;
+ if (ep != nullptr && ep->isBeingProcessed)
{
- if (*p == '_' && p[1] != 0)
+ switch (ep->type.RawValue())
{
- fname.cat(toupper(p[1]));
- p += 2;
+ case EventType::heater_fault:
+ case EventType::filament_error:
+ return DefaultAction::pauseWithMacro;
+
+ case EventType::driver_error:
+ return DefaultAction::pauseNoMacro;
+
+ default:
+ break;
}
- else
+ }
+ return DefaultAction::none;
+}
+
+// Mark the highest priority event as completed
+/*static*/ void Event::FinishedProcessing() noexcept
+{
+ TaskCriticalSectionLocker lock;
+
+ const Event *ev = eventsPending;
+ if (ev != nullptr && ev->isBeingProcessed)
+ {
+ eventsPending = ev->next;
+ delete ev;
+ }
+}
+
+// Get a description of the current event
+/*static*/ MessageType Event::GetTextDescription(const StringRef& str) noexcept
+{
+ const Event * const ep = eventsPending;
+ if (ep != nullptr && ep->isBeingProcessed)
+ {
+ switch (ep->type.RawValue())
{
- fname.cat(*p++);
+ case EventType::heater_fault:
+ {
+ const char *_ecv_array heaterFaultText = HeaterFaultText[max<size_t>(ep->param, ARRAY_SIZE(HeaterFaultText) - 1)];
+ str.printf("Heater %u fault: %s%s", ep->deviceNumber, heaterFaultText, ep->text.c_str());
+ }
+ return ErrorMessage;
+
+ case EventType::filament_error:
+ str.printf("Filament error on extruder %u: %s", ep->deviceNumber, FilamentSensorStatus(ep->param).ToString());
+ return ErrorMessage;
+
+ case EventType::driver_error:
+#if SUPPORT_CAN_EXPANSION
+ str.printf("Driver %u.%u error: %s", ep->boardAddress, ep->deviceNumber, ep->text.c_str());
+#else
+ str.printf("Driver %u error: %s", deviceNumber, ep->text.c_str());
+#endif
+ return ErrorMessage;
+
+ case EventType::driver_warning:
+#if SUPPORT_CAN_EXPANSION
+ str.printf("Driver %u.%u warning: %s", ep->boardAddress, ep->deviceNumber, ep->text.c_str());
+#else
+ str.printf("Driver %u warning: %s", deviceNumber, ep->text.c_str());
+#endif
+ return WarningMessage;
+
+ case EventType::driver_stall:
+#if SUPPORT_CAN_EXPANSION
+ str.printf("Driver %u.%u stall", ep->boardAddress, ep->deviceNumber);
+#else
+ str.printf("Driver %u stall", ep->deviceNumber);
+#endif
+ return WarningMessage;
+
+ case EventType::main_board_power_fail:
+ // This does not currently generate an event, so no text
+ return ErrorMessage;
+
+ case EventType::mcu_temperature_warning:
+#if SUPPORT_CAN_EXPANSION
+ str.printf("MCU temperature warning from board %u: temperature %.1fC", ep->boardAddress, (double)((float)ep->param/10));
+#else
+ str.printf("MCU temperature warning: temperature %.1fC", (double)((float)ep->param/10));
+#endif
+ return WarningMessage;
}
}
- fname.cat(".g");
+ str.copy("Internal error in Event");
+ return ErrorMessage;
}
// End
diff --git a/src/Platform/Event.h b/src/Platform/Event.h
index 46e26107..7fc78e14 100644
--- a/src/Platform/Event.h
+++ b/src/Platform/Event.h
@@ -3,6 +3,19 @@
*
* Created on: 18 Oct 2021
* Author: David
+ *
+ * This class manages events. An event is an occurrence reported by a machine sensor that may need to be reported or may require action to be taken.
+ * The various event types are listed in file CANlib/RRF3Common.h.
+ * When an event on a main board occurs, a corresponding Event object is created and added to the event queue, unless there is a similar event already in the queue.
+ * When an event on an expansion board occurs, it is transmitted to the main board over CAN and then treated in the same way as a main board event.
+ * The event queue is kept in priority order, with the highest priority event at the head of the queue; except that if the event at the head of the queue is
+ * being processed, it remains at the head of the queue until processing is complete. Leaving it in the queue while it is being processed allows other similar
+ * events to be ignored.
+ *
+ * The event queue is emptied by the AutoPause GCode channel. It flags the entry at the head of the queue as being processed, takes whatever action is needed,
+ * and removes it from the queue.
+ *
+ * A main board power failure bypasses the event mechanism. Triggers do not use the event mechanism.
*/
#ifndef SRC_PLATFORM_EVENT_H_
@@ -13,28 +26,59 @@
#include <CoreTypes.h>
#include <RRF3Common.h>
#include <General/FreelistManager.h>
-#include <General/StringRef.h>
+#include <General/String.h>
+#include <General/SafeVsnprintf.h>
+#include <Platform/MessageType.h>
+
+class VariableSet;
class Event
{
public:
+ // Type of default action for when there is no macro file to process the event
+ enum class DefaultAction
+ {
+ none, // do nothing other than logging ir
+ pauseNoMacro, // pause, but don't run pause.g
+ pauseWithMacro // pause, running pause.g
+ };
+
void* operator new(size_t sz) noexcept { return FreelistManager::Allocate<Event>(); }
void operator delete(void* p) noexcept { FreelistManager::Release<Event>(p); }
- Event(Event *p_next, EventType et, EventParameter p_param, CanAddress p_ba, uint8_t devNum) noexcept;
+ // Get a description of the current event and return the appropriate message type
+ static MessageType GetTextDescription(const StringRef& str) noexcept;
+
+ // Queue an event, or release it if we have a similar event pending already. Returns true if the event was added, false if it was released.
+ static bool AddEvent(EventType et, uint16_t p_param, CanAddress p_ba, uint8_t devNum, const char *_ecv_array format, va_list vargs) noexcept;
- // Append a description of the event to a string
- void AppendText(const StringRef& str) const noexcept;
+ // Get the highest priority event if there is one start processing it
+ static bool StartProcessing() noexcept;
// Get the name of the macro that we run when this event occurs
- void GetMacroFileName(const StringRef& fname) const noexcept;
+ static void GetMacroFileName(const StringRef& fname) noexcept;
+
+ // Get the parameters for invoking the macro file the current event
+ static void GetParameters(VariableSet& vars) noexcept;
+
+ // Get the default action for the current event
+ static DefaultAction GetDefaultAction() noexcept;
+
+ // Mark the highest priority event as completed
+ static void FinishedProcessing() noexcept;
private:
- Event *next; // next event in a linked list
- EventParameter param; // details about the event
- EventType type; // what type of event it is
- CanAddress boardAddress; // which board it came from
- uint8_t deviceNumber; // which device raised it
+ Event(Event *_ecv_null pnext, EventType et, uint16_t p_param, uint8_t devNum, CanAddress p_ba, const char *_ecv_array format, va_list vargs) noexcept;
+
+ Event *_ecv_null next; // next event in a linked list
+ uint16_t param; // details about the event, e.g. for a heater fault it is the type of the fault
+ EventType type; // what type of event it is
+ CanAddress boardAddress; // which board it came from
+ uint8_t deviceNumber; // which device raised it, e.g. heater number, driver number, trigger number
+ volatile bool isBeingProcessed; // true if this event is being processed, so it must remain at the head of the queue
+ String<50> text; // additional info to display to the user
+
+ static Event * _ecv_null eventsPending; // linked list of events waiting to be processed
};
#endif /* SRC_PLATFORM_EVENT_H_ */
diff --git a/src/Platform/EventManager.cpp b/src/Platform/EventManager.cpp
deleted file mode 100644
index e0d4c3f5..00000000
--- a/src/Platform/EventManager.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * EventManager.cpp
- *
- * Created on: 19 Oct 2021
- * Author: David
- */
-
-#include "EventManager.h"
-
-EventManager::EventManager() : eventsPending(nullptr), lastWarningMillis(0)
-{
-}
-
-// End
diff --git a/src/Platform/EventManager.h b/src/Platform/EventManager.h
deleted file mode 100644
index 8f3d23c9..00000000
--- a/src/Platform/EventManager.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * EventManager.h
- *
- * Created on: 19 Oct 2021
- * Author: David
- */
-
-#ifndef SRC_PLATFORM_EVENTMANAGER_H_
-#define SRC_PLATFORM_EVENTMANAGER_H_
-
-#include "Event.h"
-
-class EventManager
-{
-public:
- EventManager();
-
-private:
- Event *eventsPending; // linked list of pending events
- uint32_t lastWarningMillis; // when we last sent a warning message
-};
-
-#endif /* SRC_PLATFORM_EVENTMANAGER_H_ */
diff --git a/src/Platform/Logger.h b/src/Platform/Logger.h
index b2eee38b..b612bb7d 100644
--- a/src/Platform/Logger.h
+++ b/src/Platform/Logger.h
@@ -40,7 +40,7 @@ public:
private:
NamedEnum(MessageLogLevel, uint8_t, debug, info, warn, off);
- MessageLogLevel GetMessageLogLevel(MessageType mt) const noexcept { return (MessageLogLevel) ((mt & MessageType::LogOff)>>30); }
+ MessageLogLevel GetMessageLogLevel(MessageType mt) const noexcept { return (MessageLogLevel) ((mt & MessageType::LogLevelMask) >> MessageType::LogLevelShift); }
static const uint8_t LogEnabledThreshold = 3;
diff --git a/src/Platform/MessageType.h b/src/Platform/MessageType.h
index 482732bb..4da31ab6 100644
--- a/src/Platform/MessageType.h
+++ b/src/Platform/MessageType.h
@@ -41,8 +41,11 @@ enum MessageType : uint32_t
RawMessageFlag = 0x8000000u, // Do not encapsulate this message
BinaryCodeReplyFlag = 0x10000000u, // This message comes from a binary G-Code buffer
PushFlag = 0x20000000u, // There is more to come; the message has been truncated
+
LogMessageLowBit = 0x40000000u, // Log level consists of two bits this is the low bit
LogMessageHighBit = 0x80000000u, // Log level consists of two bits this is the high bit
+ LogLevelMask = 0xC0000000u, // Mask for all the log level bits
+ LogLevelShift = 30, // How many bits we have to shift a MessageType right by to get the logging level
// Common combinations
NoDestinationMessage = 0u, // A message that is going nowhere
diff --git a/src/Platform/Platform.h b/src/Platform/Platform.h
index 201e10f2..33d748da 100644
--- a/src/Platform/Platform.h
+++ b/src/Platform/Platform.h
@@ -31,7 +31,6 @@ Licence: GPL
#include <Heating/TemperatureError.h>
#include "OutputMemory.h"
#include "UniqueId.h"
-#include "EventManager.h"
#include <Storage/FileStore.h>
#include <Storage/FileData.h>
#include <Storage/MassStorage.h> // must be after Pins.h because it needs NumSdCards defined
@@ -873,7 +872,6 @@ private:
#endif
// Event handling
- EventManager eventManager;
uint32_t lastDriverPollMillis; // when we last checked the drivers and voltage monitoring
#ifdef DUET3MINI