1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356 |
- #include "Marlin.h"
- #include "ultralcd.h"
- #include "planner.h"
- #include "stepper.h"
- #include "endstops.h"
- #include "temperature.h"
- #include "cardreader.h"
- #include "configuration_store.h"
- #include "language.h"
- #include "pins_arduino.h"
- #include "math.h"
- #include "nozzle.h"
- #include "printcounter.h"
- #include "duration_t.h"
- #include "types.h"
- #include "parser.h"
- #if ENABLED(AUTO_POWER_CONTROL)
- #include "power.h"
- #endif
- #if ABL_PLANAR
- #include "vector_3.h"
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- #include "least_squares_fit.h"
- #endif
- #elif ENABLED(MESH_BED_LEVELING)
- #include "mesh_bed_leveling.h"
- #endif
- #if ENABLED(BEZIER_CURVE_SUPPORT)
- #include "planner_bezier.h"
- #endif
- #if ENABLED(FWRETRACT)
- #include "fwretract.h"
- #endif
- #if ENABLED(POWER_LOSS_RECOVERY)
- #include "power_loss_recovery.h"
- #endif
- #if ENABLED(FILAMENT_RUNOUT_SENSOR)
- #include "runout.h"
- #endif
- #if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
- #include "buzzer.h"
- #endif
- #if ENABLED(USE_WATCHDOG)
- #include "watchdog.h"
- #endif
- #if ENABLED(MAX7219_DEBUG)
- #include "Max7219_Debug_LEDs.h"
- #endif
- #if HAS_COLOR_LEDS
- #include "leds.h"
- #endif
- #if HAS_SERVOS
- #include "servo.h"
- #endif
- #if HAS_DIGIPOTSS
- #include <SPI.h>
- #endif
- #if HAS_TRINAMIC
- #include "tmc_util.h"
- #endif
- #if ENABLED(DAC_STEPPER_CURRENT)
- #include "stepper_dac.h"
- #endif
- #if ENABLED(EXPERIMENTAL_I2CBUS)
- #include "twibus.h"
- #endif
- #if ENABLED(I2C_POSITION_ENCODERS)
- #include "I2CPositionEncoder.h"
- #endif
- #if ENABLED(M100_FREE_MEMORY_WATCHER)
- void gcode_M100();
- void M100_dump_routine(const char * const title, const char *start, const char *end);
- #endif
- #if ENABLED(G26_MESH_VALIDATION)
- bool g26_debug_flag;
- void gcode_G26();
- #endif
- #if ENABLED(SDSUPPORT)
- CardReader card;
- #endif
- #if ENABLED(EXPERIMENTAL_I2CBUS)
- TWIBus i2c;
- #endif
- #if ENABLED(G38_PROBE_TARGET)
- bool G38_move = false,
- G38_endstop_hit = false;
- #endif
- #if ENABLED(AUTO_BED_LEVELING_UBL)
- #include "ubl.h"
- #endif
- #if ENABLED(CNC_COORDINATE_SYSTEMS)
- int8_t active_coordinate_system = -1;
- float coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ];
- #endif
- bool Running = true;
- uint8_t marlin_debug_flags = DEBUG_NONE;
- float current_position[XYZE] = { 0 };
- float destination[XYZE] = { 0 };
- uint8_t axis_homed, axis_known_position;
- static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
- uint8_t commands_in_queue = 0,
- cmd_queue_index_r = 0,
- cmd_queue_index_w = 0;
- char command_queue[BUFSIZE][MAX_CMD_SIZE];
- static const char *injected_commands_P = NULL;
- #if ENABLED(TEMPERATURE_UNITS_SUPPORT)
- TempUnit input_temp_units = TEMPUNIT_C;
- #endif
- static const float homing_feedrate_mm_s[] PROGMEM = {
- #if ENABLED(HANGPRINTER)
- MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE),
- MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), 0
- #else
- #if ENABLED(DELTA)
- MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z),
- #else
- MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY),
- #endif
- MMM_TO_MMS(HOMING_FEEDRATE_Z), 0
- #endif
- };
- FORCE_INLINE float homing_feedrate(const AxisEnum a) { return pgm_read_float(&homing_feedrate_mm_s[a]); }
- float feedrate_mm_s = MMM_TO_MMS(1500.0f);
- static float saved_feedrate_mm_s;
- int16_t feedrate_percentage = 100, saved_feedrate_percentage;
- bool axis_relative_modes[XYZE] = AXIS_RELATIVE_MODES;
- #if HAS_WORKSPACE_OFFSET
- #if HAS_POSITION_SHIFT
-
- float position_shift[XYZ] = { 0 };
- #endif
- #if HAS_HOME_OFFSET
-
-
- float home_offset[XYZ] = { 0 };
- #endif
- #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
-
- float workspace_offset[XYZ] = { 0 };
- #endif
- #endif
- float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
- soft_endstop_max[XYZ] = { X_MAX_BED, Y_MAX_BED, Z_MAX_POS };
- #if HAS_SOFTWARE_ENDSTOPS
- bool soft_endstops_enabled = true;
- #if IS_KINEMATIC
- float soft_endstop_radius, soft_endstop_radius_2;
- #endif
- #endif
- #if FAN_COUNT > 0
- int16_t fanSpeeds[FAN_COUNT] = { 0 };
- #if ENABLED(EXTRA_FAN_SPEED)
- int16_t old_fanSpeeds[FAN_COUNT],
- new_fanSpeeds[FAN_COUNT];
- #endif
- #if ENABLED(PROBING_FANS_OFF)
- bool fans_paused;
- int16_t paused_fanSpeeds[FAN_COUNT] = { 0 };
- #endif
- #endif
- #if ENABLED(USE_CONTROLLER_FAN)
- int controllerFanSpeed;
- #endif
- uint8_t active_extruder;
- static bool relative_mode;
- volatile bool wait_for_heatup = true;
- #if HAS_RESUME_CONTINUE
- volatile bool wait_for_user;
- #endif
- #if HAS_AUTO_REPORTING || ENABLED(HOST_KEEPALIVE_FEATURE)
- bool suspend_auto_report;
- #endif
- const char axis_codes[XYZE] = { 'X', 'Y', 'Z', 'E' };
- #if ENABLED(HANGPRINTER)
- const char axis_codes_hangprinter[ABCDE] = { 'A', 'B', 'C', 'D', 'E' };
- #define RAW_AXIS_CODES(I) axis_codes_hangprinter[I]
- #else
- #define RAW_AXIS_CODES(I) axis_codes[I]
- #endif
- static int serial_count;
- millis_t previous_move_ms;
- static millis_t max_inactive_time;
- static millis_t stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL;
- #if ENABLED(LCD_USE_I2C_BUZZER)
- #define BUZZ(d,f) lcd_buzz(d, f)
- #elif PIN_EXISTS(BEEPER)
- Buzzer buzzer;
- #define BUZZ(d,f) buzzer.tone(d, f)
- #else
- #define BUZZ(d,f) NOOP
- #endif
- uint8_t target_extruder;
- #if HAS_BED_PROBE
- float zprobe_zoffset;
- #endif
- #if HAS_ABL
- float xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_SPEED);
- #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s
- #elif defined(XY_PROBE_SPEED)
- #define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_SPEED)
- #else
- #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE()
- #endif
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- #if ENABLED(DELTA)
- #define ADJUST_DELTA(V) \
- if (planner.leveling_active) { \
- const float zadj = bilinear_z_offset(V); \
- delta[A_AXIS] += zadj; \
- delta[B_AXIS] += zadj; \
- delta[C_AXIS] += zadj; \
- }
- #else
- #define ADJUST_DELTA(V) if (planner.leveling_active) { delta[Z_AXIS] += bilinear_z_offset(V); }
- #endif
- #elif IS_KINEMATIC
- #define ADJUST_DELTA(V) NOOP
- #endif
- #if HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
- const static char msg_wait_for_bed_heating[] PROGMEM = "Wait for bed heating...\n";
- #endif
- #if HOTENDS > 1
- float hotend_offset[XYZ][HOTENDS];
- #endif
- #if HAS_Z_SERVO_PROBE
- const int z_servo_angle[2] = Z_SERVO_ANGLES;
- #endif
- #if ENABLED(BARICUDA)
- uint8_t baricuda_valve_pressure = 0,
- baricuda_e_to_p_pressure = 0;
- #endif
- #if HAS_POWER_SWITCH
- bool powersupply_on = (
- #if ENABLED(PS_DEFAULT_OFF)
- false
- #else
- true
- #endif
- );
- #if ENABLED(AUTO_POWER_CONTROL)
- #define PSU_ON() powerManager.power_on()
- #define PSU_OFF() powerManager.power_off()
- #else
- #define PSU_ON() PSU_PIN_ON()
- #define PSU_OFF() PSU_PIN_OFF()
- #endif
- #endif
- #if ENABLED(DELTA)
- float delta[ABC];
-
- float delta_height,
- delta_endstop_adj[ABC] = { 0 },
- delta_radius,
- delta_tower_angle_trim[ABC],
- delta_tower[ABC][2],
- delta_diagonal_rod,
- delta_calibration_radius,
- delta_diagonal_rod_2_tower[ABC],
- delta_segments_per_second,
- delta_clip_start_height = Z_MAX_POS;
- float delta_safe_distance_from_top();
- #elif ENABLED(HANGPRINTER)
- float anchor_A_y,
- anchor_A_z,
- anchor_B_x,
- anchor_B_y,
- anchor_B_z,
- anchor_C_x,
- anchor_C_y,
- anchor_C_z,
- anchor_D_z,
- line_lengths[ABCD],
- line_lengths_origin[ABCD],
- delta_segments_per_second;
- #endif
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- int bilinear_grid_spacing[2], bilinear_start[2];
- float bilinear_grid_factor[2],
- z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
- #if ENABLED(ABL_BILINEAR_SUBDIVISION)
- #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt[A]
- #define ABL_BG_FACTOR(A) bilinear_grid_factor_virt[A]
- #define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X
- #define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y
- #define ABL_BG_GRID(X,Y) z_values_virt[X][Y]
- #else
- #define ABL_BG_SPACING(A) bilinear_grid_spacing[A]
- #define ABL_BG_FACTOR(A) bilinear_grid_factor[A]
- #define ABL_BG_POINTS_X GRID_MAX_POINTS_X
- #define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y
- #define ABL_BG_GRID(X,Y) z_values[X][Y]
- #endif
- #endif
- #if IS_SCARA
-
- const float L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2,
- L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
- L2_2 = sq(float(L2));
- float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND,
- delta[ABC];
- #endif
- float cartes[XYZ] = { 0 };
- #if ENABLED(FILAMENT_WIDTH_SENSOR)
- bool filament_sensor;
- float filament_width_nominal = DEFAULT_NOMINAL_FILAMENT_DIA,
- filament_width_meas = DEFAULT_MEASURED_FILAMENT_DIA;
- uint8_t meas_delay_cm = MEASUREMENT_DELAY_CM;
- int8_t measurement_delay[MAX_MEASUREMENT_DELAY + 1],
- filwidth_delay_index[2] = { 0, -1 };
- #endif
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- AdvancedPauseMenuResponse advanced_pause_menu_response;
- float filament_change_unload_length[EXTRUDERS],
- filament_change_load_length[EXTRUDERS];
- #endif
- #if ENABLED(MIXING_EXTRUDER)
- float mixing_factor[MIXING_STEPPERS];
- #if MIXING_VIRTUAL_TOOLS > 1
- float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS];
- #endif
- #endif
- static bool send_ok[BUFSIZE];
- #if HAS_SERVOS
- Servo servo[NUM_SERVOS];
- #define MOVE_SERVO(I, P) servo[I].move(P)
- #if HAS_Z_SERVO_PROBE
- #define DEPLOY_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[0])
- #define STOW_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[1])
- #endif
- #endif
- #ifdef CHDK
- millis_t chdkHigh = 0;
- bool chdkActive = false;
- #endif
- #if ENABLED(HOST_KEEPALIVE_FEATURE)
- MarlinBusyState busy_state = NOT_BUSY;
- static millis_t next_busy_signal_ms = 0;
- uint8_t host_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL;
- #else
- #define host_keepalive() NOOP
- #endif
- #if ENABLED(I2C_POSITION_ENCODERS)
- I2CPositionEncodersMgr I2CPEM;
- #endif
- #if ENABLED(CNC_WORKSPACE_PLANES)
- static WorkspacePlane workspace_plane = PLANE_XY;
- #endif
- FORCE_INLINE float pgm_read_any(const float *p) { return pgm_read_float_near(p); }
- FORCE_INLINE signed char pgm_read_any(const signed char *p) { return pgm_read_byte_near(p); }
- #define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG) \
- static const PROGMEM type array##_P[XYZ] = { X_##CONFIG, Y_##CONFIG, Z_##CONFIG }; \
- static inline type array(const AxisEnum axis) { return pgm_read_any(&array##_P[axis]); } \
- typedef void __void_##CONFIG##__
- XYZ_CONSTS_FROM_CONFIG(float, base_min_pos, MIN_POS);
- XYZ_CONSTS_FROM_CONFIG(float, base_max_pos, MAX_POS);
- XYZ_CONSTS_FROM_CONFIG(float, base_home_pos, HOME_POS);
- XYZ_CONSTS_FROM_CONFIG(float, max_length, MAX_LENGTH);
- XYZ_CONSTS_FROM_CONFIG(float, home_bump_mm, HOME_BUMP_MM);
- XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR);
- void stop();
- void get_available_commands();
- void process_next_command();
- void process_parsed_command();
- void get_cartesian_from_steppers();
- void set_current_from_steppers_for_axis(const AxisEnum axis);
- #if ENABLED(ARC_SUPPORT)
- void plan_arc(const float (&cart)[XYZE], const float (&offset)[2], const bool clockwise);
- #endif
- #if ENABLED(BEZIER_CURVE_SUPPORT)
- void plan_cubic_move(const float (&cart)[XYZE], const float (&offset)[4]);
- #endif
- void report_current_position();
- void report_current_position_detail();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- void print_xyz(const char* prefix, const char* suffix, const float x, const float y, const float z) {
- serialprintPGM(prefix);
- SERIAL_CHAR('(');
- SERIAL_ECHO(x);
- SERIAL_ECHOPAIR(", ", y);
- SERIAL_ECHOPAIR(", ", z);
- SERIAL_CHAR(')');
- if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
- }
- void print_xyz(const char* prefix, const char* suffix, const float xyz[]) {
- print_xyz(prefix, suffix, xyz[X_AXIS], xyz[Y_AXIS], xyz[Z_AXIS]);
- }
- #define DEBUG_POS(SUFFIX,VAR) do { \
- print_xyz(PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n"), VAR); }while(0)
- #endif
- void sync_plan_position() {
- #if DISABLED(HANGPRINTER)
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position);
- #endif
- planner.set_position_mm(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART]);
- #endif
- }
- void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_CART]); }
- #if IS_KINEMATIC
- inline void sync_plan_position_kinematic() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position_kinematic", current_position);
- #endif
- planner.set_position_mm_kinematic(current_position);
- }
- #endif
- #if ENABLED(SDSUPPORT)
- #include "SdFatUtil.h"
- int freeMemory() { return SdFatUtil::FreeRam(); }
- #else
- extern "C" {
- extern char __bss_end;
- extern char __heap_start;
- extern void* __brkval;
- int freeMemory() {
- int free_memory;
- if (int(__brkval) == 0)
- free_memory = (int(&free_memory)) - (int(&__bss_end));
- else
- free_memory = (int(&free_memory)) - (int(__brkval));
- return free_memory;
- }
- }
- #endif
- #if ENABLED(DIGIPOT_I2C)
- extern void digipot_i2c_set_current(uint8_t channel, float current);
- extern void digipot_i2c_init();
- #endif
- static bool drain_injected_commands_P() {
- if (injected_commands_P != NULL) {
- size_t i = 0;
- char c, cmd[30];
- strncpy_P(cmd, injected_commands_P, sizeof(cmd) - 1);
- cmd[sizeof(cmd) - 1] = '\0';
- while ((c = cmd[i]) && c != '\n') i++;
- cmd[i] = '\0';
- if (enqueue_and_echo_command(cmd))
- injected_commands_P = c ? injected_commands_P + i + 1 : NULL;
- }
- return (injected_commands_P != NULL);
- }
- void enqueue_and_echo_commands_P(const char * const pgcode) {
- injected_commands_P = pgcode;
- (void)drain_injected_commands_P();
- }
- void clear_command_queue() {
- cmd_queue_index_r = cmd_queue_index_w = commands_in_queue = 0;
- }
- inline void _commit_command(bool say_ok) {
- send_ok[cmd_queue_index_w] = say_ok;
- if (++cmd_queue_index_w >= BUFSIZE) cmd_queue_index_w = 0;
- commands_in_queue++;
- }
- inline bool _enqueuecommand(const char* cmd, bool say_ok=false) {
- if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
- strcpy(command_queue[cmd_queue_index_w], cmd);
- _commit_command(say_ok);
- return true;
- }
- bool enqueue_and_echo_command(const char* cmd) {
- if (_enqueuecommand(cmd)) {
- SERIAL_ECHO_START();
- SERIAL_ECHOPAIR(MSG_ENQUEUEING, cmd);
- SERIAL_CHAR('"');
- SERIAL_EOL();
- return true;
- }
- return false;
- }
- #if HAS_QUEUE_NOW
- void enqueue_and_echo_command_now(const char* cmd) {
- while (!enqueue_and_echo_command(cmd)) idle();
- }
- #if HAS_LCD_QUEUE_NOW
- void enqueue_and_echo_commands_now_P(const char * const pgcode) {
- enqueue_and_echo_commands_P(pgcode);
- while (drain_injected_commands_P()) idle();
- }
- #endif
- #endif
- void setup_killpin() {
- #if HAS_KILL
- SET_INPUT_PULLUP(KILL_PIN);
- #endif
- }
- void setup_powerhold() {
- #if HAS_SUICIDE
- OUT_WRITE(SUICIDE_PIN, HIGH);
- #endif
- #if HAS_POWER_SWITCH
- #if ENABLED(PS_DEFAULT_OFF)
- PSU_OFF();
- #else
- PSU_ON();
- #endif
- #endif
- }
- void suicide() {
- #if HAS_SUICIDE
- OUT_WRITE(SUICIDE_PIN, LOW);
- #endif
- }
- void servo_init() {
- #if NUM_SERVOS >= 1 && HAS_SERVO_0
- servo[0].attach(SERVO0_PIN);
- servo[0].detach();
- #endif
- #if NUM_SERVOS >= 2 && HAS_SERVO_1
- servo[1].attach(SERVO1_PIN);
- servo[1].detach();
- #endif
- #if NUM_SERVOS >= 3 && HAS_SERVO_2
- servo[2].attach(SERVO2_PIN);
- servo[2].detach();
- #endif
- #if NUM_SERVOS >= 4 && HAS_SERVO_3
- servo[3].attach(SERVO3_PIN);
- servo[3].detach();
- #endif
- #if HAS_Z_SERVO_PROBE
-
- STOW_Z_SERVO();
- #endif
- }
- #if HAS_STEPPER_RESET
- void disableStepperDrivers() {
- OUT_WRITE(STEPPER_RESET_PIN, LOW);
- }
- void enableStepperDrivers() { SET_INPUT(STEPPER_RESET_PIN); }
- #endif
- #if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
- void i2c_on_receive(int bytes) {
- i2c.receive(bytes);
- }
- void i2c_on_request() {
- i2c.reply("Hello World!\n");
- }
- #endif
- void gcode_line_error(const char* err, bool doFlush = true) {
- SERIAL_ERROR_START();
- serialprintPGM(err);
- SERIAL_ERRORLN(gcode_LastN);
-
- if (doFlush) flush_and_request_resend();
- serial_count = 0;
- }
- inline void get_serial_commands() {
- static char serial_line_buffer[MAX_CMD_SIZE];
- static bool serial_comment_mode = false;
-
-
- #if NO_TIMEOUTS > 0
- static millis_t last_command_time = 0;
- const millis_t ms = millis();
- if (commands_in_queue == 0 && !MYSERIAL0.available() && ELAPSED(ms, last_command_time + NO_TIMEOUTS)) {
- SERIAL_ECHOLNPGM(MSG_WAIT);
- last_command_time = ms;
- }
- #endif
-
- int c;
- while (commands_in_queue < BUFSIZE && (c = MYSERIAL0.read()) >= 0) {
- char serial_char = c;
-
- if (serial_char == '\n' || serial_char == '\r') {
- serial_comment_mode = false;
-
- if (!serial_count) { thermalManager.manage_heater(); continue; }
- serial_line_buffer[serial_count] = 0;
- serial_count = 0;
- char* command = serial_line_buffer;
- while (*command == ' ') command++;
- char *npos = (*command == 'N') ? command : NULL;
- if (npos) {
- bool M110 = strstr_P(command, PSTR("M110")) != NULL;
- if (M110) {
- char* n2pos = strchr(command + 4, 'N');
- if (n2pos) npos = n2pos;
- }
- gcode_N = strtol(npos + 1, NULL, 10);
- if (gcode_N != gcode_LastN + 1 && !M110)
- return gcode_line_error(PSTR(MSG_ERR_LINE_NO));
- char *apos = strrchr(command, '*');
- if (apos) {
- uint8_t checksum = 0, count = uint8_t(apos - command);
- while (count) checksum ^= command[--count];
- if (strtol(apos + 1, NULL, 10) != checksum)
- return gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH));
- }
- else
- return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM));
- gcode_LastN = gcode_N;
- }
- #if ENABLED(SDSUPPORT)
- else if (card.saving && strcmp(command, "M29") != 0)
- return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM));
- #endif
-
- if (IsStopped()) {
- char* gpos = strchr(command, 'G');
- if (gpos) {
- switch (strtol(gpos + 1, NULL, 10)) {
- case 0:
- case 1:
- #if ENABLED(ARC_SUPPORT)
- case 2:
- case 3:
- #endif
- #if ENABLED(BEZIER_CURVE_SUPPORT)
- case 5:
- #endif
- SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
- LCD_MESSAGEPGM(MSG_STOPPED);
- break;
- }
- }
- }
- #if DISABLED(EMERGENCY_PARSER)
-
- if (strcmp(command, "M108") == 0) {
- wait_for_heatup = false;
- #if ENABLED(NEWPANEL)
- wait_for_user = false;
- #endif
- }
- if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
- if (strcmp(command, "M410") == 0) quickstop_stepper();
- #endif
- #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
- last_command_time = ms;
- #endif
-
- _enqueuecommand(serial_line_buffer, true);
- }
- else if (serial_count >= MAX_CMD_SIZE - 1) {
-
-
- }
- else if (serial_char == '\\') {
- if ((c = MYSERIAL0.read()) >= 0 && !serial_comment_mode)
- serial_line_buffer[serial_count++] = (char)c;
-
- }
- else {
- if (serial_char == ';') serial_comment_mode = true;
- if (!serial_comment_mode) serial_line_buffer[serial_count++] = serial_char;
- }
- }
- }
- #if ENABLED(SDSUPPORT)
- #if ENABLED(PRINTER_EVENT_LEDS) && HAS_RESUME_CONTINUE
- static bool lights_off_after_print;
- #endif
-
- inline void get_sdcard_commands() {
- static bool stop_buffering = false,
- sd_comment_mode = false;
- if (!card.sdprinting) return;
-
- if (commands_in_queue == 0) stop_buffering = false;
- uint16_t sd_count = 0;
- bool card_eof = card.eof();
- while (commands_in_queue < BUFSIZE && !card_eof && !stop_buffering) {
- const int16_t n = card.get();
- char sd_char = (char)n;
- card_eof = card.eof();
- if (card_eof || n == -1
- || sd_char == '\n' || sd_char == '\r'
- || ((sd_char == '#' || sd_char == ':') && !sd_comment_mode)
- ) {
- if (card_eof) {
- card.printingHasFinished();
- if (card.sdprinting)
- sd_count = 0;
- else {
- SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
- #if ENABLED(PRINTER_EVENT_LEDS)
- LCD_MESSAGEPGM(MSG_INFO_COMPLETED_PRINTS);
- leds.set_green();
- #if HAS_RESUME_CONTINUE
- lights_off_after_print = true;
- enqueue_and_echo_commands_P(PSTR("M0 S"
- #if ENABLED(NEWPANEL)
- "1800"
- #else
- "60"
- #endif
- ));
- #else
- safe_delay(2000);
- leds.set_off();
- #endif
- #endif
- }
- }
- else if (n == -1) {
- SERIAL_ERROR_START();
- SERIAL_ECHOLNPGM(MSG_SD_ERR_READ);
- }
- if (sd_char == '#') stop_buffering = true;
- sd_comment_mode = false;
-
- if (!sd_count) { thermalManager.manage_heater(); continue; }
- command_queue[cmd_queue_index_w][sd_count] = '\0';
- sd_count = 0;
- _commit_command(false);
- }
- else if (sd_count >= MAX_CMD_SIZE - 1) {
-
- }
- else {
- if (sd_char == ';') sd_comment_mode = true;
- if (!sd_comment_mode) command_queue[cmd_queue_index_w][sd_count++] = sd_char;
- }
- }
- }
- #if ENABLED(POWER_LOSS_RECOVERY)
- inline bool drain_job_recovery_commands() {
- static uint8_t job_recovery_commands_index = 0;
- if (job_recovery_commands_count) {
- if (_enqueuecommand(job_recovery_commands[job_recovery_commands_index])) {
- ++job_recovery_commands_index;
- if (!--job_recovery_commands_count) job_recovery_phase = JOB_RECOVERY_DONE;
- }
- return true;
- }
- return false;
- }
- #endif
- #endif
- void get_available_commands() {
-
- if (drain_injected_commands_P()) return;
- get_serial_commands();
- #if ENABLED(POWER_LOSS_RECOVERY)
-
- if (job_recovery_phase == JOB_RECOVERY_YES && drain_job_recovery_commands()) return;
- #endif
- #if ENABLED(SDSUPPORT)
- get_sdcard_commands();
- #endif
- }
- bool get_target_extruder_from_command(const uint16_t code) {
- if (parser.seenval('T')) {
- const int8_t e = parser.value_byte();
- if (e >= EXTRUDERS) {
- SERIAL_ECHO_START();
- SERIAL_CHAR('M');
- SERIAL_ECHO(code);
- SERIAL_ECHOLNPAIR(" " MSG_INVALID_EXTRUDER " ", e);
- return true;
- }
- target_extruder = e;
- }
- else
- target_extruder = active_extruder;
- return false;
- }
- #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
- bool extruder_duplication_enabled = false;
- #endif
- #if ENABLED(DUAL_X_CARRIAGE)
- static DualXMode dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
- static float x_home_pos(const int extruder) {
- if (extruder == 0)
- return base_home_pos(X_AXIS);
- else
-
- return hotend_offset[X_AXIS][1] > 0 ? hotend_offset[X_AXIS][1] : X2_HOME_POS;
- }
- static int x_home_dir(const int extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
- static float inactive_extruder_x_pos = X2_MAX_POS;
- static bool active_extruder_parked = false;
- static float raised_parked_position[XYZE];
- static millis_t delayed_move_time = 0;
- static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET;
- static int16_t duplicate_extruder_temp_offset = 0;
- #endif
- #if HAS_WORKSPACE_OFFSET || ENABLED(DUAL_X_CARRIAGE) || ENABLED(DELTA)
-
- void update_software_endstops(const AxisEnum axis) {
- #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
- workspace_offset[axis] = home_offset[axis] + position_shift[axis];
- #endif
- #if ENABLED(DUAL_X_CARRIAGE)
- if (axis == X_AXIS) {
-
- const float dual_max_x = MAX(hotend_offset[X_AXIS][1], X2_MAX_POS);
- if (active_extruder != 0) {
-
- soft_endstop_min[X_AXIS] = X2_MIN_POS;
- soft_endstop_max[X_AXIS] = dual_max_x;
- }
- else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
-
-
- soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS);
- soft_endstop_max[X_AXIS] = MIN(base_max_pos(X_AXIS), dual_max_x - duplicate_extruder_x_offset);
- }
- else {
-
- soft_endstop_min[axis] = base_min_pos(axis);
- soft_endstop_max[axis] = base_max_pos(axis);
- }
- }
- #elif ENABLED(DELTA)
- soft_endstop_min[axis] = base_min_pos(axis);
- soft_endstop_max[axis] = axis == Z_AXIS ? delta_height
- #if HAS_BED_PROBE
- - zprobe_zoffset
- #endif
- : base_max_pos(axis);
- #else
- soft_endstop_min[axis] = base_min_pos(axis);
- soft_endstop_max[axis] = base_max_pos(axis);
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("For ", axis_codes[axis]);
- #if HAS_HOME_OFFSET
- SERIAL_ECHOPAIR(" axis:\n home_offset = ", home_offset[axis]);
- #endif
- #if HAS_POSITION_SHIFT
- SERIAL_ECHOPAIR("\n position_shift = ", position_shift[axis]);
- #endif
- SERIAL_ECHOPAIR("\n soft_endstop_min = ", soft_endstop_min[axis]);
- SERIAL_ECHOLNPAIR("\n soft_endstop_max = ", soft_endstop_max[axis]);
- }
- #endif
- #if ENABLED(DELTA)
- switch (axis) {
- #if HAS_SOFTWARE_ENDSTOPS
- case X_AXIS:
- case Y_AXIS:
-
- soft_endstop_radius = MIN3(ABS(MAX(soft_endstop_min[X_AXIS], soft_endstop_min[Y_AXIS])), soft_endstop_max[X_AXIS], soft_endstop_max[Y_AXIS]);
- soft_endstop_radius_2 = sq(soft_endstop_radius);
- break;
- #endif
- case Z_AXIS:
- delta_clip_start_height = soft_endstop_max[axis] - delta_safe_distance_from_top();
- default: break;
- }
- #endif
- }
- #endif
- #if HAS_M206_COMMAND
-
- static void set_home_offset(const AxisEnum axis, const float v) {
- home_offset[axis] = v;
- update_software_endstops(axis);
- }
- #endif
- static void set_axis_is_at_home(const AxisEnum axis) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR(">>> set_axis_is_at_home(", axis_codes[axis]);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- SBI(axis_known_position, axis);
- SBI(axis_homed, axis);
- #if HAS_POSITION_SHIFT
- position_shift[axis] = 0;
- update_software_endstops(axis);
- #endif
- #if ENABLED(DUAL_X_CARRIAGE)
- if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
- current_position[X_AXIS] = x_home_pos(active_extruder);
- return;
- }
- #endif
- #if ENABLED(MORGAN_SCARA)
-
- if (axis == X_AXIS || axis == Y_AXIS) {
- float homeposition[XYZ] = {
- base_home_pos(X_AXIS),
- base_home_pos(Y_AXIS),
- base_home_pos(Z_AXIS)
- };
-
-
-
- inverse_kinematics(homeposition);
- forward_kinematics_SCARA(delta[A_AXIS], delta[B_AXIS]);
-
-
- current_position[axis] = cartes[axis];
-
- soft_endstop_min[axis] = base_min_pos(axis);
- soft_endstop_max[axis] = base_max_pos(axis);
- }
- else
- #elif ENABLED(DELTA)
- current_position[axis] = (axis == Z_AXIS ? delta_height
- #if HAS_BED_PROBE
- - zprobe_zoffset
- #endif
- : base_home_pos(axis));
- #else
- current_position[axis] = base_home_pos(axis);
- #endif
-
- #if HAS_BED_PROBE && Z_HOME_DIR < 0
- if (axis == Z_AXIS) {
- #if HOMING_Z_WITH_PROBE
- current_position[Z_AXIS] -= zprobe_zoffset;
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("*** Z HOMED WITH PROBE (Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) ***");
- SERIAL_ECHOLNPAIR("> zprobe_zoffset = ", zprobe_zoffset);
- }
- #endif
- #elif ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("*** Z HOMED TO ENDSTOP (Z_MIN_PROBE_ENDSTOP) ***");
- #endif
- }
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- #if HAS_HOME_OFFSET
- SERIAL_ECHOPAIR("> home_offset[", axis_codes[axis]);
- SERIAL_ECHOLNPAIR("] = ", home_offset[axis]);
- #endif
- DEBUG_POS("", current_position);
- SERIAL_ECHOPAIR("<<< set_axis_is_at_home(", axis_codes[axis]);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- #if ENABLED(I2C_POSITION_ENCODERS)
- I2CPEM.homed(axis);
- #endif
- }
- /**
- * Homing bump feedrate (mm/s)
- */
- inline float get_homing_bump_feedrate(const AxisEnum axis) {
- #if HOMING_Z_WITH_PROBE
- if (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_SPEED_SLOW);
- #endif
- static const uint8_t homing_bump_divisor[] PROGMEM = HOMING_BUMP_DIVISOR;
- uint8_t hbd = pgm_read_byte(&homing_bump_divisor[axis]);
- if (hbd < 1) {
- hbd = 10;
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM("Warning: Homing Bump Divisor < 1");
- }
- return homing_feedrate(axis) / hbd;
- }
- /**
- * Some planner shorthand inline functions
- */
- /**
- * Move the planner to the current position from wherever it last moved
- * (or from wherever it has been told it is located).
- *
- * Impossible on Hangprinter because current_position and position are of different sizes
- */
- inline void buffer_line_to_current_position() {
- #if DISABLED(HANGPRINTER) // emptying this function probably breaks do_blocking_move_to()
- planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], feedrate_mm_s, active_extruder);
- #endif
- }
- /**
- * Move the planner to the position stored in the destination array, which is
- * used by G0/G1/G2/G3/G5 and many other functions to set a destination.
- */
- inline void buffer_line_to_destination(const float &fr_mm_s) {
- #if ENABLED(HANGPRINTER)
- UNUSED(fr_mm_s);
- #else
- planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_CART], fr_mm_s, active_extruder);
- #endif
- }
- #if IS_KINEMATIC
- /**
- * Calculate delta, start a line, and set current_position to destination
- */
- void prepare_uninterpolated_move_to_destination(const float fr_mm_s=0) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("prepare_uninterpolated_move_to_destination", destination);
- #endif
- #if UBL_SEGMENTED
- // ubl segmented line will do z-only moves in single segment
- ubl.prepare_segmented_line_to(destination, MMS_SCALED(fr_mm_s ? fr_mm_s : feedrate_mm_s));
- #else
- if ( current_position[X_AXIS] == destination[X_AXIS]
- && current_position[Y_AXIS] == destination[Y_AXIS]
- && current_position[Z_AXIS] == destination[Z_AXIS]
- && current_position[E_CART] == destination[E_CART]
- ) return;
- planner.buffer_line_kinematic(destination, MMS_SCALED(fr_mm_s ? fr_mm_s : feedrate_mm_s), active_extruder);
- #endif
- set_current_from_destination();
- }
- #endif // IS_KINEMATIC
- /**
- * Plan a move to (X, Y, Z) and set the current_position.
- * The final current_position may not be the one that was requested
- * Caution: 'destination' is modified by this function.
- */
- void do_blocking_move_to(const float rx, const float ry, const float rz, const float &fr_mm_s/*=0.0*/) {
- const float old_feedrate_mm_s = feedrate_mm_s;
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) print_xyz(PSTR(">>> do_blocking_move_to"), NULL, LOGICAL_X_POSITION(rx), LOGICAL_Y_POSITION(ry), LOGICAL_Z_POSITION(rz));
- #endif
- const float z_feedrate = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS);
- #if ENABLED(DELTA)
- if (!position_is_reachable(rx, ry)) return;
- feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
- set_destination_from_current(); // sync destination at the start
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("set_destination_from_current", destination);
- #endif
- // when in the danger zone
- if (current_position[Z_AXIS] > delta_clip_start_height) {
- if (rz > delta_clip_start_height) { // staying in the danger zone
- destination[X_AXIS] = rx; // move directly (uninterpolated)
- destination[Y_AXIS] = ry;
- destination[Z_AXIS] = rz;
- prepare_uninterpolated_move_to_destination(); // set_current_from_destination
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("danger zone move", current_position);
- #endif
- return;
- }
- destination[Z_AXIS] = delta_clip_start_height;
- prepare_uninterpolated_move_to_destination(); // set_current_from_destination
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("zone border move", current_position);
- #endif
- }
- if (rz > current_position[Z_AXIS]) { // raising?
- destination[Z_AXIS] = rz;
- prepare_uninterpolated_move_to_destination(z_feedrate); // set_current_from_destination
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("z raise move", current_position);
- #endif
- }
- destination[X_AXIS] = rx;
- destination[Y_AXIS] = ry;
- prepare_move_to_destination(); // set_current_from_destination
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("xy move", current_position);
- #endif
- if (rz < current_position[Z_AXIS]) { // lowering?
- destination[Z_AXIS] = rz;
- prepare_uninterpolated_move_to_destination(z_feedrate); // set_current_from_destination
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("z lower move", current_position);
- #endif
- }
- #elif IS_SCARA
- if (!position_is_reachable(rx, ry)) return;
- set_destination_from_current();
- // If Z needs to raise, do it before moving XY
- if (destination[Z_AXIS] < rz) {
- destination[Z_AXIS] = rz;
- prepare_uninterpolated_move_to_destination(z_feedrate);
- }
- destination[X_AXIS] = rx;
- destination[Y_AXIS] = ry;
- prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S);
- // If Z needs to lower, do it after moving XY
- if (destination[Z_AXIS] > rz) {
- destination[Z_AXIS] = rz;
- prepare_uninterpolated_move_to_destination(z_feedrate);
- }
- #else
- // If Z needs to raise, do it before moving XY
- if (current_position[Z_AXIS] < rz) {
- feedrate_mm_s = z_feedrate;
- current_position[Z_AXIS] = rz;
- buffer_line_to_current_position();
- }
- feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
- current_position[X_AXIS] = rx;
- current_position[Y_AXIS] = ry;
- buffer_line_to_current_position();
- // If Z needs to lower, do it after moving XY
- if (current_position[Z_AXIS] > rz) {
- feedrate_mm_s = z_feedrate;
- current_position[Z_AXIS] = rz;
- buffer_line_to_current_position();
- }
- #endif
- planner.synchronize();
- feedrate_mm_s = old_feedrate_mm_s;
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< do_blocking_move_to");
- #endif
- }
- void do_blocking_move_to_x(const float &rx, const float &fr_mm_s/*=0.0*/) {
- do_blocking_move_to(rx, current_position[Y_AXIS], current_position[Z_AXIS], fr_mm_s);
- }
- void do_blocking_move_to_z(const float &rz, const float &fr_mm_s/*=0.0*/) {
- do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], rz, fr_mm_s);
- }
- void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm_s/*=0.0*/) {
- do_blocking_move_to(rx, ry, current_position[Z_AXIS], fr_mm_s);
- }
- //
- // Prepare to do endstop or probe moves
- // with custom feedrates.
- //
- // - Save current feedrates
- // - Reset the rate multiplier
- // - Reset the command timeout
- // - Enable the endstops (for endstop moves)
- //
- void setup_for_endstop_or_probe_move() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("setup_for_endstop_or_probe_move", current_position);
- #endif
- saved_feedrate_mm_s = feedrate_mm_s;
- saved_feedrate_percentage = feedrate_percentage;
- feedrate_percentage = 100;
- }
- void clean_up_after_endstop_or_probe_move() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("clean_up_after_endstop_or_probe_move", current_position);
- #endif
- feedrate_mm_s = saved_feedrate_mm_s;
- feedrate_percentage = saved_feedrate_percentage;
- }
- #if HAS_AXIS_UNHOMED_ERR
- bool axis_unhomed_error(const bool x/*=true*/, const bool y/*=true*/, const bool z/*=true*/) {
- #if ENABLED(HOME_AFTER_DEACTIVATE)
- const bool xx = x && !TEST(axis_known_position, X_AXIS),
- yy = y && !TEST(axis_known_position, Y_AXIS),
- zz = z && !TEST(axis_known_position, Z_AXIS);
- #else
- const bool xx = x && !TEST(axis_homed, X_AXIS),
- yy = y && !TEST(axis_homed, Y_AXIS),
- zz = z && !TEST(axis_homed, Z_AXIS);
- #endif
- if (xx || yy || zz) {
- SERIAL_ECHO_START();
- SERIAL_ECHOPGM(MSG_HOME " ");
- if (xx) SERIAL_ECHOPGM(MSG_X);
- if (yy) SERIAL_ECHOPGM(MSG_Y);
- if (zz) SERIAL_ECHOPGM(MSG_Z);
- SERIAL_ECHOLNPGM(" " MSG_FIRST);
- #if ENABLED(ULTRA_LCD)
- lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : "");
- #endif
- return true;
- }
- return false;
- }
- #endif // HAS_AXIS_UNHOMED_ERR
- #if ENABLED(Z_PROBE_SLED)
- #ifndef SLED_DOCKING_OFFSET
- #define SLED_DOCKING_OFFSET 0
- #endif
- /**
- * Method to dock/undock a sled designed by Charles Bell.
- *
- * stow[in] If false, move to MAX_X and engage the solenoid
- * If true, move to MAX_X and release the solenoid
- */
- static void dock_sled(bool stow) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("dock_sled(", stow);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- // Dock sled a bit closer to ensure proper capturing
- do_blocking_move_to_x(X_MAX_POS + SLED_DOCKING_OFFSET - ((stow) ? 1 : 0));
- #if HAS_SOLENOID_1 && DISABLED(EXT_SOLENOID)
- WRITE(SOL1_PIN, !stow); // switch solenoid
- #endif
- }
- #elif ENABLED(Z_PROBE_ALLEN_KEY)
- FORCE_INLINE void do_blocking_move_to(const float (&raw)[XYZ], const float &fr_mm_s) {
- do_blocking_move_to(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], fr_mm_s);
- }
- void run_deploy_moves_script() {
- #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Z)
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_X
- #define Z_PROBE_ALLEN_KEY_DEPLOY_1_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Y
- #define Z_PROBE_ALLEN_KEY_DEPLOY_1_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Z
- #define Z_PROBE_ALLEN_KEY_DEPLOY_1_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE 0.0
- #endif
- const float deploy_1[] = { Z_PROBE_ALLEN_KEY_DEPLOY_1_X, Z_PROBE_ALLEN_KEY_DEPLOY_1_Y, Z_PROBE_ALLEN_KEY_DEPLOY_1_Z };
- do_blocking_move_to(deploy_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Z)
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_X
- #define Z_PROBE_ALLEN_KEY_DEPLOY_2_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Y
- #define Z_PROBE_ALLEN_KEY_DEPLOY_2_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Z
- #define Z_PROBE_ALLEN_KEY_DEPLOY_2_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE 0.0
- #endif
- const float deploy_2[] = { Z_PROBE_ALLEN_KEY_DEPLOY_2_X, Z_PROBE_ALLEN_KEY_DEPLOY_2_Y, Z_PROBE_ALLEN_KEY_DEPLOY_2_Z };
- do_blocking_move_to(deploy_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Z)
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_X
- #define Z_PROBE_ALLEN_KEY_DEPLOY_3_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Y
- #define Z_PROBE_ALLEN_KEY_DEPLOY_3_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Z
- #define Z_PROBE_ALLEN_KEY_DEPLOY_3_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE 0.0
- #endif
- const float deploy_3[] = { Z_PROBE_ALLEN_KEY_DEPLOY_3_X, Z_PROBE_ALLEN_KEY_DEPLOY_3_Y, Z_PROBE_ALLEN_KEY_DEPLOY_3_Z };
- do_blocking_move_to(deploy_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Z)
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_X
- #define Z_PROBE_ALLEN_KEY_DEPLOY_4_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Y
- #define Z_PROBE_ALLEN_KEY_DEPLOY_4_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Z
- #define Z_PROBE_ALLEN_KEY_DEPLOY_4_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE 0.0
- #endif
- const float deploy_4[] = { Z_PROBE_ALLEN_KEY_DEPLOY_4_X, Z_PROBE_ALLEN_KEY_DEPLOY_4_Y, Z_PROBE_ALLEN_KEY_DEPLOY_4_Z };
- do_blocking_move_to(deploy_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Z)
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_X
- #define Z_PROBE_ALLEN_KEY_DEPLOY_5_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Y
- #define Z_PROBE_ALLEN_KEY_DEPLOY_5_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Z
- #define Z_PROBE_ALLEN_KEY_DEPLOY_5_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE 0.0
- #endif
- const float deploy_5[] = { Z_PROBE_ALLEN_KEY_DEPLOY_5_X, Z_PROBE_ALLEN_KEY_DEPLOY_5_Y, Z_PROBE_ALLEN_KEY_DEPLOY_5_Z };
- do_blocking_move_to(deploy_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE));
- #endif
- }
- void run_stow_moves_script() {
- #if defined(Z_PROBE_ALLEN_KEY_STOW_1_X) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Z)
- #ifndef Z_PROBE_ALLEN_KEY_STOW_1_X
- #define Z_PROBE_ALLEN_KEY_STOW_1_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_1_Y
- #define Z_PROBE_ALLEN_KEY_STOW_1_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_1_Z
- #define Z_PROBE_ALLEN_KEY_STOW_1_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE 0.0
- #endif
- const float stow_1[] = { Z_PROBE_ALLEN_KEY_STOW_1_X, Z_PROBE_ALLEN_KEY_STOW_1_Y, Z_PROBE_ALLEN_KEY_STOW_1_Z };
- do_blocking_move_to(stow_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_STOW_2_X) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Z)
- #ifndef Z_PROBE_ALLEN_KEY_STOW_2_X
- #define Z_PROBE_ALLEN_KEY_STOW_2_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_2_Y
- #define Z_PROBE_ALLEN_KEY_STOW_2_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_2_Z
- #define Z_PROBE_ALLEN_KEY_STOW_2_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE 0.0
- #endif
- const float stow_2[] = { Z_PROBE_ALLEN_KEY_STOW_2_X, Z_PROBE_ALLEN_KEY_STOW_2_Y, Z_PROBE_ALLEN_KEY_STOW_2_Z };
- do_blocking_move_to(stow_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_STOW_3_X) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Z)
- #ifndef Z_PROBE_ALLEN_KEY_STOW_3_X
- #define Z_PROBE_ALLEN_KEY_STOW_3_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_3_Y
- #define Z_PROBE_ALLEN_KEY_STOW_3_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_3_Z
- #define Z_PROBE_ALLEN_KEY_STOW_3_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE 0.0
- #endif
- const float stow_3[] = { Z_PROBE_ALLEN_KEY_STOW_3_X, Z_PROBE_ALLEN_KEY_STOW_3_Y, Z_PROBE_ALLEN_KEY_STOW_3_Z };
- do_blocking_move_to(stow_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_STOW_4_X) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Z)
- #ifndef Z_PROBE_ALLEN_KEY_STOW_4_X
- #define Z_PROBE_ALLEN_KEY_STOW_4_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_4_Y
- #define Z_PROBE_ALLEN_KEY_STOW_4_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_4_Z
- #define Z_PROBE_ALLEN_KEY_STOW_4_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE 0.0
- #endif
- const float stow_4[] = { Z_PROBE_ALLEN_KEY_STOW_4_X, Z_PROBE_ALLEN_KEY_STOW_4_Y, Z_PROBE_ALLEN_KEY_STOW_4_Z };
- do_blocking_move_to(stow_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE));
- #endif
- #if defined(Z_PROBE_ALLEN_KEY_STOW_5_X) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Z)
- #ifndef Z_PROBE_ALLEN_KEY_STOW_5_X
- #define Z_PROBE_ALLEN_KEY_STOW_5_X current_position[X_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_5_Y
- #define Z_PROBE_ALLEN_KEY_STOW_5_Y current_position[Y_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_5_Z
- #define Z_PROBE_ALLEN_KEY_STOW_5_Z current_position[Z_AXIS]
- #endif
- #ifndef Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE
- #define Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE 0.0
- #endif
- const float stow_5[] = { Z_PROBE_ALLEN_KEY_STOW_5_X, Z_PROBE_ALLEN_KEY_STOW_5_Y, Z_PROBE_ALLEN_KEY_STOW_5_Z };
- do_blocking_move_to(stow_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE));
- #endif
- }
- #endif // Z_PROBE_ALLEN_KEY
- #if ENABLED(PROBING_FANS_OFF)
- void fans_pause(const bool p) {
- if (p != fans_paused) {
- fans_paused = p;
- if (p)
- for (uint8_t x = 0; x < FAN_COUNT; x++) {
- paused_fanSpeeds[x] = fanSpeeds[x];
- fanSpeeds[x] = 0;
- }
- else
- for (uint8_t x = 0; x < FAN_COUNT; x++)
- fanSpeeds[x] = paused_fanSpeeds[x];
- }
- }
- #endif // PROBING_FANS_OFF
- #if HAS_BED_PROBE
- // TRIGGERED_WHEN_STOWED_TEST can easily be extended to servo probes, ... if needed.
- #if ENABLED(PROBE_IS_TRIGGERED_WHEN_STOWED_TEST)
- #if ENABLED(Z_MIN_PROBE_ENDSTOP)
- #define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
- #else
- #define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
- #endif
- #endif
- #if QUIET_PROBING
- void probing_pause(const bool p) {
- #if ENABLED(PROBING_HEATERS_OFF)
- thermalManager.pause(p);
- #endif
- #if ENABLED(PROBING_FANS_OFF)
- fans_pause(p);
- #endif
- if (p) safe_delay(
- #if DELAY_BEFORE_PROBING > 25
- DELAY_BEFORE_PROBING
- #else
- 25
- #endif
- );
- }
- #endif
- #if ENABLED(BLTOUCH)
- void bltouch_command(int angle) {
- MOVE_SERVO(Z_PROBE_SERVO_NR, angle);
- safe_delay(BLTOUCH_DELAY);
- }
- bool set_bltouch_deployed(const bool deploy) {
- if (deploy && TEST_BLTOUCH()) {
- bltouch_command(BLTOUCH_RESET);
- bltouch_command(BLTOUCH_DEPLOY);
- bltouch_command(BLTOUCH_STOW);
- safe_delay(1500);
-
-
- if (TEST_BLTOUCH()) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_STOP_BLTOUCH);
- stop();
- return true;
- }
- }
- bltouch_command(deploy ? BLTOUCH_DEPLOY : BLTOUCH_STOW);
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("set_bltouch_deployed(", deploy);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- return false;
- }
- #endif
-
- inline void do_probe_raise(const float z_raise) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("do_probe_raise(", z_raise);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- float z_dest = z_raise;
- if (zprobe_zoffset < 0) z_dest -= zprobe_zoffset;
- NOMORE(z_dest, Z_MAX_POS);
- if (z_dest > current_position[Z_AXIS])
- do_blocking_move_to_z(z_dest);
- }
-
- bool set_probe_deployed(const bool deploy) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- DEBUG_POS("set_probe_deployed", current_position);
- SERIAL_ECHOLNPAIR("deploy: ", deploy);
- }
- #endif
- if (endstops.z_probe_enabled == deploy) return false;
-
-
- #if ENABLED(FIX_MOUNTED_PROBE)
- const bool deploy_stow_condition = deploy;
- #else
- constexpr bool deploy_stow_condition = true;
- #endif
-
- #if ENABLED(UNKNOWN_Z_NO_RAISE)
- const bool unknown_condition = TEST(axis_known_position, Z_AXIS);
- #else
- constexpr float unknown_condition = true;
- #endif
- if (deploy_stow_condition && unknown_condition)
- do_probe_raise(MAX(Z_CLEARANCE_BETWEEN_PROBES, Z_CLEARANCE_DEPLOY_PROBE));
- #if ENABLED(Z_PROBE_SLED) || ENABLED(Z_PROBE_ALLEN_KEY)
- #if ENABLED(Z_PROBE_SLED)
- #define _AUE_ARGS true, false, false
- #else
- #define _AUE_ARGS
- #endif
- if (axis_unhomed_error(_AUE_ARGS)) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_STOP_UNHOMED);
- stop();
- return true;
- }
- #endif
- const float oldXpos = current_position[X_AXIS],
- oldYpos = current_position[Y_AXIS];
- #ifdef _TRIGGERED_WHEN_STOWED_TEST
-
- if (_TRIGGERED_WHEN_STOWED_TEST == deploy) {
-
-
-
- if (!deploy) endstops.enable_z_probe(false);
-
- #endif
- #if ENABLED(SOLENOID_PROBE)
- #if HAS_SOLENOID_1
- WRITE(SOL1_PIN, deploy);
- #endif
- #elif ENABLED(Z_PROBE_SLED)
- dock_sled(!deploy);
- #elif HAS_Z_SERVO_PROBE && DISABLED(BLTOUCH)
- MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[deploy ? 0 : 1]);
- #elif ENABLED(Z_PROBE_ALLEN_KEY)
- deploy ? run_deploy_moves_script() : run_stow_moves_script();
- #endif
- #ifdef _TRIGGERED_WHEN_STOWED_TEST
- }
- if (_TRIGGERED_WHEN_STOWED_TEST == deploy) {
- if (IsRunning()) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("Z-Probe failed");
- LCD_ALERTMESSAGEPGM("Err: ZPROBE");
- }
- stop();
- return true;
- }
- #endif
- do_blocking_move_to(oldXpos, oldYpos, current_position[Z_AXIS]);
- endstops.enable_z_probe(deploy);
- return false;
- }
-
- static bool do_probe_move(const float z, const float fr_mm_s) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS(">>> do_probe_move", current_position);
- #endif
- #if HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
-
- if (thermalManager.isHeatingBed()) {
- serialprintPGM(msg_wait_for_bed_heating);
- LCD_MESSAGEPGM(MSG_BED_HEATING);
- while (thermalManager.isHeatingBed()) safe_delay(200);
- lcd_reset_status();
- }
- #endif
-
- #if ENABLED(BLTOUCH)
- if (set_bltouch_deployed(true)) return true;
- #endif
- #if QUIET_PROBING
- probing_pause(true);
- #endif
-
- do_blocking_move_to_z(z, fr_mm_s);
-
- const bool probe_triggered = TEST(endstops.trigger_state(),
- #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
- Z_MIN
- #else
- Z_MIN_PROBE
- #endif
- );
- #if QUIET_PROBING
- probing_pause(false);
- #endif
-
- #if ENABLED(BLTOUCH)
- if (probe_triggered && set_bltouch_deployed(false)) return true;
- #endif
- endstops.hit_on_purpose();
-
- set_current_from_steppers_for_axis(Z_AXIS);
-
- SYNC_PLAN_POSITION_KINEMATIC();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("<<< do_probe_move", current_position);
- #endif
- return !probe_triggered;
- }
-
- static float run_z_probe() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS(">>> run_z_probe", current_position);
- #endif
-
-
- const float z_probe_low_point = TEST(axis_known_position, Z_AXIS) ? -zprobe_zoffset + Z_PROBE_LOW_POINT : -10.0;
-
- #if MULTIPLE_PROBING == 2
-
- if (do_probe_move(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_FAST))) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("FAST Probe fail!");
- DEBUG_POS("<<< run_z_probe", current_position);
- }
- #endif
- return NAN;
- }
- float first_probe_z = current_position[Z_AXIS];
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("1st Probe Z:", first_probe_z);
- #endif
-
- do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
- #else
-
-
- float z = Z_CLEARANCE_DEPLOY_PROBE + 5.0;
- if (zprobe_zoffset < 0) z -= zprobe_zoffset;
- if (current_position[Z_AXIS] > z) {
-
- if (!do_probe_move(z, MMM_TO_MMS(Z_PROBE_SPEED_FAST)))
- do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
- }
- #endif
- #if MULTIPLE_PROBING > 2
- float probes_total = 0;
- for (uint8_t p = MULTIPLE_PROBING + 1; --p;) {
- #endif
-
- if (do_probe_move(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_SLOW))) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("SLOW Probe fail!");
- DEBUG_POS("<<< run_z_probe", current_position);
- }
- #endif
- return NAN;
- }
- #if MULTIPLE_PROBING > 2
- probes_total += current_position[Z_AXIS];
- if (p > 1) do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
- }
- #endif
- #if MULTIPLE_PROBING > 2
-
- const float measured_z = probes_total * (1.0f / (MULTIPLE_PROBING));
- #elif MULTIPLE_PROBING == 2
- const float z2 = current_position[Z_AXIS];
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("2nd Probe Z:", z2);
- SERIAL_ECHOLNPAIR(" Discrepancy:", first_probe_z - z2);
- }
- #endif
-
- const float measured_z = (z2 * 3.0 + first_probe_z * 2.0) * 0.2;
- #else
-
- const float measured_z = current_position[Z_AXIS];
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("<<< run_z_probe", current_position);
- #endif
- return measured_z;
- }
-
- float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after, const uint8_t verbose_level, const bool probe_relative) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR(">>> probe_pt(", LOGICAL_X_POSITION(rx));
- SERIAL_ECHOPAIR(", ", LOGICAL_Y_POSITION(ry));
- SERIAL_ECHOPAIR(", ", raise_after == PROBE_PT_RAISE ? "raise" : raise_after == PROBE_PT_STOW ? "stow" : "none");
- SERIAL_ECHOPAIR(", ", int(verbose_level));
- SERIAL_ECHOPAIR(", ", probe_relative ? "probe" : "nozzle");
- SERIAL_ECHOLNPGM("_relative)");
- DEBUG_POS("", current_position);
- }
- #endif
-
- float nx = rx, ny = ry;
- if (probe_relative) {
- if (!position_is_reachable_by_probe(rx, ry)) return NAN;
- nx -= (X_PROBE_OFFSET_FROM_EXTRUDER);
- ny -= (Y_PROBE_OFFSET_FROM_EXTRUDER);
- }
- else if (!position_is_reachable(nx, ny)) return NAN;
- const float nz =
- #if ENABLED(DELTA)
-
- MIN(current_position[Z_AXIS], delta_clip_start_height)
- #else
- current_position[Z_AXIS]
- #endif
- ;
- const float old_feedrate_mm_s = feedrate_mm_s;
- feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
-
- do_blocking_move_to(nx, ny, nz);
- float measured_z = NAN;
- if (!DEPLOY_PROBE()) {
- measured_z = run_z_probe() + zprobe_zoffset;
- const bool big_raise = raise_after == PROBE_PT_BIG_RAISE;
- if (big_raise || raise_after == PROBE_PT_RAISE)
- do_blocking_move_to_z(current_position[Z_AXIS] + (big_raise ? 25 : Z_CLEARANCE_BETWEEN_PROBES), MMM_TO_MMS(Z_PROBE_SPEED_FAST));
- else if (raise_after == PROBE_PT_STOW)
- if (STOW_PROBE()) measured_z = NAN;
- }
- if (verbose_level > 2) {
- SERIAL_PROTOCOLPGM("Bed X: ");
- SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(rx), 3);
- SERIAL_PROTOCOLPGM(" Y: ");
- SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(ry), 3);
- SERIAL_PROTOCOLPGM(" Z: ");
- SERIAL_PROTOCOL_F(measured_z, 3);
- SERIAL_EOL();
- }
- feedrate_mm_s = old_feedrate_mm_s;
- if (isnan(measured_z)) {
- LCD_MESSAGEPGM(MSG_ERR_PROBING_FAILED);
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_ERR_PROBING_FAILED);
- }
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< probe_pt");
- #endif
- return measured_z;
- }
- #endif
- #if HAS_LEVELING
- bool leveling_is_valid() {
- return
- #if ENABLED(MESH_BED_LEVELING)
- mbl.has_mesh()
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- !!bilinear_grid_spacing[X_AXIS]
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
- ubl.mesh_is_valid()
- #else
- true
- #endif
- ;
- }
-
- void set_bed_leveling_enabled(const bool enable) {
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- const bool can_change = (!enable || leveling_is_valid());
- #else
- constexpr bool can_change = true;
- #endif
- if (can_change && enable != planner.leveling_active) {
- planner.synchronize();
- #if ENABLED(MESH_BED_LEVELING)
- if (!enable)
- planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
- const bool enabling = enable && leveling_is_valid();
- planner.leveling_active = enabling;
- if (enabling) planner.unapply_leveling(current_position);
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
- #if PLANNER_LEVELING
- if (planner.leveling_active) {
-
- planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
- planner.leveling_active = false;
- }
- else {
- planner.leveling_active = true;
-
- planner.unapply_leveling(current_position);
- }
- #else
-
- #if ENABLED(SKEW_CORRECTION)
- float pos[XYZ] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
- planner.skew(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]);
- #else
- const float (&pos)[XYZE] = current_position;
- #endif
- if (planner.leveling_active) {
- current_position[Z_AXIS] += ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
- planner.leveling_active = false;
- }
- else {
- planner.leveling_active = true;
- current_position[Z_AXIS] -= ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
- }
- #endif
- #else
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
-
- const float reset[XYZ] = { -9999.999, -9999.999, 0 };
- (void)bilinear_z_offset(reset);
- #endif
-
- planner.leveling_active = enable;
- if (!enable)
-
-
- set_current_from_steppers_for_axis(
- #if ABL_PLANAR
- ALL_AXES
- #else
- Z_AXIS
- #endif
- );
- else
-
-
- planner.unapply_leveling(current_position);
- SYNC_PLAN_POSITION_KINEMATIC();
- #endif
- }
- }
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- void set_z_fade_height(const float zfh, const bool do_report) {
- if (planner.z_fade_height == zfh) return;
- const bool leveling_was_active = planner.leveling_active;
- set_bed_leveling_enabled(false);
- planner.set_z_fade_height(zfh);
- if (leveling_was_active) {
- const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
- set_bed_leveling_enabled(true);
- if (do_report && memcmp(oldpos, current_position, sizeof(oldpos)))
- report_current_position();
- }
- }
- #endif
-
- void reset_bed_level() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("reset_bed_level");
- #endif
- set_bed_leveling_enabled(false);
- #if ENABLED(MESH_BED_LEVELING)
- mbl.reset();
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
- ubl.reset();
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- bilinear_start[X_AXIS] = bilinear_start[Y_AXIS] =
- bilinear_grid_spacing[X_AXIS] = bilinear_grid_spacing[Y_AXIS] = 0;
- for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
- for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
- z_values[x][y] = NAN;
- #elif ABL_PLANAR
- planner.bed_level_matrix.set_to_identity();
- #endif
- }
- #endif
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(MESH_BED_LEVELING)
-
-
-
- void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const element_2d_fn fn) {
- #ifndef SCAD_MESH_OUTPUT
- for (uint8_t x = 0; x < sx; x++) {
- for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++)
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOL(int(x));
- }
- SERIAL_EOL();
- #endif
- #ifdef SCAD_MESH_OUTPUT
- SERIAL_PROTOCOLLNPGM("measured_z = [");
- #endif
- for (uint8_t y = 0; y < sy; y++) {
- #ifdef SCAD_MESH_OUTPUT
- SERIAL_PROTOCOLPGM(" [");
- #else
- if (y < 10) SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOL(int(y));
- #endif
- for (uint8_t x = 0; x < sx; x++) {
- SERIAL_PROTOCOLCHAR(' ');
- const float offset = fn(x, y);
- if (!isnan(offset)) {
- if (offset >= 0) SERIAL_PROTOCOLCHAR('+');
- SERIAL_PROTOCOL_F(offset, int(precision));
- }
- else {
- #ifdef SCAD_MESH_OUTPUT
- for (uint8_t i = 3; i < precision + 3; i++)
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOLPGM("NAN");
- #else
- for (uint8_t i = 0; i < precision + 3; i++)
- SERIAL_PROTOCOLCHAR(i ? '=' : ' ');
- #endif
- }
- #ifdef SCAD_MESH_OUTPUT
- if (x < sx - 1) SERIAL_PROTOCOLCHAR(',');
- #endif
- }
- #ifdef SCAD_MESH_OUTPUT
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOLCHAR(']');
- if (y < sy - 1) SERIAL_PROTOCOLCHAR(',');
- #endif
- SERIAL_EOL();
- }
- #ifdef SCAD_MESH_OUTPUT
- SERIAL_PROTOCOLPGM("];");
- #endif
- SERIAL_EOL();
- }
- #endif
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
-
- static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPGM("Extrapolate [");
- if (x < 10) SERIAL_CHAR(' ');
- SERIAL_ECHO(int(x));
- SERIAL_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' ');
- SERIAL_CHAR(' ');
- if (y < 10) SERIAL_CHAR(' ');
- SERIAL_ECHO(int(y));
- SERIAL_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' ');
- SERIAL_CHAR(']');
- }
- #endif
- if (!isnan(z_values[x][y])) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
- #endif
- return;
- }
- SERIAL_EOL();
-
- const uint8_t x1 = x + xdir, y1 = y + ydir, x2 = x1 + xdir, y2 = y1 + ydir;
- float a1 = z_values[x1][y ], a2 = z_values[x2][y ],
- b1 = z_values[x ][y1], b2 = z_values[x ][y2],
- c1 = z_values[x1][y1], c2 = z_values[x2][y2];
-
- if (isnan(a2)) a2 = 0.0; if (isnan(a1)) a1 = a2;
- if (isnan(b2)) b2 = 0.0; if (isnan(b1)) b1 = b2;
- if (isnan(c2)) c2 = 0.0; if (isnan(c1)) c1 = c2;
- const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;
-
- z_values[x][y] = (a + b + c) / 3.0;
-
-
-
- }
-
-
- #if ENABLED(EXTRAPOLATE_FROM_EDGE)
- #if GRID_MAX_POINTS_X < GRID_MAX_POINTS_Y
- #define HALF_IN_X
- #elif GRID_MAX_POINTS_Y < GRID_MAX_POINTS_X
- #define HALF_IN_Y
- #endif
- #endif
- /**
- * Fill in the unprobed points (corners of circular print surface)
- * using linear extrapolation, away from the center.
- */
- static void extrapolate_unprobed_bed_level() {
- #ifdef HALF_IN_X
- constexpr uint8_t ctrx2 = 0, xlen = GRID_MAX_POINTS_X - 1;
- #else
- constexpr uint8_t ctrx1 = (GRID_MAX_POINTS_X - 1) / 2, // left-of-center
- ctrx2 = (GRID_MAX_POINTS_X) / 2, // right-of-center
- xlen = ctrx1;
- #endif
- #ifdef HALF_IN_Y
- constexpr uint8_t ctry2 = 0, ylen = GRID_MAX_POINTS_Y - 1;
- #else
- constexpr uint8_t ctry1 = (GRID_MAX_POINTS_Y - 1) / 2, // top-of-center
- ctry2 = (GRID_MAX_POINTS_Y) / 2, // bottom-of-center
- ylen = ctry1;
- #endif
- for (uint8_t xo = 0; xo <= xlen; xo++)
- for (uint8_t yo = 0; yo <= ylen; yo++) {
- uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo;
- #ifndef HALF_IN_X
- const uint8_t x1 = ctrx1 - xo;
- #endif
- #ifndef HALF_IN_Y
- const uint8_t y1 = ctry1 - yo;
- #ifndef HALF_IN_X
- extrapolate_one_point(x1, y1, +1, +1); // left-below + +
- #endif
- extrapolate_one_point(x2, y1, -1, +1); // right-below - +
- #endif
- #ifndef HALF_IN_X
- extrapolate_one_point(x1, y2, +1, -1); // left-above + -
- #endif
- extrapolate_one_point(x2, y2, -1, -1); // right-above - -
- }
- }
- static void print_bilinear_leveling_grid() {
- SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
- print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3,
- [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
- );
- }
- #if ENABLED(ABL_BILINEAR_SUBDIVISION)
- #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_POINTS_X - 1) * (BILINEAR_SUBDIVISIONS) + 1
- #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_POINTS_Y - 1) * (BILINEAR_SUBDIVISIONS) + 1
- #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
- #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
- float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
- int bilinear_grid_spacing_virt[2] = { 0 };
- float bilinear_grid_factor_virt[2] = { 0 };
- static void print_bilinear_leveling_grid_virt() {
- SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
- print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
- [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; }
- );
- }
- #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
- float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
- uint8_t ep = 0, ip = 1;
- if (!x || x == ABL_TEMP_POINTS_X - 1) {
- if (x) {
- ep = GRID_MAX_POINTS_X - 1;
- ip = GRID_MAX_POINTS_X - 2;
- }
- if (WITHIN(y, 1, ABL_TEMP_POINTS_Y - 2))
- return LINEAR_EXTRAPOLATION(
- z_values[ep][y - 1],
- z_values[ip][y - 1]
- );
- else
- return LINEAR_EXTRAPOLATION(
- bed_level_virt_coord(ep + 1, y),
- bed_level_virt_coord(ip + 1, y)
- );
- }
- if (!y || y == ABL_TEMP_POINTS_Y - 1) {
- if (y) {
- ep = GRID_MAX_POINTS_Y - 1;
- ip = GRID_MAX_POINTS_Y - 2;
- }
- if (WITHIN(x, 1, ABL_TEMP_POINTS_X - 2))
- return LINEAR_EXTRAPOLATION(
- z_values[x - 1][ep],
- z_values[x - 1][ip]
- );
- else
- return LINEAR_EXTRAPOLATION(
- bed_level_virt_coord(x, ep + 1),
- bed_level_virt_coord(x, ip + 1)
- );
- }
- return z_values[x - 1][y - 1];
- }
- static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
- return (
- p[i-1] * -t * sq(1 - t)
- + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t))
- + p[i+1] * t * (1 + 4 * t - 3 * sq(t))
- - p[i+2] * sq(t) * (1 - t)
- ) * 0.5;
- }
- static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const float &tx, const float &ty) {
- float row[4], column[4];
- for (uint8_t i = 0; i < 4; i++) {
- for (uint8_t j = 0; j < 4; j++) {
- column[j] = bed_level_virt_coord(i + x - 1, j + y - 1);
- }
- row[i] = bed_level_virt_cmr(column, 1, ty);
- }
- return bed_level_virt_cmr(row, 1, tx);
- }
- void bed_level_virt_interpolate() {
- bilinear_grid_spacing_virt[X_AXIS] = bilinear_grid_spacing[X_AXIS] / (BILINEAR_SUBDIVISIONS);
- bilinear_grid_spacing_virt[Y_AXIS] = bilinear_grid_spacing[Y_AXIS] / (BILINEAR_SUBDIVISIONS);
- bilinear_grid_factor_virt[X_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[X_AXIS]);
- bilinear_grid_factor_virt[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[Y_AXIS]);
- for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
- for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
- for (uint8_t ty = 0; ty < BILINEAR_SUBDIVISIONS; ty++)
- for (uint8_t tx = 0; tx < BILINEAR_SUBDIVISIONS; tx++) {
- if ((ty && y == GRID_MAX_POINTS_Y - 1) || (tx && x == GRID_MAX_POINTS_X - 1))
- continue;
- z_values_virt[x * (BILINEAR_SUBDIVISIONS) + tx][y * (BILINEAR_SUBDIVISIONS) + ty] =
- bed_level_virt_2cmr(
- x + 1,
- y + 1,
- (float)tx / (BILINEAR_SUBDIVISIONS),
- (float)ty / (BILINEAR_SUBDIVISIONS)
- );
- }
- }
- #endif // ABL_BILINEAR_SUBDIVISION
- // Refresh after other values have been updated
- void refresh_bed_level() {
- bilinear_grid_factor[X_AXIS] = RECIPROCAL(bilinear_grid_spacing[X_AXIS]);
- bilinear_grid_factor[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing[Y_AXIS]);
- #if ENABLED(ABL_BILINEAR_SUBDIVISION)
- bed_level_virt_interpolate();
- #endif
- }
- #endif // AUTO_BED_LEVELING_BILINEAR
- #if ENABLED(SENSORLESS_HOMING)
- /**
- * Set sensorless homing if the axis has it, accounting for Core Kinematics.
- */
- void sensorless_homing_per_axis(const AxisEnum axis, const bool enable=true) {
- switch (axis) {
- #if X_SENSORLESS
- case X_AXIS:
- tmc_sensorless_homing(stepperX, enable);
- #if CORE_IS_XY && Y_SENSORLESS
- tmc_sensorless_homing(stepperY, enable);
- #elif CORE_IS_XZ && Z_SENSORLESS
- tmc_sensorless_homing(stepperZ, enable);
- #endif
- break;
- #endif
- #if Y_SENSORLESS
- case Y_AXIS:
- tmc_sensorless_homing(stepperY, enable);
- #if CORE_IS_XY && X_SENSORLESS
- tmc_sensorless_homing(stepperX, enable);
- #elif CORE_IS_YZ && Z_SENSORLESS
- tmc_sensorless_homing(stepperZ, enable);
- #endif
- break;
- #endif
- #if Z_SENSORLESS
- case Z_AXIS:
- tmc_sensorless_homing(stepperZ, enable);
- #if CORE_IS_XZ && X_SENSORLESS
- tmc_sensorless_homing(stepperX, enable);
- #elif CORE_IS_YZ && Y_SENSORLESS
- tmc_sensorless_homing(stepperY, enable);
- #endif
- break;
- #endif
- default: break;
- }
- }
- #endif // SENSORLESS_HOMING
- /**
- * Home an individual linear axis
- */
- static void do_homing_move(const AxisEnum axis, const float distance, const float fr_mm_s=0) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR(">>> do_homing_move(", axis_codes[axis]);
- SERIAL_ECHOPAIR(", ", distance);
- SERIAL_ECHOPGM(", ");
- if (fr_mm_s)
- SERIAL_ECHO(fr_mm_s);
- else {
- SERIAL_ECHOPAIR("[", homing_feedrate(axis));
- SERIAL_CHAR(']');
- }
- SERIAL_ECHOLNPGM(")");
- }
- #endif
- #if HOMING_Z_WITH_PROBE && HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
- // Wait for bed to heat back up between probing points
- if (axis == Z_AXIS && distance < 0 && thermalManager.isHeatingBed()) {
- serialprintPGM(msg_wait_for_bed_heating);
- LCD_MESSAGEPGM(MSG_BED_HEATING);
- while (thermalManager.isHeatingBed()) safe_delay(200);
- lcd_reset_status();
- }
- #endif
- // Only do some things when moving towards an endstop
- const int8_t axis_home_dir =
- #if ENABLED(DUAL_X_CARRIAGE)
- (axis == X_AXIS) ? x_home_dir(active_extruder) :
- #endif
- home_dir(axis);
- const bool is_home_dir = (axis_home_dir > 0) == (distance > 0);
- if (is_home_dir) {
- #if HOMING_Z_WITH_PROBE && QUIET_PROBING
- if (axis == Z_AXIS) probing_pause(true);
- #endif
- // Disable stealthChop if used. Enable diag1 pin on driver.
- #if ENABLED(SENSORLESS_HOMING)
- sensorless_homing_per_axis(axis);
- #endif
- }
- // Tell the planner the axis is at 0
- current_position[axis] = 0;
- // Do the move, which is required to hit an endstop
- #if IS_SCARA
- SYNC_PLAN_POSITION_KINEMATIC();
- current_position[axis] = distance;
- inverse_kinematics(current_position);
- planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
- #elif ENABLED(HANGPRINTER) // TODO: Hangprinter homing is not finished (Jan 7, 2018)
- SYNC_PLAN_POSITION_KINEMATIC();
- current_position[axis] = distance;
- inverse_kinematics(current_position);
- planner.buffer_line(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
- #else
- sync_plan_position();
- current_position[axis] = distance; // Set delta/cartesian axes directly
- planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
- #endif
- planner.synchronize();
- if (is_home_dir) {
- #if HOMING_Z_WITH_PROBE && QUIET_PROBING
- if (axis == Z_AXIS) probing_pause(false);
- #endif
- endstops.validate_homing_move();
- // Re-enable stealthChop if used. Disable diag1 pin on driver.
- #if ENABLED(SENSORLESS_HOMING)
- sensorless_homing_per_axis(axis, false);
- #endif
- }
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("<<< do_homing_move(", axis_codes[axis]);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- }
- /**
- * Home an individual "raw axis" to its endstop.
- * This applies to XYZ on Cartesian and Core robots, and
- * to the individual ABC steppers on DELTA and SCARA.
- *
- * At the end of the procedure the axis is marked as
- * homed and the current position of that axis is updated.
- * Kinematic robots should wait till all axes are homed
- * before updating the current position.
- */
- static void homeaxis(const AxisEnum axis) {
- #if IS_SCARA
- // Only Z homing (with probe) is permitted
- if (axis != Z_AXIS) { BUZZ(100, 880); return; }
- #else
- #define CAN_HOME(A) \
- (axis == _AXIS(A) && ((A##_MIN_PIN > -1 && A##_HOME_DIR < 0) || (A##_MAX_PIN > -1 && A##_HOME_DIR > 0)))
- if (!CAN_HOME(X) && !CAN_HOME(Y) && !CAN_HOME(Z)) return;
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR(">>> homeaxis(", axis_codes[axis]);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- const int axis_home_dir = (
- #if ENABLED(DUAL_X_CARRIAGE)
- axis == X_AXIS ? x_home_dir(active_extruder) :
- #endif
- home_dir(axis)
- );
-
- #if HOMING_Z_WITH_PROBE
- if (axis == Z_AXIS && DEPLOY_PROBE()) return;
- #endif
-
- #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
- switch (axis) {
- #if ENABLED(X_DUAL_ENDSTOPS)
- case X_AXIS:
- #endif
- #if ENABLED(Y_DUAL_ENDSTOPS)
- case Y_AXIS:
- #endif
- #if ENABLED(Z_DUAL_ENDSTOPS)
- case Z_AXIS:
- #endif
- stepper.set_homing_dual_axis(true);
- default: break;
- }
- #endif
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 1 Fast:");
- #endif
- #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
-
- if (axis == Z_AXIS && set_bltouch_deployed(true)) return;
- #endif
- do_homing_move(axis, 1.5f * max_length(axis) * axis_home_dir);
- #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
-
- if (axis == Z_AXIS) set_bltouch_deployed(false);
- #endif
-
- const float bump = axis_home_dir * (
- #if HOMING_Z_WITH_PROBE
- (axis == Z_AXIS && (Z_HOME_BUMP_MM)) ? MAX(Z_CLEARANCE_BETWEEN_PROBES, Z_HOME_BUMP_MM) :
- #endif
- home_bump_mm(axis)
- );
-
- if (bump) {
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Move Away:");
- #endif
- do_homing_move(axis, -bump
- #if HOMING_Z_WITH_PROBE
- , axis == Z_AXIS ? MMM_TO_MMS(Z_PROBE_SPEED_FAST) : 0.00
- #endif
- );
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 2 Slow:");
- #endif
- #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
-
- if (axis == Z_AXIS && set_bltouch_deployed(true)) return;
- #endif
- do_homing_move(axis, 2 * bump, get_homing_bump_feedrate(axis));
- #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
-
- if (axis == Z_AXIS) set_bltouch_deployed(false);
- #endif
- }
-
- #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
- const bool pos_dir = axis_home_dir > 0;
- #if ENABLED(X_DUAL_ENDSTOPS)
- if (axis == X_AXIS) {
- const float adj = ABS(endstops.x_endstop_adj);
- if (adj) {
- if (pos_dir ? (endstops.x_endstop_adj > 0) : (endstops.x_endstop_adj < 0)) stepper.set_x_lock(true); else stepper.set_x2_lock(true);
- do_homing_move(axis, pos_dir ? -adj : adj);
- stepper.set_x_lock(false);
- stepper.set_x2_lock(false);
- }
- }
- #endif
- #if ENABLED(Y_DUAL_ENDSTOPS)
- if (axis == Y_AXIS) {
- const float adj = ABS(endstops.y_endstop_adj);
- if (adj) {
- if (pos_dir ? (endstops.y_endstop_adj > 0) : (endstops.y_endstop_adj < 0)) stepper.set_y_lock(true); else stepper.set_y2_lock(true);
- do_homing_move(axis, pos_dir ? -adj : adj);
- stepper.set_y_lock(false);
- stepper.set_y2_lock(false);
- }
- }
- #endif
- #if ENABLED(Z_DUAL_ENDSTOPS)
- if (axis == Z_AXIS) {
- const float adj = ABS(endstops.z_endstop_adj);
- if (adj) {
- if (pos_dir ? (endstops.z_endstop_adj > 0) : (endstops.z_endstop_adj < 0)) stepper.set_z_lock(true); else stepper.set_z2_lock(true);
- do_homing_move(axis, pos_dir ? -adj : adj);
- stepper.set_z_lock(false);
- stepper.set_z2_lock(false);
- }
- }
- #endif
- stepper.set_homing_dual_axis(false);
- #endif
- #if IS_SCARA
- set_axis_is_at_home(axis);
- SYNC_PLAN_POSITION_KINEMATIC();
- #elif ENABLED(DELTA)
-
-
-
-
- if (delta_endstop_adj[axis] * Z_HOME_DIR <= 0) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("delta_endstop_adj:");
- #endif
- do_homing_move(axis, delta_endstop_adj[axis] - (MIN_STEPS_PER_SEGMENT + 1) * planner.steps_to_mm[axis] * Z_HOME_DIR);
- }
- #else
-
-
- set_axis_is_at_home(axis);
- sync_plan_position();
- destination[axis] = current_position[axis];
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("> AFTER set_axis_is_at_home", current_position);
- #endif
- #endif
-
- #if HOMING_Z_WITH_PROBE
- if (axis == Z_AXIS && STOW_PROBE()) return;
- #endif
-
- #if ENABLED(FWRETRACT)
- if (axis == Z_AXIS) fwretract.hop_amount = 0.0;
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("<<< homeaxis(", axis_codes[axis]);
- SERIAL_CHAR(')');
- SERIAL_EOL();
- }
- #endif
- }
- #if ENABLED(MIXING_EXTRUDER)
- void normalize_mix() {
- float mix_total = 0.0;
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mix_total += mixing_factor[i];
-
- if (!NEAR(mix_total, 1.0)) {
- SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling.");
- const float inverse_sum = RECIPROCAL(mix_total);
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_factor[i] *= inverse_sum;
- }
- }
- #if ENABLED(DIRECT_MIXING_IN_G1)
-
-
-
- void gcode_get_mix() {
- const char mixing_codes[] = { 'A', 'B'
- #if MIXING_STEPPERS > 2
- , 'C'
- #if MIXING_STEPPERS > 3
- , 'D'
- #if MIXING_STEPPERS > 4
- , 'H'
- #if MIXING_STEPPERS > 5
- , 'I'
- #endif
- #endif
- #endif
- #endif
- };
- byte mix_bits = 0;
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++) {
- if (parser.seenval(mixing_codes[i])) {
- SBI(mix_bits, i);
- mixing_factor[i] = MAX(parser.value_float(), 0.0);
- }
- }
-
-
- if (mix_bits) {
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
- if (!TEST(mix_bits, i)) mixing_factor[i] = 0.0;
- normalize_mix();
- }
- }
- #endif
- #endif
- void gcode_get_destination() {
- LOOP_XYZE(i) {
- if (parser.seen(axis_codes[i])) {
- const float v = parser.value_axis_units((AxisEnum)i);
- destination[i] = (axis_relative_modes[i] || relative_mode)
- ? current_position[i] + v
- : (i == E_CART) ? v : LOGICAL_TO_NATIVE(v, i);
- }
- else
- destination[i] = current_position[i];
- }
- if (parser.linearval('F') > 0)
- feedrate_mm_s = MMM_TO_MMS(parser.value_feedrate());
- #if ENABLED(PRINTCOUNTER)
- if (!DEBUGGING(DRYRUN))
- print_job_timer.incFilamentUsed(destination[E_CART] - current_position[E_CART]);
- #endif
-
- #if ENABLED(MIXING_EXTRUDER) && ENABLED(DIRECT_MIXING_IN_G1)
- gcode_get_mix();
- #endif
- }
- #if ENABLED(HOST_KEEPALIVE_FEATURE)
-
- void host_keepalive() {
- const millis_t ms = millis();
- if (!suspend_auto_report && host_keepalive_interval && busy_state != NOT_BUSY) {
- if (PENDING(ms, next_busy_signal_ms)) return;
- switch (busy_state) {
- case IN_HANDLER:
- case IN_PROCESS:
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_BUSY_PROCESSING);
- break;
- case PAUSED_FOR_USER:
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_USER);
- break;
- case PAUSED_FOR_INPUT:
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_INPUT);
- break;
- default:
- break;
- }
- }
- next_busy_signal_ms = ms + host_keepalive_interval * 1000UL;
- }
- #endif
- #if ENABLED(NO_MOTION_BEFORE_HOMING)
- #define G0_G1_CONDITION !axis_unhomed_error(parser.seen('X'), parser.seen('Y'), parser.seen('Z'))
- #else
- #define G0_G1_CONDITION true
- #endif
- inline void gcode_G0_G1(
- #if IS_SCARA
- bool fast_move=false
- #endif
- ) {
- if (IsRunning() && G0_G1_CONDITION) {
- gcode_get_destination();
- #if ENABLED(FWRETRACT)
- if (MIN_AUTORETRACT <= MAX_AUTORETRACT) {
-
- if (fwretract.autoretract_enabled && parser.seen('E') && !(parser.seen('X') || parser.seen('Y') || parser.seen('Z'))) {
- const float echange = destination[E_CART] - current_position[E_CART];
-
- if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) {
- current_position[E_CART] = destination[E_CART];
- sync_plan_position_e();
- return fwretract.retract(echange < 0.0);
- }
- }
- }
- #endif
- #if IS_SCARA
- fast_move ? prepare_uninterpolated_move_to_destination() : prepare_move_to_destination();
- #else
- prepare_move_to_destination();
- #endif
- #if ENABLED(NANODLP_Z_SYNC)
- #if ENABLED(NANODLP_ALL_AXIS)
- #define _MOVE_SYNC parser.seenval('X') || parser.seenval('Y') || parser.seenval('Z')
- #else
- #define _MOVE_SYNC parser.seenval('Z')
- #endif
- if (_MOVE_SYNC) {
- planner.synchronize();
- SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
- }
- #endif
- }
- }
- #if ENABLED(ARC_SUPPORT)
- inline void gcode_G2_G3(const bool clockwise) {
- #if ENABLED(NO_MOTION_BEFORE_HOMING)
- if (axis_unhomed_error()) return;
- #endif
- if (IsRunning()) {
- #if ENABLED(SF_ARC_FIX)
- const bool relative_mode_backup = relative_mode;
- relative_mode = true;
- #endif
- gcode_get_destination();
- #if ENABLED(SF_ARC_FIX)
- relative_mode = relative_mode_backup;
- #endif
- float arc_offset[2] = { 0, 0 };
- if (parser.seenval('R')) {
- const float r = parser.value_linear_units(),
- p1 = current_position[X_AXIS], q1 = current_position[Y_AXIS],
- p2 = destination[X_AXIS], q2 = destination[Y_AXIS];
- if (r && (p2 != p1 || q2 != q1)) {
- const float e = clockwise ^ (r < 0) ? -1 : 1,
- dx = p2 - p1, dy = q2 - q1,
- d = HYPOT(dx, dy),
- h = SQRT(sq(r) - sq(d * 0.5f)),
- mx = (p1 + p2) * 0.5f, my = (q1 + q2) * 0.5f,
- sx = -dy / d, sy = dx / d,
- cx = mx + e * h * sx, cy = my + e * h * sy;
- arc_offset[0] = cx - p1;
- arc_offset[1] = cy - q1;
- }
- }
- else {
- if (parser.seenval('I')) arc_offset[0] = parser.value_linear_units();
- if (parser.seenval('J')) arc_offset[1] = parser.value_linear_units();
- }
- if (arc_offset[0] || arc_offset[1]) {
- #if ENABLED(ARC_P_CIRCLES)
-
- int8_t circles_to_do = parser.byteval('P');
- if (!WITHIN(circles_to_do, 0, 100)) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS);
- }
- while (circles_to_do--)
- plan_arc(current_position, arc_offset, clockwise);
- #endif
-
- plan_arc(destination, arc_offset, clockwise);
- }
- else {
-
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS);
- }
- }
- }
- #endif
- void dwell(millis_t time) {
- time += millis();
- while (PENDING(millis(), time)) idle();
- }
- inline void gcode_G4() {
- millis_t dwell_ms = 0;
- if (parser.seenval('P')) dwell_ms = parser.value_millis();
- if (parser.seenval('S')) dwell_ms = parser.value_millis_from_seconds();
- planner.synchronize();
- #if ENABLED(NANODLP_Z_SYNC)
- SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
- #endif
- if (!lcd_hasstatus()) LCD_MESSAGEPGM(MSG_DWELL);
- dwell(dwell_ms);
- }
- #if ENABLED(BEZIER_CURVE_SUPPORT)
-
-
- inline void gcode_G5() {
- #if ENABLED(NO_MOTION_BEFORE_HOMING)
- if (axis_unhomed_error()) return;
- #endif
- if (IsRunning()) {
- #if ENABLED(CNC_WORKSPACE_PLANES)
- if (workspace_plane != PLANE_XY) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_ERR_BAD_PLANE_MODE);
- return;
- }
- #endif
- gcode_get_destination();
- const float offset[] = {
- parser.linearval('I'),
- parser.linearval('J'),
- parser.linearval('P'),
- parser.linearval('Q')
- };
- plan_cubic_move(destination, offset);
- }
- }
- #endif
- #if ENABLED(UNREGISTERED_MOVE_SUPPORT)
-
-
- inline void gcode_G6() {
- bool count_it = false;
- #if ENABLED(NO_MOTION_BEFORE_HOMING)
- if (axis_unhomed_error()) return;
- #endif
- if (IsRunning()) {
- float go[MOV_AXIS] = { 0.0 },
- tmp_fr_mm_s = 0.0;
- LOOP_MOV_AXIS(i)
- if (parser.seen(RAW_AXIS_CODES(i)))
- go[i] = parser.value_axis_units((AxisEnum)i);
- #if ENABLED(HANGPRINTER)
- #define GO_SRC line_lengths
- #elif ENABLED(DELTA)
- #define GO_SRC delta
- #else
- #define GO_SRC current_position
- #endif
- if (
- #if ENABLED(HANGPRINTER)
- parser.byteval('S') != 2
- #else
- parser.seen('R')
- #endif
- )
- LOOP_MOV_AXIS(i) go[i] += GO_SRC[i];
- else
- LOOP_MOV_AXIS(i) if (!parser.seen(RAW_AXIS_CODES(i))) go[i] += GO_SRC[i];
- tmp_fr_mm_s = parser.linearval('F') > 0.0 ? MMM_TO_MMS(parser.value_feedrate()) : feedrate_mm_s;
- #if ENABLED(HANGPRINTER)
- if (parser.byteval('S') == 2) {
- LOOP_MOV_AXIS(i) line_lengths[i] = go[i];
- count_it = true;
- }
- #endif
- planner.buffer_segment(go[A_AXIS], go[B_AXIS], go[C_AXIS]
- #if ENABLED(HANGPRINTER)
- , go[D_AXIS]
- #endif
- , current_position[E_CART], tmp_fr_mm_s, active_extruder, 0.0, count_it
- );
- }
- }
- #endif
- #if ENABLED(FWRETRACT)
-
- inline void gcode_G10() {
- #if EXTRUDERS > 1
- const bool rs = parser.boolval('S');
- #endif
- fwretract.retract(true
- #if EXTRUDERS > 1
- , rs
- #endif
- );
- }
-
- inline void gcode_G11() { fwretract.retract(false); }
- #endif
- #if ENABLED(NOZZLE_CLEAN_FEATURE)
-
- inline void gcode_G12() {
-
- if (axis_unhomed_error()) return;
- const uint8_t pattern = parser.ushortval('P', 0),
- strokes = parser.ushortval('S', NOZZLE_CLEAN_STROKES),
- objects = parser.ushortval('T', NOZZLE_CLEAN_TRIANGLES);
- const float radius = parser.floatval('R', NOZZLE_CLEAN_CIRCLE_RADIUS);
- Nozzle::clean(pattern, strokes, radius, objects);
- }
- #endif
- #if ENABLED(CNC_WORKSPACE_PLANES)
- inline void report_workspace_plane() {
- SERIAL_ECHO_START();
- SERIAL_ECHOPGM("Workspace Plane ");
- serialprintPGM(
- workspace_plane == PLANE_YZ ? PSTR("YZ\n") :
- workspace_plane == PLANE_ZX ? PSTR("ZX\n") :
- PSTR("XY\n")
- );
- }
- inline void set_workspace_plane(const WorkspacePlane plane) {
- workspace_plane = plane;
- if (DEBUGGING(INFO)) report_workspace_plane();
- }
-
- inline void gcode_G17() { set_workspace_plane(PLANE_XY); }
- inline void gcode_G18() { set_workspace_plane(PLANE_ZX); }
- inline void gcode_G19() { set_workspace_plane(PLANE_YZ); }
- #endif
- #if ENABLED(CNC_COORDINATE_SYSTEMS)
-
- bool select_coordinate_system(const int8_t _new) {
- if (active_coordinate_system == _new) return false;
- float old_offset[XYZ] = { 0 }, new_offset[XYZ] = { 0 };
- if (WITHIN(active_coordinate_system, 0, MAX_COORDINATE_SYSTEMS - 1))
- COPY(old_offset, coordinate_system[active_coordinate_system]);
- if (WITHIN(_new, 0, MAX_COORDINATE_SYSTEMS - 1))
- COPY(new_offset, coordinate_system[_new]);
- active_coordinate_system = _new;
- LOOP_XYZ(i) {
- const float diff = new_offset[i] - old_offset[i];
- if (diff) {
- position_shift[i] += diff;
- update_software_endstops((AxisEnum)i);
- }
- }
- return true;
- }
-
- inline void gcode_G53() {
- const int8_t _system = active_coordinate_system;
- active_coordinate_system = -1;
- if (parser.chain()) {
- process_parsed_command();
- active_coordinate_system = _system;
- }
- }
-
- inline void gcode_G54_59(uint8_t subcode=0) {
- const int8_t _space = parser.codenum - 54 + subcode;
- if (select_coordinate_system(_space)) {
- SERIAL_PROTOCOLLNPAIR("Select workspace ", _space);
- report_current_position();
- }
- }
- FORCE_INLINE void gcode_G54() { gcode_G54_59(); }
- FORCE_INLINE void gcode_G55() { gcode_G54_59(); }
- FORCE_INLINE void gcode_G56() { gcode_G54_59(); }
- FORCE_INLINE void gcode_G57() { gcode_G54_59(); }
- FORCE_INLINE void gcode_G58() { gcode_G54_59(); }
- FORCE_INLINE void gcode_G59() { gcode_G54_59(parser.subcode); }
- #endif
- #if ENABLED(INCH_MODE_SUPPORT)
-
- inline void gcode_G20() { parser.set_input_linear_units(LINEARUNIT_INCH); }
-
- inline void gcode_G21() { parser.set_input_linear_units(LINEARUNIT_MM); }
- #endif
- #if ENABLED(NOZZLE_PARK_FEATURE)
-
- inline void gcode_G27() {
-
- if (axis_unhomed_error()) return;
- Nozzle::park(parser.ushortval('P'));
- }
- #endif
- #if ENABLED(QUICK_HOME)
- static void quick_home_xy() {
-
- current_position[X_AXIS] = current_position[Y_AXIS] = 0.0;
- sync_plan_position();
- const int x_axis_home_dir =
- #if ENABLED(DUAL_X_CARRIAGE)
- x_home_dir(active_extruder)
- #else
- home_dir(X_AXIS)
- #endif
- ;
- const float mlx = max_length(X_AXIS),
- mly = max_length(Y_AXIS),
- mlratio = mlx > mly ? mly / mlx : mlx / mly,
- fr_mm_s = MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)) * SQRT(sq(mlratio) + 1.0);
- #if ENABLED(SENSORLESS_HOMING)
- sensorless_homing_per_axis(X_AXIS);
- sensorless_homing_per_axis(Y_AXIS);
- #endif
- do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * home_dir(Y_AXIS), fr_mm_s);
- endstops.validate_homing_move();
- current_position[X_AXIS] = current_position[Y_AXIS] = 0.0;
- #if ENABLED(SENSORLESS_HOMING)
- sensorless_homing_per_axis(X_AXIS, false);
- sensorless_homing_per_axis(Y_AXIS, false);
- #endif
- }
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- void log_machine_info() {
- SERIAL_ECHOPGM("Machine Type: ");
- #if ENABLED(DELTA)
- SERIAL_ECHOLNPGM("Delta");
- #elif IS_SCARA
- SERIAL_ECHOLNPGM("SCARA");
- #elif IS_CORE
- SERIAL_ECHOLNPGM("Core");
- #else
- SERIAL_ECHOLNPGM("Cartesian");
- #endif
- SERIAL_ECHOPGM("Probe: ");
- #if ENABLED(PROBE_MANUALLY)
- SERIAL_ECHOLNPGM("PROBE_MANUALLY");
- #elif ENABLED(FIX_MOUNTED_PROBE)
- SERIAL_ECHOLNPGM("FIX_MOUNTED_PROBE");
- #elif ENABLED(BLTOUCH)
- SERIAL_ECHOLNPGM("BLTOUCH");
- #elif HAS_Z_SERVO_PROBE
- SERIAL_ECHOLNPGM("SERVO PROBE");
- #elif ENABLED(Z_PROBE_SLED)
- SERIAL_ECHOLNPGM("Z_PROBE_SLED");
- #elif ENABLED(Z_PROBE_ALLEN_KEY)
- SERIAL_ECHOLNPGM("Z_PROBE_ALLEN_KEY");
- #else
- SERIAL_ECHOLNPGM("NONE");
- #endif
- #if HAS_BED_PROBE
- SERIAL_ECHOPAIR("Probe Offset X:", X_PROBE_OFFSET_FROM_EXTRUDER);
- SERIAL_ECHOPAIR(" Y:", Y_PROBE_OFFSET_FROM_EXTRUDER);
- SERIAL_ECHOPAIR(" Z:", zprobe_zoffset);
- #if X_PROBE_OFFSET_FROM_EXTRUDER > 0
- SERIAL_ECHOPGM(" (Right");
- #elif X_PROBE_OFFSET_FROM_EXTRUDER < 0
- SERIAL_ECHOPGM(" (Left");
- #elif Y_PROBE_OFFSET_FROM_EXTRUDER != 0
- SERIAL_ECHOPGM(" (Middle");
- #else
- SERIAL_ECHOPGM(" (Aligned With");
- #endif
- #if Y_PROBE_OFFSET_FROM_EXTRUDER > 0
- #if IS_SCARA
- SERIAL_ECHOPGM("-Distal");
- #else
- SERIAL_ECHOPGM("-Back");
- #endif
- #elif Y_PROBE_OFFSET_FROM_EXTRUDER < 0
- #if IS_SCARA
- SERIAL_ECHOPGM("-Proximal");
- #else
- SERIAL_ECHOPGM("-Front");
- #endif
- #elif X_PROBE_OFFSET_FROM_EXTRUDER != 0
- SERIAL_ECHOPGM("-Center");
- #endif
- if (zprobe_zoffset < 0)
- SERIAL_ECHOPGM(" & Below");
- else if (zprobe_zoffset > 0)
- SERIAL_ECHOPGM(" & Above");
- else
- SERIAL_ECHOPGM(" & Same Z as");
- SERIAL_ECHOLNPGM(" Nozzle)");
- #endif
- #if HAS_ABL
- SERIAL_ECHOPGM("Auto Bed Leveling: ");
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- SERIAL_ECHOPGM("LINEAR");
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- SERIAL_ECHOPGM("BILINEAR");
- #elif ENABLED(AUTO_BED_LEVELING_3POINT)
- SERIAL_ECHOPGM("3POINT");
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
- SERIAL_ECHOPGM("UBL");
- #endif
- if (planner.leveling_active) {
- SERIAL_ECHOLNPGM(" (enabled)");
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- if (planner.z_fade_height)
- SERIAL_ECHOLNPAIR("Z Fade: ", planner.z_fade_height);
- #endif
- #if ABL_PLANAR
- const float diff[XYZ] = {
- planner.get_axis_position_mm(X_AXIS) - current_position[X_AXIS],
- planner.get_axis_position_mm(Y_AXIS) - current_position[Y_AXIS],
- planner.get_axis_position_mm(Z_AXIS) - current_position[Z_AXIS]
- };
- SERIAL_ECHOPGM("ABL Adjustment X");
- if (diff[X_AXIS] > 0) SERIAL_CHAR('+');
- SERIAL_ECHO(diff[X_AXIS]);
- SERIAL_ECHOPGM(" Y");
- if (diff[Y_AXIS] > 0) SERIAL_CHAR('+');
- SERIAL_ECHO(diff[Y_AXIS]);
- SERIAL_ECHOPGM(" Z");
- if (diff[Z_AXIS] > 0) SERIAL_CHAR('+');
- SERIAL_ECHO(diff[Z_AXIS]);
- #else
- #if ENABLED(AUTO_BED_LEVELING_UBL)
- SERIAL_ECHOPGM("UBL Adjustment Z");
- const float rz = ubl.get_z_correction(current_position[X_AXIS], current_position[Y_AXIS]);
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- SERIAL_ECHOPAIR("Bilinear Grid X", bilinear_start[X_AXIS]);
- SERIAL_ECHOPAIR(" Y", bilinear_start[Y_AXIS]);
- SERIAL_ECHOPAIR(" W", ABL_BG_SPACING(X_AXIS));
- SERIAL_ECHOLNPAIR(" H", ABL_BG_SPACING(Y_AXIS));
- SERIAL_ECHOPGM("ABL Adjustment Z");
- const float rz = bilinear_z_offset(current_position);
- #endif
- SERIAL_ECHO(ftostr43sign(rz, '+'));
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- if (planner.z_fade_height) {
- SERIAL_ECHOPAIR(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position[Z_AXIS]), '+'));
- SERIAL_CHAR(')');
- }
- #endif
- #endif
- }
- else
- SERIAL_ECHOLNPGM(" (disabled)");
- SERIAL_EOL();
- #elif ENABLED(MESH_BED_LEVELING)
- SERIAL_ECHOPGM("Mesh Bed Leveling");
- if (planner.leveling_active) {
- SERIAL_ECHOLNPGM(" (enabled)");
- SERIAL_ECHOPAIR("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- , 1.0
- #endif
- ), '+'));
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- if (planner.z_fade_height) {
- SERIAL_ECHOPAIR(" (", ftostr43sign(
- mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS], planner.fade_scaling_factor_for_z(current_position[Z_AXIS])), '+'
- ));
- SERIAL_CHAR(')');
- }
- #endif
- }
- else
- SERIAL_ECHOPGM(" (disabled)");
- SERIAL_EOL();
- #endif
- }
- #endif
- #if ENABLED(DELTA)
- #if ENABLED(SENSORLESS_HOMING)
- inline void delta_sensorless_homing(const bool on=true) {
- sensorless_homing_per_axis(A_AXIS, on);
- sensorless_homing_per_axis(B_AXIS, on);
- sensorless_homing_per_axis(C_AXIS, on);
- }
- #endif
-
- inline void home_delta() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
- #endif
-
- ZERO(current_position);
- sync_plan_position();
-
- #if ENABLED(SENSORLESS_HOMING)
- delta_sensorless_homing();
- #endif
-
- current_position[X_AXIS] = current_position[Y_AXIS] = current_position[Z_AXIS] = (delta_height + 10);
- feedrate_mm_s = homing_feedrate(X_AXIS);
- buffer_line_to_current_position();
- planner.synchronize();
-
- #if ENABLED(SENSORLESS_HOMING)
- delta_sensorless_homing(false);
- #endif
- endstops.validate_homing_move();
-
-
- homeaxis(A_AXIS);
- homeaxis(B_AXIS);
- homeaxis(C_AXIS);
-
-
-
-
- LOOP_XYZ(i) set_axis_is_at_home((AxisEnum)i);
- SYNC_PLAN_POSITION_KINEMATIC();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("<<< home_delta", current_position);
- #endif
- }
- #elif ENABLED(HANGPRINTER)
-
- inline void home_hangprinter() {
- SERIAL_ECHOLNPGM("Warning: G28 is not implemented for Hangprinter.");
- }
- #endif
- #ifdef Z_AFTER_PROBING
- void move_z_after_probing() {
- if (current_position[Z_AXIS] != Z_AFTER_PROBING) {
- do_blocking_move_to_z(Z_AFTER_PROBING);
- current_position[Z_AXIS] = Z_AFTER_PROBING;
- }
- }
- #endif
- #if ENABLED(Z_SAFE_HOMING)
- inline void home_z_safely() {
-
- if (!TEST(axis_known_position, X_AXIS) || !TEST(axis_known_position, Y_AXIS)) {
- LCD_MESSAGEPGM(MSG_ERR_Z_HOMING);
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_ERR_Z_HOMING);
- return;
- }
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Z_SAFE_HOMING >>>");
- #endif
- SYNC_PLAN_POSITION_KINEMATIC();
-
- destination[X_AXIS] = Z_SAFE_HOMING_X_POINT;
- destination[Y_AXIS] = Z_SAFE_HOMING_Y_POINT;
- destination[Z_AXIS] = current_position[Z_AXIS];
- #if HOMING_Z_WITH_PROBE
- destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
- destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
- #endif
- if (position_is_reachable(destination[X_AXIS], destination[Y_AXIS])) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination);
- #endif
-
- #if ENABLED(DUAL_X_CARRIAGE)
- active_extruder_parked = false;
- #endif
- #if ENABLED(SENSORLESS_HOMING)
- safe_delay(500);
- #endif
- do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]);
- homeaxis(Z_AXIS);
- }
- else {
- LCD_MESSAGEPGM(MSG_ZPROBE_OUT);
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT);
- }
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING");
- #endif
- }
- #endif
- #if ENABLED(PROBE_MANUALLY)
- bool g29_in_progress = false;
- #else
- constexpr bool g29_in_progress = false;
- #endif
- inline void gcode_G28(const bool always_home_all) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM(">>> G28");
- log_machine_info();
- }
- #endif
- #if ENABLED(MARLIN_DEV_MODE)
- if (parser.seen('S')) {
- LOOP_XYZ(a) set_axis_is_at_home((AxisEnum)a);
- SYNC_PLAN_POSITION_KINEMATIC();
- SERIAL_ECHOLNPGM("Simulated Homing");
- report_current_position();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28");
- #endif
- return;
- }
- #endif
- if (all_axes_known() && parser.boolval('O')) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("> homing not needed, skip");
- SERIAL_ECHOLNPGM("<<< G28");
- }
- #endif
- return;
- }
-
- planner.synchronize();
-
- #if ENABLED(PROBE_MANUALLY)
- g29_in_progress = false;
- #endif
-
- #if HAS_LEVELING
- #if ENABLED(RESTORE_LEVELING_AFTER_G28)
- const bool leveling_was_active = planner.leveling_active;
- #endif
- set_bed_leveling_enabled(false);
- #endif
- #if ENABLED(CNC_WORKSPACE_PLANES)
- workspace_plane = PLANE_XY;
- #endif
- #if ENABLED(BLTOUCH)
-
- bltouch_command(BLTOUCH_RESET);
- set_bltouch_deployed(false);
- #endif
-
- #if HOTENDS > 1
- #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)
- const uint8_t old_tool_index = active_extruder;
- #endif
- tool_change(0, 0, true);
- #endif
- #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
- extruder_duplication_enabled = false;
- #endif
- setup_for_endstop_or_probe_move();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> endstops.enable(true)");
- #endif
- endstops.enable(true);
- #if ENABLED(DELTA)
- home_delta();
- UNUSED(always_home_all);
- #elif ENABLED(HANGPRINTER)
- home_hangprinter();
- UNUSED(always_home_all);
- #else
- const bool homeX = always_home_all || parser.seen('X'),
- homeY = always_home_all || parser.seen('Y'),
- homeZ = always_home_all || parser.seen('Z'),
- home_all = (!homeX && !homeY && !homeZ) || (homeX && homeY && homeZ);
- set_destination_from_current();
- #if Z_HOME_DIR > 0
- if (home_all || homeZ) homeaxis(Z_AXIS);
- #endif
- const float z_homing_height = (
- #if ENABLED(UNKNOWN_Z_NO_RAISE)
- !TEST(axis_known_position, Z_AXIS) ? 0 :
- #endif
- (parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT)
- );
- if (z_homing_height && (home_all || homeX || homeY)) {
-
- destination[Z_AXIS] = z_homing_height;
- if (destination[Z_AXIS] > current_position[Z_AXIS]) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING))
- SERIAL_ECHOLNPAIR("Raise Z (before homing) to ", destination[Z_AXIS]);
- #endif
- do_blocking_move_to_z(destination[Z_AXIS]);
- }
- }
- #if ENABLED(QUICK_HOME)
- if (home_all || (homeX && homeY)) quick_home_xy();
- #endif
-
- #if ENABLED(HOME_Y_BEFORE_X)
- if (home_all || homeY
- #if ENABLED(CODEPENDENT_XY_HOMING)
- || homeX
- #endif
- ) homeaxis(Y_AXIS);
- #endif
-
- if (home_all || homeX
- #if ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X)
- || homeY
- #endif
- ) {
- #if ENABLED(DUAL_X_CARRIAGE)
-
- active_extruder = 1;
- homeaxis(X_AXIS);
-
- inactive_extruder_x_pos = current_position[X_AXIS];
-
- active_extruder = 0;
- homeaxis(X_AXIS);
-
- COPY(raised_parked_position, current_position);
- delayed_move_time = 0;
- active_extruder_parked = true;
- #else
- homeaxis(X_AXIS);
- #endif
- }
-
- #if DISABLED(HOME_Y_BEFORE_X)
- if (home_all || homeY) homeaxis(Y_AXIS);
- #endif
-
- #if Z_HOME_DIR < 0
- if (home_all || homeZ) {
- #if ENABLED(Z_SAFE_HOMING)
- home_z_safely();
- #else
- homeaxis(Z_AXIS);
- #endif
- #if HOMING_Z_WITH_PROBE && defined(Z_AFTER_PROBING)
- move_z_after_probing();
- #endif
- } // home_all || homeZ
- #endif // Z_HOME_DIR < 0
- SYNC_PLAN_POSITION_KINEMATIC();
- #endif // !DELTA (gcode_G28)
- endstops.not_homing();
- #if ENABLED(DELTA) && ENABLED(DELTA_HOME_TO_SAFE_ZONE)
- // move to a height where we can use the full xy-area
- do_blocking_move_to_z(delta_clip_start_height);
- #endif
- #if ENABLED(RESTORE_LEVELING_AFTER_G28)
- set_bed_leveling_enabled(leveling_was_active);
- #endif
- clean_up_after_endstop_or_probe_move();
- // Restore the active tool after homing
- #if HOTENDS > 1 && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE))
- #if ENABLED(PARKING_EXTRUDER)
- #define NO_FETCH false
- #else
- #define NO_FETCH true
- #endif
- tool_change(old_tool_index, 0, NO_FETCH);
- #endif
- lcd_refresh();
- report_current_position();
- #if ENABLED(NANODLP_Z_SYNC)
- #if ENABLED(NANODLP_ALL_AXIS)
- #define _HOME_SYNC true
- #else
- #define _HOME_SYNC (home_all || homeZ)
- #endif
- if (_HOME_SYNC)
- SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
- #endif
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28");
- #endif
- }
- void home_all_axes() { gcode_G28(true); }
- #if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
- inline void _manual_goto_xy(const float &rx, const float &ry) {
- #ifdef MANUAL_PROBE_START_Z
- #if MANUAL_PROBE_HEIGHT > 0
- do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT);
- do_blocking_move_to_z(MAX(0,MANUAL_PROBE_START_Z));
- #else
- do_blocking_move_to(rx, ry, MAX(0,MANUAL_PROBE_START_Z));
- #endif
- #elif MANUAL_PROBE_HEIGHT > 0
- const float prev_z = current_position[Z_AXIS];
- do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT);
- do_blocking_move_to_z(prev_z);
- #else
- do_blocking_move_to_xy(rx, ry);
- #endif
- current_position[X_AXIS] = rx;
- current_position[Y_AXIS] = ry;
- #if ENABLED(LCD_BED_LEVELING)
- lcd_wait_for_move = false;
- #endif
- }
- #endif
- #if ENABLED(MESH_BED_LEVELING)
-
- void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
-
- inline void gcode_G29() {
- static int mbl_probe_index = -1;
- #if HAS_SOFTWARE_ENDSTOPS
- static bool enable_soft_endstops;
- #endif
- MeshLevelingState state = (MeshLevelingState)parser.byteval('S', (int8_t)MeshReport);
- if (!WITHIN(state, 0, 5)) {
- SERIAL_PROTOCOLLNPGM("S out of range (0-5).");
- return;
- }
- int8_t px, py;
- switch (state) {
- case MeshReport:
- if (leveling_is_valid()) {
- SERIAL_PROTOCOLLNPAIR("State: ", planner.leveling_active ? MSG_ON : MSG_OFF);
- mbl.report_mesh();
- }
- else
- SERIAL_PROTOCOLLNPGM("Mesh bed leveling has no data.");
- break;
- case MeshStart:
- mbl.reset();
- mbl_probe_index = 0;
- if (!lcd_wait_for_move) {
- enqueue_and_echo_commands_P(PSTR("G28\nG29 S2"));
- return;
- }
- state = MeshNext;
- case MeshNext:
- if (mbl_probe_index < 0) {
- SERIAL_PROTOCOLLNPGM("Start mesh probing with \"G29 S1\" first.");
- return;
- }
-
- if (mbl_probe_index == 0) {
- #if HAS_SOFTWARE_ENDSTOPS
-
- enable_soft_endstops = soft_endstops_enabled;
- #endif
-
- do_blocking_move_to_z(0);
- }
- else {
-
- mbl.set_zigzag_z(mbl_probe_index - 1, current_position[Z_AXIS]);
- #if HAS_SOFTWARE_ENDSTOPS
- soft_endstops_enabled = enable_soft_endstops;
- #endif
- }
-
- if (mbl_probe_index < GRID_MAX_POINTS) {
- #if HAS_SOFTWARE_ENDSTOPS
-
-
- soft_endstops_enabled = false;
- #endif
- mbl.zigzag(mbl_probe_index++, px, py);
- _manual_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
- }
- else {
-
- current_position[Z_AXIS] = MANUAL_PROBE_HEIGHT;
- buffer_line_to_current_position();
- planner.synchronize();
-
- mbl_probe_index = -1;
- SERIAL_PROTOCOLLNPGM("Mesh probing done.");
- BUZZ(100, 659);
- BUZZ(100, 698);
- home_all_axes();
- set_bed_leveling_enabled(true);
- #if ENABLED(MESH_G28_REST_ORIGIN)
- current_position[Z_AXIS] = 0;
- set_destination_from_current();
- buffer_line_to_destination(homing_feedrate(Z_AXIS));
- planner.synchronize();
- #endif
- #if ENABLED(LCD_BED_LEVELING)
- lcd_wait_for_move = false;
- #endif
- }
- break;
- case MeshSet:
- if (parser.seenval('X')) {
- px = parser.value_int() - 1;
- if (!WITHIN(px, 0, GRID_MAX_POINTS_X - 1)) {
- SERIAL_PROTOCOLPAIR("X out of range (1-", int(GRID_MAX_POINTS_X));
- SERIAL_PROTOCOLLNPGM(")");
- return;
- }
- }
- else {
- SERIAL_CHAR('X'); echo_not_entered();
- return;
- }
- if (parser.seenval('Y')) {
- py = parser.value_int() - 1;
- if (!WITHIN(py, 0, GRID_MAX_POINTS_Y - 1)) {
- SERIAL_PROTOCOLPAIR("Y out of range (1-", int(GRID_MAX_POINTS_Y));
- SERIAL_PROTOCOLLNPGM(")");
- return;
- }
- }
- else {
- SERIAL_CHAR('Y'); echo_not_entered();
- return;
- }
- if (parser.seenval('Z'))
- mbl.z_values[px][py] = parser.value_linear_units();
- else {
- SERIAL_CHAR('Z'); echo_not_entered();
- return;
- }
- break;
- case MeshSetZOffset:
- if (parser.seenval('Z'))
- mbl.z_offset = parser.value_linear_units();
- else {
- SERIAL_CHAR('Z'); echo_not_entered();
- return;
- }
- break;
- case MeshReset:
- reset_bed_level();
- break;
- }
- if (state == MeshNext) {
- SERIAL_PROTOCOLPAIR("MBL G29 point ", MIN(mbl_probe_index, GRID_MAX_POINTS));
- SERIAL_PROTOCOLLNPAIR(" of ", int(GRID_MAX_POINTS));
- }
- report_current_position();
- }
- #elif OLDSCHOOL_ABL
- #if ABL_GRID
- #if ENABLED(PROBE_Y_FIRST)
- #define PR_OUTER_VAR xCount
- #define PR_OUTER_END abl_grid_points_x
- #define PR_INNER_VAR yCount
- #define PR_INNER_END abl_grid_points_y
- #else
- #define PR_OUTER_VAR yCount
- #define PR_OUTER_END abl_grid_points_y
- #define PR_INNER_VAR xCount
- #define PR_INNER_END abl_grid_points_x
- #endif
- #endif
-
- inline void gcode_G29() {
- #if ENABLED(DEBUG_LEVELING_FEATURE) || ENABLED(PROBE_MANUALLY)
- const bool seenQ = parser.seen('Q');
- #else
- constexpr bool seenQ = false;
- #endif
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- const uint8_t old_debug_flags = marlin_debug_flags;
- if (seenQ) marlin_debug_flags |= DEBUG_LEVELING;
- if (DEBUGGING(LEVELING)) {
- DEBUG_POS(">>> G29", current_position);
- log_machine_info();
- }
- marlin_debug_flags = old_debug_flags;
- #if DISABLED(PROBE_MANUALLY)
- if (seenQ) return;
- #endif
- #endif
- #if ENABLED(PROBE_MANUALLY)
- const bool seenA = parser.seen('A');
- #else
- constexpr bool seenA = false;
- #endif
- const bool no_action = seenA || seenQ,
- faux =
- #if ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY)
- parser.boolval('C')
- #else
- no_action
- #endif
- ;
-
- if (axis_unhomed_error()) return;
- if (!no_action && planner.leveling_active && parser.boolval('O')) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("> Auto-level not needed, skip");
- SERIAL_ECHOLNPGM("<<< G29");
- }
- #endif
- return;
- }
-
- #if ENABLED(PROBE_MANUALLY)
- #define ABL_VAR static
- #else
- #define ABL_VAR
- #endif
- ABL_VAR int verbose_level;
- ABL_VAR float xProbe, yProbe, measured_z;
- ABL_VAR bool dryrun, abl_should_enable;
- #if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
- ABL_VAR int16_t abl_probe_index;
- #endif
- #if HAS_SOFTWARE_ENDSTOPS && ENABLED(PROBE_MANUALLY)
- ABL_VAR bool enable_soft_endstops = true;
- #endif
- #if ABL_GRID
- #if ENABLED(PROBE_MANUALLY)
- ABL_VAR uint8_t PR_OUTER_VAR;
- ABL_VAR int8_t PR_INNER_VAR;
- #endif
- ABL_VAR int left_probe_bed_position, right_probe_bed_position, front_probe_bed_position, back_probe_bed_position;
- ABL_VAR float xGridSpacing = 0, yGridSpacing = 0;
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- ABL_VAR uint8_t abl_grid_points_x = GRID_MAX_POINTS_X,
- abl_grid_points_y = GRID_MAX_POINTS_Y;
- ABL_VAR bool do_topography_map;
- #else
- uint8_t constexpr abl_grid_points_x = GRID_MAX_POINTS_X,
- abl_grid_points_y = GRID_MAX_POINTS_Y;
- #endif
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- ABL_VAR int16_t abl_points;
- #elif ENABLED(PROBE_MANUALLY)
- int16_t constexpr abl_points = GRID_MAX_POINTS;
- #endif
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- ABL_VAR float zoffset;
- #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
- ABL_VAR int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
- ABL_VAR float eqnAMatrix[GRID_MAX_POINTS * 3],
- eqnBVector[GRID_MAX_POINTS],
- mean;
- #endif
- #elif ENABLED(AUTO_BED_LEVELING_3POINT)
- #if ENABLED(PROBE_MANUALLY)
- int8_t constexpr abl_points = 3;
- #endif
-
- ABL_VAR vector_3 points[3] = {
- vector_3(PROBE_PT_1_X, PROBE_PT_1_Y, 0),
- vector_3(PROBE_PT_2_X, PROBE_PT_2_Y, 0),
- vector_3(PROBE_PT_3_X, PROBE_PT_3_Y, 0)
- };
- #endif
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- struct linear_fit_data lsf_results;
- incremental_LSF_reset(&lsf_results);
- #endif
-
- if (!g29_in_progress) {
- #if ENABLED(DUAL_X_CARRIAGE)
- if (active_extruder != 0) tool_change(0);
- #endif
- #if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
- abl_probe_index = -1;
- #endif
- abl_should_enable = planner.leveling_active;
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- const bool seen_w = parser.seen('W');
- if (seen_w) {
- if (!leveling_is_valid()) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("No bilinear grid");
- return;
- }
- const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position[Z_AXIS];
- if (!WITHIN(rz, -10, 10)) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("Bad Z value");
- return;
- }
- const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
- ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
- int8_t i = parser.byteval('I', -1),
- j = parser.byteval('J', -1);
- if (!isnan(rx) && !isnan(ry)) {
-
- i = (rx - bilinear_start[X_AXIS] + 0.5f * xGridSpacing) / xGridSpacing;
- j = (ry - bilinear_start[Y_AXIS] + 0.5f * yGridSpacing) / yGridSpacing;
- i = constrain(i, 0, GRID_MAX_POINTS_X - 1);
- j = constrain(j, 0, GRID_MAX_POINTS_Y - 1);
- }
- if (WITHIN(i, 0, GRID_MAX_POINTS_X - 1) && WITHIN(j, 0, GRID_MAX_POINTS_Y)) {
- set_bed_leveling_enabled(false);
- z_values[i][j] = rz;
- #if ENABLED(ABL_BILINEAR_SUBDIVISION)
- bed_level_virt_interpolate();
- #endif
- set_bed_leveling_enabled(abl_should_enable);
- if (abl_should_enable) report_current_position();
- }
- return;
- }
- #else
- constexpr bool seen_w = false;
- #endif
-
- if (!seen_w && parser.seen('J')) {
- reset_bed_level();
- return;
- }
- verbose_level = parser.intval('V');
- if (!WITHIN(verbose_level, 0, 4)) {
- SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-4).");
- return;
- }
- dryrun = parser.boolval('D')
- #if ENABLED(PROBE_MANUALLY)
- || no_action
- #endif
- ;
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- do_topography_map = verbose_level > 2 || parser.boolval('T');
-
-
- abl_grid_points_x = parser.intval('X', GRID_MAX_POINTS_X);
- abl_grid_points_y = parser.intval('Y', GRID_MAX_POINTS_Y);
- if (parser.seenval('P')) abl_grid_points_x = abl_grid_points_y = parser.value_int();
- if (!WITHIN(abl_grid_points_x, 2, GRID_MAX_POINTS_X)) {
- SERIAL_PROTOCOLLNPGM("?Probe points (X) is implausible (2-" STRINGIFY(GRID_MAX_POINTS_X) ").");
- return;
- }
- if (!WITHIN(abl_grid_points_y, 2, GRID_MAX_POINTS_Y)) {
- SERIAL_PROTOCOLLNPGM("?Probe points (Y) is implausible (2-" STRINGIFY(GRID_MAX_POINTS_Y) ").");
- return;
- }
- abl_points = abl_grid_points_x * abl_grid_points_y;
- mean = 0;
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- zoffset = parser.linearval('Z');
- #endif
- #if ABL_GRID
- xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_SPEED));
- left_probe_bed_position = parser.seenval('L') ? int(RAW_X_POSITION(parser.value_linear_units())) : LEFT_PROBE_BED_POSITION;
- right_probe_bed_position = parser.seenval('R') ? int(RAW_X_POSITION(parser.value_linear_units())) : RIGHT_PROBE_BED_POSITION;
- front_probe_bed_position = parser.seenval('F') ? int(RAW_Y_POSITION(parser.value_linear_units())) : FRONT_PROBE_BED_POSITION;
- back_probe_bed_position = parser.seenval('B') ? int(RAW_Y_POSITION(parser.value_linear_units())) : BACK_PROBE_BED_POSITION;
- if (
- #if IS_SCARA || ENABLED(DELTA)
- !position_is_reachable_by_probe(left_probe_bed_position, 0)
- || !position_is_reachable_by_probe(right_probe_bed_position, 0)
- || !position_is_reachable_by_probe(0, front_probe_bed_position)
- || !position_is_reachable_by_probe(0, back_probe_bed_position)
- #else
- !position_is_reachable_by_probe(left_probe_bed_position, front_probe_bed_position)
- || !position_is_reachable_by_probe(right_probe_bed_position, back_probe_bed_position)
- #endif
- ) {
- SERIAL_PROTOCOLLNPGM("? (L,R,F,B) out of bounds.");
- return;
- }
-
- xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (abl_grid_points_x - 1);
- yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (abl_grid_points_y - 1);
- #endif
- if (verbose_level > 0) {
- SERIAL_PROTOCOLPGM("G29 Auto Bed Leveling");
- if (dryrun) SERIAL_PROTOCOLPGM(" (DRYRUN)");
- SERIAL_EOL();
- }
- planner.synchronize();
-
-
- if (!no_action) set_bed_leveling_enabled(false);
- #if HAS_BED_PROBE
-
- if (DEPLOY_PROBE()) {
- set_bed_leveling_enabled(abl_should_enable);
- return;
- }
- #endif
- if (!faux) setup_for_endstop_or_probe_move();
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- #if ENABLED(PROBE_MANUALLY)
- if (!no_action)
- #endif
- if ( xGridSpacing != bilinear_grid_spacing[X_AXIS]
- || yGridSpacing != bilinear_grid_spacing[Y_AXIS]
- || left_probe_bed_position != bilinear_start[X_AXIS]
- || front_probe_bed_position != bilinear_start[Y_AXIS]
- ) {
-
- reset_bed_level();
-
- bilinear_grid_spacing[X_AXIS] = xGridSpacing;
- bilinear_grid_spacing[Y_AXIS] = yGridSpacing;
- bilinear_start[X_AXIS] = left_probe_bed_position;
- bilinear_start[Y_AXIS] = front_probe_bed_position;
-
- abl_should_enable = false;
- }
- #endif
- #if ENABLED(AUTO_BED_LEVELING_3POINT)
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
- #endif
-
- points[0].z = points[1].z = points[2].z = 0;
- #endif
- }
- #if ENABLED(PROBE_MANUALLY)
-
-
- if (!no_action) {
- ++abl_probe_index;
- g29_in_progress = true;
- }
-
- if (seenA && g29_in_progress) {
- SERIAL_PROTOCOLLNPGM("Manual G29 aborted");
- #if HAS_SOFTWARE_ENDSTOPS
- soft_endstops_enabled = enable_soft_endstops;
- #endif
- set_bed_leveling_enabled(abl_should_enable);
- g29_in_progress = false;
- #if ENABLED(LCD_BED_LEVELING)
- lcd_wait_for_move = false;
- #endif
- }
-
- if (verbose_level || seenQ) {
- SERIAL_PROTOCOLPGM("Manual G29 ");
- if (g29_in_progress) {
- SERIAL_PROTOCOLPAIR("point ", MIN(abl_probe_index + 1, abl_points));
- SERIAL_PROTOCOLLNPAIR(" of ", abl_points);
- }
- else
- SERIAL_PROTOCOLLNPGM("idle");
- }
- if (no_action) return;
- if (abl_probe_index == 0) {
-
- #if HAS_SOFTWARE_ENDSTOPS
- enable_soft_endstops = soft_endstops_enabled;
- #endif
-
- do_blocking_move_to_z(0);
- }
- else {
- #if ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT)
- const uint16_t index = abl_probe_index - 1;
- #endif
-
-
- measured_z = current_position[Z_AXIS];
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- mean += measured_z;
- eqnBVector[index] = measured_z;
- eqnAMatrix[index + 0 * abl_points] = xProbe;
- eqnAMatrix[index + 1 * abl_points] = yProbe;
- eqnAMatrix[index + 2 * abl_points] = 1;
- incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
- #elif ENABLED(AUTO_BED_LEVELING_3POINT)
- points[index].z = measured_z;
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- z_values[xCount][yCount] = measured_z + zoffset;
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_PROTOCOLPAIR("Save X", xCount);
- SERIAL_PROTOCOLPAIR(" Y", yCount);
- SERIAL_PROTOCOLLNPAIR(" Z", measured_z + zoffset);
- }
- #endif
- #endif
- }
-
-
-
- #if ABL_GRID
-
- while (abl_probe_index < abl_points) {
-
- PR_OUTER_VAR = abl_probe_index / PR_INNER_END;
- PR_INNER_VAR = abl_probe_index - (PR_OUTER_VAR * PR_INNER_END);
-
- bool zig = (PR_OUTER_VAR & 1);
- if (zig) PR_INNER_VAR = (PR_INNER_END - 1) - PR_INNER_VAR;
- const float xBase = xCount * xGridSpacing + left_probe_bed_position,
- yBase = yCount * yGridSpacing + front_probe_bed_position;
- xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
- yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- indexIntoAB[xCount][yCount] = abl_probe_index;
- #endif
-
- if (position_is_reachable(xProbe, yProbe)) break;
- ++abl_probe_index;
- }
-
- if (abl_probe_index < abl_points) {
- _manual_goto_xy(xProbe, yProbe);
- #if HAS_SOFTWARE_ENDSTOPS
-
-
- soft_endstops_enabled = false;
- #endif
- return;
- }
- else {
-
- SERIAL_PROTOCOLLNPGM("Grid probing done.");
-
- #if HAS_SOFTWARE_ENDSTOPS
- soft_endstops_enabled = enable_soft_endstops;
- #endif
- }
- #elif ENABLED(AUTO_BED_LEVELING_3POINT)
-
- if (abl_probe_index < abl_points) {
- xProbe = points[abl_probe_index].x;
- yProbe = points[abl_probe_index].y;
- _manual_goto_xy(xProbe, yProbe);
- #if HAS_SOFTWARE_ENDSTOPS
-
-
- soft_endstops_enabled = false;
- #endif
- return;
- }
- else {
- SERIAL_PROTOCOLLNPGM("3-point probing done.");
-
- #if HAS_SOFTWARE_ENDSTOPS
- soft_endstops_enabled = enable_soft_endstops;
- #endif
- if (!dryrun) {
- vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
- if (planeNormal.z < 0) {
- planeNormal.x *= -1;
- planeNormal.y *= -1;
- planeNormal.z *= -1;
- }
- planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
-
- abl_should_enable = false;
- }
- }
- #endif
- #else
- {
- const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;
- measured_z = 0;
- #if ABL_GRID
- bool zig = PR_OUTER_END & 1;
- measured_z = 0;
-
- for (uint8_t PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_END && !isnan(measured_z); PR_OUTER_VAR++) {
- int8_t inStart, inStop, inInc;
- if (zig) {
- inStart = 0;
- inStop = PR_INNER_END;
- inInc = 1;
- }
- else {
- inStart = PR_INNER_END - 1;
- inStop = -1;
- inInc = -1;
- }
- zig ^= true;
-
- for (int8_t PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc) {
- float xBase = left_probe_bed_position + xGridSpacing * xCount,
- yBase = front_probe_bed_position + yGridSpacing * yCount;
- xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
- yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- indexIntoAB[xCount][yCount] = ++abl_probe_index;
- #endif
- #if IS_KINEMATIC
-
- if (!position_is_reachable_by_probe(xProbe, yProbe)) continue;
- #endif
- measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, raise_after, verbose_level);
- if (isnan(measured_z)) {
- set_bed_leveling_enabled(abl_should_enable);
- break;
- }
- #if ENABLED(AUTO_BED_LEVELING_LINEAR)
- mean += measured_z;
- eqnBVector[abl_probe_index] = measured_z;
- eqnAMatrix[abl_probe_index + 0 * abl_points] = xProbe;
- eqnAMatrix[abl_probe_index + 1 * abl_points] = yProbe;
- eqnAMatrix[abl_probe_index + 2 * abl_points] = 1;
- incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- z_values[xCount][yCount] = measured_z + zoffset;
- #endif
- abl_should_enable = false;
- idle();
- }
- }
- #elif ENABLED(AUTO_BED_LEVELING_3POINT)
-
- for (uint8_t i = 0; i < 3; ++i) {
-
- xProbe = points[i].x;
- yProbe = points[i].y;
- measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, raise_after, verbose_level);
- if (isnan(measured_z)) {
- set_bed_leveling_enabled(abl_should_enable);
- break;
- }
- points[i].z = measured_z;
- }
- if (!dryrun && !isnan(measured_z)) {
- vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
- if (planeNormal.z < 0) {
- planeNormal.x *= -1;
- planeNormal.y *= -1;
- planeNormal.z *= -1;
- }
- planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
-
- abl_should_enable = false;
- }
- #endif
-
- if (STOW_PROBE()) {
- set_bed_leveling_enabled(abl_should_enable);
- measured_z = NAN;
- }
- }
- #endif
-
-
-
-
-
-
-
-
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("> probing complete", current_position);
- #endif
- #if ENABLED(PROBE_MANUALLY)
- g29_in_progress = false;
- #if ENABLED(LCD_BED_LEVELING)
- lcd_wait_for_move = false;
- #endif
- #endif
-
- if (!isnan(measured_z)) {
- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
- if (!dryrun) extrapolate_unprobed_bed_level();
- print_bilinear_leveling_grid();
- refresh_bed_level();
- #if ENABLED(ABL_BILINEAR_SUBDIVISION)
- print_bilinear_leveling_grid_virt();
- #endif
- #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
-
-
- float plane_equation_coefficients[3];
- finish_incremental_LSF(&lsf_results);
- plane_equation_coefficients[0] = -lsf_results.A;
- plane_equation_coefficients[1] = -lsf_results.B;
- plane_equation_coefficients[2] = -lsf_results.D;
- mean /= abl_points;
- if (verbose_level) {
- SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[0], 8);
- SERIAL_PROTOCOLPGM(" b: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[1], 8);
- SERIAL_PROTOCOLPGM(" d: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[2], 8);
- SERIAL_EOL();
- if (verbose_level > 2) {
- SERIAL_PROTOCOLPGM("Mean of sampled points: ");
- SERIAL_PROTOCOL_F(mean, 8);
- SERIAL_EOL();
- }
- }
-
- if (!dryrun)
- planner.bed_level_matrix = matrix_3x3::create_look_at(
- vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1)
- );
-
- if (do_topography_map) {
- SERIAL_PROTOCOLLNPGM("\nBed Height Topography:\n"
- " +--- BACK --+\n"
- " | |\n"
- " L | (+) | R\n"
- " E | | I\n"
- " F | (-) N (+) | G\n"
- " T | | H\n"
- " | (-) | T\n"
- " | |\n"
- " O-- FRONT --+\n"
- " (0,0)");
- float min_diff = 999;
- for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
- for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
- int ind = indexIntoAB[xx][yy];
- float diff = eqnBVector[ind] - mean,
- x_tmp = eqnAMatrix[ind + 0 * abl_points],
- y_tmp = eqnAMatrix[ind + 1 * abl_points],
- z_tmp = 0;
- apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
- NOMORE(min_diff, eqnBVector[ind] - z_tmp);
- if (diff >= 0.0)
- SERIAL_PROTOCOLPGM(" +");
- else
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOL_F(diff, 5);
- }
- SERIAL_EOL();
- }
- SERIAL_EOL();
- if (verbose_level > 3) {
- SERIAL_PROTOCOLLNPGM("\nCorrected Bed Height vs. Bed Topology:");
- for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
- for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
- int ind = indexIntoAB[xx][yy];
- float x_tmp = eqnAMatrix[ind + 0 * abl_points],
- y_tmp = eqnAMatrix[ind + 1 * abl_points],
- z_tmp = 0;
- apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
- float diff = eqnBVector[ind] - z_tmp - min_diff;
- if (diff >= 0.0)
- SERIAL_PROTOCOLPGM(" +");
-
- else
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOL_F(diff, 5);
- }
- SERIAL_EOL();
- }
- SERIAL_EOL();
- }
- }
- #endif
- #if ABL_PLANAR
-
- if (verbose_level > 0)
- planner.bed_level_matrix.debug(PSTR("\n\nBed Level Correction Matrix:"));
- if (!dryrun) {
-
-
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("G29 uncorrected XYZ", current_position);
- #endif
- float converted[XYZ];
- COPY(converted, current_position);
- planner.leveling_active = true;
- planner.unapply_leveling(converted);
- planner.leveling_active = false;
-
- if ( NEAR(current_position[X_AXIS], xProbe - (X_PROBE_OFFSET_FROM_EXTRUDER))
- && NEAR(current_position[Y_AXIS], yProbe - (Y_PROBE_OFFSET_FROM_EXTRUDER))
- ) {
- const float simple_z = current_position[Z_AXIS] - measured_z;
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPAIR("Z from Probe:", simple_z);
- SERIAL_ECHOPAIR(" Matrix:", converted[Z_AXIS]);
- SERIAL_ECHOLNPAIR(" Discrepancy:", simple_z - converted[Z_AXIS]);
- }
- #endif
- converted[Z_AXIS] = simple_z;
- }
-
- COPY(current_position, converted);
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("G29 corrected XYZ", current_position);
- #endif
- }
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- if (!dryrun) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("G29 uncorrected Z:", current_position[Z_AXIS]);
- #endif
-
-
- current_position[Z_AXIS] -= bilinear_z_offset(current_position);
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR(" corrected Z:", current_position[Z_AXIS]);
- #endif
- }
- #endif
- #ifdef Z_PROBE_END_SCRIPT
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("Z Probe End Script: ", Z_PROBE_END_SCRIPT);
- #endif
- planner.synchronize();
- enqueue_and_echo_commands_P(PSTR(Z_PROBE_END_SCRIPT));
- #endif
-
- planner.leveling_active = dryrun ? abl_should_enable : true;
- }
-
- if (!faux) clean_up_after_endstop_or_probe_move();
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G29");
- #endif
- KEEPALIVE_STATE(IN_HANDLER);
- if (planner.leveling_active)
- SYNC_PLAN_POSITION_KINEMATIC();
- #if HAS_BED_PROBE && defined(Z_AFTER_PROBING)
- move_z_after_probing();
- #endif
- report_current_position();
- }
- #endif
- #if HAS_BED_PROBE
-
- inline void gcode_G30() {
- const float xpos = parser.linearval('X', current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER),
- ypos = parser.linearval('Y', current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER);
- if (!position_is_reachable_by_probe(xpos, ypos)) return;
-
- #if HAS_LEVELING
- set_bed_leveling_enabled(false);
- #endif
- setup_for_endstop_or_probe_move();
- const ProbePtRaise raise_after = parser.boolval('E', true) ? PROBE_PT_STOW : PROBE_PT_NONE;
- const float measured_z = probe_pt(xpos, ypos, raise_after, parser.intval('V', 1));
- if (!isnan(measured_z)) {
- SERIAL_PROTOCOLPAIR_F("Bed X: ", xpos);
- SERIAL_PROTOCOLPAIR_F(" Y: ", ypos);
- SERIAL_PROTOCOLLNPAIR_F(" Z: ", measured_z);
- }
- clean_up_after_endstop_or_probe_move();
- #ifdef Z_AFTER_PROBING
- if (raise_after == PROBE_PT_STOW) move_z_after_probing();
- #endif
- report_current_position();
- }
- #if ENABLED(Z_PROBE_SLED)
-
- inline void gcode_G31() { DEPLOY_PROBE(); }
-
- inline void gcode_G32() { STOW_PROBE(); }
- #endif
- #endif
- #if ENABLED(DELTA_AUTO_CALIBRATION)
- constexpr uint8_t _7P_STEP = 1,
- _4P_STEP = _7P_STEP * 2,
- NPP = _7P_STEP * 6;
- enum CalEnum : char {
- CEN = 0,
- __A = 1,
- _AB = __A + _7P_STEP,
- __B = _AB + _7P_STEP,
- _BC = __B + _7P_STEP,
- __C = _BC + _7P_STEP,
- _CA = __C + _7P_STEP,
- };
- #define LOOP_CAL_PT(VAR, S, N) for (uint8_t VAR=S; VAR<=NPP; VAR+=N)
- #define F_LOOP_CAL_PT(VAR, S, N) for (float VAR=S; VAR<NPP+0.9999; VAR+=N)
- #define I_LOOP_CAL_PT(VAR, S, N) for (float VAR=S; VAR>CEN+0.9999; VAR-=N)
- #define LOOP_CAL_ALL(VAR) LOOP_CAL_PT(VAR, CEN, 1)
- #define LOOP_CAL_RAD(VAR) LOOP_CAL_PT(VAR, __A, _7P_STEP)
- #define LOOP_CAL_ACT(VAR, _4P, _OP) LOOP_CAL_PT(VAR, _OP ? _AB : __A, _4P ? _4P_STEP : _7P_STEP)
- #if HOTENDS > 1
- const uint8_t old_tool_index = active_extruder;
- #define AC_CLEANUP() ac_cleanup(old_tool_index)
- #else
- #define AC_CLEANUP() ac_cleanup()
- #endif
- float lcd_probe_pt(const float &rx, const float &ry);
- void ac_home() {
- endstops.enable(true);
- home_delta();
- endstops.not_homing();
- }
- void ac_setup(const bool reset_bed) {
- #if HOTENDS > 1
- tool_change(0, 0, true);
- #endif
- planner.synchronize();
- setup_for_endstop_or_probe_move();
- #if HAS_LEVELING
- if (reset_bed) reset_bed_level();
- #endif
- }
- void ac_cleanup(
- #if HOTENDS > 1
- const uint8_t old_tool_index
- #endif
- ) {
- #if ENABLED(DELTA_HOME_TO_SAFE_ZONE)
- do_blocking_move_to_z(delta_clip_start_height);
- #endif
- #if HAS_BED_PROBE
- STOW_PROBE();
- #endif
- clean_up_after_endstop_or_probe_move();
- #if HOTENDS > 1
- tool_change(old_tool_index, 0, true);
- #endif
- }
- void print_signed_float(const char * const prefix, const float &f) {
- SERIAL_PROTOCOLPGM(" ");
- serialprintPGM(prefix);
- SERIAL_PROTOCOLCHAR(':');
- if (f >= 0) SERIAL_CHAR('+');
- SERIAL_PROTOCOL_F(f, 2);
- }
-
- static void print_calibration_settings(const bool end_stops, const bool tower_angles) {
- SERIAL_PROTOCOLPAIR(".Height:", delta_height);
- if (end_stops) {
- print_signed_float(PSTR("Ex"), delta_endstop_adj[A_AXIS]);
- print_signed_float(PSTR("Ey"), delta_endstop_adj[B_AXIS]);
- print_signed_float(PSTR("Ez"), delta_endstop_adj[C_AXIS]);
- }
- if (end_stops && tower_angles) {
- SERIAL_PROTOCOLPAIR(" Radius:", delta_radius);
- SERIAL_EOL();
- SERIAL_CHAR('.');
- SERIAL_PROTOCOL_SP(13);
- }
- if (tower_angles) {
- print_signed_float(PSTR("Tx"), delta_tower_angle_trim[A_AXIS]);
- print_signed_float(PSTR("Ty"), delta_tower_angle_trim[B_AXIS]);
- print_signed_float(PSTR("Tz"), delta_tower_angle_trim[C_AXIS]);
- }
- if ((!end_stops && tower_angles) || (end_stops && !tower_angles)) {
- SERIAL_PROTOCOLPAIR(" Radius:", delta_radius);
- }
- SERIAL_EOL();
- }
-
- static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) {
- SERIAL_PROTOCOLPGM(". ");
- print_signed_float(PSTR("c"), z_pt[CEN]);
- if (tower_points) {
- print_signed_float(PSTR(" x"), z_pt[__A]);
- print_signed_float(PSTR(" y"), z_pt[__B]);
- print_signed_float(PSTR(" z"), z_pt[__C]);
- }
- if (tower_points && opposite_points) {
- SERIAL_EOL();
- SERIAL_CHAR('.');
- SERIAL_PROTOCOL_SP(13);
- }
- if (opposite_points) {
- print_signed_float(PSTR("yz"), z_pt[_BC]);
- print_signed_float(PSTR("zx"), z_pt[_CA]);
- print_signed_float(PSTR("xy"), z_pt[_AB]);
- }
- SERIAL_EOL();
- }
-
- static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool _1p_cal, const bool _4p_cal, const bool _4p_opp) {
- if (!_0p_cal) {
- float S2 = sq(z_pt[CEN]);
- int16_t N = 1;
- if (!_1p_cal) {
- LOOP_CAL_ACT(rad, _4p_cal, _4p_opp) {
- S2 += sq(z_pt[rad]);
- N++;
- }
- return LROUND(SQRT(S2 / N) * 1000.0) / 1000.0 + 0.00001;
- }
- }
- return 0.00001;
- }
-
- static float calibration_probe(const float &nx, const float &ny, const bool stow) {
- #if HAS_BED_PROBE
- return probe_pt(nx, ny, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, false);
- #else
- UNUSED(stow);
- return lcd_probe_pt(nx, ny);
- #endif
- }
-
- static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const bool towers_set, const bool stow_after_each) {
- const bool _0p_calibration = probe_points == 0,
- _1p_calibration = probe_points == 1 || probe_points == -1,
- _4p_calibration = probe_points == 2,
- _4p_opposite_points = _4p_calibration && !towers_set,
- _7p_calibration = probe_points >= 3,
- _7p_no_intermediates = probe_points == 3,
- _7p_1_intermediates = probe_points == 4,
- _7p_2_intermediates = probe_points == 5,
- _7p_4_intermediates = probe_points == 6,
- _7p_6_intermediates = probe_points == 7,
- _7p_8_intermediates = probe_points == 8,
- _7p_11_intermediates = probe_points == 9,
- _7p_14_intermediates = probe_points == 10,
- _7p_intermed_points = probe_points >= 4,
- _7p_6_center = probe_points >= 5 && probe_points <= 7,
- _7p_9_center = probe_points >= 8;
- LOOP_CAL_ALL(rad) z_pt[rad] = 0.0;
- if (!_0p_calibration) {
- if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) {
- z_pt[CEN] += calibration_probe(0, 0, stow_after_each);
- if (isnan(z_pt[CEN])) return false;
- }
- if (_7p_calibration) {
- const float start = _7p_9_center ? float(_CA) + _7P_STEP / 3.0 : _7p_6_center ? float(_CA) : float(__C),
- steps = _7p_9_center ? _4P_STEP / 3.0 : _7p_6_center ? _7P_STEP : _4P_STEP;
- I_LOOP_CAL_PT(rad, start, steps) {
- const float a = RADIANS(210 + (360 / NPP) * (rad - 1)),
- r = delta_calibration_radius * 0.1;
- z_pt[CEN] += calibration_probe(cos(a) * r, sin(a) * r, stow_after_each);
- if (isnan(z_pt[CEN])) return false;
- }
- z_pt[CEN] /= float(_7p_2_intermediates ? 7 : probe_points);
- }
- if (!_1p_calibration) {
- const CalEnum start = _4p_opposite_points ? _AB : __A;
- const float steps = _7p_14_intermediates ? _7P_STEP / 15.0 :
- _7p_11_intermediates ? _7P_STEP / 12.0 :
- _7p_8_intermediates ? _7P_STEP / 9.0 :
- _7p_6_intermediates ? _7P_STEP / 7.0 :
- _7p_4_intermediates ? _7P_STEP / 5.0 :
- _7p_2_intermediates ? _7P_STEP / 3.0 :
- _7p_1_intermediates ? _7P_STEP / 2.0 :
- _7p_no_intermediates ? _7P_STEP :
- _4P_STEP;
- bool zig_zag = true;
- F_LOOP_CAL_PT(rad, start, _7p_9_center ? steps * 3 : steps) {
- const int8_t offset = _7p_9_center ? 2 : 0;
- for (int8_t circle = 0; circle <= offset; circle++) {
- const float a = RADIANS(210 + (360 / NPP) * (rad - 1)),
- r = delta_calibration_radius * (1 - 0.1 * (zig_zag ? offset - circle : circle)),
- interpol = fmod(rad, 1);
- const float z_temp = calibration_probe(cos(a) * r, sin(a) * r, stow_after_each);
- if (isnan(z_temp)) return false;
-
- z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cos(RADIANS(interpol * 90)));
- z_pt[uint8_t(LROUND(rad - interpol)) % NPP + 1] += z_temp * sq(sin(RADIANS(interpol * 90)));
- }
- zig_zag = !zig_zag;
- }
- if (_7p_intermed_points)
- LOOP_CAL_RAD(rad)
- z_pt[rad] /= _7P_STEP / steps;
- do_blocking_move_to_xy(0.0, 0.0);
- }
- }
- return true;
- }
-
- static void reverse_kinematics_probe_points(float z_pt[NPP + 1], float mm_at_pt_axis[NPP + 1][ABC]) {
- float pos[XYZ] = { 0.0 };
- LOOP_CAL_ALL(rad) {
- const float a = RADIANS(210 + (360 / NPP) * (rad - 1)),
- r = (rad == CEN ? 0.0 : delta_calibration_radius);
- pos[X_AXIS] = cos(a) * r;
- pos[Y_AXIS] = sin(a) * r;
- pos[Z_AXIS] = z_pt[rad];
- inverse_kinematics(pos);
- LOOP_XYZ(axis) mm_at_pt_axis[rad][axis] = delta[axis];
- }
- }
- static void forward_kinematics_probe_points(float mm_at_pt_axis[NPP + 1][ABC], float z_pt[NPP + 1]) {
- const float r_quot = delta_calibration_radius / delta_radius;
- #define ZPP(N,I,A) ((1 / 3.0 + r_quot * (N) / 3.0 ) * mm_at_pt_axis[I][A])
- #define Z00(I, A) ZPP( 0, I, A)
- #define Zp1(I, A) ZPP(+1, I, A)
- #define Zm1(I, A) ZPP(-1, I, A)
- #define Zp2(I, A) ZPP(+2, I, A)
- #define Zm2(I, A) ZPP(-2, I, A)
- z_pt[CEN] = Z00(CEN, A_AXIS) + Z00(CEN, B_AXIS) + Z00(CEN, C_AXIS);
- z_pt[__A] = Zp2(__A, A_AXIS) + Zm1(__A, B_AXIS) + Zm1(__A, C_AXIS);
- z_pt[__B] = Zm1(__B, A_AXIS) + Zp2(__B, B_AXIS) + Zm1(__B, C_AXIS);
- z_pt[__C] = Zm1(__C, A_AXIS) + Zm1(__C, B_AXIS) + Zp2(__C, C_AXIS);
- z_pt[_BC] = Zm2(_BC, A_AXIS) + Zp1(_BC, B_AXIS) + Zp1(_BC, C_AXIS);
- z_pt[_CA] = Zp1(_CA, A_AXIS) + Zm2(_CA, B_AXIS) + Zp1(_CA, C_AXIS);
- z_pt[_AB] = Zp1(_AB, A_AXIS) + Zp1(_AB, B_AXIS) + Zm2(_AB, C_AXIS);
- }
- static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], float delta_e[ABC], float delta_r, float delta_t[ABC]) {
- const float z_center = z_pt[CEN];
- float diff_mm_at_pt_axis[NPP + 1][ABC],
- new_mm_at_pt_axis[NPP + 1][ABC];
- reverse_kinematics_probe_points(z_pt, diff_mm_at_pt_axis);
- delta_radius += delta_r;
- LOOP_XYZ(axis) delta_tower_angle_trim[axis] += delta_t[axis];
- recalc_delta_settings();
- reverse_kinematics_probe_points(z_pt, new_mm_at_pt_axis);
- LOOP_XYZ(axis) LOOP_CAL_ALL(rad) diff_mm_at_pt_axis[rad][axis] -= new_mm_at_pt_axis[rad][axis] + delta_e[axis];
- forward_kinematics_probe_points(diff_mm_at_pt_axis, z_pt);
- LOOP_CAL_RAD(rad) z_pt[rad] -= z_pt[CEN] - z_center;
- z_pt[CEN] = z_center;
- delta_radius -= delta_r;
- LOOP_XYZ(axis) delta_tower_angle_trim[axis] -= delta_t[axis];
- recalc_delta_settings();
- }
- static float auto_tune_h() {
- const float r_quot = delta_calibration_radius / delta_radius;
- float h_fac = 0.0;
- h_fac = r_quot / (2.0 / 3.0);
- h_fac = 1.0f / h_fac;
- return h_fac;
- }
- static float auto_tune_r() {
- const float diff = 0.01;
- float r_fac = 0.0,
- z_pt[NPP + 1] = { 0.0 },
- delta_e[ABC] = {0.0},
- delta_r = {0.0},
- delta_t[ABC] = {0.0};
- delta_r = diff;
- calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
- r_fac = -(z_pt[__A] + z_pt[__B] + z_pt[__C] + z_pt[_BC] + z_pt[_CA] + z_pt[_AB]) / 6.0;
- r_fac = diff / r_fac / 3.0;
- return r_fac;
- }
- static float auto_tune_a() {
- const float diff = 0.01;
- float a_fac = 0.0,
- z_pt[NPP + 1] = { 0.0 },
- delta_e[ABC] = {0.0},
- delta_r = {0.0},
- delta_t[ABC] = {0.0};
- LOOP_XYZ(axis) {
- LOOP_XYZ(axis_2) delta_t[axis_2] = 0.0;
- delta_t[axis] = diff;
- calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
- a_fac += z_pt[uint8_t((axis * _4P_STEP) - _7P_STEP + NPP) % NPP + 1] / 6.0;
- a_fac -= z_pt[uint8_t((axis * _4P_STEP) + 1 + _7P_STEP)] / 6.0;
- }
- a_fac = diff / a_fac / 3.0;
- return a_fac;
- }
-
- inline void gcode_G33() {
- const int8_t probe_points = parser.intval('P', DELTA_CALIBRATION_DEFAULT_POINTS);
- if (!WITHIN(probe_points, 0, 10)) {
- SERIAL_PROTOCOLLNPGM("?(P)oints is implausible (0-10).");
- return;
- }
- const bool towers_set = !parser.seen('T');
- const float calibration_precision = parser.floatval('C', 0.0);
- if (calibration_precision < 0) {
- SERIAL_PROTOCOLLNPGM("?(C)alibration precision is implausible (>=0).");
- return;
- }
- const int8_t force_iterations = parser.intval('F', 0);
- if (!WITHIN(force_iterations, 0, 30)) {
- SERIAL_PROTOCOLLNPGM("?(F)orce iteration is implausible (0-30).");
- return;
- }
- const int8_t verbose_level = parser.byteval('V', 1);
- if (!WITHIN(verbose_level, 0, 3)) {
- SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-3).");
- return;
- }
- const bool stow_after_each = parser.seen('E');
- const bool _0p_calibration = probe_points == 0,
- _1p_calibration = probe_points == 1 || probe_points == -1,
- _4p_calibration = probe_points == 2,
- _4p_opposite_points = _4p_calibration && !towers_set,
- _7p_9_center = probe_points >= 8,
- _tower_results = (_4p_calibration && towers_set) || probe_points >= 3,
- _opposite_results = (_4p_calibration && !towers_set) || probe_points >= 3,
- _endstop_results = probe_points != 1 && probe_points != -1 && probe_points != 0,
- _angle_results = probe_points >= 3 && towers_set;
- static const char save_message[] PROGMEM = "Save with M500 and/or copy to Configuration.h";
- int8_t iterations = 0;
- float test_precision,
- zero_std_dev = (verbose_level ? 999.0 : 0.0),
- zero_std_dev_min = zero_std_dev,
- zero_std_dev_old = zero_std_dev,
- h_factor,
- r_factor,
- a_factor,
- e_old[ABC] = {
- delta_endstop_adj[A_AXIS],
- delta_endstop_adj[B_AXIS],
- delta_endstop_adj[C_AXIS]
- },
- r_old = delta_radius,
- h_old = delta_height,
- a_old[ABC] = {
- delta_tower_angle_trim[A_AXIS],
- delta_tower_angle_trim[B_AXIS],
- delta_tower_angle_trim[C_AXIS]
- };
- SERIAL_PROTOCOLLNPGM("G33 Auto Calibrate");
- if (!_1p_calibration && !_0p_calibration) {
- LOOP_CAL_RAD(axis) {
- const float a = RADIANS(210 + (360 / NPP) * (axis - 1)),
- r = delta_calibration_radius;
- if (!position_is_reachable(cos(a) * r, sin(a) * r)) {
- SERIAL_PROTOCOLLNPGM("?(M665 B)ed radius is implausible.");
- return;
- }
- }
- }
-
- const char *checkingac = PSTR("Checking... AC");
- serialprintPGM(checkingac);
- if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)");
- SERIAL_EOL();
- lcd_setstatusPGM(checkingac);
- print_calibration_settings(_endstop_results, _angle_results);
- ac_setup(!_0p_calibration && !_1p_calibration);
- if (!_0p_calibration) ac_home();
- do {
- float z_at_pt[NPP + 1] = { 0.0 };
- test_precision = zero_std_dev_old != 999.0 ? (zero_std_dev + zero_std_dev_old) / 2 : zero_std_dev;
- iterations++;
-
- zero_std_dev_old = zero_std_dev;
- if (!probe_calibration_points(z_at_pt, probe_points, towers_set, stow_after_each)) {
- SERIAL_PROTOCOLLNPGM("Correct delta settings with M665 and M666");
- return AC_CLEANUP();
- }
- zero_std_dev = std_dev_points(z_at_pt, _0p_calibration, _1p_calibration, _4p_calibration, _4p_opposite_points);
-
- if ((zero_std_dev < test_precision || iterations <= force_iterations) && zero_std_dev > calibration_precision) {
- #if !HAS_BED_PROBE
- test_precision = 0.00;
- #endif
- if (zero_std_dev < zero_std_dev_min) {
-
- COPY(e_old, delta_endstop_adj);
- r_old = delta_radius;
- h_old = delta_height;
- COPY(a_old, delta_tower_angle_trim);
- }
- float e_delta[ABC] = { 0.0 },
- r_delta = 0.0,
- t_delta[ABC] = { 0.0 };
-
- #define ZP(N,I) ((N) * z_at_pt[I] / 4.0)
- #define Z12(I) ZP(12, I)
- #define Z4(I) ZP(4, I)
- #define Z2(I) ZP(2, I)
- #define Z1(I) ZP(1, I)
- #define Z0(I) ZP(0, I)
-
- const float cr_old = delta_calibration_radius;
- if (_7p_9_center) delta_calibration_radius *= 0.9;
- h_factor = auto_tune_h();
- r_factor = auto_tune_r();
- a_factor = auto_tune_a();
- delta_calibration_radius = cr_old;
- switch (probe_points) {
- case 0:
- test_precision = 0.00;
- break;
- case 1:
- test_precision = 0.00;
- LOOP_XYZ(axis) e_delta[axis] = +Z4(CEN);
- break;
- case 2:
- if (towers_set) {
- e_delta[A_AXIS] = (+Z4(__A) -Z2(__B) -Z2(__C)) * h_factor +Z4(CEN);
- e_delta[B_AXIS] = (-Z2(__A) +Z4(__B) -Z2(__C)) * h_factor +Z4(CEN);
- e_delta[C_AXIS] = (-Z2(__A) -Z2(__B) +Z4(__C)) * h_factor +Z4(CEN);
- r_delta = (+Z4(__A) +Z4(__B) +Z4(__C) -Z12(CEN)) * r_factor;
- }
- else {
- e_delta[A_AXIS] = (-Z4(_BC) +Z2(_CA) +Z2(_AB)) * h_factor +Z4(CEN);
- e_delta[B_AXIS] = (+Z2(_BC) -Z4(_CA) +Z2(_AB)) * h_factor +Z4(CEN);
- e_delta[C_AXIS] = (+Z2(_BC) +Z2(_CA) -Z4(_AB)) * h_factor +Z4(CEN);
- r_delta = (+Z4(_BC) +Z4(_CA) +Z4(_AB) -Z12(CEN)) * r_factor;
- }
- break;
- default:
- e_delta[A_AXIS] = (+Z2(__A) -Z1(__B) -Z1(__C) -Z2(_BC) +Z1(_CA) +Z1(_AB)) * h_factor +Z4(CEN);
- e_delta[B_AXIS] = (-Z1(__A) +Z2(__B) -Z1(__C) +Z1(_BC) -Z2(_CA) +Z1(_AB)) * h_factor +Z4(CEN);
- e_delta[C_AXIS] = (-Z1(__A) -Z1(__B) +Z2(__C) +Z1(_BC) +Z1(_CA) -Z2(_AB)) * h_factor +Z4(CEN);
- r_delta = (+Z2(__A) +Z2(__B) +Z2(__C) +Z2(_BC) +Z2(_CA) +Z2(_AB) -Z12(CEN)) * r_factor;
- if (towers_set) {
- t_delta[A_AXIS] = (+Z0(__A) -Z4(__B) +Z4(__C) +Z0(_BC) -Z4(_CA) +Z4(_AB) +Z0(CEN)) * a_factor;
- t_delta[B_AXIS] = (+Z4(__A) +Z0(__B) -Z4(__C) +Z4(_BC) +Z0(_CA) -Z4(_AB) +Z0(CEN)) * a_factor;
- t_delta[C_AXIS] = (-Z4(__A) +Z4(__B) +Z0(__C) -Z4(_BC) +Z4(_CA) +Z0(_AB) +Z0(CEN)) * a_factor;
- }
- break;
- }
- LOOP_XYZ(axis) delta_endstop_adj[axis] += e_delta[axis];
- delta_radius += r_delta;
- LOOP_XYZ(axis) delta_tower_angle_trim[axis] += t_delta[axis];
- }
- else if (zero_std_dev >= test_precision) {
-
- COPY(delta_endstop_adj, e_old);
- delta_radius = r_old;
- delta_height = h_old;
- COPY(delta_tower_angle_trim, a_old);
- }
- if (verbose_level != 0) {
-
- if (_angle_results) {
- float a_sum = 0.0;
- LOOP_XYZ(axis) a_sum += delta_tower_angle_trim[axis];
- LOOP_XYZ(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0;
- }
-
- const float z_temp = MAX3(delta_endstop_adj[A_AXIS], delta_endstop_adj[B_AXIS], delta_endstop_adj[C_AXIS]);
- delta_height -= z_temp;
- LOOP_XYZ(axis) delta_endstop_adj[axis] -= z_temp;
- }
- recalc_delta_settings();
- NOMORE(zero_std_dev_min, zero_std_dev);
-
- if (verbose_level == 3)
- print_calibration_results(z_at_pt, _tower_results, _opposite_results);
- if (verbose_level != 0) {
- if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) {
- SERIAL_PROTOCOLPGM("Calibration OK");
- SERIAL_PROTOCOL_SP(32);
- #if HAS_BED_PROBE
- if (zero_std_dev >= test_precision && !_1p_calibration && !_0p_calibration)
- SERIAL_PROTOCOLPGM("rolling back.");
- else
- #endif
- {
- SERIAL_PROTOCOLPGM("std dev:");
- SERIAL_PROTOCOL_F(zero_std_dev_min, 3);
- }
- SERIAL_EOL();
- char mess[21];
- strcpy_P(mess, PSTR("Calibration sd:"));
- if (zero_std_dev_min < 1)
- sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev_min * 1000.0)));
- else
- sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev_min)));
- lcd_setstatus(mess);
- print_calibration_settings(_endstop_results, _angle_results);
- serialprintPGM(save_message);
- SERIAL_EOL();
- }
- else {
- char mess[15];
- if (iterations < 31)
- sprintf_P(mess, PSTR("Iteration : %02i"), int(iterations));
- else
- strcpy_P(mess, PSTR("No convergence"));
- SERIAL_PROTOCOL(mess);
- SERIAL_PROTOCOL_SP(32);
- SERIAL_PROTOCOLPGM("std dev:");
- SERIAL_PROTOCOL_F(zero_std_dev, 3);
- SERIAL_EOL();
- lcd_setstatus(mess);
- if (verbose_level > 1)
- print_calibration_settings(_endstop_results, _angle_results);
- }
- }
- else {
- const char *enddryrun = PSTR("End DRY-RUN");
- serialprintPGM(enddryrun);
- SERIAL_PROTOCOL_SP(35);
- SERIAL_PROTOCOLPGM("std dev:");
- SERIAL_PROTOCOL_F(zero_std_dev, 3);
- SERIAL_EOL();
- char mess[21];
- strcpy_P(mess, enddryrun);
- strcpy_P(&mess[11], PSTR(" sd:"));
- if (zero_std_dev < 1)
- sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev * 1000.0)));
- else
- sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev)));
- lcd_setstatus(mess);
- }
- ac_home();
- }
- while (((zero_std_dev < test_precision && iterations < 31) || iterations <= force_iterations) && zero_std_dev > calibration_precision);
- AC_CLEANUP();
- }
- #endif
- #if ENABLED(G38_PROBE_TARGET)
- static bool G38_run_probe() {
- bool G38_pass_fail = false;
- #if MULTIPLE_PROBING > 1
-
- float retract_mm[XYZ];
- LOOP_XYZ(i) {
- float dist = destination[i] - current_position[i];
- retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1);
- }
- #endif
-
- planner.synchronize();
- endstops.enable(true);
- G38_move = true;
- G38_endstop_hit = false;
- prepare_move_to_destination();
- planner.synchronize();
- G38_move = false;
- endstops.hit_on_purpose();
- set_current_from_steppers_for_axis(ALL_AXES);
- SYNC_PLAN_POSITION_KINEMATIC();
- if (G38_endstop_hit) {
- G38_pass_fail = true;
- #if MULTIPLE_PROBING > 1
-
- set_destination_from_current();
- LOOP_XYZ(i) destination[i] += retract_mm[i];
- endstops.enable(false);
- prepare_move_to_destination();
- feedrate_mm_s /= 4;
-
- LOOP_XYZ(i) destination[i] -= retract_mm[i] * 2;
- planner.synchronize();
- endstops.enable(true);
- G38_move = true;
- prepare_move_to_destination();
- planner.synchronize();
- G38_move = false;
- set_current_from_steppers_for_axis(ALL_AXES);
- SYNC_PLAN_POSITION_KINEMATIC();
- #endif
- }
- endstops.hit_on_purpose();
- endstops.not_homing();
- return G38_pass_fail;
- }
-
- inline void gcode_G38(bool is_38_2) {
-
- gcode_get_destination();
- setup_for_endstop_or_probe_move();
-
- LOOP_XYZ(i)
- if (ABS(destination[i] - current_position[i]) >= G38_MINIMUM_MOVE) {
- if (!parser.seenval('F')) feedrate_mm_s = homing_feedrate((AxisEnum)i);
-
- if (!G38_run_probe() && is_38_2) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("Failed to reach target");
- }
- break;
- }
- clean_up_after_endstop_or_probe_move();
- }
- #endif
- #if HAS_MESH
-
- inline void gcode_G42() {
- #if ENABLED(NO_MOTION_BEFORE_HOMING)
- if (axis_unhomed_error()) return;
- #endif
- if (IsRunning()) {
- const bool hasI = parser.seenval('I');
- const int8_t ix = hasI ? parser.value_int() : 0;
- const bool hasJ = parser.seenval('J');
- const int8_t iy = hasJ ? parser.value_int() : 0;
- if ((hasI && !WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) || (hasJ && !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1))) {
- SERIAL_ECHOLNPGM(MSG_ERR_MESH_XY);
- return;
- }
- set_destination_from_current();
- if (hasI) destination[X_AXIS] = _GET_MESH_X(ix);
- if (hasJ) destination[Y_AXIS] = _GET_MESH_Y(iy);
- if (parser.boolval('P')) {
- if (hasI) destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
- if (hasJ) destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
- }
- const float fval = parser.linearval('F');
- if (fval > 0.0) feedrate_mm_s = MMM_TO_MMS(fval);
-
- #if IS_SCARA
- prepare_uninterpolated_move_to_destination();
- #else
- prepare_move_to_destination();
- #endif
- }
- }
- #endif
- inline void gcode_G92() {
- #if ENABLED(CNC_COORDINATE_SYSTEMS)
- switch (parser.subcode) {
- case 1:
-
- #if !IS_SCARA
- LOOP_XYZ(i) {
- const float v = position_shift[i];
- if (v) {
- position_shift[i] = 0;
- update_software_endstops((AxisEnum)i);
- }
- }
- #endif
- return;
- }
- #endif
- #if ENABLED(CNC_COORDINATE_SYSTEMS)
- #define IS_G92_0 (parser.subcode == 0)
- #else
- #define IS_G92_0 true
- #endif
- bool didE = false;
- #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER)
- bool didXYZ = false;
- #else
- constexpr bool didXYZ = false;
- #endif
- if (IS_G92_0) LOOP_XYZE(i) {
- if (parser.seenval(axis_codes[i])) {
- const float l = parser.value_axis_units((AxisEnum)i),
- v = i == E_CART ? l : LOGICAL_TO_NATIVE(l, i),
- d = v - current_position[i];
- if (!NEAR_ZERO(d)
- #if ENABLED(HANGPRINTER)
- || true
- #endif
- ) {
- #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER)
- if (i == E_CART) didE = true; else didXYZ = true;
- current_position[i] = v;
- #elif HAS_POSITION_SHIFT
- if (i == E_CART) {
- didE = true;
- current_position[E_CART] = v;
- }
- else {
- position_shift[i] += d;
- update_software_endstops((AxisEnum)i);
- }
- #endif
- }
- }
- }
- #if ENABLED(CNC_COORDINATE_SYSTEMS)
-
- if (WITHIN(active_coordinate_system, 0, MAX_COORDINATE_SYSTEMS - 1))
- COPY(coordinate_system[active_coordinate_system], position_shift);
- #endif
-
- if (didXYZ) SYNC_PLAN_POSITION_KINEMATIC();
- else if (didE) sync_plan_position_e();
- report_current_position();
- }
- #if ENABLED(MECHADUINO_I2C_COMMANDS)
-
- inline void gcode_G95() {
- i2cFloat torques[NUM_AXIS];
- LOOP_NUM_AXIS(i)
- torques[i].fval = parser.floatval(RAW_AXIS_CODES(i), 999.9);
-
- #define G95_SEND(LETTER) do { \
- if (fabs(torques[_AXIS(LETTER)].fval) < 255.0){ \
- torques[_AXIS(LETTER)].fval = -fabs(torques[_AXIS(LETTER)].fval); \
- if(!INVERT_##LETTER##_DIR) torques[_AXIS(LETTER)].fval = -torques[_AXIS(LETTER)].fval; \
- i2c.address(LETTER##_MOTOR_I2C_ADDR); \
- i2c.reset(); \
- i2c.addbyte(0x5f); \
- i2c.addbytes(torques[_AXIS(LETTER)].bval, sizeof(float)); \
- i2c.send(); \
- }} while(0)
- #if ENABLED(HANGPRINTER)
- #if ENABLED(A_IS_MECHADUINO)
- G95_SEND(A);
- #endif
- #if ENABLED(B_IS_MECHADUINO)
- G95_SEND(B);
- #endif
- #if ENABLED(C_IS_MECHADUINO)
- G95_SEND(C);
- #endif
- #if ENABLED(D_IS_MECHADUINO)
- G95_SEND(D);
- #endif
- #else
- #if ENABLED(X_IS_MECHADUINO)
- G95_SEND(X);
- #endif
- #if ENABLED(Y_IS_MECHADUINO)
- G95_SEND(Y);
- #endif
- #if ENABLED(Z_IS_MECHADUINO)
- G95_SEND(Z);
- #endif
- #endif
- #if ENABLED(E_IS_MECHADUINO)
- G95_SEND(E);
- #endif
- }
- /**
- * G96: Mark encoder reference point
- */
- inline void gcode_G96() {
- bool mark[NUM_AXIS] = { false };
- if (!parser.seen_any())
- LOOP_NUM_AXIS(i)
- mark[i] = true;
- else
- LOOP_NUM_AXIS(i)
- if (parser.seen(RAW_AXIS_CODES(i)))
- mark[i] = true;
- // 0x60 == 96
- #define G96_SEND(LETTER) do {\
- if (mark[LETTER##_AXIS]){ \
- i2c.address(LETTER##_MOTOR_I2C_ADDR); \
- i2c.reset(); \
- i2c.addbyte(0x60); \
- i2c.send(); \
- }} while(0)
- #if ENABLED(HANGPRINTER)
- #if ENABLED(A_IS_MECHADUINO)
- G96_SEND(A);
- #endif
- #if ENABLED(B_IS_MECHADUINO)
- G96_SEND(B);
- #endif
- #if ENABLED(C_IS_MECHADUINO)
- G96_SEND(C);
- #endif
- #if ENABLED(D_IS_MECHADUINO)
- G96_SEND(D);
- #endif
- #else
- #if ENABLED(X_IS_MECHADUINO)
- G96_SEND(X);
- #endif
- #if ENABLED(Y_IS_MECHADUINO)
- G96_SEND(Y);
- #endif
- #if ENABLED(Z_IS_MECHADUINO)
- G96_SEND(Z);
- #endif
- #endif
- #if ENABLED(E_IS_MECHADUINO)
- G96_SEND(E); // E ref point not used by any other commands (Feb 7, 2018)
- #endif
- }
- float ang_to_mm(float ang, const AxisEnum axis) {
- const float abs_step_in_origin =
- #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
- planner.k0[axis] * (SQRT(planner.k1[axis] + planner.k2[axis] * line_lengths_origin[axis]) - planner.sqrtk1[axis])
- #else
- line_lengths_origin[axis] * planner.axis_steps_per_mm[axis]
- #endif
- ;
- const float c = abs_step_in_origin + ang * float(STEPS_PER_MOTOR_REVOLUTION) / 360.0; // current step count
- return
- #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
- // Inverse function found in planner.cpp, where target[AXIS_A] is calculated
- ((c / planner.k0[axis] + planner.sqrtk1[axis]) * (c / planner.k0[axis] + planner.sqrtk1[axis]) - planner.k1[axis]) / planner.k2[axis] - line_lengths_origin[axis]
- #else
- c / planner.axis_steps_per_mm[axis] - line_lengths_origin[axis]
- #endif
- ;
- }
- void report_axis_position_from_encoder_data() {
- i2cFloat ang;
- #define M114_S1_RECEIVE(LETTER) do { \
- i2c.address(LETTER##_MOTOR_I2C_ADDR); \
- i2c.request(sizeof(float)); \
- i2c.capture(ang.bval, sizeof(float)); \
- if(LETTER##_INVERT_REPORTED_ANGLE == INVERT_##LETTER##_DIR) ang.fval = -ang.fval; \
- SERIAL_PROTOCOL(ang_to_mm(ang.fval, LETTER##_AXIS)); \
- } while(0)
- SERIAL_CHAR('[');
- #if ENABLED(HANGPRINTER)
- #if ENABLED(A_IS_MECHADUINO)
- M114_S1_RECEIVE(A);
- #endif
- #if ENABLED(B_IS_MECHADUINO)
- SERIAL_PROTOCOLPGM(", ");
- M114_S1_RECEIVE(B);
- #endif
- #if ENABLED(C_IS_MECHADUINO)
- SERIAL_PROTOCOLPGM(", ");
- M114_S1_RECEIVE(C);
- #endif
- #if ENABLED(D_IS_MECHADUINO)
- SERIAL_PROTOCOLPGM(", ");
- M114_S1_RECEIVE(D);
- #endif
- #else
- #if ENABLED(X_IS_MECHADUINO)
- M114_S1_RECEIVE(X);
- #endif
- #if ENABLED(Y_IS_MECHADUINO)
- SERIAL_PROTOCOLPGM(", ");
- M114_S1_RECEIVE(Y);
- #endif
- #if ENABLED(Z_IS_MECHADUINO)
- SERIAL_PROTOCOLPGM(", ");
- M114_S1_RECEIVE(Z);
- #endif
- #endif
- SERIAL_CHAR(']');
- SERIAL_EOL();
- }
- #endif // MECHADUINO_I2C_COMMANDS
- void report_xyz_from_stepper_position() {
- get_cartesian_from_steppers(); // writes to cartes[XYZ]
- SERIAL_CHAR('[');
- SERIAL_PROTOCOL(cartes[X_AXIS]);
- SERIAL_PROTOCOLPAIR(", ", cartes[Y_AXIS]);
- SERIAL_PROTOCOLPAIR(", ", cartes[Z_AXIS]);
- SERIAL_CHAR(']');
- SERIAL_EOL();
- }
- #if HAS_RESUME_CONTINUE
- /**
- * M0: Unconditional stop - Wait for user button press on LCD
- * M1: Conditional stop - Wait for user button press on LCD
- */
- inline void gcode_M0_M1() {
- const char * const args = parser.string_arg;
- millis_t ms = 0;
- bool hasP = false, hasS = false;
- if (parser.seenval('P')) {
- ms = parser.value_millis(); // milliseconds to wait
- hasP = ms > 0;
- }
- if (parser.seenval('S')) {
- ms = parser.value_millis_from_seconds();
- hasS = ms > 0;
- }
- const bool has_message = !hasP && !hasS && args && *args;
- planner.synchronize();
- #if ENABLED(ULTIPANEL)
- if (has_message)
- lcd_setstatus(args, true);
- else {
- LCD_MESSAGEPGM(MSG_USERWAIT);
- #if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
- dontExpireStatus();
- #endif
- }
- #else
- if (has_message) {
- SERIAL_ECHO_START();
- SERIAL_ECHOLN(args);
- }
- #endif
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- wait_for_user = true;
- if (ms > 0) {
- ms += millis();
- while (PENDING(millis(), ms) && wait_for_user) idle();
- }
- else
- while (wait_for_user) idle();
- #if ENABLED(PRINTER_EVENT_LEDS) && ENABLED(SDSUPPORT)
- if (lights_off_after_print) {
- leds.set_off();
- lights_off_after_print = false;
- }
- #endif
- lcd_reset_status();
- wait_for_user = false;
- KEEPALIVE_STATE(IN_HANDLER);
- }
- #endif
- #if ENABLED(SPINDLE_LASER_ENABLE)
-
-
- inline void delay_for_power_up() { dwell(SPINDLE_LASER_POWERUP_DELAY); }
-
- inline void delay_for_power_down() { dwell(SPINDLE_LASER_POWERDOWN_DELAY); }
-
- inline void ocr_val_mode() {
- uint8_t spindle_laser_power = parser.value_byte();
- WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT);
- if (SPINDLE_LASER_PWM_INVERT) spindle_laser_power = 255 - spindle_laser_power;
- analogWrite(SPINDLE_LASER_PWM_PIN, spindle_laser_power);
- }
- inline void gcode_M3_M4(bool is_M3) {
- planner.synchronize();
- #if SPINDLE_DIR_CHANGE
- const bool rotation_dir = (is_M3 && !SPINDLE_INVERT_DIR || !is_M3 && SPINDLE_INVERT_DIR) ? HIGH : LOW;
- if (SPINDLE_STOP_ON_DIR_CHANGE \
- && READ(SPINDLE_LASER_ENABLE_PIN) == SPINDLE_LASER_ENABLE_INVERT \
- && READ(SPINDLE_DIR_PIN) != rotation_dir
- ) {
- WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);
- delay_for_power_down();
- }
- WRITE(SPINDLE_DIR_PIN, rotation_dir);
- #endif
-
- #if ENABLED(SPINDLE_LASER_PWM)
- if (parser.seen('O')) ocr_val_mode();
- else {
- const float spindle_laser_power = parser.floatval('S');
- if (spindle_laser_power == 0) {
- WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);
- analogWrite(SPINDLE_LASER_PWM_PIN, SPINDLE_LASER_PWM_INVERT ? 255 : 0);
- delay_for_power_down();
- }
- else {
- int16_t ocr_val = (spindle_laser_power - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE));
- NOMORE(ocr_val, 255);
- if (spindle_laser_power <= SPEED_POWER_MIN)
- ocr_val = (SPEED_POWER_MIN - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE));
- if (spindle_laser_power >= SPEED_POWER_MAX)
- ocr_val = (SPEED_POWER_MAX - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE));
- if (SPINDLE_LASER_PWM_INVERT) ocr_val = 255 - ocr_val;
- WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT);
- analogWrite(SPINDLE_LASER_PWM_PIN, ocr_val & 0xFF);
- delay_for_power_up();
- }
- }
- #else
- WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT);
- delay_for_power_up();
- #endif
- }
-
- inline void gcode_M5() {
- planner.synchronize();
- WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);
- #if ENABLED(SPINDLE_LASER_PWM)
- analogWrite(SPINDLE_LASER_PWM_PIN, SPINDLE_LASER_PWM_INVERT ? 255 : 0);
- #endif
- delay_for_power_down();
- }
- #endif
- inline void gcode_M17() {
- LCD_MESSAGEPGM(MSG_NO_MOVE);
- enable_all_steppers();
- }
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- void do_pause_e_move(const float &length, const float &fr) {
- set_destination_from_current();
- destination[E_CART] += length / planner.e_factor[active_extruder];
- planner.buffer_line_kinematic(destination, fr, active_extruder);
- set_current_from_destination();
- planner.synchronize();
- }
- static float resume_position[XYZE];
- int8_t did_pause_print = 0;
- #if HAS_BUZZER
- static void filament_change_beep(const int8_t max_beep_count, const bool init=false) {
- static millis_t next_buzz = 0;
- static int8_t runout_beep = 0;
- if (init) next_buzz = runout_beep = 0;
- const millis_t ms = millis();
- if (ELAPSED(ms, next_buzz)) {
- if (max_beep_count < 0 || runout_beep < max_beep_count + 5) {
- next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 1000 : 500);
- BUZZ(50, 880 - (runout_beep & 1) * 220);
- runout_beep++;
- }
- }
- }
- #endif
-
- static bool ensure_safe_temperature(const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT) {
- #if ENABLED(PREVENT_COLD_EXTRUSION)
- if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
- return false;
- }
- #endif
- #if ENABLED(ULTIPANEL)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT, mode);
- #else
- UNUSED(mode);
- #endif
- wait_for_heatup = true;
- while (wait_for_heatup && thermalManager.wait_for_heating(active_extruder)) idle();
- const bool status = wait_for_heatup;
- wait_for_heatup = false;
- return status;
- }
-
- static bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &purge_length=0, const int8_t max_beep_count=0,
- const bool show_lcd=false, const bool pause_for_user=false,
- const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT
- ) {
- #if DISABLED(ULTIPANEL)
- UNUSED(show_lcd);
- #endif
- if (!ensure_safe_temperature(mode)) {
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
- #endif
- return false;
- }
- if (pause_for_user) {
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT, mode);
- #endif
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPGM(MSG_FILAMENT_CHANGE_INSERT);
- #if HAS_BUZZER
- filament_change_beep(max_beep_count, true);
- #else
- UNUSED(max_beep_count);
- #endif
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- wait_for_user = true;
- while (wait_for_user) {
- #if HAS_BUZZER
- filament_change_beep(max_beep_count);
- #endif
- idle(true);
- }
- KEEPALIVE_STATE(IN_HANDLER);
- }
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode);
- #endif
-
- if (slow_load_length) do_pause_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE);
-
- if (fast_load_length) {
- #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
- const float saved_acceleration = planner.retract_acceleration;
- planner.retract_acceleration = FILAMENT_CHANGE_FAST_LOAD_ACCEL;
- #endif
- do_pause_e_move(fast_load_length, FILAMENT_CHANGE_FAST_LOAD_FEEDRATE);
- #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
- planner.retract_acceleration = saved_acceleration;
- #endif
- }
- #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CONTINUOUS_PURGE);
- #endif
- wait_for_user = true;
- for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count)
- do_pause_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE);
- wait_for_user = false;
- #else
- do {
- if (purge_length > 0) {
-
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_PURGE, mode);
- #endif
-
- do_pause_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE);
- }
-
- #if ENABLED(ULTIPANEL)
- if (show_lcd) {
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- wait_for_user = false;
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION, mode);
- while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true);
- KEEPALIVE_STATE(IN_HANDLER);
- }
- #endif
-
- } while (
- #if ENABLED(ULTIPANEL)
- show_lcd && advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE
- #else
- 0
- #endif
- );
- #endif
- return true;
- }
-
- static bool unload_filament(const float &unload_length, const bool show_lcd=false,
- const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT
- ) {
- if (!ensure_safe_temperature(mode)) {
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
- #endif
- return false;
- }
- #if DISABLED(ULTIPANEL)
- UNUSED(show_lcd);
- #else
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, mode);
- #endif
-
- do_pause_e_move(-FILAMENT_UNLOAD_RETRACT_LENGTH, PAUSE_PARK_RETRACT_FEEDRATE);
-
- safe_delay(FILAMENT_UNLOAD_DELAY);
-
- do_pause_e_move(FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH, planner.max_feedrate_mm_s[E_AXIS]);
-
- #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
- const float saved_acceleration = planner.retract_acceleration;
- planner.retract_acceleration = FILAMENT_CHANGE_UNLOAD_ACCEL;
- #endif
- do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE);
- #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
- planner.retract_acceleration = saved_acceleration;
- #endif
-
- #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN
- disable_e_stepper(active_extruder);
- safe_delay(100);
- #endif
- return true;
- }
-
- static bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false) {
- if (did_pause_print) return false;
- #ifdef ACTION_ON_PAUSE
- SERIAL_ECHOLNPGM("//action:" ACTION_ON_PAUSE);
- #endif
- if (!DEBUGGING(DRYRUN) && unload_length && thermalManager.targetTooColdToExtrude(active_extruder)) {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
- #if ENABLED(ULTIPANEL)
- if (show_lcd)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
- LCD_MESSAGEPGM(MSG_M600_TOO_COLD);
- #endif
- return false;
- }
-
- ++did_pause_print;
-
- #if ENABLED(SDSUPPORT)
- if (card.sdprinting) {
- card.pauseSDPrint();
- ++did_pause_print;
- }
- #endif
- print_job_timer.pause();
-
- COPY(resume_position, current_position);
-
- planner.synchronize();
-
- if (retract && thermalManager.hotEnoughToExtrude(active_extruder))
- do_pause_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE);
-
- if (!axis_unhomed_error())
- Nozzle::park(2, park_point);
-
- if (unload_length)
- unload_filament(unload_length, show_lcd);
- return true;
- }
-
- static void wait_for_filament_reload(const int8_t max_beep_count=0) {
- bool nozzle_timed_out = false;
- #if ENABLED(ULTIPANEL)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
- #endif
- SERIAL_ECHO_START();
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
- #if HAS_BUZZER
- filament_change_beep(max_beep_count, true);
- #endif
-
- const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL;
- HOTEND_LOOP()
- thermalManager.start_heater_idle_timer(e, nozzle_timeout);
-
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- wait_for_user = true;
- while (wait_for_user) {
- #if HAS_BUZZER
- filament_change_beep(max_beep_count);
- #endif
-
-
- if (!nozzle_timed_out)
- HOTEND_LOOP()
- nozzle_timed_out |= thermalManager.is_heater_idle(e);
- if (nozzle_timed_out) {
- #if ENABLED(ULTIPANEL)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE);
- #endif
- SERIAL_ECHO_START();
- #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT);
- #elif ENABLED(EMERGENCY_PARSER)
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_M108);
- #else
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_LCD);
- #endif
-
- while (wait_for_user) idle(true);
-
- HOTEND_LOOP() thermalManager.reset_heater_idle_timer(e);
-
- ensure_safe_temperature();
- #if ENABLED(ULTIPANEL)
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
- #endif
- SERIAL_ECHO_START();
- #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
- #elif ENABLED(EMERGENCY_PARSER)
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_M108);
- #else
- SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_LCD);
- #endif
-
- const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL;
- HOTEND_LOOP()
- thermalManager.start_heater_idle_timer(e, nozzle_timeout);
- wait_for_user = true;
- nozzle_timed_out = false;
- #if HAS_BUZZER
- filament_change_beep(max_beep_count, true);
- #endif
- }
- idle(true);
- }
- KEEPALIVE_STATE(IN_HANDLER);
- }
-
- static void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &purge_length=ADVANCED_PAUSE_PURGE_LENGTH, const int8_t max_beep_count=0) {
- if (!did_pause_print) return;
-
- bool nozzle_timed_out = false;
- HOTEND_LOOP() {
- nozzle_timed_out |= thermalManager.is_heater_idle(e);
- thermalManager.reset_heater_idle_timer(e);
- }
- if (nozzle_timed_out || thermalManager.hotEnoughToExtrude(active_extruder)) {
-
- load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out);
- }
- #if ENABLED(ULTIPANEL)
-
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_RESUME);
- #endif
-
- #if ENABLED(FWRETRACT)
-
- if (fwretract.retracted[active_extruder])
- do_pause_e_move(-fwretract.retract_length, fwretract.retract_feedrate_mm_s);
- #endif
-
- if (resume_position[E_CART] < 0) do_pause_e_move(resume_position[E_CART], PAUSE_PARK_RETRACT_FEEDRATE);
-
- do_blocking_move_to_xy(resume_position[X_AXIS], resume_position[Y_AXIS], NOZZLE_PARK_XY_FEEDRATE);
-
- do_blocking_move_to_z(resume_position[Z_AXIS], NOZZLE_PARK_Z_FEEDRATE);
-
-
- planner.set_e_position_mm((destination[E_CART] = current_position[E_CART] = resume_position[E_CART]));
- #if ENABLED(FILAMENT_RUNOUT_SENSOR)
- runout.reset();
- #endif
- #if ENABLED(ULTIPANEL)
-
- lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
- #endif
- #ifdef ACTION_ON_RESUME
- SERIAL_ECHOLNPGM("//action:" ACTION_ON_RESUME);
- #endif
- --did_pause_print;
- #if ENABLED(SDSUPPORT)
- if (did_pause_print) {
- card.startFileprint();
- --did_pause_print;
- }
- #endif
- }
- #endif
- #if ENABLED(SDSUPPORT)
-
- inline void gcode_M20() {
- SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
- card.ls();
- SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
- }
-
- inline void gcode_M21() { card.initsd(); }
-
- inline void gcode_M22() { card.release(); }
-
- inline void gcode_M23() {
- #if ENABLED(POWER_LOSS_RECOVERY)
- card.removeJobRecoveryFile();
- #endif
-
- for (char *fn = parser.string_arg; *fn; ++fn) if (*fn == ' ') *fn = '\0';
- card.openFile(parser.string_arg, true);
- }
-
- inline void gcode_M24() {
- #if ENABLED(PARK_HEAD_ON_PAUSE)
- resume_print();
- #endif
- #if ENABLED(POWER_LOSS_RECOVERY)
- if (parser.seenval('S')) card.setIndex(parser.value_long());
- #endif
- card.startFileprint();
- #if ENABLED(POWER_LOSS_RECOVERY)
- if (parser.seenval('T'))
- print_job_timer.resume(parser.value_long());
- else
- #endif
- print_job_timer.start();
- }
-
- inline void gcode_M25() {
- card.pauseSDPrint();
- print_job_timer.pause();
- #if ENABLED(PARK_HEAD_ON_PAUSE)
- enqueue_and_echo_commands_P(PSTR("M125"));
- #endif
- }
-
- inline void gcode_M26() {
- if (card.cardOK && parser.seenval('S'))
- card.setIndex(parser.value_long());
- }
-
- inline void gcode_M27() {
- if (parser.seen('C')) {
- SERIAL_ECHOPGM("Current file: ");
- card.printFilename();
- }
- #if ENABLED(AUTO_REPORT_SD_STATUS)
- else if (parser.seenval('S'))
- card.set_auto_report_interval(parser.value_byte());
- #endif
- else
- card.getStatus();
- }
-
- inline void gcode_M28() { card.openFile(parser.string_arg, false); }
-
- inline void gcode_M29() {
-
- }
-
- inline void gcode_M30() {
- if (card.cardOK) {
- card.closefile();
- card.removeFile(parser.string_arg);
- }
- }
- #endif
- inline void gcode_M31() {
- char buffer[21];
- duration_t elapsed = print_job_timer.duration();
- elapsed.toString(buffer);
- lcd_setstatus(buffer);
- SERIAL_ECHO_START();
- SERIAL_ECHOLNPAIR("Print time: ", buffer);
- }
- #if ENABLED(SDSUPPORT)
-
- inline void gcode_M32() {
- if (card.sdprinting) planner.synchronize();
- if (card.cardOK) {
- const bool call_procedure = parser.boolval('P');
- card.openFile(parser.string_arg, true, call_procedure);
- if (parser.seenval('S')) card.setIndex(parser.value_long());
- card.startFileprint();
-
- if (!call_procedure) print_job_timer.start();
- }
- }
- #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
-
- inline void gcode_M33() {
- card.printLongPath(parser.string_arg);
- }
- #endif
- #if ENABLED(SDCARD_SORT_ALPHA) && ENABLED(SDSORT_GCODE)
-
- inline void gcode_M34() {
- if (parser.seen('S')) card.setSortOn(parser.value_bool());
- if (parser.seenval('F')) {
- const int v = parser.value_long();
- card.setSortFolders(v < 0 ? -1 : v > 0 ? 1 : 0);
- }
-
- }
- #endif
-
- inline void gcode_M928() {
- card.openLogFile(parser.string_arg);
- }
- #endif
- static bool pin_is_protected(const pin_t pin) {
- static const pin_t sensitive_pins[] PROGMEM = SENSITIVE_PINS;
- for (uint8_t i = 0; i < COUNT(sensitive_pins); i++)
- if (pin == (pin_t)pgm_read_byte(&sensitive_pins[i])) return true;
- return false;
- }
- inline void protected_pin_err() {
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM(MSG_ERR_PROTECTED_PIN);
- }
- inline void gcode_M42() {
- if (!parser.seenval('S')) return;
- const byte pin_status = parser.value_byte();
- const pin_t pin_number = parser.byteval('P', LED_PIN);
- if (pin_number < 0) return;
- if (!parser.boolval('I') && pin_is_protected(pin_number)) return protected_pin_err();
- pinMode(pin_number, OUTPUT);
- digitalWrite(pin_number, pin_status);
- analogWrite(pin_number, pin_status);
- #if FAN_COUNT > 0
- switch (pin_number) {
- #if HAS_FAN0
- case FAN_PIN: fanSpeeds[0] = pin_status; break;
- #endif
- #if HAS_FAN1
- case FAN1_PIN: fanSpeeds[1] = pin_status; break;
- #endif
- #if HAS_FAN2
- case FAN2_PIN: fanSpeeds[2] = pin_status; break;
- #endif
- }
- #endif
- }
- #if ENABLED(PINS_DEBUGGING)
- #include "pinsDebug.h"
- inline void toggle_pins() {
- const bool ignore_protection = parser.boolval('I');
- const int repeat = parser.intval('R', 1),
- start = parser.intval('S'),
- end = parser.intval('L', NUM_DIGITAL_PINS - 1),
- wait = parser.intval('W', 500);
- for (uint8_t pin = start; pin <= end; pin++) {
-
- if (!ignore_protection && pin_is_protected(pin)) {
- report_pin_state_extended(pin, ignore_protection, true, "Untouched ");
- SERIAL_EOL();
- }
- else {
- report_pin_state_extended(pin, ignore_protection, true, "Pulsing ");
- #if AVR_AT90USB1286_FAMILY
- if (pin == TEENSY_E2) {
- SET_OUTPUT(TEENSY_E2);
- for (int16_t j = 0; j < repeat; j++) {
- WRITE(TEENSY_E2, LOW); safe_delay(wait);
- WRITE(TEENSY_E2, HIGH); safe_delay(wait);
- WRITE(TEENSY_E2, LOW); safe_delay(wait);
- }
- }
- else if (pin == TEENSY_E3) {
- SET_OUTPUT(TEENSY_E3);
- for (int16_t j = 0; j < repeat; j++) {
- WRITE(TEENSY_E3, LOW); safe_delay(wait);
- WRITE(TEENSY_E3, HIGH); safe_delay(wait);
- WRITE(TEENSY_E3, LOW); safe_delay(wait);
- }
- }
- else
- #endif
- {
- pinMode(pin, OUTPUT);
- for (int16_t j = 0; j < repeat; j++) {
- digitalWrite(pin, 0); safe_delay(wait);
- digitalWrite(pin, 1); safe_delay(wait);
- digitalWrite(pin, 0); safe_delay(wait);
- }
- }
- }
- SERIAL_EOL();
- }
- SERIAL_ECHOLNPGM("Done.");
- }
- inline void servo_probe_test() {
- #if !(NUM_SERVOS > 0 && HAS_SERVO_0)
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("SERVO not setup");
- #elif !HAS_Z_SERVO_PROBE
- SERIAL_ERROR_START();
- SERIAL_ERRORLNPGM("Z_PROBE_SERVO_NR not setup");
- #else
- const uint8_t probe_index = parser.byteval('P', Z_PROBE_SERVO_NR);
- SERIAL_PROTOCOLLNPGM("Servo probe test");
- SERIAL_PROTOCOLLNPAIR(". using index: ", probe_index);
- SERIAL_PROTOCOLLNPAIR(". deploy angle: ", z_servo_angle[0]);
- SERIAL_PROTOCOLLNPAIR(". stow angle: ", z_servo_angle[1]);
- bool probe_inverting;
- #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
- #define PROBE_TEST_PIN Z_MIN_PIN
- SERIAL_PROTOCOLLNPAIR(". probe uses Z_MIN pin: ", PROBE_TEST_PIN);
- SERIAL_PROTOCOLLNPGM(". uses Z_MIN_ENDSTOP_INVERTING (ignores Z_MIN_PROBE_ENDSTOP_INVERTING)");
- SERIAL_PROTOCOLPGM(". Z_MIN_ENDSTOP_INVERTING: ");
- #if Z_MIN_ENDSTOP_INVERTING
- SERIAL_PROTOCOLLNPGM("true");
- #else
- SERIAL_PROTOCOLLNPGM("false");
- #endif
- probe_inverting = Z_MIN_ENDSTOP_INVERTING;
- #elif ENABLED(Z_MIN_PROBE_ENDSTOP)
- #define PROBE_TEST_PIN Z_MIN_PROBE_PIN
- SERIAL_PROTOCOLLNPAIR(". probe uses Z_MIN_PROBE_PIN: ", PROBE_TEST_PIN);
- SERIAL_PROTOCOLLNPGM(". uses Z_MIN_PROBE_ENDSTOP_INVERTING (ignores Z_MIN_ENDSTOP_INVERTING)");
- SERIAL_PROTOCOLPGM(". Z_MIN_PROBE_ENDSTOP_INVERTING: ");
- #if Z_MIN_PROBE_ENDSTOP_INVERTING
- SERIAL_PROTOCOLLNPGM("true");
- #else
- SERIAL_PROTOCOLLNPGM("false");
- #endif
- probe_inverting = Z_MIN_PROBE_ENDSTOP_INVERTING;
- #endif
- SERIAL_PROTOCOLLNPGM(". deploy & stow 4 times");
- SET_INPUT_PULLUP(PROBE_TEST_PIN);
- bool deploy_state, stow_state;
- for (uint8_t i = 0; i < 4; i++) {
- MOVE_SERVO(probe_index, z_servo_angle[0]);
- safe_delay(500);
- deploy_state = READ(PROBE_TEST_PIN);
- MOVE_SERVO(probe_index, z_servo_angle[1]);
- safe_delay(500);
- stow_state = READ(PROBE_TEST_PIN);
- }
- if (probe_inverting != deploy_state) SERIAL_PROTOCOLLNPGM("WARNING - INVERTING setting probably backwards");
- if (deploy_state != stow_state) {
- SERIAL_PROTOCOLLNPGM("BLTouch clone detected");
- if (deploy_state) {
- SERIAL_PROTOCOLLNPGM(". DEPLOYED state: HIGH (logic 1)");
- SERIAL_PROTOCOLLNPGM(". STOWED (triggered) state: LOW (logic 0)");
- }
- else {
- SERIAL_PROTOCOLLNPGM(". DEPLOYED state: LOW (logic 0)");
- SERIAL_PROTOCOLLNPGM(". STOWED (triggered) state: HIGH (logic 1)");
- }
- #if ENABLED(BLTOUCH)
- SERIAL_PROTOCOLLNPGM("ERROR: BLTOUCH enabled - set this device up as a Z Servo Probe with inverting as true.");
- #endif
- }
- else {
- MOVE_SERVO(probe_index, z_servo_angle[0]);
- safe_delay(500);
- SERIAL_PROTOCOLLNPGM("please trigger probe");
- uint16_t probe_counter = 0;
-
- for (uint16_t j = 0; j < 500 * 30 && probe_counter == 0 ; j++) {
- safe_delay(2);
- if (0 == j % (500 * 1)) reset_stepper_timeout();
- if (deploy_state != READ(PROBE_TEST_PIN)) {
- for (probe_counter = 1; probe_counter < 50 && deploy_state != READ(PROBE_TEST_PIN); ++probe_counter)
- safe_delay(2);
- if (probe_counter == 50)
- SERIAL_PROTOCOLLNPGM("Z Servo Probe detected");
- else if (probe_counter >= 2)
- SERIAL_PROTOCOLLNPAIR("BLTouch compatible probe detected - pulse width (+/- 4mS): ", probe_counter * 2);
- else
- SERIAL_PROTOCOLLNPGM("noise detected - please re-run test");
- MOVE_SERVO(probe_index, z_servo_angle[1]);
- }
- }
- if (probe_counter == 0) SERIAL_PROTOCOLLNPGM("trigger not detected");
- }
- #endif
- }
-
- inline void gcode_M43() {
- if (parser.seen('T')) {
- toggle_pins();
- return;
- }
-
- if (parser.seen('E')) {
- endstops.monitor_flag = parser.value_bool();
- SERIAL_PROTOCOLPGM("endstop monitor ");
- serialprintPGM(endstops.monitor_flag ? PSTR("en") : PSTR("dis"));
- SERIAL_PROTOCOLLNPGM("abled");
- return;
- }
- if (parser.seen('S')) {
- servo_probe_test();
- return;
- }
-
- const pin_t first_pin = parser.byteval('P'),
- last_pin = parser.seenval('P') ? first_pin : NUM_DIGITAL_PINS - 1;
- if (first_pin > last_pin) return;
- const bool ignore_protection = parser.boolval('I');
-
- if (parser.boolval('W')) {
- SERIAL_PROTOCOLLNPGM("Watching pins");
- byte pin_state[last_pin - first_pin + 1];
- for (pin_t pin = first_pin; pin <= last_pin; pin++) {
- if (!ignore_protection && pin_is_protected(pin)) continue;
- pinMode(pin, INPUT_PULLUP);
- delay(1);
-
|