mmu.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  1. //! @file
  2. #include "mmu.h"
  3. #include "planner.h"
  4. #include "language.h"
  5. #include "lcd.h"
  6. #include "uart2.h"
  7. #include "temperature.h"
  8. #include "Configuration_prusa.h"
  9. #include "fsensor.h"
  10. #include "cardreader.h"
  11. #include "ultralcd.h"
  12. #include "sound.h"
  13. #include "printers.h"
  14. #include <avr/pgmspace.h>
  15. #include "io_atmega2560.h"
  16. #include "AutoDeplete.h"
  17. #ifdef TMC2130
  18. #include "tmc2130.h"
  19. #endif //TMC2130
  20. #define MMU_TODELAY 100
  21. #define MMU_TIMEOUT 10
  22. #define MMU_CMD_TIMEOUT 45000ul //5min timeout for mmu commands (except P0)
  23. #define MMU_P0_TIMEOUT 3000ul //timeout for P0 command: 3seconds
  24. #define MMU_MAX_RESEND_ATTEMPTS 2
  25. #ifdef MMU_HWRESET
  26. #define MMU_RST_PIN 76
  27. #endif //MMU_HWRESET
  28. namespace
  29. {
  30. enum class S : uint_least8_t
  31. {
  32. WaitStealthMode,
  33. GetFindaInit,
  34. GetBuildNr,
  35. GetVersion,
  36. Init,
  37. Disabled,
  38. Idle,
  39. GetFinda,
  40. WaitCmd, //!< wait for command response
  41. GetDrvError, //!< get power failures count
  42. };
  43. }
  44. bool mmu_enabled = false;
  45. bool mmu_ready = false;
  46. bool mmu_fil_loaded = false; //if true: blocks execution of duplicit T-codes
  47. static S mmu_state = S::Disabled;
  48. MmuCmd mmu_cmd = MmuCmd::None;
  49. //idler ir sensor
  50. uint8_t mmu_idl_sens = 0;
  51. bool ir_sensor_detected = false;
  52. bool mmu_loading_flag = false;
  53. uint8_t mmu_extruder = MMU_FILAMENT_UNKNOWN;
  54. //! This variable probably has no meaning and is planed to be removed
  55. uint8_t tmp_extruder = MMU_FILAMENT_UNKNOWN;
  56. int8_t mmu_finda = -1;
  57. int16_t mmu_version = -1;
  58. int16_t mmu_buildnr = -1;
  59. uint32_t mmu_last_request = 0;
  60. uint32_t mmu_last_response = 0;
  61. MmuCmd mmu_last_cmd = MmuCmd::None;
  62. uint16_t mmu_power_failures = 0;
  63. #ifdef MMU_DEBUG
  64. static const auto DEBUG_PUTS_P = puts_P;
  65. static const auto DEBUG_PRINTF_P = printf_P;
  66. #else //MMU_DEBUG
  67. #define DEBUG_PUTS_P(str)
  68. #define DEBUG_PRINTF_P( __fmt, ... )
  69. #endif //MMU_DEBUG
  70. #if defined(MMU_FINDA_DEBUG) && defined(MMU_DEBUG)
  71. static const auto FDEBUG_PUTS_P = puts_P;
  72. static const auto FDEBUG_PRINTF_P = printf_P;
  73. #else
  74. #define FDEBUG_PUTS_P(str)
  75. #define FDEBUG_PRINTF_P( __fmt, ... )
  76. #endif //defined(MMU_FINDA_DEBUG) && defined(MMU_DEBUG)
  77. //clear rx buffer
  78. void mmu_clr_rx_buf(void)
  79. {
  80. while (fgetc(uart2io) >= 0);
  81. }
  82. //send command - puts
  83. int mmu_puts_P(const char* str)
  84. {
  85. mmu_clr_rx_buf(); //clear rx buffer
  86. int r = fputs_P(str, uart2io); //send command
  87. mmu_last_request = _millis();
  88. return r;
  89. }
  90. //send command - printf
  91. int mmu_printf_P(const char* format, ...)
  92. {
  93. va_list args;
  94. va_start(args, format);
  95. mmu_clr_rx_buf(); //clear rx buffer
  96. int r = vfprintf_P(uart2io, format, args); //send command
  97. va_end(args);
  98. mmu_last_request = _millis();
  99. return r;
  100. }
  101. //check 'ok' response
  102. int8_t mmu_rx_ok(void)
  103. {
  104. int8_t res = uart2_rx_str_P(PSTR("ok\n"));
  105. if (res == 1) mmu_last_response = _millis();
  106. return res;
  107. }
  108. //check 'start' response
  109. int8_t mmu_rx_start(void)
  110. {
  111. int8_t res = uart2_rx_str_P(PSTR("start\n"));
  112. if (res == 1) mmu_last_response = _millis();
  113. return res;
  114. }
  115. //initialize mmu2 unit - first part - should be done at begining of startup process
  116. void mmu_init(void)
  117. {
  118. #ifdef MMU_HWRESET
  119. digitalWrite(MMU_RST_PIN, HIGH);
  120. pinMode(MMU_RST_PIN, OUTPUT); //setup reset pin
  121. #endif //MMU_HWRESET
  122. uart2_init(); //init uart2
  123. _delay_ms(10); //wait 10ms for sure
  124. mmu_reset(); //reset mmu (HW or SW), do not wait for response
  125. mmu_state = S::Init;
  126. PIN_INP(IR_SENSOR_PIN); //input mode
  127. PIN_SET(IR_SENSOR_PIN); //pullup
  128. }
  129. //if IR_SENSOR defined, always returns true
  130. //otherwise check for ir sensor and returns true if idler IR sensor was detected, otherwise returns false
  131. bool check_for_ir_sensor()
  132. {
  133. #ifdef IR_SENSOR
  134. return true;
  135. #else //IR_SENSOR
  136. bool detected = false;
  137. //if IR_SENSOR_PIN input is low and pat9125sensor is not present we detected idler sensor
  138. if ((PIN_GET(IR_SENSOR_PIN) == 0)
  139. #ifdef PAT9125
  140. && fsensor_not_responding
  141. #endif //PAT9125
  142. )
  143. {
  144. detected = true;
  145. //printf_P(PSTR("Idler IR sensor detected\n"));
  146. }
  147. else
  148. {
  149. //printf_P(PSTR("Idler IR sensor not detected\n"));
  150. }
  151. return detected;
  152. #endif //IR_SENSOR
  153. }
  154. //mmu main loop - state machine processing
  155. void mmu_loop(void)
  156. {
  157. static uint8_t mmu_attempt_nr = 0;
  158. // printf_P(PSTR("MMU loop, state=%d\n"), mmu_state);
  159. switch (mmu_state)
  160. {
  161. case S::Disabled:
  162. return;
  163. case S::Init:
  164. if (mmu_rx_start() > 0)
  165. {
  166. DEBUG_PUTS_P(PSTR("MMU => 'start'"));
  167. DEBUG_PUTS_P(PSTR("MMU <= 'S1'"));
  168. mmu_puts_P(PSTR("S1\n")); //send 'read version' request
  169. mmu_state = S::GetVersion;
  170. }
  171. else if (_millis() > 30000) //30sec after reset disable mmu
  172. {
  173. puts_P(PSTR("MMU not responding - DISABLED"));
  174. mmu_state = S::Disabled;
  175. }
  176. return;
  177. case S::GetVersion:
  178. if (mmu_rx_ok() > 0)
  179. {
  180. fscanf_P(uart2io, PSTR("%u"), &mmu_version); //scan version from buffer
  181. DEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_version);
  182. DEBUG_PUTS_P(PSTR("MMU <= 'S2'"));
  183. mmu_puts_P(PSTR("S2\n")); //send 'read buildnr' request
  184. mmu_state = S::GetBuildNr;
  185. }
  186. return;
  187. case S::GetBuildNr:
  188. if (mmu_rx_ok() > 0)
  189. {
  190. fscanf_P(uart2io, PSTR("%u"), &mmu_buildnr); //scan buildnr from buffer
  191. DEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_buildnr);
  192. bool version_valid = mmu_check_version();
  193. if (!version_valid) mmu_show_warning();
  194. else puts_P(PSTR("MMU version valid"));
  195. if ((PRINTER_TYPE == PRINTER_MK3) || (PRINTER_TYPE == PRINTER_MK3_SNMM))
  196. {
  197. FDEBUG_PUTS_P(PSTR("MMU <= 'P0'"));
  198. mmu_puts_P(PSTR("P0\n")); //send 'read finda' request
  199. mmu_state = S::GetFindaInit;
  200. }
  201. else
  202. {
  203. DEBUG_PUTS_P(PSTR("MMU <= 'M1'"));
  204. mmu_puts_P(PSTR("M1\n")); //set mmu mode to stealth
  205. mmu_state = S::WaitStealthMode;
  206. }
  207. }
  208. return;
  209. case S::WaitStealthMode:
  210. if (mmu_rx_ok() > 0)
  211. {
  212. FDEBUG_PUTS_P(PSTR("MMU <= 'P0'"));
  213. mmu_puts_P(PSTR("P0\n")); //send 'read finda' request
  214. mmu_state = S::GetFindaInit;
  215. }
  216. return;
  217. case S::GetFindaInit:
  218. if (mmu_rx_ok() > 0)
  219. {
  220. fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer
  221. FDEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_finda);
  222. puts_P(PSTR("MMU - ENABLED"));
  223. mmu_enabled = true;
  224. mmu_state = S::Idle;
  225. }
  226. return;
  227. case S::Idle:
  228. if (mmu_cmd != MmuCmd::None) //command request ?
  229. {
  230. if ((mmu_cmd >= MmuCmd::T0) && (mmu_cmd <= MmuCmd::T4))
  231. {
  232. const uint8_t filament = mmu_cmd - MmuCmd::T0;
  233. DEBUG_PRINTF_P(PSTR("MMU <= 'T%d'\n"), filament);
  234. mmu_printf_P(PSTR("T%d\n"), filament);
  235. mmu_state = S::WaitCmd; // wait for response
  236. mmu_fil_loaded = true;
  237. mmu_idl_sens = 1;
  238. }
  239. else if ((mmu_cmd >= MmuCmd::L0) && (mmu_cmd <= MmuCmd::L4))
  240. {
  241. const uint8_t filament = mmu_cmd - MmuCmd::L0;
  242. DEBUG_PRINTF_P(PSTR("MMU <= 'L%d'\n"), filament);
  243. mmu_printf_P(PSTR("L%d\n"), filament);
  244. mmu_state = S::WaitCmd; // wait for response
  245. }
  246. else if (mmu_cmd == MmuCmd::C0)
  247. {
  248. DEBUG_PRINTF_P(PSTR("MMU <= 'C0'\n"));
  249. mmu_puts_P(PSTR("C0\n")); //send 'continue loading'
  250. mmu_state = S::WaitCmd;
  251. mmu_idl_sens = 1;
  252. }
  253. else if (mmu_cmd == MmuCmd::U0)
  254. {
  255. DEBUG_PRINTF_P(PSTR("MMU <= 'U0'\n"));
  256. mmu_puts_P(PSTR("U0\n")); //send 'unload current filament'
  257. mmu_fil_loaded = false;
  258. mmu_state = S::WaitCmd;
  259. }
  260. else if ((mmu_cmd >= MmuCmd::E0) && (mmu_cmd <= MmuCmd::E4))
  261. {
  262. const uint8_t filament = mmu_cmd - MmuCmd::E0;
  263. DEBUG_PRINTF_P(PSTR("MMU <= 'E%d'\n"), filament);
  264. mmu_printf_P(PSTR("E%d\n"), filament); //send eject filament
  265. mmu_fil_loaded = false;
  266. mmu_state = S::WaitCmd;
  267. }
  268. else if (mmu_cmd == MmuCmd::R0)
  269. {
  270. DEBUG_PRINTF_P(PSTR("MMU <= 'R0'\n"));
  271. mmu_puts_P(PSTR("R0\n")); //send recover after eject
  272. mmu_state = S::WaitCmd;
  273. }
  274. else if (mmu_cmd == MmuCmd::S3)
  275. {
  276. DEBUG_PRINTF_P(PSTR("MMU <= 'S3'\n"));
  277. mmu_puts_P(PSTR("S3\n")); //send power failures request
  278. mmu_state = S::GetDrvError;
  279. }
  280. mmu_last_cmd = mmu_cmd;
  281. mmu_cmd = MmuCmd::None;
  282. }
  283. else if ((mmu_last_response + 300) < _millis()) //request every 300ms
  284. {
  285. #ifndef IR_SENSOR
  286. if(check_for_ir_sensor()) ir_sensor_detected = true;
  287. #endif //IR_SENSOR not defined
  288. FDEBUG_PUTS_P(PSTR("MMU <= 'P0'"));
  289. mmu_puts_P(PSTR("P0\n")); //send 'read finda' request
  290. mmu_state = S::GetFinda;
  291. }
  292. return;
  293. case S::GetFinda: //response to command P0
  294. if (mmu_rx_ok() > 0)
  295. {
  296. fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer
  297. FDEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_finda);
  298. //printf_P(PSTR("Eact: %d\n"), int(e_active()));
  299. if (!mmu_finda && CHECK_FSENSOR && fsensor_enabled) {
  300. fsensor_stop_and_save_print();
  301. enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover
  302. ad_markDepleted(mmu_extruder);
  303. if (lcd_autoDepleteEnabled() && !ad_allDepleted())
  304. {
  305. enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command
  306. }
  307. else
  308. {
  309. enquecommand_front_P(PSTR("M600")); //save print and run M600 command
  310. }
  311. }
  312. mmu_state = S::Idle;
  313. if (mmu_cmd == MmuCmd::None)
  314. mmu_ready = true;
  315. }
  316. else if ((mmu_last_request + MMU_P0_TIMEOUT) < _millis())
  317. { //resend request after timeout (30s)
  318. mmu_state = S::Idle;
  319. }
  320. return;
  321. case S::WaitCmd: //response to mmu commands
  322. if (mmu_idl_sens)
  323. {
  324. if (PIN_GET(IR_SENSOR_PIN) == 0 && mmu_loading_flag)
  325. {
  326. DEBUG_PRINTF_P(PSTR("MMU <= 'A'\n"));
  327. mmu_puts_P(PSTR("A\n")); //send 'abort' request
  328. mmu_idl_sens = 0;
  329. //printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n"));
  330. }
  331. //else
  332. //printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n"));
  333. }
  334. if (mmu_rx_ok() > 0)
  335. {
  336. DEBUG_PRINTF_P(PSTR("MMU => 'ok'\n"));
  337. mmu_attempt_nr = 0;
  338. mmu_last_cmd = MmuCmd::None;
  339. mmu_ready = true;
  340. mmu_state = S::Idle;
  341. }
  342. else if ((mmu_last_request + MMU_CMD_TIMEOUT) < _millis())
  343. { //resend request after timeout (5 min)
  344. if (mmu_last_cmd != MmuCmd::None)
  345. {
  346. if (mmu_attempt_nr++ < MMU_MAX_RESEND_ATTEMPTS) {
  347. DEBUG_PRINTF_P(PSTR("MMU retry attempt nr. %d\n"), mmu_attempt_nr - 1);
  348. mmu_cmd = mmu_last_cmd;
  349. }
  350. else {
  351. mmu_cmd = MmuCmd::None;
  352. mmu_last_cmd = MmuCmd::None; //check
  353. mmu_attempt_nr = 0;
  354. }
  355. }
  356. mmu_state = S::Idle;
  357. }
  358. return;
  359. case S::GetDrvError:
  360. if (mmu_rx_ok() > 0)
  361. {
  362. fscanf_P(uart2io, PSTR("%d"), &mmu_power_failures); //scan power failures
  363. DEBUG_PRINTF_P(PSTR("MMU => 'ok'\n"));
  364. mmu_last_cmd = MmuCmd::None;
  365. mmu_ready = true;
  366. mmu_state = S::Idle;
  367. }
  368. else if ((mmu_last_request + MMU_CMD_TIMEOUT) < _millis())
  369. { //resend request after timeout (5 min)
  370. mmu_state = S::Idle;
  371. }
  372. }
  373. }
  374. void mmu_reset(void)
  375. {
  376. #ifdef MMU_HWRESET //HW - pulse reset pin
  377. digitalWrite(MMU_RST_PIN, LOW);
  378. _delay_us(100);
  379. digitalWrite(MMU_RST_PIN, HIGH);
  380. #else //SW - send X0 command
  381. mmu_puts_P(PSTR("X0\n"));
  382. #endif
  383. }
  384. int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament)
  385. {
  386. printf_P(PSTR("MMU <= 'F%d %d'\n"), extruder, filament);
  387. mmu_printf_P(PSTR("F%d %d\n"), extruder, filament);
  388. unsigned char timeout = MMU_TIMEOUT; //10x100ms
  389. while ((mmu_rx_ok() <= 0) && (--timeout))
  390. delay_keep_alive(MMU_TODELAY);
  391. return timeout?1:0;
  392. }
  393. //! @brief Enqueue MMUv2 command
  394. //!
  395. //! Call manage_response() after enqueuing to process command.
  396. //! If T command is enqueued, it disables current for extruder motor if TMC2130 driver present.
  397. //! If T or L command is enqueued, it marks filament loaded in AutoDeplete module.
  398. void mmu_command(MmuCmd cmd)
  399. {
  400. if ((cmd >= MmuCmd::T0) && (cmd <= MmuCmd::T4))
  401. {
  402. //disable extruder motor
  403. #ifdef TMC2130
  404. tmc2130_set_pwr(E_AXIS, 0);
  405. #endif //TMC2130
  406. //printf_P(PSTR("E-axis disabled\n"));
  407. ad_markLoaded(cmd - MmuCmd::T0);
  408. }
  409. if ((cmd >= MmuCmd::L0) && (cmd <= MmuCmd::L4))
  410. {
  411. ad_markLoaded(cmd - MmuCmd::L0);
  412. }
  413. mmu_cmd = cmd;
  414. mmu_ready = false;
  415. }
  416. //! @brief Rotate extruder idler to catch filament
  417. //! @par synchronize
  418. //! * true blocking call
  419. //! * false non-blocking call
  420. void mmu_load_step(bool synchronize)
  421. {
  422. current_position[E_AXIS] = current_position[E_AXIS] + MMU_LOAD_FEEDRATE * 0.1;
  423. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
  424. if (synchronize) st_synchronize();
  425. }
  426. //! @brief Is nozzle hot enough to move extruder wheels and do we have idler sensor?
  427. //!
  428. //! Do load steps only if temperature is higher then min. temp for safe extrusion and
  429. //! idler sensor present.
  430. //! Otherwise "cold extrusion prevented" would be send to serial line periodically
  431. //! and watchdog reset will be triggered by lack of keep_alive processing.
  432. //!
  433. //! @retval true temperature is high enough to move extruder
  434. //! @retval false temperature is not high enough to move extruder, turned
  435. //! off E-stepper to prevent over-heating and allow filament pull-out if necessary
  436. bool can_extrude()
  437. {
  438. if ((degHotend(active_extruder) < EXTRUDE_MINTEMP) || !ir_sensor_detected)
  439. {
  440. disable_e0();
  441. delay_keep_alive(100);
  442. return false;
  443. }
  444. return true;
  445. }
  446. bool mmu_get_response(uint8_t move)
  447. {
  448. mmu_loading_flag = false;
  449. printf_P(PSTR("mmu_get_response - begin move:%d\n"), move);
  450. KEEPALIVE_STATE(IN_PROCESS);
  451. while (mmu_cmd != MmuCmd::None)
  452. {
  453. delay_keep_alive(100);
  454. }
  455. while (!mmu_ready)
  456. {
  457. if ((mmu_state != S::WaitCmd) && (mmu_last_cmd == MmuCmd::None))
  458. break;
  459. switch (move) {
  460. case MMU_LOAD_MOVE:
  461. mmu_loading_flag = true;
  462. if (can_extrude()) mmu_load_step();
  463. //don't rely on "ok" signal from mmu unit; if filament detected by idler sensor during loading stop loading movements to prevent infinite loading
  464. if (PIN_GET(IR_SENSOR_PIN) == 0) move = MMU_NO_MOVE;
  465. break;
  466. case MMU_UNLOAD_MOVE:
  467. if (PIN_GET(IR_SENSOR_PIN) == 0) //filament is still detected by idler sensor, printer helps with unlading
  468. {
  469. if (can_extrude())
  470. {
  471. printf_P(PSTR("Unload 1\n"));
  472. current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
  473. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
  474. st_synchronize();
  475. }
  476. }
  477. else //filament was unloaded from idler, no additional movements needed
  478. {
  479. printf_P(PSTR("Unloading finished 1\n"));
  480. disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
  481. move = MMU_NO_MOVE;
  482. }
  483. break;
  484. case MMU_TCODE_MOVE: //first do unload and then continue with infinite loading movements
  485. if (PIN_GET(IR_SENSOR_PIN) == 0) //filament detected by idler sensor, we must unload first
  486. {
  487. if (can_extrude())
  488. {
  489. printf_P(PSTR("Unload 2\n"));
  490. current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
  491. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
  492. st_synchronize();
  493. }
  494. }
  495. else //delay to allow mmu unit to pull out filament from bondtech gears and then start with infinite loading
  496. {
  497. printf_P(PSTR("Unloading finished 2\n"));
  498. disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
  499. delay_keep_alive(MMU_LOAD_TIME_MS);
  500. move = MMU_LOAD_MOVE;
  501. printf_P(PSTR("mmu_get_response - begin move:%d\n"), move);
  502. }
  503. break;
  504. case MMU_NO_MOVE:
  505. default:
  506. delay_keep_alive(100);
  507. break;
  508. }
  509. }
  510. printf_P(PSTR("mmu_get_response() returning: %d\n"), mmu_ready);
  511. bool ret = mmu_ready;
  512. mmu_ready = false;
  513. // printf_P(PSTR("mmu_get_response - end %d\n"), ret?1:0);
  514. return ret;
  515. }
  516. //! @brief Wait for active extruder to reach temperature set
  517. //!
  518. //! This function is blocking and showing lcd_wait_for_heater() screen
  519. //! which is constantly updated with nozzle temperature.
  520. void mmu_wait_for_heater_blocking()
  521. {
  522. while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)
  523. {
  524. delay_keep_alive(1000);
  525. lcd_wait_for_heater();
  526. }
  527. }
  528. void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move)
  529. {
  530. bool response = false;
  531. mmu_print_saved = false;
  532. bool lcd_update_was_enabled = false;
  533. float hotend_temp_bckp = degTargetHotend(active_extruder);
  534. float z_position_bckp = current_position[Z_AXIS];
  535. float x_position_bckp = current_position[X_AXIS];
  536. float y_position_bckp = current_position[Y_AXIS];
  537. uint8_t screen = 0; //used for showing multiscreen messages
  538. while(!response)
  539. {
  540. response = mmu_get_response(move); //wait for "ok" from mmu
  541. if (!response) { //no "ok" was received in reserved time frame, user will fix the issue on mmu unit
  542. if (!mmu_print_saved) { //first occurence, we are saving current position, park print head in certain position and disable nozzle heater
  543. uint8_t mmu_fail = eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL);
  544. uint16_t mmu_fail_tot = eeprom_read_word((uint16_t*)EEPROM_MMU_FAIL_TOT);
  545. if(mmu_fail < 255) eeprom_update_byte((uint8_t*)EEPROM_MMU_FAIL, mmu_fail + 1);
  546. if(mmu_fail_tot < 65535) eeprom_update_word((uint16_t*)EEPROM_MMU_FAIL_TOT, mmu_fail_tot + 1);
  547. if (lcd_update_enabled) {
  548. lcd_update_was_enabled = true;
  549. lcd_update_enable(false);
  550. }
  551. st_synchronize();
  552. mmu_print_saved = true;
  553. printf_P(PSTR("MMU not responding\n"));
  554. hotend_temp_bckp = degTargetHotend(active_extruder);
  555. if (move_axes) {
  556. z_position_bckp = current_position[Z_AXIS];
  557. x_position_bckp = current_position[X_AXIS];
  558. y_position_bckp = current_position[Y_AXIS];
  559. //lift z
  560. current_position[Z_AXIS] += Z_PAUSE_LIFT;
  561. if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
  562. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
  563. st_synchronize();
  564. //Move XY to side
  565. current_position[X_AXIS] = X_PAUSE_POS;
  566. current_position[Y_AXIS] = Y_PAUSE_POS;
  567. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
  568. st_synchronize();
  569. }
  570. if (turn_off_nozzle) {
  571. //set nozzle target temperature to 0
  572. setAllTargetHotends(0);
  573. }
  574. disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
  575. }
  576. //first three lines are used for printing multiscreen message; last line contains measured and target nozzle temperature
  577. if (screen == 0) { //screen 0
  578. lcd_display_message_fullscreen_P(_i("MMU needs user attention."));
  579. screen++;
  580. }
  581. else { //screen 1
  582. if((degTargetHotend(active_extruder) == 0) && turn_off_nozzle) lcd_display_message_fullscreen_P(_i("Press the knob to resume nozzle temperature."));
  583. else lcd_display_message_fullscreen_P(_i("Fix the issue and then press button on MMU unit."));
  584. screen=0;
  585. }
  586. lcd_set_degree();
  587. //5 seconds delay
  588. for (uint8_t i = 0; i < 5; i++) {
  589. if (lcd_clicked()) {
  590. setTargetHotend(hotend_temp_bckp, active_extruder);
  591. /// mmu_cmd = mmu_last_cmd;
  592. break;
  593. }
  594. //Print the hotend temperature (9 chars total) and fill rest of the line with space
  595. lcd_set_cursor(0, 4); //line 4
  596. int chars = lcd_printf_P(_N("%c%3d/%d%c"), LCD_STR_THERMOMETER[0],(int)(degHotend(active_extruder) + 0.5), (int)(degTargetHotend(active_extruder) + 0.5), LCD_STR_DEGREE[0]);
  597. lcd_space(9 - chars);
  598. delay_keep_alive(1000);
  599. }
  600. }
  601. else if (mmu_print_saved) {
  602. printf_P(PSTR("MMU starts responding\n"));
  603. if (turn_off_nozzle)
  604. {
  605. lcd_clear();
  606. setTargetHotend(hotend_temp_bckp, active_extruder);
  607. if (((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)) {
  608. lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature..."));
  609. delay_keep_alive(3000);
  610. }
  611. mmu_wait_for_heater_blocking();
  612. }
  613. if (move_axes) {
  614. lcd_clear();
  615. lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position..."));
  616. current_position[X_AXIS] = x_position_bckp;
  617. current_position[Y_AXIS] = y_position_bckp;
  618. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
  619. st_synchronize();
  620. current_position[Z_AXIS] = z_position_bckp;
  621. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
  622. st_synchronize();
  623. }
  624. else {
  625. lcd_clear();
  626. lcd_display_message_fullscreen_P(_i("MMU OK. Resuming..."));
  627. delay_keep_alive(1000); //delay just for showing MMU OK message for a while in case that there are no xyz movements
  628. }
  629. }
  630. }
  631. if (lcd_update_was_enabled) lcd_update_enable(true);
  632. #ifdef TMC2130
  633. //enable extruder motor (disabled in mmu_command, start of T-code processing)
  634. tmc2130_set_pwr(E_AXIS, 1);
  635. //printf_P(PSTR("E-axis enabled\n"));
  636. #endif //TMC2130
  637. }
  638. //! @brief load filament to nozzle of multimaterial printer
  639. //!
  640. //! This function is used only only after T? (user select filament) and M600 (change filament).
  641. //! It is not used after T0 .. T4 command (select filament), in such case, gcode is responsible for loading
  642. //! filament to nozzle.
  643. //!
  644. void mmu_load_to_nozzle()
  645. {
  646. st_synchronize();
  647. bool saved_e_relative_mode = axis_relative_modes[E_AXIS];
  648. if (!saved_e_relative_mode) axis_relative_modes[E_AXIS] = true;
  649. if (ir_sensor_detected)
  650. {
  651. current_position[E_AXIS] += 3.0f;
  652. }
  653. else
  654. {
  655. current_position[E_AXIS] += 7.2f;
  656. }
  657. float feedrate = 562;
  658. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate / 60, active_extruder);
  659. st_synchronize();
  660. current_position[E_AXIS] += 14.4f;
  661. feedrate = 871;
  662. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate / 60, active_extruder);
  663. st_synchronize();
  664. current_position[E_AXIS] += 36.0f;
  665. feedrate = 1393;
  666. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate / 60, active_extruder);
  667. st_synchronize();
  668. current_position[E_AXIS] += 14.4f;
  669. feedrate = 871;
  670. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate / 60, active_extruder);
  671. st_synchronize();
  672. if (!saved_e_relative_mode) axis_relative_modes[E_AXIS] = false;
  673. }
  674. void mmu_M600_wait_and_beep() {
  675. //Beep and wait for user to remove old filament and prepare new filament for load
  676. KEEPALIVE_STATE(PAUSED_FOR_USER);
  677. int counterBeep = 0;
  678. lcd_display_message_fullscreen_P(_i("Remove old filament and press the knob to start loading new filament."));
  679. bool bFirst=true;
  680. while (!lcd_clicked()){
  681. manage_heater();
  682. manage_inactivity(true);
  683. #if BEEPER > 0
  684. if (counterBeep == 500) {
  685. counterBeep = 0;
  686. }
  687. SET_OUTPUT(BEEPER);
  688. if (counterBeep == 0) {
  689. if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst))
  690. {
  691. bFirst=false;
  692. WRITE(BEEPER, HIGH);
  693. }
  694. }
  695. if (counterBeep == 20) {
  696. WRITE(BEEPER, LOW);
  697. }
  698. counterBeep++;
  699. #endif //BEEPER > 0
  700. delay_keep_alive(4);
  701. }
  702. WRITE(BEEPER, LOW);
  703. }
  704. void mmu_M600_load_filament(bool automatic)
  705. {
  706. //load filament for mmu v2
  707. tmp_extruder = mmu_extruder;
  708. if (!automatic) {
  709. #ifdef MMU_M600_SWITCH_EXTRUDER
  710. bool yes = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Do you want to switch extruder?"), false);
  711. if(yes) tmp_extruder = choose_extruder_menu();
  712. #endif //MMU_M600_SWITCH_EXTRUDER
  713. }
  714. else {
  715. tmp_extruder = ad_getAlternative(tmp_extruder);
  716. }
  717. lcd_update_enable(false);
  718. lcd_clear();
  719. lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_LOADING_FILAMENT));
  720. lcd_print(" ");
  721. lcd_print(tmp_extruder + 1);
  722. snmm_filaments_used |= (1 << tmp_extruder); //for stop print
  723. // printf_P(PSTR("T code: %d \n"), tmp_extruder);
  724. // mmu_printf_P(PSTR("T%d\n"), tmp_extruder);
  725. mmu_command(MmuCmd::T0 + tmp_extruder);
  726. manage_response(false, true, MMU_LOAD_MOVE);
  727. mmu_continue_loading();
  728. mmu_extruder = tmp_extruder; //filament change is finished
  729. mmu_load_to_nozzle();
  730. load_filament_final_feed();
  731. st_synchronize();
  732. }
  733. #ifdef SNMM
  734. void extr_mov(float shift, float feed_rate)
  735. { //move extruder no matter what the current heater temperature is
  736. set_extrude_min_temp(.0);
  737. current_position[E_AXIS] += shift;
  738. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feed_rate, active_extruder);
  739. set_extrude_min_temp(EXTRUDE_MINTEMP);
  740. }
  741. #endif //SNMM
  742. void change_extr(int
  743. #ifdef SNMM
  744. extr
  745. #endif //SNMM
  746. ) { //switches multiplexer for extruders
  747. #ifdef SNMM
  748. st_synchronize();
  749. _delay(100);
  750. disable_e0();
  751. disable_e1();
  752. disable_e2();
  753. mmu_extruder = extr;
  754. pinMode(E_MUX0_PIN, OUTPUT);
  755. pinMode(E_MUX1_PIN, OUTPUT);
  756. switch (extr) {
  757. case 1:
  758. WRITE(E_MUX0_PIN, HIGH);
  759. WRITE(E_MUX1_PIN, LOW);
  760. break;
  761. case 2:
  762. WRITE(E_MUX0_PIN, LOW);
  763. WRITE(E_MUX1_PIN, HIGH);
  764. break;
  765. case 3:
  766. WRITE(E_MUX0_PIN, HIGH);
  767. WRITE(E_MUX1_PIN, HIGH);
  768. break;
  769. default:
  770. WRITE(E_MUX0_PIN, LOW);
  771. WRITE(E_MUX1_PIN, LOW);
  772. break;
  773. }
  774. _delay(100);
  775. #endif
  776. }
  777. int get_ext_nr()
  778. { //reads multiplexer input pins and return current extruder number (counted from 0)
  779. #ifndef SNMM
  780. return(mmu_extruder); //update needed
  781. #else
  782. return(2 * READ(E_MUX1_PIN) + READ(E_MUX0_PIN));
  783. #endif
  784. }
  785. void display_loading()
  786. {
  787. switch (mmu_extruder)
  788. {
  789. case 1: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T1)); break;
  790. case 2: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T2)); break;
  791. case 3: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T3)); break;
  792. default: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T0)); break;
  793. }
  794. }
  795. void extr_adj(int extruder) //loading filament for SNMM
  796. {
  797. #ifndef SNMM
  798. MmuCmd cmd = MmuCmd::L0 + extruder;
  799. if (cmd > MmuCmd::L4)
  800. {
  801. printf_P(PSTR("Filament out of range %d \n"),extruder);
  802. return;
  803. }
  804. mmu_command(cmd);
  805. //show which filament is currently loaded
  806. lcd_update_enable(false);
  807. lcd_clear();
  808. lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_LOADING_FILAMENT));
  809. //if(strlen(_T(MSG_LOADING_FILAMENT))>18) lcd.setCursor(0, 1);
  810. //else lcd.print(" ");
  811. lcd_print(" ");
  812. lcd_print(extruder + 1);
  813. // get response
  814. manage_response(false, false);
  815. lcd_update_enable(true);
  816. //lcd_return_to_status();
  817. #else
  818. bool correct;
  819. max_feedrate[E_AXIS] =80;
  820. //max_feedrate[E_AXIS] = 50;
  821. START:
  822. lcd_clear();
  823. lcd_set_cursor(0, 0);
  824. switch (extruder) {
  825. case 1: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T1)); break;
  826. case 2: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T2)); break;
  827. case 3: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T3)); break;
  828. default: lcd_display_message_fullscreen_P(_T(MSG_FILAMENT_LOADING_T0)); break;
  829. }
  830. KEEPALIVE_STATE(PAUSED_FOR_USER);
  831. do{
  832. extr_mov(0.001,1000);
  833. delay_keep_alive(2);
  834. } while (!lcd_clicked());
  835. //delay_keep_alive(500);
  836. KEEPALIVE_STATE(IN_HANDLER);
  837. st_synchronize();
  838. //correct = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FIL_LOADED_CHECK, false);
  839. //if (!correct) goto START;
  840. //extr_mov(BOWDEN_LENGTH/2.f, 500); //dividing by 2 is there because of max. extrusion length limitation (x_max + y_max)
  841. //extr_mov(BOWDEN_LENGTH/2.f, 500);
  842. extr_mov(bowden_length[extruder], 500);
  843. lcd_clear();
  844. lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_LOADING_FILAMENT));
  845. if(strlen(_T(MSG_LOADING_FILAMENT))>18) lcd_set_cursor(0, 1);
  846. else lcd_print(" ");
  847. lcd_print(mmu_extruder + 1);
  848. lcd_set_cursor(0, 2); lcd_puts_P(_T(MSG_PLEASE_WAIT));
  849. st_synchronize();
  850. max_feedrate[E_AXIS] = 50;
  851. lcd_update_enable(true);
  852. lcd_return_to_status();
  853. lcdDrawUpdate = 2;
  854. #endif
  855. }
  856. struct E_step
  857. {
  858. float extrude; //!< extrude distance in mm
  859. float feed_rate; //!< feed rate in mm/s
  860. };
  861. static const E_step ramming_sequence[] PROGMEM =
  862. {
  863. {1.0, 1000.0/60},
  864. {1.0, 1500.0/60},
  865. {2.0, 2000.0/60},
  866. {1.5, 3000.0/60},
  867. {2.5, 4000.0/60},
  868. {-15.0, 5000.0/60},
  869. {-14.0, 1200.0/60},
  870. {-6.0, 600.0/60},
  871. {10.0, 700.0/60},
  872. {-10.0, 400.0/60},
  873. {-50.0, 2000.0/60},
  874. };
  875. //! @brief Unload sequence to optimize shape of the tip of the unloaded filament
  876. void mmu_filament_ramming()
  877. {
  878. for(uint8_t i = 0; i < (sizeof(ramming_sequence)/sizeof(E_step));++i)
  879. {
  880. current_position[E_AXIS] += pgm_read_float(&(ramming_sequence[i].extrude));
  881. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
  882. current_position[E_AXIS], pgm_read_float(&(ramming_sequence[i].feed_rate)), active_extruder);
  883. st_synchronize();
  884. }
  885. }
  886. void extr_unload()
  887. { //unload just current filament for multimaterial printers
  888. #ifdef SNMM
  889. float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
  890. float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
  891. uint8_t SilentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
  892. #endif
  893. if (degHotend0() > EXTRUDE_MINTEMP)
  894. {
  895. #ifndef SNMM
  896. st_synchronize();
  897. //show which filament is currently unloaded
  898. lcd_update_enable(false);
  899. lcd_clear();
  900. lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_UNLOADING_FILAMENT));
  901. lcd_print(" ");
  902. if (mmu_extruder == MMU_FILAMENT_UNKNOWN) lcd_print(" ");
  903. else lcd_print(mmu_extruder + 1);
  904. mmu_filament_ramming();
  905. mmu_command(MmuCmd::U0);
  906. // get response
  907. manage_response(false, true, MMU_UNLOAD_MOVE);
  908. lcd_update_enable(true);
  909. #else //SNMM
  910. lcd_clear();
  911. lcd_display_message_fullscreen_P(PSTR(""));
  912. max_feedrate[E_AXIS] = 50;
  913. lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_UNLOADING_FILAMENT));
  914. lcd_print(" ");
  915. lcd_print(mmu_extruder + 1);
  916. lcd_set_cursor(0, 2); lcd_puts_P(_T(MSG_PLEASE_WAIT));
  917. if (current_position[Z_AXIS] < 15) {
  918. current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion
  919. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder);
  920. }
  921. current_position[E_AXIS] += 10; //extrusion
  922. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder);
  923. st_current_set(2, E_MOTOR_HIGH_CURRENT);
  924. if (current_temperature[0] < 230) { //PLA & all other filaments
  925. current_position[E_AXIS] += 5.4;
  926. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
  927. current_position[E_AXIS] += 3.2;
  928. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
  929. current_position[E_AXIS] += 3;
  930. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
  931. }
  932. else { //ABS
  933. current_position[E_AXIS] += 3.1;
  934. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
  935. current_position[E_AXIS] += 3.1;
  936. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
  937. current_position[E_AXIS] += 4;
  938. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
  939. /*current_position[X_AXIS] += 23; //delay
  940. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay
  941. current_position[X_AXIS] -= 23; //delay
  942. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay*/
  943. delay_keep_alive(4700);
  944. }
  945. max_feedrate[E_AXIS] = 80;
  946. current_position[E_AXIS] -= (bowden_length[mmu_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
  947. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
  948. current_position[E_AXIS] -= (bowden_length[mmu_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
  949. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
  950. st_synchronize();
  951. //st_current_init();
  952. if (SilentMode != SILENT_MODE_OFF) st_current_set(2, tmp_motor[2]); //set back to normal operation currents
  953. else st_current_set(2, tmp_motor_loud[2]);
  954. lcd_update_enable(true);
  955. lcd_return_to_status();
  956. max_feedrate[E_AXIS] = 50;
  957. #endif //SNMM
  958. }
  959. else
  960. {
  961. show_preheat_nozzle_warning();
  962. }
  963. //lcd_return_to_status();
  964. }
  965. //wrapper functions for loading filament
  966. void extr_adj_0()
  967. {
  968. #ifndef SNMM
  969. enquecommand_P(PSTR("M701 E0"));
  970. #else
  971. change_extr(0);
  972. extr_adj(0);
  973. #endif
  974. }
  975. void extr_adj_1()
  976. {
  977. #ifndef SNMM
  978. enquecommand_P(PSTR("M701 E1"));
  979. #else
  980. change_extr(1);
  981. extr_adj(1);
  982. #endif
  983. }
  984. void extr_adj_2()
  985. {
  986. #ifndef SNMM
  987. enquecommand_P(PSTR("M701 E2"));
  988. #else
  989. change_extr(2);
  990. extr_adj(2);
  991. #endif
  992. }
  993. void extr_adj_3()
  994. {
  995. #ifndef SNMM
  996. enquecommand_P(PSTR("M701 E3"));
  997. #else
  998. change_extr(3);
  999. extr_adj(3);
  1000. #endif
  1001. }
  1002. void extr_adj_4()
  1003. {
  1004. #ifndef SNMM
  1005. enquecommand_P(PSTR("M701 E4"));
  1006. #else
  1007. change_extr(4);
  1008. extr_adj(4);
  1009. #endif
  1010. }
  1011. void mmu_load_to_nozzle_0()
  1012. {
  1013. lcd_mmu_load_to_nozzle(0);
  1014. }
  1015. void mmu_load_to_nozzle_1()
  1016. {
  1017. lcd_mmu_load_to_nozzle(1);
  1018. }
  1019. void mmu_load_to_nozzle_2()
  1020. {
  1021. lcd_mmu_load_to_nozzle(2);
  1022. }
  1023. void mmu_load_to_nozzle_3()
  1024. {
  1025. lcd_mmu_load_to_nozzle(3);
  1026. }
  1027. void mmu_load_to_nozzle_4()
  1028. {
  1029. lcd_mmu_load_to_nozzle(4);
  1030. }
  1031. void mmu_eject_fil_0()
  1032. {
  1033. mmu_eject_filament(0, true);
  1034. }
  1035. void mmu_eject_fil_1()
  1036. {
  1037. mmu_eject_filament(1, true);
  1038. }
  1039. void mmu_eject_fil_2()
  1040. {
  1041. mmu_eject_filament(2, true);
  1042. }
  1043. void mmu_eject_fil_3()
  1044. {
  1045. mmu_eject_filament(3, true);
  1046. }
  1047. void mmu_eject_fil_4()
  1048. {
  1049. mmu_eject_filament(4, true);
  1050. }
  1051. void load_all()
  1052. {
  1053. #ifndef SNMM
  1054. enquecommand_P(PSTR("M701 E0"));
  1055. enquecommand_P(PSTR("M701 E1"));
  1056. enquecommand_P(PSTR("M701 E2"));
  1057. enquecommand_P(PSTR("M701 E3"));
  1058. enquecommand_P(PSTR("M701 E4"));
  1059. #else
  1060. for (int i = 0; i < 4; i++)
  1061. {
  1062. change_extr(i);
  1063. extr_adj(i);
  1064. }
  1065. #endif
  1066. }
  1067. //wrapper functions for changing extruders
  1068. void extr_change_0()
  1069. {
  1070. change_extr(0);
  1071. lcd_return_to_status();
  1072. }
  1073. void extr_change_1()
  1074. {
  1075. change_extr(1);
  1076. lcd_return_to_status();
  1077. }
  1078. void extr_change_2()
  1079. {
  1080. change_extr(2);
  1081. lcd_return_to_status();
  1082. }
  1083. void extr_change_3()
  1084. {
  1085. change_extr(3);
  1086. lcd_return_to_status();
  1087. }
  1088. #ifdef SNMM
  1089. //wrapper functions for unloading filament
  1090. void extr_unload_all()
  1091. {
  1092. if (degHotend0() > EXTRUDE_MINTEMP)
  1093. {
  1094. for (int i = 0; i < 4; i++)
  1095. {
  1096. change_extr(i);
  1097. extr_unload();
  1098. }
  1099. }
  1100. else
  1101. {
  1102. show_preheat_nozzle_warning();
  1103. lcd_return_to_status();
  1104. }
  1105. }
  1106. //unloading just used filament (for snmm)
  1107. void extr_unload_used()
  1108. {
  1109. if (degHotend0() > EXTRUDE_MINTEMP) {
  1110. for (int i = 0; i < 4; i++) {
  1111. if (snmm_filaments_used & (1 << i)) {
  1112. change_extr(i);
  1113. extr_unload();
  1114. }
  1115. }
  1116. snmm_filaments_used = 0;
  1117. }
  1118. else {
  1119. show_preheat_nozzle_warning();
  1120. lcd_return_to_status();
  1121. }
  1122. }
  1123. #endif //SNMM
  1124. void extr_unload_0()
  1125. {
  1126. change_extr(0);
  1127. extr_unload();
  1128. }
  1129. void extr_unload_1()
  1130. {
  1131. change_extr(1);
  1132. extr_unload();
  1133. }
  1134. void extr_unload_2()
  1135. {
  1136. change_extr(2);
  1137. extr_unload();
  1138. }
  1139. void extr_unload_3()
  1140. {
  1141. change_extr(3);
  1142. extr_unload();
  1143. }
  1144. void extr_unload_4()
  1145. {
  1146. change_extr(4);
  1147. extr_unload();
  1148. }
  1149. bool mmu_check_version()
  1150. {
  1151. return (mmu_buildnr >= MMU_REQUIRED_FW_BUILDNR);
  1152. }
  1153. void mmu_show_warning()
  1154. {
  1155. printf_P(PSTR("MMU2 firmware version invalid. Required version: build number %d or higher."), MMU_REQUIRED_FW_BUILDNR);
  1156. kill(_i("Please update firmware in your MMU2. Waiting for reset."));
  1157. }
  1158. void lcd_mmu_load_to_nozzle(uint8_t filament_nr)
  1159. {
  1160. if (degHotend0() > EXTRUDE_MINTEMP)
  1161. {
  1162. tmp_extruder = filament_nr;
  1163. lcd_update_enable(false);
  1164. lcd_clear();
  1165. lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_LOADING_FILAMENT));
  1166. lcd_print(" ");
  1167. lcd_print(tmp_extruder + 1);
  1168. mmu_command(MmuCmd::T0 + tmp_extruder);
  1169. manage_response(true, true, MMU_TCODE_MOVE);
  1170. mmu_continue_loading();
  1171. mmu_extruder = tmp_extruder; //filament change is finished
  1172. mmu_load_to_nozzle();
  1173. load_filament_final_feed();
  1174. st_synchronize();
  1175. custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
  1176. lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT));
  1177. lcd_return_to_status();
  1178. lcd_update_enable(true);
  1179. lcd_load_filament_color_check();
  1180. lcd_setstatuspgm(_T(WELCOME_MSG));
  1181. custom_message_type = CUSTOM_MSG_TYPE_STATUS;
  1182. }
  1183. else
  1184. {
  1185. show_preheat_nozzle_warning();
  1186. }
  1187. }
  1188. void mmu_eject_filament(uint8_t filament, bool recover)
  1189. {
  1190. if (filament < 5)
  1191. {
  1192. if (degHotend0() > EXTRUDE_MINTEMP)
  1193. {
  1194. st_synchronize();
  1195. {
  1196. LcdUpdateDisabler disableLcdUpdate;
  1197. lcd_clear();
  1198. lcd_set_cursor(0, 1); lcd_puts_P(_i("Ejecting filament"));
  1199. current_position[E_AXIS] -= 80;
  1200. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
  1201. st_synchronize();
  1202. mmu_command(MmuCmd::E0 + filament);
  1203. manage_response(false, false, MMU_UNLOAD_MOVE);
  1204. if (recover)
  1205. {
  1206. lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob."));
  1207. mmu_command(MmuCmd::R0);
  1208. manage_response(false, false);
  1209. }
  1210. }
  1211. }
  1212. else
  1213. {
  1214. show_preheat_nozzle_warning();
  1215. }
  1216. }
  1217. else
  1218. {
  1219. puts_P(PSTR("Filament nr out of range!"));
  1220. }
  1221. }
  1222. static void load_more()
  1223. {
  1224. for (uint8_t i = 0; i < MMU_IDLER_SENSOR_ATTEMPTS_NR; i++)
  1225. {
  1226. if (PIN_GET(IR_SENSOR_PIN) == 0) return;
  1227. DEBUG_PRINTF_P(PSTR("Additional load attempt nr. %d\n"), i);
  1228. mmu_command(MmuCmd::C0);
  1229. manage_response(true, true, MMU_LOAD_MOVE);
  1230. }
  1231. }
  1232. void mmu_continue_loading()
  1233. {
  1234. if (ir_sensor_detected)
  1235. {
  1236. load_more();
  1237. if (PIN_GET(IR_SENSOR_PIN) != 0) {
  1238. uint8_t mmu_load_fail = eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL);
  1239. uint16_t mmu_load_fail_tot = eeprom_read_word((uint16_t*)EEPROM_MMU_LOAD_FAIL_TOT);
  1240. if(mmu_load_fail < 255) eeprom_update_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL, mmu_load_fail + 1);
  1241. if(mmu_load_fail_tot < 65535) eeprom_update_word((uint16_t*)EEPROM_MMU_LOAD_FAIL_TOT, mmu_load_fail_tot + 1);
  1242. mmu_command(MmuCmd::T0 + tmp_extruder);
  1243. manage_response(true, true, MMU_TCODE_MOVE);
  1244. load_more();
  1245. if (PIN_GET(IR_SENSOR_PIN) != 0)
  1246. {
  1247. //pause print, show error message and then repeat last T-code
  1248. stop_and_save_print_to_ram(0, 0);
  1249. //lift z
  1250. current_position[Z_AXIS] += Z_PAUSE_LIFT;
  1251. if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
  1252. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
  1253. st_synchronize();
  1254. //Move XY to side
  1255. current_position[X_AXIS] = X_PAUSE_POS;
  1256. current_position[Y_AXIS] = Y_PAUSE_POS;
  1257. plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
  1258. st_synchronize();
  1259. mmu_command(MmuCmd::U0);
  1260. manage_response(false, true, MMU_UNLOAD_MOVE);
  1261. setAllTargetHotends(0);
  1262. lcd_setstatuspgm(_i("MMU load failed "));////MSG_RECOVERING_PRINT c=20 r=1
  1263. mmu_fil_loaded = false; //so we can retry same T-code again
  1264. isPrintPaused = true;
  1265. }
  1266. }
  1267. }
  1268. else { //mmu_ir_sensor_detected == false
  1269. mmu_command(MmuCmd::C0);
  1270. }
  1271. }