MMU: Sync code with 32-bit
The changes in this commit are mainly formatting But there are some changes like adding a new function planner_draining()
This commit is contained in:
parent
e405e9140c
commit
592fc56bfc
|
|
@ -34,7 +34,7 @@ void waitForHotendTargetTemp(uint16_t delay, F f) {
|
|||
}
|
||||
|
||||
void WaitForHotendTargetTempBeep() {
|
||||
waitForHotendTargetTemp(3000, []{ });
|
||||
waitForHotendTargetTemp(200, [] {});
|
||||
MakeSound(Prompt);
|
||||
}
|
||||
|
||||
|
|
@ -73,14 +73,17 @@ void MMU2::Start() {
|
|||
mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication
|
||||
|
||||
SetCurrentTool(MMU2_NO_TOOL);
|
||||
state = xState::Connecting;
|
||||
|
||||
// start the communication
|
||||
logic.Start();
|
||||
logic.ResetRetryAttempts();
|
||||
logic.ResetCommunicationTimeoutAttempts();
|
||||
|
||||
state = xState::Connecting;
|
||||
logic.Start();
|
||||
}
|
||||
|
||||
MMU2::~MMU2() {}
|
||||
|
||||
void MMU2::Stop() {
|
||||
StopKeepPowered();
|
||||
PowerOff();
|
||||
|
|
@ -153,8 +156,9 @@ void MMU2::PowerOn() {
|
|||
}
|
||||
|
||||
bool MMU2::ReadRegister(uint8_t address) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function
|
||||
} while (!manage_response(false, false));
|
||||
|
|
@ -165,8 +169,9 @@ bool MMU2::ReadRegister(uint8_t address) {
|
|||
}
|
||||
|
||||
bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t data) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// special cases - intercept requests of registers which influence the printer's behaviour too + perform the change even on the printer's side
|
||||
switch (address) {
|
||||
|
|
@ -192,12 +197,11 @@ void MMU2::mmu_loop() {
|
|||
// Atomic compare_exchange would have been the most appropriate solution here, but this gets called only in Marlin's task,
|
||||
// so thread safety should be kept
|
||||
static bool avoidRecursion = false;
|
||||
if (avoidRecursion)
|
||||
if (avoidRecursion) {
|
||||
return;
|
||||
}
|
||||
avoidRecursion = true;
|
||||
|
||||
mmu_loop_inner(true);
|
||||
|
||||
avoidRecursion = false;
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +212,7 @@ void __attribute__((noinline)) MMU2::mmu_loop_inner(bool reportErrors) {
|
|||
|
||||
void MMU2::CheckFINDARunout() {
|
||||
// Check for FINDA filament runout
|
||||
if (!FindaDetectsFilament() && check_fsensor()) {
|
||||
if (!FindaDetectsFilament() && check_fsensor()) { // Check if we have filament runout detected from sensors
|
||||
SERIAL_ECHOLNPGM("FINDA filament runout!");
|
||||
marlin_stop_and_save_print_to_ram();
|
||||
restore_print_from_ram_and_continue(0);
|
||||
|
|
@ -301,8 +305,12 @@ bool MMU2::VerifyFilamentEnteredPTFE() {
|
|||
filament_inserted = filament_inserted && (WhereIsFilament() == FilamentState::AT_FSENSOR);
|
||||
tlur.Progress(filament_inserted);
|
||||
safe_delay_keep_alive(0);
|
||||
if (planner_draining()) {
|
||||
return false; // power panic or a similar issue happened, bail out fast
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Disable_E0();
|
||||
if (!filament_inserted) {
|
||||
IncrementLoadFails();
|
||||
|
|
@ -318,8 +326,9 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
|
|||
Disable_E0(); // it may seem counterintuitive to disable the E-motor, but it gets enabled in the planner whenever the E-motor is to move
|
||||
tool_change_extruder = slot;
|
||||
logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in
|
||||
if (manage_response(true, true))
|
||||
if (manage_response(true, true)) {
|
||||
break;
|
||||
}
|
||||
// otherwise: failed to perform the command - unload first and then let it run again
|
||||
IncrementMMUFails();
|
||||
|
||||
|
|
@ -335,7 +344,7 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
|
|||
}
|
||||
if (VerifyFilamentEnteredPTFE()) {
|
||||
return true; // success
|
||||
} else { // Prepare a retry attempt
|
||||
} else { // Prepare a retry attempt
|
||||
UnloadInner();
|
||||
if (retries == 2 && cutter_enabled()) {
|
||||
CutFilamentInner(slot); // try cutting filament tip at the last attempt
|
||||
|
|
@ -347,6 +356,9 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
|
|||
|
||||
void MMU2::ToolChangeCommon(uint8_t slot) {
|
||||
while (!ToolChangeCommonOnce(slot)) { // while not successfully fed into extruder's PTFE tube
|
||||
if (planner_draining()) {
|
||||
return; // power panic happening, pretend the G-code finished ok
|
||||
}
|
||||
// failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code
|
||||
// @@TODO theoretically logic layer may not need to be spoiled with the printer error - may be just the manage_response needs it...
|
||||
logic.SetPrinterError(ErrorCode::LOAD_TO_EXTRUDER_FAILED);
|
||||
|
|
@ -357,15 +369,16 @@ void MMU2::ToolChangeCommon(uint8_t slot) {
|
|||
static_cast<void>(manage_response(true, true)); // yes, I'd like to silence [[nodiscard]] warning at this spot by casting to void
|
||||
}
|
||||
|
||||
SetCurrentTool(slot); //filament change is finished
|
||||
SetCurrentTool(slot); // filament change is finished
|
||||
SpoolJoin::spooljoin.setSlot(slot);
|
||||
|
||||
++toolchange_counter;
|
||||
}
|
||||
|
||||
bool MMU2::tool_change(uint8_t slot) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (slot != extruder) {
|
||||
if (/*FindaDetectsFilament()*/
|
||||
|
|
@ -390,8 +403,9 @@ bool MMU2::tool_change(uint8_t slot) {
|
|||
///- Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
|
||||
///- Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
|
||||
bool MMU2::tool_change(char code, uint8_t slot) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FSensorBlockRunout blockRunout;
|
||||
|
||||
|
|
@ -435,8 +449,9 @@ void MMU2::SetCurrentTool(uint8_t ex){
|
|||
}
|
||||
|
||||
bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @@TODO - this is not supported in the new MMU yet
|
||||
// slot = slot; // @@TODO
|
||||
|
|
@ -461,8 +476,9 @@ void MMU2::UnloadInner() {
|
|||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.UnloadFilament();
|
||||
if (manage_response(false, true))
|
||||
if (manage_response(false, true)) {
|
||||
break;
|
||||
}
|
||||
IncrementMMUFails();
|
||||
}
|
||||
MakeSound(Confirm);
|
||||
|
|
@ -473,15 +489,16 @@ void MMU2::UnloadInner() {
|
|||
}
|
||||
|
||||
bool MMU2::unload() {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
|
||||
WaitForHotendTargetTempBeep();
|
||||
}
|
||||
|
||||
{
|
||||
ReportingRAII rep(CommandInProgress::UnloadFilament);
|
||||
WaitForHotendTargetTempBeep();
|
||||
UnloadInner();
|
||||
}
|
||||
|
||||
ScreenUpdateEnable();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -490,15 +507,17 @@ void MMU2::CutFilamentInner(uint8_t slot) {
|
|||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.CutFilament(slot);
|
||||
if (manage_response(false, true))
|
||||
if (manage_response(false, true)) {
|
||||
break;
|
||||
}
|
||||
IncrementMMUFails();
|
||||
}
|
||||
}
|
||||
|
||||
bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enableFullScreenMsg) {
|
||||
FullScreenMsgCut(slot);
|
||||
|
|
@ -528,8 +547,9 @@ bool MMU2::loading_test(uint8_t slot) {
|
|||
}
|
||||
|
||||
bool MMU2::load_filament(uint8_t slot) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FullScreenMsgLoad(slot);
|
||||
{
|
||||
|
|
@ -537,8 +557,9 @@ bool MMU2::load_filament(uint8_t slot) {
|
|||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.LoadFilament(slot);
|
||||
if (manage_response(false, false))
|
||||
if (manage_response(false, false)) {
|
||||
break;
|
||||
}
|
||||
IncrementMMUFails();
|
||||
}
|
||||
MakeSound(SoundType::Confirm);
|
||||
|
|
@ -548,10 +569,9 @@ bool MMU2::load_filament(uint8_t slot) {
|
|||
}
|
||||
|
||||
bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
|
||||
WaitForHotendTargetTempBeep();
|
||||
}
|
||||
|
||||
FullScreenMsgLoad(slot);
|
||||
{
|
||||
|
|
@ -559,6 +579,8 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
|||
ReportingRAII rep(CommandInProgress::ToolChange);
|
||||
FSensorBlockRunout blockRunout;
|
||||
|
||||
WaitForHotendTargetTempBeep();
|
||||
|
||||
if (extruder != MMU2_NO_TOOL) { // we already have some filament loaded - free it + shape its tip properly
|
||||
filament_ramming();
|
||||
}
|
||||
|
|
@ -574,8 +596,9 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
|||
}
|
||||
|
||||
bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
|
||||
if (!WaitForMMUReady())
|
||||
if (!WaitForMMUReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enableFullScreenMsg) {
|
||||
FullScreenMsgEject(slot);
|
||||
|
|
@ -589,8 +612,9 @@ bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
|
|||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.EjectFilament(slot);
|
||||
if (manage_response(false, true))
|
||||
if (manage_response(false, true)) {
|
||||
break;
|
||||
}
|
||||
IncrementMMUFails();
|
||||
}
|
||||
SetCurrentTool(MMU2_NO_TOOL);
|
||||
|
|
@ -611,8 +635,9 @@ void MMU2::Home(uint8_t mode) {
|
|||
}
|
||||
|
||||
void MMU2::SaveHotendTemp(bool turn_off_nozzle) {
|
||||
if (mmu_print_saved & SavedState::Cooldown)
|
||||
if (mmu_print_saved & SavedState::Cooldown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)) {
|
||||
Disable_E0();
|
||||
|
|
@ -701,8 +726,7 @@ void MMU2::CheckUserInput() {
|
|||
lastButton = Buttons::NoButton; // Clear it.
|
||||
}
|
||||
|
||||
if (mmu2.MMULastErrorSource() == MMU2::ErrorSourcePrinter && btn != Buttons::NoButton)
|
||||
{
|
||||
if (mmu2.MMULastErrorSource() == ErrorSourcePrinter && btn != Buttons::NoButton) {
|
||||
// When the printer has raised an error screen, and a button was selected
|
||||
// the error screen should always be dismissed.
|
||||
ClearPrinterError();
|
||||
|
|
@ -720,7 +744,7 @@ void MMU2::CheckUserInput() {
|
|||
SERIAL_ECHOLN((int)buttons_to_uint8t(btn));
|
||||
ResumeHotendTemp(); // Recover the hotend temp before we attempt to do anything else...
|
||||
|
||||
if (mmu2.MMULastErrorSource() == MMU2::ErrorSourceMMU) {
|
||||
if (mmu2.MMULastErrorSource() == ErrorSourceMMU) {
|
||||
// Do not send a button to the MMU unless the MMU is in error state
|
||||
Button(buttons_to_uint8t(btn));
|
||||
}
|
||||
|
|
@ -782,6 +806,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
|
|||
// - failed -> then do the safety moves on the printer like before
|
||||
// - finished ok -> proceed with reading other commands
|
||||
safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status
|
||||
// also disables stepper motor unlocking
|
||||
|
||||
if (mmu_print_saved & SavedState::CooldownPending) {
|
||||
if (!nozzleTimeout.running()) {
|
||||
|
|
@ -803,9 +828,8 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
|
|||
// command/operation completed, let Marlin continue its work
|
||||
// the E may have some more moves to finish - wait for them
|
||||
ResumeHotendTemp();
|
||||
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
|
||||
if (!TuneMenuEntered())
|
||||
{
|
||||
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
|
||||
if (!TuneMenuEntered()) {
|
||||
// If the error screen is sleeping (running 'Tune' menu)
|
||||
// then don't reset retry attempts because we this will trigger
|
||||
// an automatic retry attempt when 'Tune' button is selected. We want the
|
||||
|
|
@ -860,7 +884,7 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
|
|||
case Finished:
|
||||
// At this point it is safe to trigger a runout and not interrupt the MMU protocol
|
||||
CheckFINDARunout();
|
||||
break;
|
||||
[[fallthrough]]; // let Finished be reported the same way like Processing
|
||||
|
||||
case Processing:
|
||||
OnMMUProgressMsg(logic.Progress());
|
||||
|
|
@ -920,15 +944,17 @@ void MMU2::filament_ramming() {
|
|||
execute_extruder_sequence(ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
|
||||
}
|
||||
|
||||
void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t steps) {
|
||||
void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t stepCount) {
|
||||
planner_synchronize();
|
||||
|
||||
const E_Step *step = sequence;
|
||||
for (uint8_t i = steps; i > 0; --i) {
|
||||
// Plan the moves
|
||||
for (const E_Step *step = sequence, *end = sequence + stepCount; step != end; step++) {
|
||||
extruder_move(pgm_read_float(&(step->extrude)), pgm_read_float(&(step->feedRate)));
|
||||
step++;
|
||||
}
|
||||
planner_synchronize(); // it looks like it's better to sync the moves at the end - smoother move (if the sequence is not too long).
|
||||
|
||||
// Wait for the moves to finish
|
||||
// it looks like it's better to sync the moves at the end - smoother move (if the sequence is not too long).
|
||||
planner_synchronize();
|
||||
|
||||
Disable_E0();
|
||||
}
|
||||
|
|
@ -1031,7 +1057,7 @@ void MMU2::OnMMUProgressMsgChanged(ProgressCode pc) {
|
|||
switch (pc) {
|
||||
case ProgressCode::UnloadingToFinda:
|
||||
if ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::UnloadFilament
|
||||
|| ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::ToolChange)) {
|
||||
|| ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::ToolChange)) {
|
||||
// If MK3S sent U0 command, ramming sequence takes care of releasing the filament.
|
||||
// If Toolchange is done while printing, PrusaSlicer takes care of releasing the filament
|
||||
// If printing is not in progress, ToolChange will issue a U0 command.
|
||||
|
|
@ -1079,14 +1105,10 @@ void MMU2::OnMMUProgressMsgSame(ProgressCode pc) {
|
|||
case FilamentState::AT_FSENSOR:
|
||||
// fsensor triggered, finish FeedingToExtruder state
|
||||
loadFilamentStarted = false;
|
||||
|
||||
// Abort any excess E-move from the planner queue
|
||||
planner_abort_queued_moves();
|
||||
|
||||
// After the MMU knows the FSENSOR is triggered it will:
|
||||
// 1. Push the filament by additional 30mm (see fsensorToNozzle)
|
||||
// 2. Disengage the idler and push another 2mm.
|
||||
extruder_move(logic.ExtraLoadDistance() + 2, logic.PulleySlowFeedRate());
|
||||
{
|
||||
extruder_move(logic.ExtraLoadDistance() + 2, logic.PulleySlowFeedRate());
|
||||
}
|
||||
break;
|
||||
case FilamentState::NOT_PRESENT:
|
||||
// fsensor not triggered, continue moving extruder
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ typedef float feedRate_t;
|
|||
#else
|
||||
#include "protocol_logic.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
struct E_Step;
|
||||
|
|
@ -32,6 +33,7 @@ struct Version {
|
|||
class MMU2 {
|
||||
public:
|
||||
MMU2();
|
||||
~MMU2();
|
||||
|
||||
/// Powers ON the MMU, then initializes the UART and protocol logic
|
||||
void Start();
|
||||
|
|
@ -48,17 +50,17 @@ public:
|
|||
|
||||
/// Different levels of resetting the MMU
|
||||
enum ResetForm : uint8_t {
|
||||
Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself
|
||||
ResetPin = 1, ///< trigger the reset pin of the MMU
|
||||
CutThePower = 2, ///< power off and power on (that includes +5V and +24V power lines)
|
||||
Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself
|
||||
ResetPin = 1, ///< trigger the reset pin of the MMU
|
||||
CutThePower = 2, ///< power off and power on (that includes +5V and +24V power lines)
|
||||
EraseEEPROM = 42, ///< erase MMU EEPROM and then perform a software reset
|
||||
};
|
||||
|
||||
/// Saved print state on error.
|
||||
enum SavedState : uint8_t {
|
||||
None = 0, // No state saved.
|
||||
None = 0, // No state saved.
|
||||
ParkExtruder = 1, // The extruder was parked.
|
||||
Cooldown = 2, // The extruder was allowed to cool.
|
||||
Cooldown = 2, // The extruder was allowed to cool.
|
||||
CooldownPending = 4,
|
||||
};
|
||||
|
||||
|
|
@ -207,9 +209,9 @@ public:
|
|||
};
|
||||
inline void InvokeErrorScreen(ErrorCode ec) {
|
||||
// The printer may not raise an error when the MMU is busy
|
||||
if (!logic.CommandInProgress() // MMU must not be busy
|
||||
if (!logic.CommandInProgress() // MMU must not be busy
|
||||
&& MMUCurrentErrorCode() == ErrorCode::OK // The protocol must not be in error state
|
||||
&& lastErrorCode != ec) // The error code is not a duplicate
|
||||
&& lastErrorCode != ec) // The error code is not a duplicate
|
||||
{
|
||||
ReportError(ec, ErrorSource::ErrorSourcePrinter);
|
||||
}
|
||||
|
|
@ -273,7 +275,9 @@ private:
|
|||
StepStatus LogicStep(bool reportErrors);
|
||||
|
||||
void filament_ramming();
|
||||
void execute_extruder_sequence(const E_Step *sequence, uint8_t steps);
|
||||
|
||||
void execute_extruder_sequence(const E_Step *sequence, uint8_t stepCount);
|
||||
|
||||
void execute_load_to_nozzle_sequence();
|
||||
|
||||
/// Reports an error into attached ExtUIs
|
||||
|
|
@ -342,8 +346,9 @@ private:
|
|||
|
||||
void SetCurrentTool(uint8_t ex);
|
||||
|
||||
ProtocolLogic logic; ///< implementation of the protocol logic layer
|
||||
uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet
|
||||
ProtocolLogic logic; ///< implementation of the protocol logic layer
|
||||
|
||||
uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet
|
||||
uint8_t tool_change_extruder; ///< only used for UI purposes
|
||||
|
||||
pos3d resume_position;
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@ static constexpr uint8_t FindErrorIndex(uint16_t pec) {
|
|||
return (i != errorCodesEnd) ? (i-errorCodes) : (errorCodesSize - 1);
|
||||
}
|
||||
|
||||
// check that the searching algoritm works
|
||||
static_assert( FindErrorIndex(ERR_MECHANICAL_FINDA_DIDNT_TRIGGER) == 0);
|
||||
static_assert( FindErrorIndex(ERR_MECHANICAL_FINDA_FILAMENT_STUCK) == 1);
|
||||
static_assert( FindErrorIndex(ERR_MECHANICAL_FSENSOR_DIDNT_TRIGGER) == 2);
|
||||
static_assert( FindErrorIndex(ERR_MECHANICAL_FSENSOR_FILAMENT_STUCK) == 3);
|
||||
// check that the searching algorithm works
|
||||
static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_DIDNT_TRIGGER) == 0);
|
||||
static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_FILAMENT_STUCK) == 1);
|
||||
static_assert(FindErrorIndex(ERR_MECHANICAL_FSENSOR_DIDNT_TRIGGER) == 2);
|
||||
static_assert(FindErrorIndex(ERR_MECHANICAL_FSENSOR_FILAMENT_STUCK) == 3);
|
||||
|
||||
constexpr ErrorCode operator&(ErrorCode a, ErrorCode b){
|
||||
constexpr ErrorCode operator&(ErrorCode a, ErrorCode b) {
|
||||
return (ErrorCode)((uint16_t)a & (uint16_t)b);
|
||||
}
|
||||
|
||||
constexpr bool ContainsBit(ErrorCode ec, ErrorCode mask){
|
||||
constexpr bool ContainsBit(ErrorCode ec, ErrorCode mask) {
|
||||
return (uint16_t)ec & (uint16_t)mask;
|
||||
}
|
||||
|
||||
|
|
@ -96,93 +96,115 @@ uint8_t PrusaErrorCodeIndex(ErrorCode ec) {
|
|||
return FindErrorIndex(ERR_SYSTEM_UNLOAD_MANUALLY);
|
||||
case ErrorCode::MCU_UNDERVOLTAGE_VCC:
|
||||
return FindErrorIndex(ERR_ELECTRICAL_MMU_MCU_ERROR);
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Electrical issues which can be detected somehow.
|
||||
// Need to be placed before TMC-related errors in order to process couples of error bits between single ones
|
||||
// and to keep the code size down.
|
||||
if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) {
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION)
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_MMU_PULLEY_SELFTEST_FAILED);
|
||||
}
|
||||
} else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) {
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION)
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_MMU_SELECTOR_SELFTEST_FAILED);
|
||||
}
|
||||
} else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) {
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION)
|
||||
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_MMU_IDLER_SELFTEST_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
// TMC-related errors - multiple of these can occur at once
|
||||
// - in such a case we report the first which gets found/converted into Prusa-Error-Codes (usually the fact, that one TMC has an issue is serious enough)
|
||||
// By carefully ordering the checks here we can prioritize the errors being reported to the user.
|
||||
if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) {
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH))
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_RESET);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_UNDERVOLTAGE_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_SHORTED);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_PULLEY_TOO_HOT);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_TMC_PULLEY_OVERHEAT_ERROR);
|
||||
}
|
||||
} else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) {
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH))
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_RESET);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_UNDERVOLTAGE_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_SHORTED);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_SELECTOR_TOO_HOT);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_TMC_SELECTOR_OVERHEAT_ERROR);
|
||||
}
|
||||
} else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) {
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH))
|
||||
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_RESET);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_UNDERVOLTAGE_ERROR);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
|
||||
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_SHORTED);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_IDLER_TOO_HOT);
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR))
|
||||
}
|
||||
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
|
||||
return FindErrorIndex(ERR_TEMPERATURE_TMC_IDLER_OVERHEAT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// if nothing got caught, return a generic runtime error
|
||||
// if nothing got caught, return a generic error
|
||||
return FindErrorIndex(ERR_OTHER_UNKNOWN_ERROR);
|
||||
}
|
||||
|
||||
uint16_t PrusaErrorCode(uint8_t i){
|
||||
uint16_t PrusaErrorCode(uint8_t i) {
|
||||
return pgm_read_word(errorCodes + i);
|
||||
}
|
||||
|
||||
const char * PrusaErrorTitle(uint8_t i){
|
||||
const char *PrusaErrorTitle(uint8_t i) {
|
||||
return (const char *)pgm_read_ptr(errorTitles + i);
|
||||
}
|
||||
|
||||
const char * PrusaErrorDesc(uint8_t i){
|
||||
const char *PrusaErrorDesc(uint8_t i) {
|
||||
return (const char *)pgm_read_ptr(errorDescs + i);
|
||||
}
|
||||
|
||||
uint8_t PrusaErrorButtons(uint8_t i){
|
||||
uint8_t PrusaErrorButtons(uint8_t i) {
|
||||
return pgm_read_byte(errorButtons + i);
|
||||
}
|
||||
|
||||
const char * PrusaErrorButtonTitle(uint8_t bi){
|
||||
const char *PrusaErrorButtonTitle(uint8_t bi) {
|
||||
// -1 represents the hidden NoOperation button which is not drawn in any way
|
||||
return (const char *)pgm_read_ptr(btnOperation + bi - 1);
|
||||
}
|
||||
|
||||
const char * PrusaErrorButtonMore(){
|
||||
const char *PrusaErrorButtonMore() {
|
||||
return MSG_BTN_MORE;
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +215,6 @@ Buttons ButtonPressed(ErrorCode ec) {
|
|||
|
||||
const auto result = ButtonAvailable(ec);
|
||||
buttonSelectedOperation = ButtonOperations::NoOperation; // Reset operation
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +363,7 @@ Buttons ButtonAvailable(ErrorCode ec) {
|
|||
return Buttons::NoButton;
|
||||
}
|
||||
|
||||
void SetButtonResponse(ButtonOperations rsp){
|
||||
void SetButtonResponse(ButtonOperations rsp) {
|
||||
buttonSelectedOperation = rsp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void LogEchoEvent_P(const char *msg_P);
|
|||
} while (0)
|
||||
#define MMU2_ERROR_MSG(S) MMU2_ECHO_MSG(S) //!@todo Decide MMU errors on serial line
|
||||
|
||||
#else // #ifndef UNITTEST
|
||||
#else // #ifndef UNITTEST
|
||||
#include "stubs/stub_interfaces.h"
|
||||
#define MMU2_ECHO_MSGLN(S) marlinLogSim.AppendLine(S)
|
||||
#define MMU2_ERROR_MSGLN(S) marlinLogSim.AppendLine(S)
|
||||
|
|
@ -65,4 +65,4 @@ void LogEchoEvent_P(const char *msg_P);
|
|||
#define SERIAL_ECHOPGM(S) /* */
|
||||
#define SERIAL_ECHOLN(S) /*marlinLogSim.AppendLine(S)*/
|
||||
|
||||
#endif // #ifndef UNITTEST
|
||||
#endif // #ifndef UNITTEST
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ void extruder_schedule_turning(float feed_rate);
|
|||
float move_raise_z(float delta);
|
||||
|
||||
void planner_abort_queued_moves();
|
||||
bool planner_draining();
|
||||
void planner_synchronize();
|
||||
bool planner_any_moves();
|
||||
float stepper_get_machine_position_E_mm();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ void planner_abort_queued_moves() {
|
|||
planner_aborted = false;
|
||||
}
|
||||
|
||||
bool planner_draining() {
|
||||
return planner_aborted;
|
||||
}
|
||||
|
||||
void planner_synchronize() {
|
||||
st_synchronize();
|
||||
}
|
||||
|
|
@ -46,33 +50,33 @@ bool planner_any_moves() {
|
|||
return blocks_queued();
|
||||
}
|
||||
|
||||
float planner_get_machine_position_E_mm(){
|
||||
float planner_get_machine_position_E_mm() {
|
||||
return current_position[E_AXIS];
|
||||
}
|
||||
|
||||
float stepper_get_machine_position_E_mm(){
|
||||
float stepper_get_machine_position_E_mm() {
|
||||
return st_get_position_mm(E_AXIS);
|
||||
}
|
||||
|
||||
float planner_get_current_position_E(){
|
||||
float planner_get_current_position_E() {
|
||||
return current_position[E_AXIS];
|
||||
}
|
||||
|
||||
void planner_set_current_position_E(float e){
|
||||
void planner_set_current_position_E(float e) {
|
||||
current_position[E_AXIS] = e;
|
||||
}
|
||||
|
||||
pos3d planner_current_position(){
|
||||
pos3d planner_current_position() {
|
||||
return pos3d(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
|
||||
}
|
||||
|
||||
void motion_do_blocking_move_to_xy(float rx, float ry, float feedRate_mm_s){
|
||||
void motion_do_blocking_move_to_xy(float rx, float ry, float feedRate_mm_s) {
|
||||
current_position[X_AXIS] = rx;
|
||||
current_position[Y_AXIS] = ry;
|
||||
planner_line_to_current_position_sync(feedRate_mm_s);
|
||||
}
|
||||
|
||||
void motion_do_blocking_move_to_z(float z, float feedRate_mm_s){
|
||||
void motion_do_blocking_move_to_z(float z, float feedRate_mm_s) {
|
||||
current_position[Z_AXIS] = z;
|
||||
planner_line_to_current_position_sync(feedRate_mm_s);
|
||||
}
|
||||
|
|
@ -84,32 +88,31 @@ void nozzle_park() {
|
|||
}
|
||||
|
||||
bool marlin_printingIsActive() {
|
||||
// return IS_SD_PRINTING || usb_timer_running();
|
||||
return printer_active();
|
||||
}
|
||||
|
||||
void marlin_manage_heater(){
|
||||
void marlin_manage_heater() {
|
||||
manage_heater();
|
||||
}
|
||||
|
||||
void marlin_manage_inactivity(bool b){
|
||||
manage_inactivity(b);
|
||||
void marlin_manage_inactivity(bool ignore_stepper_queue) {
|
||||
manage_inactivity(ignore_stepper_queue);
|
||||
}
|
||||
|
||||
void marlin_idle(bool b){
|
||||
void marlin_idle(bool ignore_stepper_queue) {
|
||||
manage_heater();
|
||||
manage_inactivity(b);
|
||||
manage_inactivity(ignore_stepper_queue);
|
||||
}
|
||||
|
||||
void marlin_refresh_print_state_in_ram(){
|
||||
void marlin_refresh_print_state_in_ram() {
|
||||
refresh_print_state_in_ram();
|
||||
}
|
||||
|
||||
void marlin_clear_print_state_in_ram(){
|
||||
void marlin_clear_print_state_in_ram() {
|
||||
clear_print_state_in_ram();
|
||||
}
|
||||
|
||||
void marlin_stop_and_save_print_to_ram(){
|
||||
void marlin_stop_and_save_print_to_ram() {
|
||||
stop_and_save_print_to_ram(0,0);
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +136,15 @@ void safe_delay_keep_alive(uint16_t t) {
|
|||
delay_keep_alive(t);
|
||||
}
|
||||
|
||||
void Enable_E0(){ enable_e0(); }
|
||||
void Disable_E0(){ disable_e0(); }
|
||||
void Enable_E0() {
|
||||
enable_e0();
|
||||
}
|
||||
|
||||
bool all_axes_homed(){
|
||||
void Disable_E0() {
|
||||
disable_e0();
|
||||
}
|
||||
|
||||
bool all_axes_homed() {
|
||||
return axis_known_position[X_AXIS] && axis_known_position[Y_AXIS];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/// @file
|
||||
/// @file mmu2_protocol.cpp
|
||||
#include "mmu2_protocol.h"
|
||||
|
||||
// protocol definition
|
||||
|
|
@ -112,11 +112,8 @@ DecodeStatus Protocol::DecodeRequest(uint8_t c) {
|
|||
rqState = RequestStates::Code;
|
||||
return DecodeStatus::MessageCompleted;
|
||||
}
|
||||
} else {
|
||||
requestMsg.code = RequestMsgCodes::unknown;
|
||||
rqState = RequestStates::Error;
|
||||
return DecodeStatus::Error;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default: //case error:
|
||||
if (IsNewLine(c)) {
|
||||
rqState = RequestStates::Code;
|
||||
|
|
@ -331,7 +328,7 @@ uint8_t Protocol::UInt8ToHex(uint8_t value, uint8_t *dst) {
|
|||
return charsOut;
|
||||
}
|
||||
|
||||
uint8_t Protocol::UInt16ToHex(uint16_t value, uint8_t *dst) {
|
||||
uint8_t __attribute__((noinline)) Protocol::UInt16ToHex(uint16_t value, uint8_t *dst) {
|
||||
constexpr uint16_t topNibbleMask = 0xf000;
|
||||
if (value == 0) {
|
||||
*dst = '0';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/// @file protocol.h
|
||||
/// @file mmu2_protocol.h
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "mmu2_crc.h"
|
||||
|
|
@ -8,6 +8,7 @@ namespace modules {
|
|||
/// @brief The MMU communication protocol implementation and related stuff.
|
||||
///
|
||||
/// See description of the new protocol in the MMU 2021 doc
|
||||
|
||||
namespace protocol {
|
||||
|
||||
/// Definition of request message codes
|
||||
|
|
@ -179,17 +180,9 @@ public:
|
|||
/// @returns number of bytes written into txbuff
|
||||
static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Encode response to Query operation status
|
||||
/// @param msg source request message for this response
|
||||
/// @param code status of operation (Processing, Error, Finished)
|
||||
/// @param value related to status of operation(e.g. error code or progress)
|
||||
/// @param rcs status of operation (Processing, Error, Finished)
|
||||
/// @param txbuff where to format the message
|
||||
/// @returns number of bytes written into txbuff
|
||||
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseCommandStatus rcs, uint8_t *txbuff);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
// on MK3/S/+ we shuffle the timers a bit, thus "_millis" may not equal "millis"
|
||||
#include "system_timer.h"
|
||||
#else
|
||||
// irrelevant on Buddy FW, just keep "_millis" as "millis"
|
||||
// irrelevant on Buddy FW, just keep "_millis" as "millis"
|
||||
#include <wiring_time.h>
|
||||
#define _millis millis
|
||||
#ifdef UNITTEST
|
||||
|
|
@ -32,18 +32,18 @@ namespace MMU2 {
|
|||
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]
|
||||
};
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ StepStatus ProtocolLogic::ExpectingMessage() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
[[fallthrough]]; // otherwise
|
||||
[[fallthrough]]; // otherwise
|
||||
default:
|
||||
RecordUARTActivity(); // something has happened on the UART, update the timeout record
|
||||
return ProtocolError;
|
||||
|
|
@ -194,7 +194,7 @@ StepStatus ProtocolLogic::ExpectingMessage() {
|
|||
}
|
||||
if (bytesConsumed != 0) {
|
||||
RecordUARTActivity(); // something has happened on the UART, update the timeout record
|
||||
return Processing; // consumed some bytes, but message still not ready
|
||||
return Processing; // consumed some bytes, but message still not ready
|
||||
} else if (Elapsed(linkLayerTimeout) && currentScope != Scope::Stopped) {
|
||||
return CommunicationTimeout;
|
||||
}
|
||||
|
|
@ -267,6 +267,8 @@ StepStatus ProtocolLogic::ScopeStep() {
|
|||
if (!ExpectsResponse()) {
|
||||
// we are waiting for something
|
||||
switch (currentScope) {
|
||||
case Scope::StartSeq:
|
||||
return Processing;
|
||||
case Scope::DelayedRestart:
|
||||
return DelayedRestartWait();
|
||||
case Scope::Idle:
|
||||
|
|
@ -280,17 +282,18 @@ StepStatus ProtocolLogic::ScopeStep() {
|
|||
}
|
||||
} else {
|
||||
// we are expecting a message
|
||||
if (auto expmsg = ExpectingMessage(); expmsg != MessageReady) // this whole statement takes 12B
|
||||
if (auto expmsg = ExpectingMessage(); expmsg != MessageReady) { // this whole statement takes 12B
|
||||
return expmsg;
|
||||
}
|
||||
|
||||
// process message
|
||||
switch (currentScope) {
|
||||
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:
|
||||
|
|
@ -335,7 +338,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();
|
||||
}
|
||||
|
|
@ -723,12 +726,13 @@ void ProtocolLogic::FormatLastResponseMsgAndClearLRB(char *dst) {
|
|||
for (uint8_t i = 0; i < lrb; ++i) {
|
||||
uint8_t b = lastReceivedBytes[i];
|
||||
// Check for printable character, including space
|
||||
if (b < 32 || b > 127)
|
||||
if (b < 32 || b > 127) {
|
||||
b = '.';
|
||||
}
|
||||
*dst++ = b;
|
||||
}
|
||||
*dst = 0; // terminate properly
|
||||
lrb = 0; // reset the input buffer index in case of a clean message
|
||||
lrb = 0; // reset the input buffer index in case of a clean message
|
||||
}
|
||||
|
||||
void ProtocolLogic::LogRequestMsg(const uint8_t *txbuff, uint8_t size) {
|
||||
|
|
@ -738,8 +742,9 @@ void ProtocolLogic::LogRequestMsg(const uint8_t *txbuff, uint8_t size) {
|
|||
for (uint8_t i = 0; i < size; ++i) {
|
||||
uint8_t b = txbuff[i];
|
||||
// Check for printable character, including space
|
||||
if (b < 32 || b > 127)
|
||||
if (b < 32 || b > 127) {
|
||||
b = '.';
|
||||
}
|
||||
tmp[i + 1] = b;
|
||||
}
|
||||
tmp[size + 1] = 0;
|
||||
|
|
@ -809,7 +814,7 @@ StepStatus ProtocolLogic::Step() {
|
|||
// We are ok, switching to Idle if there is no potential next request planned.
|
||||
// But the trouble is we must report a finished command if the previous command has just been finished
|
||||
// i.e. only try to find some planned command if we just finished the Idle cycle
|
||||
if (!ActivatePlannedRequest()) { // if nothing is planned, switch to Idle
|
||||
if (!ActivatePlannedRequest()) { // if nothing is planned, switch to Idle
|
||||
SwitchToIdle();
|
||||
} else if (ExpectsResponse()) {
|
||||
// if the previous cycle was Idle and now we have planned a new command -> avoid returning Finished
|
||||
|
|
@ -845,8 +850,9 @@ StepStatus ProtocolLogic::Step() {
|
|||
}
|
||||
|
||||
uint8_t ProtocolLogic::CommandInProgress() const {
|
||||
if (currentScope != Scope::Command)
|
||||
if (currentScope != Scope::Command) {
|
||||
return 0;
|
||||
}
|
||||
return (uint8_t)ReqMsg().code;
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +868,7 @@ void ProtocolLogic::ResetRetryAttempts() {
|
|||
retryAttempts = MAX_RETRIES;
|
||||
}
|
||||
|
||||
void __attribute__((noinline)) ProtocolLogic::ResetCommunicationTimeoutAttempts() {
|
||||
void ProtocolLogic::ResetCommunicationTimeoutAttempts() {
|
||||
SERIAL_ECHOLNPGM("RSTCommTimeout");
|
||||
dataTO.Reset();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,22 +52,22 @@ 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)
|
||||
CommandError, ///< the command in progress stopped due to unrecoverable error, user interaction required
|
||||
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
|
||||
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)
|
||||
CommandError, ///< the command in progress stopped due to unrecoverable error, user interaction required
|
||||
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.
|
||||
};
|
||||
|
||||
inline constexpr uint32_t linkLayerTimeout = 2000; ///< default link layer communication timeout
|
||||
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)
|
||||
inline constexpr uint32_t heartBeatPeriod = linkLayerTimeout / 2; ///< period of heart beat messages (Q0)
|
||||
|
||||
static_assert(heartBeatPeriod < linkLayerTimeout && linkLayerTimeout < dataLayerTimeout, "Incorrect ordering of timeouts");
|
||||
|
||||
|
|
@ -229,9 +229,9 @@ private:
|
|||
ErrorCode explicitPrinterError;
|
||||
|
||||
enum class State : uint_fast8_t {
|
||||
Stopped, ///< stopped for whatever reason
|
||||
Stopped, ///< stopped for whatever reason
|
||||
InitSequence, ///< initial sequence running
|
||||
Running ///< normal operation - Idle + Command processing
|
||||
Running ///< normal operation - Idle + Command processing
|
||||
};
|
||||
|
||||
enum class Scope : uint_fast8_t {
|
||||
|
|
@ -347,25 +347,25 @@ 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<uint8_t, 16> 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
|
||||
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.
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@ namespace MMU2 {
|
|||
/// When the printer's FW starts, the MMU mode is either Stopped or NotResponding (based on user's preference).
|
||||
/// When the MMU successfully establishes communication, the state changes to Active.
|
||||
enum class xState : uint_fast8_t {
|
||||
Active, ///< MMU has been detected, connected, communicates and is ready to be worked with.
|
||||
/// The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all.
|
||||
/// !!! Must be 0 !!! marlin_vars.mmu2_state is set to 0 if not active
|
||||
Stopped,
|
||||
|
||||
Active, ///< MMU has been detected, connected, communicates and is ready to be worked with.
|
||||
Connecting, ///< MMU is connected but it doesn't communicate (yet). The user wants the MMU, but it is not ready to be worked with.
|
||||
Stopped ///< The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all.
|
||||
};
|
||||
|
||||
} // namespace MMU2
|
||||
|
|
|
|||
Loading…
Reference in New Issue