diff --git a/Firmware/mmu2/registers.h b/Firmware/mmu2/registers.h index 489facc39..29d4da9c5 100644 --- a/Firmware/mmu2/registers.h +++ b/Firmware/mmu2/registers.h @@ -1,8 +1,10 @@ #pragma once + +namespace MMU2 { + // Register map for MMU -enum class Register : uint8_t -{ +enum class Register : uint8_t { Project_Major = 0x00, Project_Minor = 0x01, Project_Revision = 0x02, @@ -38,3 +40,5 @@ enum class Register : uint8_t Set_Get_Idler_iRun = 0x20, Reserved = 0x21, }; + +} // namespace MMU2 diff --git a/Firmware/mmu2_protocol_logic.cpp b/Firmware/mmu2_protocol_logic.cpp index d01510c8c..bad34310c 100644 --- a/Firmware/mmu2_protocol_logic.cpp +++ b/Firmware/mmu2_protocol_logic.cpp @@ -9,6 +9,11 @@ // irrelevant on Buddy FW, just keep "_millis" as "millis" #include #define _millis millis + #ifdef UNITTEST + #define strncmp_P strncmp + #else + #include + #endif #endif #include @@ -16,7 +21,7 @@ namespace MMU2 { -/// Beware: +/// Beware - on AVR/MK3S: /// Changing the supportedMmuVersion numbers requires patching MSG_DESC_FW_UPDATE_NEEDED and all its related translations by hand. /// /// The message reads: @@ -24,21 +29,23 @@ namespace MMU2 { /// /// Currently, this is not possible to perform automatically at compile time with the existing languages/translations infrastructure. /// To save space a "dumb" solution was chosen + a few static_assert checks in errors_list.h preventing the code from compiling when the string doesn't match. +/// ----- +/// On Buddy FW we should improve the error screen to be able to print formatted strings static constexpr uint8_t supportedMmuFWVersion[3] PROGMEM = { mmuVersionMajor, mmuVersionMinor, mmuVersionPatch }; const Register ProtocolLogic::regs8Addrs[ProtocolLogic::regs8Count] PROGMEM = { - Register::FINDA_State, // FINDA state + Register::FINDA_State, // FINDA state Register::Set_Get_Selector_Slot, // Selector slot - Register::Set_Get_Idler_Slot, // Idler slot + Register::Set_Get_Idler_Slot, // Idler slot }; const Register ProtocolLogic::regs16Addrs[ProtocolLogic::regs16Count] PROGMEM = { - Register::MMU_Errors, // MMU errors - aka statistics + Register::MMU_Errors, // MMU errors - aka statistics Register::Get_Pulley_Position, // Pulley position [mm] }; const Register ProtocolLogic::initRegs8Addrs[ProtocolLogic::initRegs8Count] PROGMEM = { - Register::Extra_Load_Distance, // extra load distance [mm] + Register::Extra_Load_Distance, // extra load distance [mm] Register::Pulley_Slow_Feedrate, // pulley slow feedrate [mm/s] }; @@ -181,7 +188,7 @@ StepStatus ProtocolLogic::ExpectingMessage() { break; } } - [[fallthrough]]; // otherwise + [[fallthrough]]; // otherwise default: RecordUARTActivity(); // something has happened on the UART, update the timeout record return ProtocolError; @@ -197,7 +204,11 @@ StepStatus ProtocolLogic::ExpectingMessage() { } void ProtocolLogic::SendMsg(RequestMsg rq) { +#ifdef __AVR__ + // Buddy FW cannot use stack-allocated txbuff - DMA doesn't work with CCMRAM + // No restrictions on MK3/S/+ though uint8_t txbuff[Protocol::MaxRequestSize()]; +#endif uint8_t len = Protocol::EncodeRequest(rq, txbuff); uart->write(txbuff, len); LogRequestMsg(txbuff, len); @@ -205,7 +216,11 @@ void ProtocolLogic::SendMsg(RequestMsg rq) { } void ProtocolLogic::SendWriteMsg(RequestMsg rq) { +#ifdef __AVR__ + // Buddy FW cannot use stack-allocated txbuff - DMA doesn't work with CCMRAM + // No restrictions on MK3/S/+ though uint8_t txbuff[Protocol::MaxRequestSize()]; +#endif uint8_t len = Protocol::EncodeWriteRequest(rq.value, rq.value2, txbuff); uart->write(txbuff, len); LogRequestMsg(txbuff, len); @@ -275,9 +290,9 @@ StepStatus ProtocolLogic::ScopeStep() { case Scope::StartSeq: return StartSeqStep(); // ~270B case Scope::Idle: - return IdleStep(); // ~300B + return IdleStep(); // ~300B case Scope::Command: - return CommandStep(); // ~430B + return CommandStep(); // ~430B case Scope::Stopped: return StoppedStep(); default: @@ -322,7 +337,7 @@ StepStatus ProtocolLogic::StartSeqStep() { StepStatus ProtocolLogic::DelayedRestartWait() { if (Elapsed(heartBeatPeriod)) { // this basically means, that we are waiting until there is some traffic on while (uart->read() != -1) - ; // clear the input buffer + ; // clear the input buffer // switch to StartSeq Start(); } @@ -349,6 +364,7 @@ StepStatus ProtocolLogic::ProcessCommandQueryResponse() { return Processing; case ResponseMsgParamCodes::Error: // in case of an error the progress code remains as it has been before + progressCode = ProgressCode::ERRWaitingForUser; errorCode = static_cast(rsp.paramValue); // keep on reporting the state of fsensor regularly even in command error state // - the MMU checks FINDA and fsensor even while recovering from errors @@ -469,9 +485,11 @@ StepStatus ProtocolLogic::IdleStep() { case ResponseMsgParamCodes::Processing: // @@TODO we may actually use this branch to report progress of manual operation on the MMU // The MMU sends e.g. X0 P27 after its restart when the user presses an MMU button to move the Selector + progressCode = static_cast(rsp.paramValue); errorCode = ErrorCode::OK; break; default: + progressCode = ProgressCode::ERRWaitingForUser; errorCode = static_cast(rsp.paramValue); StartReading8bitRegisters(); // continue Idle state without restarting the communication return CommandError; @@ -758,6 +776,7 @@ void ProtocolLogic::LogResponse() { StepStatus ProtocolLogic::SuppressShortDropOuts(const char *msg_P, StepStatus ss) { if (dataTO.Record(ss)) { LogError(msg_P); + dataTO.Reset(); // prepare for another run of consecutive retries before firing an error return dataTO.InitialCause(); } else { return Processing; // suppress short drop outs of communication diff --git a/Firmware/mmu2_protocol_logic.h b/Firmware/mmu2_protocol_logic.h index 251674ce8..bf884106b 100644 --- a/Firmware/mmu2_protocol_logic.h +++ b/Firmware/mmu2_protocol_logic.h @@ -3,37 +3,39 @@ #include #ifdef __AVR__ -#include "mmu2/error_codes.h" -#include "mmu2/progress_codes.h" -#include "mmu2/buttons.h" -#include "mmu2/registers.h" -#include "mmu2_protocol.h" + #include "mmu2/error_codes.h" + #include "mmu2/progress_codes.h" + #include "mmu2/buttons.h" + #include "mmu2/registers.h" + #include "mmu2_protocol.h" // #include std array is not available on AVR ... we need to "fake" it namespace std { -template +template class array { T data[N]; + public: array() = default; - inline constexpr T* begin()const { return data; } - inline constexpr T* end()const { return data + N; } + inline constexpr T *begin() const { return data; } + inline constexpr T *end() const { return data + N; } static constexpr uint8_t size() { return N; } - inline T &operator[](uint8_t i){ + inline T &operator[](uint8_t i) { return data[i]; } }; -} +} // namespace std #else -#include -#include "../../../../../../Prusa-Firmware-MMU/src/logic/error_codes.h" -#include "../../../../../../Prusa-Firmware-MMU/src/logic/progress_codes.h" + #include + #include "../../../../../../Prusa-Firmware-MMU/src/logic/error_codes.h" + #include "../../../../../../Prusa-Firmware-MMU/src/logic/progress_codes.h" -// prevent ARM HAL macros from breaking our code -#undef CRC -#include "../../../../../../Prusa-Firmware-MMU/src/modules/protocol.h" -#include "buttons.h" + // prevent ARM HAL macros from breaking our code + #undef CRC + #include "../../../../../../Prusa-Firmware-MMU/src/modules/protocol.h" + #include "buttons.h" + #include "registers.h" #endif #include "mmu2_serial.h" @@ -50,9 +52,9 @@ class ProtocolLogic; /// ProtocolLogic stepping statuses enum StepStatus : uint_fast8_t { Processing = 0, - MessageReady, ///< a message has been successfully decoded from the received bytes - Finished, ///< Scope finished successfully - Interrupted, ///< received "Finished" message related to a different command than originally issued (most likely the MMU restarted while doing something) + MessageReady, ///< a message has been successfully decoded from the received bytes + Finished, ///< Scope finished successfully + Interrupted, ///< received "Finished" message related to a different command than originally issued (most likely the MMU restarted while doing something) CommunicationTimeout, ///< the MMU failed to respond to a request within a specified time frame ProtocolError, ///< bytes read from the MMU didn't form a valid response CommandRejected, ///< the MMU rejected the command due to some other command in progress, may be the user is operating the MMU locally (button commands) @@ -60,19 +62,17 @@ enum StepStatus : uint_fast8_t { VersionMismatch, ///< the MMU reports its firmware version incompatible with our implementation PrinterError, ///< printer's explicit error - MMU is fine, but the printer was unable to complete the requested operation CommunicationRecovered, - ButtonPushed, ///< The MMU reported the user pushed one of its three buttons. + ButtonPushed, ///< The MMU reported the user pushed one of its three buttons. }; -static constexpr uint32_t linkLayerTimeout = 2000; ///< default link layer communication timeout -static constexpr uint32_t dataLayerTimeout = linkLayerTimeout * 3; ///< data layer communication timeout -static constexpr uint32_t heartBeatPeriod = linkLayerTimeout / 2; ///< period of heart beat messages (Q0) +inline constexpr uint32_t linkLayerTimeout = 2000; ///< default link layer communication timeout +inline constexpr uint32_t dataLayerTimeout = linkLayerTimeout * 3; ///< data layer communication timeout +inline constexpr uint32_t heartBeatPeriod = linkLayerTimeout / 2; ///< period of heart beat messages (Q0) static_assert(heartBeatPeriod < linkLayerTimeout && linkLayerTimeout < dataLayerTimeout, "Incorrect ordering of timeouts"); ///< Filter of short consecutive drop outs which are recovered instantly class DropOutFilter { - StepStatus cause; - uint8_t occurrences; public: static constexpr uint8_t maxOccurrences = 10; // ideally set this to >8 seconds -> 12x heartBeatPeriod static_assert(maxOccurrences > 1, "we should really silently ignore at least 1 comm drop out if recovered immediately afterwards"); @@ -86,6 +86,10 @@ public: /// Rearms the object for further processing - basically call this once the MMU responds with something meaningful (e.g. S0 A2) inline void Reset() { occurrences = maxOccurrences; } + +private: + StepStatus cause; + uint8_t occurrences = maxOccurrences; }; /// Logic layer of the MMU vs. printer communication protocol @@ -115,11 +119,11 @@ public: /// Sets the extra load distance to be reported to the MMU. /// Beware - this call doesn't send anything to the MMU. /// The MMU gets the newly set value either by a communication restart or via an explicit WriteRegister call - inline void PlanExtraLoadDistance(uint8_t eld_mm){ + inline void PlanExtraLoadDistance(uint8_t eld_mm) { initRegs8[0] = eld_mm; } /// @returns the currently preset extra load distance - inline uint8_t ExtraLoadDistance()const { + inline uint8_t ExtraLoadDistance() const { return initRegs8[0]; } @@ -187,13 +191,13 @@ public: inAutoRetry = iar; } - inline void SetPrinterError(ErrorCode ec){ + inline void SetPrinterError(ErrorCode ec) { explicitPrinterError = ec; } - inline void ClearPrinterError(){ + inline void ClearPrinterError() { explicitPrinterError = ErrorCode::OK; } - inline bool IsPrinterError()const { + inline bool IsPrinterError() const { return explicitPrinterError != ErrorCode::OK; } inline ErrorCode PrinterError() const { @@ -228,15 +232,6 @@ private: Running ///< normal operation - Idle + Command processing }; - // individual sub-state machines - may be they can be combined into a union since only one is active at once - // or we can blend them into ProtocolLogic at the cost of a less nice code (but hopefully shorter) -// Stopped stopped; -// StartSeq startSeq; -// DelayedRestart delayedRestart; -// Idle idle; -// Command command; -// ProtocolLogicPartBase *currentState; ///< command currently being processed - enum class Scope : uint_fast8_t { Stopped, StartSeq, @@ -350,25 +345,30 @@ private: /// Activate the planned state once the immediate response to a sent request arrived bool ActivatePlannedRequest(); - uint32_t lastUARTActivityMs; ///< timestamp - last ms when something occurred on the UART - DropOutFilter dataTO; ///< Filter of short consecutive drop outs which are recovered instantly + uint32_t lastUARTActivityMs; ///< timestamp - last ms when something occurred on the UART + DropOutFilter dataTO; ///< Filter of short consecutive drop outs which are recovered instantly - ResponseMsg rsp; ///< decoded response message from the MMU protocol + ResponseMsg rsp; ///< decoded response message from the MMU protocol - State state; ///< internal state of ProtocolLogic + State state; ///< internal state of ProtocolLogic - Protocol protocol; ///< protocol codec + Protocol protocol; ///< protocol codec std::array lastReceivedBytes; ///< remembers the last few bytes of incoming communication for diagnostic purposes uint8_t lrb; - MMU2Serial *uart; ///< UART interface + MMU2Serial *uart; ///< UART interface ErrorCode errorCode; ///< last received error code from the MMU ProgressCode progressCode; ///< last received progress code from the MMU Buttons buttonCode; ///< Last received button from the MMU. - uint8_t lastFSensor; ///< last state of filament sensor + uint8_t lastFSensor; ///< last state of filament sensor + +#ifndef __AVR__ + uint8_t txbuff[Protocol::MaxRequestSize()]; ///< In Buddy FW - a static transmit buffer needs to exist as DMA cannot be used from CCMRAM. + ///< On MK3/S/+ the transmit buffer is allocated on the stack without restrictions +#endif // 8bit registers static constexpr uint8_t regs8Count = 3;