diff options
author | David Crocker <dcrocker@eschertech.com> | 2021-10-21 17:42:03 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2021-10-21 17:42:03 +0300 |
commit | cdb43e776df2eda0b526a6e1a43d4ee0fbf4ac91 (patch) | |
tree | 4dacd1947bc7fe84bd224f5300d88d15e0db5918 | |
parent | 7f6d0bee5de31caffc05df7d517ef73127e940cb (diff) |
Implementation of heater in expansion mode mostly done
Still need to implement tuning cycle report
-rw-r--r-- | src/CAN/CommandProcessor.cpp | 20 | ||||
-rw-r--r-- | src/Heating/FOPDT.cpp | 11 | ||||
-rw-r--r-- | src/Heating/FOPDT.h | 1 | ||||
-rw-r--r-- | src/Heating/Heat.cpp | 122 | ||||
-rw-r--r-- | src/Heating/Heat.h | 9 | ||||
-rw-r--r-- | src/Heating/Heater.cpp | 65 | ||||
-rw-r--r-- | src/Heating/Heater.h | 19 | ||||
-rw-r--r-- | src/Heating/LocalHeater.cpp | 189 | ||||
-rw-r--r-- | src/Heating/LocalHeater.h | 7 | ||||
-rw-r--r-- | src/Heating/RemoteHeater.cpp | 11 | ||||
-rw-r--r-- | src/Heating/RemoteHeater.h | 4 |
11 files changed, 429 insertions, 29 deletions
diff --git a/src/CAN/CommandProcessor.cpp b/src/CAN/CommandProcessor.cpp index a59d9146..a206e43a 100644 --- a/src/CAN/CommandProcessor.cpp +++ b/src/CAN/CommandProcessor.cpp @@ -424,45 +424,45 @@ void CommandProcessor::ProcessReceivedMessage(CanMessageBuffer *buf) noexcept rslt = EutGetInfo(buf->msg.getInfo, replyRef, extra); break; -#if 0 // heater commands not implemented yet // Heater commands case CanMessageType::m950Heater: requestId = buf->msg.generic.requestId; - rslt = Heat::ConfigureHeater(buf->msg.generic, replyRef); + rslt = reprap.GetHeat().ConfigureHeater(buf->msg.generic, replyRef); break; case CanMessageType::heaterFeedForward: requestId = buf->msg.heaterFeedForward.requestId; - rslt = Heat::FeedForward(buf->msg.heaterFeedForward, replyRef); + rslt = reprap.GetHeat().FeedForward(buf->msg.heaterFeedForward, replyRef); break; + case CanMessageType::updateHeaterModelNew: requestId = buf->msg.heaterModelNew.requestId; - rslt = Heat::ProcessM307New(buf->msg.heaterModelNew, replyRef); + rslt = reprap.GetHeat().ProcessM307New(buf->msg.heaterModelNew, replyRef); break; case CanMessageType::setHeaterTemperature: requestId = buf->msg.setTemp.requestId; - rslt = Heat::SetTemperature(buf->msg.setTemp, replyRef); + rslt = reprap.GetHeat().SetTemperature(buf->msg.setTemp, replyRef); break; case CanMessageType::heaterTuningCommand: requestId = buf->msg.heaterTuningCommand.requestId; - rslt = Heat::TuningCommand(buf->msg.heaterTuningCommand, replyRef); + rslt = reprap.GetHeat().TuningCommand(buf->msg.heaterTuningCommand, replyRef); break; case CanMessageType::setHeaterFaultDetection: requestId = buf->msg.setHeaterFaultDetection.requestId; - rslt = Heat::SetFaultDetection(buf->msg.setHeaterFaultDetection, replyRef); + rslt = reprap.GetHeat().SetFaultDetection(buf->msg.setHeaterFaultDetection, replyRef); break; case CanMessageType::setHeaterMonitors: requestId = buf->msg.setHeaterMonitors.requestId; - rslt = Heat::SetHeaterMonitors(buf->msg.setHeaterMonitors, replyRef); + rslt = reprap.GetHeat().SetHeaterMonitors(buf->msg.setHeaterMonitors, replyRef); break; -#endif + case CanMessageType::m308New: requestId = buf->msg.generic.requestId; - rslt = reprap.GetHeat().EutProcessM308(buf->msg.generic, replyRef); + rslt = reprap.GetHeat().ProcessM308(buf->msg.generic, replyRef); break; // Fan commands diff --git a/src/Heating/FOPDT.cpp b/src/Heating/FOPDT.cpp index a4021864..911e9100 100644 --- a/src/Heating/FOPDT.cpp +++ b/src/Heating/FOPDT.cpp @@ -140,9 +140,14 @@ M301PidParameters FopDt::GetM301PidParameters(bool forLoadChange) const noexcept // Override the PID parameters. We set both sets to the same parameters. void FopDt::SetM301PidParameters(const M301PidParameters& pp) noexcept { - loadChangeParams.kP = setpointChangeParams.kP = pp.kP * (1.0/255.0); - loadChangeParams.recipTi = setpointChangeParams.recipTi = pp.kI/pp.kP; - loadChangeParams.tD = setpointChangeParams.tD = pp.kD/pp.kP; + SetRawPidParameters(pp.kP * (1.0/255.0), pp.kI/pp.kP, pp.kD/pp.kP); +} + +void FopDt::SetRawPidParameters(float p_kP, float p_recipTi, float p_tD) noexcept +{ + loadChangeParams.kP = setpointChangeParams.kP = p_kP; + loadChangeParams.recipTi = setpointChangeParams.recipTi = p_recipTi; + loadChangeParams.tD = setpointChangeParams.tD = p_tD; pidParametersOverridden = true; } diff --git a/src/Heating/FOPDT.h b/src/Heating/FOPDT.h index 7edee12a..23802165 100644 --- a/src/Heating/FOPDT.h +++ b/src/Heating/FOPDT.h @@ -66,6 +66,7 @@ public: bool ArePidParametersOverridden() const noexcept { return pidParametersOverridden; } M301PidParameters GetM301PidParameters(bool forLoadChange) const noexcept; void SetM301PidParameters(const M301PidParameters& params) noexcept; + void SetRawPidParameters(float p_kP, float p_recipTi, float p_tD) noexcept; const PidParameters& GetPidParameters(bool forLoadChange) const noexcept { diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index 76667f81..50d2171d 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -1320,7 +1320,127 @@ void Heat::ProcessRemoteHeaterTuningReport(CanAddress src, const CanMessageHeate #if SUPPORT_REMOTE_COMMANDS -GCodeResult Heat::EutProcessM308(const CanMessageGeneric& msg, const StringRef& reply) noexcept +static GCodeResult UnknownHeater(unsigned int heater, const StringRef& reply) noexcept +{ + reply.printf("Board %u does not have heater %u", CanInterface::GetCanAddress(), heater); + return GCodeResult::error; +} + +GCodeResult Heat::ConfigureHeater(const CanMessageGeneric& msg, const StringRef& reply) noexcept +{ + CanMessageGenericParser parser(msg, M950HeaterParams); + uint16_t heater; + if (!parser.GetUintParam('H', heater)) + { + return GCodeResult::remoteInternalError; + } + + if (heater >= MaxHeaters) + { + reply.copy("Heater number out of range"); + return GCodeResult::error; + } + + PwmFrequency freq = DefaultFanPwmFreq; + const bool seenFreq = parser.GetUintParam('Q', freq); + + String<StringLength50> pinName; + if (parser.GetStringParam('C', pinName.GetRef())) + { + uint16_t sensorNumber; + if (!parser.GetUintParam('T', sensorNumber)) + { + reply.copy("Missing sensor number"); + return GCodeResult::error; + } + + WriteLocker lock(heatersLock); + + Heater *oldHeater = nullptr; + std::swap(oldHeater, heaters[heater]); + delete oldHeater; + + Heater *newHeater = new LocalHeater(heater); + const GCodeResult rslt = newHeater->ConfigurePortAndSensor(pinName.c_str(), freq, sensorNumber, reply); + if (rslt == GCodeResult::ok || rslt == GCodeResult::warning) + { + heaters[heater] = newHeater; + } + else + { + delete newHeater; + } + return rslt; + } + + const auto h = FindHeater(heater); + if (h.IsNull()) + { + return UnknownHeater(heater, reply); + } + + if (seenFreq) + { + return h->SetPwmFrequency(freq, reply); + } + + return h->ReportDetails(reply); +} + +GCodeResult Heat::ProcessM307New(const CanMessageUpdateHeaterModelNew& msg, const StringRef& reply) noexcept +{ + const auto h = FindHeater(msg.heater); + return (h.IsNotNull()) ? h->SetOrReportModelNew(msg.heater, msg, reply) : UnknownHeater(msg.heater, reply); +} + +GCodeResult Heat::SetTemperature(const CanMessageSetHeaterTemperature& msg, const StringRef& reply) noexcept +{ + const auto h = FindHeater(msg.heaterNumber); + return (h.IsNotNull()) ? h->SetTemperature(msg, reply) : UnknownHeater(msg.heaterNumber, reply); +} + +GCodeResult Heat::SetFaultDetection(const CanMessageSetHeaterFaultDetectionParameters& msg, const StringRef& reply) noexcept +{ + const auto h = FindHeater(msg.heater); + return (h.IsNotNull()) + ? h->SetFaultDetectionParameters(msg.maxTempExcursion, msg.maxFaultTime, reply) + : UnknownHeater(msg.heater, reply); +} + +GCodeResult Heat::SetHeaterMonitors(const CanMessageSetHeaterMonitors& msg, const StringRef& reply) noexcept +{ + const auto h = FindHeater(msg.heater); + return (h.IsNotNull()) ? h->SetHeaterMonitors(msg, reply) : UnknownHeater(msg.heater, reply); +} + +GCodeResult Heat::TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept +{ + if (heaterBeingTuned != -1 && heaterBeingTuned != (int)msg.heaterNumber) + { + reply.printf("Heater %d is already being tuned", heaterBeingTuned); + return GCodeResult::error; + } + const auto h = FindHeater(msg.heaterNumber); + if (h.IsNull()) + { + return UnknownHeater(msg.heaterNumber, reply); + } + heaterBeingTuned = (int)msg.heaterNumber; // setting this is OK even if we are stopping or fail to start tuning, because we check it in the heater task loop + return h->TuningCommand(msg, reply); +} + +GCodeResult Heat::FeedForward(const CanMessageHeaterFeedForward& msg, const StringRef& reply) noexcept +{ + const auto h = FindHeater(msg.heaterNumber); + if (h.IsNull()) + { + return UnknownHeater(msg.heaterNumber, reply); + } + h->FeedForwardAdjustment(msg.fanPwmAdjustment, msg.extrusionAdjustment); + return GCodeResult::ok; +} + +GCodeResult Heat::ProcessM308(const CanMessageGeneric& msg, const StringRef& reply) noexcept { CanMessageGenericParser parser(msg, M308NewParams); uint16_t sensorNum; diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h index 7bdfbb52..172bd80a 100644 --- a/src/Heating/Heat.h +++ b/src/Heating/Heat.h @@ -141,7 +141,14 @@ public: #endif #if SUPPORT_REMOTE_COMMANDS - GCodeResult EutProcessM308(const CanMessageGeneric& msg, const StringRef& reply) noexcept; + GCodeResult ConfigureHeater(const CanMessageGeneric& msg, const StringRef& reply) noexcept; + GCodeResult ProcessM307New(const CanMessageUpdateHeaterModelNew& msg, const StringRef& reply) noexcept; + GCodeResult ProcessM308(const CanMessageGeneric& msg, const StringRef& reply) noexcept; + GCodeResult SetFaultDetection(const CanMessageSetHeaterFaultDetectionParameters& msg, const StringRef& reply) noexcept; + GCodeResult SetHeaterMonitors(const CanMessageSetHeaterMonitors& msg, const StringRef& reply) noexcept; + GCodeResult SetTemperature(const CanMessageSetHeaterTemperature& msg, const StringRef& reply) noexcept; + GCodeResult TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept; + GCodeResult FeedForward(const CanMessageHeaterFeedForward& msg, const StringRef& reply) noexcept; #endif static ReadWriteLock sensorsLock; // needs to be public so that the OMT in EndstopsManager can lock it diff --git a/src/Heating/Heater.cpp b/src/Heating/Heater.cpp index 40b00321..19125f73 100644 --- a/src/Heating/Heater.cpp +++ b/src/Heating/Heater.cpp @@ -636,4 +636,69 @@ void Heater::SetAsBedOrChamberHeater() noexcept } } +#if SUPPORT_REMOTE_COMMANDS + +GCodeResult Heater::SetHeaterMonitors(const CanMessageSetHeaterMonitors& msg, const StringRef& reply) noexcept +{ + for (size_t i = 0; i < min<size_t>(msg.numMonitors, MaxMonitorsPerHeater); ++i) + { + monitors[i].Set(msg.monitors[i].sensor, msg.monitors[i].limit, (HeaterMonitorAction)msg.monitors[i].action, (HeaterMonitorTrigger)msg.monitors[i].trigger); + } + return GCodeResult::ok; +} + +GCodeResult Heater::SetOrReportModelNew(unsigned int heater, const CanMessageUpdateHeaterModelNew& msg, const StringRef& reply) noexcept +{ + const GCodeResult rslt = SetModel(msg.heatingRate, msg.coolingRate, msg.coolingRateChangeFanOn, msg.deadTime, msg.maxPwm, msg.standardVoltage, msg.usePid, msg.inverted, reply); + if (msg.pidParametersOverridden && (rslt == GCodeResult::ok || rslt == GCodeResult::warning)) + { + SetRawPidParameters(msg.kP, msg.recipTi, msg.tD); + } + return rslt; +} + +GCodeResult Heater::SetTemperature(const CanMessageSetHeaterTemperature& msg, const StringRef& reply) noexcept +{ + switch (msg.command) + { + case CanMessageSetHeaterTemperature::commandNone: + activeTemperature = standbyTemperature = msg.setPoint; + return GCodeResult::ok; + + case CanMessageSetHeaterTemperature::commandOff: + activeTemperature = standbyTemperature = msg.setPoint; + SwitchOff(); + return GCodeResult::ok; + + case CanMessageSetHeaterTemperature::commandOn: + activeTemperature = standbyTemperature = msg.setPoint; + return SwitchOn(reply); + + case CanMessageSetHeaterTemperature::commandResetFault: + activeTemperature = standbyTemperature = msg.setPoint; + return ResetFault(reply); + + case CanMessageSetHeaterTemperature::commandSuspend: + Suspend(true); + return GCodeResult::ok; + + case CanMessageSetHeaterTemperature::commandUnsuspend: + activeTemperature = standbyTemperature = msg.setPoint; + Suspend(false); + return GCodeResult::ok; + + case CanMessageSetHeaterTemperature::commandReset: + ResetHeater(); + return GCodeResult::ok; + + default: + break; + } + + reply.printf("Unknown command %u to heater %u", msg.command, heaterNumber); + return GCodeResult::ok; +} + +#endif + // End diff --git a/src/Heating/Heater.h b/src/Heating/Heater.h index ccff80fe..c9029ed4 100644 --- a/src/Heating/Heater.h +++ b/src/Heating/Heater.h @@ -20,12 +20,20 @@ # include "CanId.h" #endif + #define TUNE_WITH_HALF_FAN 0 class HeaterMonitor; struct CanMessageHeaterTuningReport; struct CanHeaterReport; +#if SUPPORT_REMOTE_COMMANDS +struct CanMessageUpdateHeaterModelNew; +struct CanMessageSetHeaterTemperature; +struct CanMessageSetHeaterMonitors; +struct CanMessageHeaterTuningCommand; +#endif + // Enumeration to describe the status of a heater. Note that the web interface returns the numerical values, so don't change them. NamedEnum(HeaterStatus, uint8_t, off, standby, active, fault, tuning, offline); @@ -81,6 +89,13 @@ public: const FopDt& GetModel() const noexcept { return model; } // Get the process model GCodeResult SetOrReportModel(unsigned int heater, GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException); +#if SUPPORT_REMOTE_COMMANDS + virtual GCodeResult TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept = 0; + GCodeResult SetOrReportModelNew(unsigned int heater, const CanMessageUpdateHeaterModelNew& msg, const StringRef& reply) noexcept; + GCodeResult SetTemperature(const CanMessageSetHeaterTemperature& msg, const StringRef& reply) noexcept; + GCodeResult SetHeaterMonitors(const CanMessageSetHeaterMonitors& msg, const StringRef& reply) noexcept; +#endif + bool IsHeaterEnabled() const noexcept // Is this heater enabled? { return model.IsEnabled(); } @@ -126,6 +141,10 @@ protected: void CalculateModel(HeaterParameters& params) noexcept; // calculate G, td and tc from the accumulated readings void SetAndReportModel(bool usingFans) noexcept; +#if SUPPORT_REMOTE_COMMANDS + void SetRawPidParameters(float p_kP, float p_recipTi, float p_tD) noexcept { model.SetRawPidParameters(p_kP, p_recipTi, p_tD); } +#endif + HeaterMonitor monitors[MaxMonitorsPerHeater]; // embedding them in the Heater uses less memory than dynamic allocation bool tuned; // true if tuning was successful diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp index c3a20f7c..1e2192f8 100644 --- a/src/Heating/LocalHeater.cpp +++ b/src/Heating/LocalHeater.cpp @@ -14,6 +14,33 @@ #include <Platform/RepRap.h> #include <Tools/Tool.h> +#if SUPPORT_REMOTE_COMMANDS + +# include <CAN/CanInterface.h> + +namespace ExpansionMode +{ + +// Variables used during heater tuning +static float tuningHighTemp; // the target upper temperature +static float tuningLowTemp; // the target lower temperature +static float tuningPeakTempDrop; // must be well below TuningHysteresis + +static uint32_t dHigh; +static uint32_t dLow; +static uint32_t tOn; +static uint32_t tOff; +static float heatingRate; +static float coolingRate; +static float tuningVoltage; // the VIN voltage with the heater on + +static uint16_t cyclesDone; +static bool tuningCycleComplete; + +} + +#endif + // Member functions and constructors LocalHeater::LocalHeater(unsigned int heaterNum) noexcept : Heater(heaterNum), mode(HeaterMode::off) @@ -596,6 +623,25 @@ void LocalHeater::DoTuningStep() noexcept break; case HeaterMode::tuning1: // Heating up +#if SUPPORT_REMOTE_COMMANDS + if (CanInterface::InExpansionMode()) + { + if (temperature >= ExpansionMode::tuningHighTemp) // if reached target + { + // Move on to next phase + lastPwm = 0.0; + SetHeater(0.0); + peakTemp = afterPeakTemp = temperature; + lastOffTime = peakTime = afterPeakTime = now; + mode = HeaterMode::tuning2; + } + else + { + lastPwm = tuningPwm; + } + return; + } +#endif tuningPhase = 1; { const bool isBedOrChamberHeater = reprap.GetHeat().IsBedOrChamberHeater(GetHeaterNumber()); @@ -613,24 +659,55 @@ void LocalHeater::DoTuningStep() noexcept reprap.GetPlatform().Message(GenericMessage, "Auto tune cancelled because target temperature was not reached\n"); break; } + } - if (temperature >= tuningTargetTemp) // if reached target - { - // Move on to next phase - lastPwm = 0.0; - SetHeater(0.0); - peakTemp = afterPeakTemp = temperature; - lastOffTime = peakTime = afterPeakTime = now; - tuningVoltage.Clear(); - idleCyclesDone = 0; - mode = HeaterMode::tuning2; - tuningPhase = 2; - ReportTuningUpdate(); - } + if (temperature >= tuningTargetTemp) // if reached target + { + // Move on to next phase + lastPwm = 0.0; + SetHeater(0.0); + peakTemp = afterPeakTemp = temperature; + lastOffTime = peakTime = afterPeakTime = now; + tuningVoltage.Clear(); + idleCyclesDone = 0; + mode = HeaterMode::tuning2; + tuningPhase = 2; + ReportTuningUpdate(); } return; case HeaterMode::tuning2: // Heater is off, record the peak temperature and time +#if SUPPORT_REMOTE_COMMANDS + if (CanInterface::InExpansionMode()) + { + if (temperature >= peakTemp) + { + peakTemp = afterPeakTemp = temperature; + peakTime = afterPeakTime = now; + } + else if (temperature < ExpansionMode::tuningLowTemp) + { + // Temperature has dropped below the low limit. + // If we have been doing idle cycles, see whether we can switch to collecting data, and turn the heater on. + // If we have been collecting data, see if we have enough, and either turn the heater on to start another cycle or finish tuning. + + // Save the data (don't know whether we need it yet) + ExpansionMode::dHigh = peakTime - lastOffTime; + ExpansionMode::tOff = now - lastOffTime; + ExpansionMode::coolingRate = (afterPeakTemp - temperature) * SecondsToMillis/(now - afterPeakTime); + lastOnTime = peakTime = afterPeakTime = now; + peakTemp = afterPeakTemp = temperature; + lastPwm = tuningPwm; // turn on heater at specified power + mode = HeaterMode::tuning3; + } + else if (afterPeakTime == peakTime && ExpansionMode::tuningHighTemp - temperature >= ExpansionMode::tuningPeakTempDrop) + { + afterPeakTime = now; + afterPeakTemp = temperature; + } + return; + } +#endif if (temperature >= peakTemp) { peakTemp = afterPeakTemp = temperature; @@ -729,6 +806,40 @@ void LocalHeater::DoTuningStep() noexcept return; case HeaterMode::tuning3: // Heater is turned on, record the lowest temperature and time +#if SUPPORT_REMOTE_COMMANDS + if (CanInterface::InExpansionMode()) + { + if (temperature <= peakTemp) + { + peakTemp = afterPeakTemp = temperature; + peakTime = afterPeakTime = now; + } + else if (temperature >= ExpansionMode::tuningHighTemp) + { + // We have reached the target temperature, so record a data point and turn the heater off +# if HAS_VOLTAGE_MONITOR + ExpansionMode::tuningVoltage = reprap.GetPlatform().GetCurrentPowerVoltage(); // save this while the heater is on +# else + tuningVoltage = 0.0; +# endif + ExpansionMode::dLow = peakTime - lastOnTime; + ExpansionMode::tOn = now - lastOnTime; + ExpansionMode::heatingRate = (temperature - afterPeakTemp) * SecondsToMillis/(now - afterPeakTime); + lastOffTime = peakTime = afterPeakTime = now; + peakTemp = afterPeakTemp = temperature; + lastPwm = 0.0; // turn heater off + mode = HeaterMode::tuning2; + ++ExpansionMode::cyclesDone; + ExpansionMode::tuningCycleComplete = true; + } + else if (afterPeakTime == peakTime && temperature - ExpansionMode::tuningLowTemp >= ExpansionMode::tuningPeakTempDrop) + { + afterPeakTime = now; + afterPeakTemp = temperature; + } + return; + } +#endif #if HAS_VOLTAGE_MONITOR tuningVoltage.Add(reprap.GetPlatform().GetCurrentPowerVoltage()); #endif @@ -800,4 +911,56 @@ void LocalHeater::RaiseHeaterFault(const char *format, ...) noexcept reprap.FlagTemperatureFault(GetHeaterNumber()); } +#if SUPPORT_REMOTE_COMMANDS + +// Start or stop running heater tuning cycles +GCodeResult LocalHeater::TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept +{ + if (msg.on) + { + if (lastPwm > 0.0 || GetAveragePWM() > 0.02) + { + reply.printf("heater %u must be off and cold before auto tuning it", GetHeaterNumber()); + return GCodeResult::error; + } + + // We could do some more checks here but the main board should have done all the checks needed already + ExpansionMode::tuningHighTemp = msg.highTemp; + ExpansionMode::tuningLowTemp = msg.lowTemp; + tuningPwm = msg.pwm; + ExpansionMode::tuningPeakTempDrop = msg.peakTempDrop; + timeSetHeating = millis(); + ExpansionMode::tuningCycleComplete = false; + ExpansionMode::cyclesDone = 0; + mode = HeaterMode::tuning1; + } + else + { + SwitchOff(); + } + return GCodeResult::ok; +} + +// Get a heater tuning cycle report, if we have one. Caller must fill in the heater number. +/*static*/ bool LocalHeater::GetTuningCycleData(CanMessageHeaterTuningReport& msg) noexcept +{ + if (ExpansionMode::tuningCycleComplete) + { + msg.cyclesDone = ExpansionMode::cyclesDone; + msg.dhigh = ExpansionMode::dHigh; + msg.dlow = ExpansionMode::dLow; + msg.ton = ExpansionMode::tOn; + msg.toff = ExpansionMode::tOff; + msg.heatingRate = ExpansionMode::heatingRate; + msg.coolingRate = ExpansionMode::coolingRate; + msg.voltage = ExpansionMode::tuningVoltage; + ExpansionMode::tuningCycleComplete = false; + return true; + } + + return false; +} + +#endif + // End diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h index e1b6b74b..5dc2c6bd 100644 --- a/src/Heating/LocalHeater.h +++ b/src/Heating/LocalHeater.h @@ -40,13 +40,18 @@ public: void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing void FeedForwardAdjustment(float fanPwmChange, float extrusionChange) noexcept override; void SetExtrusionFeedForward(float pwm) noexcept override; // Set extrusion feedforward - #if SUPPORT_CAN_EXPANSION bool IsLocal() const noexcept override { return true; } void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override { } void UpdateHeaterTuning(CanAddress src, const CanMessageHeaterTuningReport& msg) noexcept override { } #endif +#if SUPPORT_REMOTE_COMMANDS + GCodeResult TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept override; + + static bool GetTuningCycleData(CanMessageHeaterTuningReport& msg) noexcept; // get a heater tuning cycle report, if we have one +#endif + protected: void ResetHeater() noexcept override; HeaterMode GetMode() const noexcept override { return mode; } diff --git a/src/Heating/RemoteHeater.cpp b/src/Heating/RemoteHeater.cpp index 8e522f6c..e3e52912 100644 --- a/src/Heating/RemoteHeater.cpp +++ b/src/Heating/RemoteHeater.cpp @@ -513,6 +513,17 @@ void RemoteHeater::StopTuning() noexcept } } +#if SUPPORT_REMOTE_COMMANDS + +// This should never be called +GCodeResult RemoteHeater::TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept +{ + reply.copy("not supported on remote heaters"); + return GCodeResult::error; +} + +#endif + #endif // End diff --git a/src/Heating/RemoteHeater.h b/src/Heating/RemoteHeater.h index 91c96ab0..a6c09029 100644 --- a/src/Heating/RemoteHeater.h +++ b/src/Heating/RemoteHeater.h @@ -35,6 +35,10 @@ public: void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override; void UpdateHeaterTuning(CanAddress src, const CanMessageHeaterTuningReport& msg) noexcept override; +#if SUPPORT_REMOTE_COMMANDS + GCodeResult TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept override; +#endif + protected: void ResetHeater() noexcept override; HeaterMode GetMode() const noexcept override; |