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:
Guðni Már Gilbert 2024-03-28 23:15:35 +00:00 committed by gudnimg
parent e405e9140c
commit 592fc56bfc
11 changed files with 231 additions and 175 deletions

View File

@ -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();
@ -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()) {
@ -804,8 +829,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
// 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())
{
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();
}
@ -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());
}
break;
case FilamentState::NOT_PRESENT:
// fsensor not triggered, continue moving extruder

View File

@ -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();
@ -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
@ -343,6 +347,7 @@ 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
uint8_t tool_change_extruder; ///< only used for UI purposes

View File

@ -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;
}

View File

@ -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();

View File

@ -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];
}

View File

@ -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';

View File

@ -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);

View File

@ -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
@ -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,8 +282,9 @@ 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) {
@ -723,8 +726,9 @@ 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
@ -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;
@ -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();
}

View File

@ -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 {
/// 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