My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Marlin.pde 40KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295
  1. /*
  2. Reprap firmware based on Sprinter and grbl.
  3. Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. This firmware is a mashup between Sprinter and grbl.
  17. (https://github.com/kliment/Sprinter)
  18. (https://github.com/simen/grbl/tree)
  19. It has preliminary support for Matthew Roberts advance algorithm
  20. http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
  21. */
  22. #include "EEPROMwrite.h"
  23. #include "fastio.h"
  24. #include "Configuration.h"
  25. #include "pins.h"
  26. #include "Marlin.h"
  27. #include "ultralcd.h"
  28. #include "streaming.h"
  29. #include "planner.h"
  30. #include "stepper.h"
  31. #include "temperature.h"
  32. #include "motion_control.h"
  33. #ifdef SIMPLE_LCD
  34. #include "Simplelcd.h"
  35. #endif
  36. char version_string[] = "1.0.0 Alpha 1";
  37. #ifdef SDSUPPORT
  38. #include "SdFat.h"
  39. #endif //SDSUPPORT
  40. // look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html
  41. // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
  42. //Implemented Codes
  43. //-------------------
  44. // G0 -> G1
  45. // G1 - Coordinated Movement X Y Z E
  46. // G2 - CW ARC
  47. // G3 - CCW ARC
  48. // G4 - Dwell S<seconds> or P<milliseconds>
  49. // G28 - Home all Axis
  50. // G90 - Use Absolute Coordinates
  51. // G91 - Use Relative Coordinates
  52. // G92 - Set current position to cordinates given
  53. //RepRap M Codes
  54. // M104 - Set extruder target temp
  55. // M105 - Read current temp
  56. // M106 - Fan on
  57. // M107 - Fan off
  58. // M109 - Wait for extruder current temp to reach target temp.
  59. // M114 - Display current position
  60. //Custom M Codes
  61. // M20 - List SD card
  62. // M21 - Init SD card
  63. // M22 - Release SD card
  64. // M23 - Select SD file (M23 filename.g)
  65. // M24 - Start/resume SD print
  66. // M25 - Pause SD print
  67. // M26 - Set SD position in bytes (M26 S12345)
  68. // M27 - Report SD print status
  69. // M28 - Start SD write (M28 filename.g)
  70. // M29 - Stop SD write
  71. // M42 - Change pin status via gcode
  72. // M80 - Turn on Power Supply
  73. // M81 - Turn off Power Supply
  74. // M82 - Set E codes absolute (default)
  75. // M83 - Set E codes relative while in Absolute Coordinates (G90) mode
  76. // M84 - Disable steppers until next move,
  77. // or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout.
  78. // M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
  79. // M92 - Set axis_steps_per_unit - same syntax as G92
  80. // M115 - Capabilities string
  81. // M140 - Set bed target temp
  82. // M190 - Wait for bed current temp to reach target temp.
  83. // M200 - Set filament diameter
  84. // M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
  85. // M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
  86. // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
  87. // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate
  88. // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
  89. // M220 - set speed factor override percentage S:factor in percent
  90. // M301 - Set PID parameters P I and D
  91. // M500 - stores paramters in EEPROM
  92. // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). D
  93. // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
  94. //Stepper Movement Variables
  95. char axis_codes[NUM_AXIS] = {
  96. 'X', 'Y', 'Z', 'E'};
  97. float destination[NUM_AXIS] = {
  98. 0.0, 0.0, 0.0, 0.0};
  99. float current_position[NUM_AXIS] = {
  100. 0.0, 0.0, 0.0, 0.0};
  101. float offset[3] = {0.0, 0.0, 0.0};
  102. bool home_all_axis = true;
  103. float feedrate = 1500.0, next_feedrate, saved_feedrate;
  104. long gcode_N, gcode_LastN;
  105. float homing_feedrate[] = HOMING_FEEDRATE;
  106. bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
  107. bool relative_mode = false; //Determines Absolute or Relative Coordinates
  108. bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode.
  109. uint8_t fanpwm=0;
  110. volatile int feedmultiply=100; //100->1 200->2
  111. int saved_feedmultiply;
  112. volatile bool feedmultiplychanged=false;
  113. // comm variables
  114. #define MAX_CMD_SIZE 96
  115. #define BUFSIZE 4
  116. char cmdbuffer[BUFSIZE][MAX_CMD_SIZE];
  117. bool fromsd[BUFSIZE];
  118. int bufindr = 0;
  119. int bufindw = 0;
  120. int buflen = 0;
  121. int i = 0;
  122. char serial_char;
  123. int serial_count = 0;
  124. boolean comment_mode = false;
  125. char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc
  126. extern float HeaterPower;
  127. #include "EEPROM.h"
  128. const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
  129. float tt = 0, bt = 0;
  130. //Inactivity shutdown variables
  131. unsigned long previous_millis_cmd = 0;
  132. unsigned long max_inactive_time = 0;
  133. unsigned long stepper_inactive_time = 0;
  134. unsigned long starttime=0;
  135. unsigned long stoptime=0;
  136. #ifdef SDSUPPORT
  137. Sd2Card card;
  138. SdVolume volume;
  139. SdFile root;
  140. SdFile file;
  141. uint32_t filesize = 0;
  142. uint32_t sdpos = 0;
  143. bool sdmode = false;
  144. bool sdactive = false;
  145. bool savetosd = false;
  146. int16_t n;
  147. unsigned long autostart_atmillis=0;
  148. void initsd(){
  149. sdactive = false;
  150. #if SDSS >- 1
  151. if(root.isOpen())
  152. root.close();
  153. if (!card.init(SPI_FULL_SPEED,SDSS)){
  154. //if (!card.init(SPI_HALF_SPEED,SDSS))
  155. Serial.println("SD init fail");
  156. }
  157. else if (!volume.init(&card))
  158. Serial.println("volume.init failed");
  159. else if (!root.openRoot(&volume))
  160. Serial.println("openRoot failed");
  161. else
  162. {
  163. sdactive = true;
  164. Serial.println("SD card ok");
  165. }
  166. #endif //SDSS
  167. }
  168. void quickinitsd(){
  169. sdactive=false;
  170. autostart_atmillis=millis()+5000;
  171. }
  172. inline void write_command(char *buf){
  173. char* begin = buf;
  174. char* npos = 0;
  175. char* end = buf + strlen(buf) - 1;
  176. file.writeError = false;
  177. if((npos = strchr(buf, 'N')) != NULL){
  178. begin = strchr(npos, ' ') + 1;
  179. end = strchr(npos, '*') - 1;
  180. }
  181. end[1] = '\r';
  182. end[2] = '\n';
  183. end[3] = '\0';
  184. //Serial.println(begin);
  185. file.write(begin);
  186. if (file.writeError){
  187. Serial.println("error writing to file");
  188. }
  189. }
  190. #endif //SDSUPPORT
  191. ///adds an command to the main command buffer
  192. void enquecommand(const char *cmd)
  193. {
  194. if(buflen < BUFSIZE)
  195. {
  196. //this is dangerous if a mixing of serial and this happsens
  197. strcpy(&(cmdbuffer[bufindw][0]),cmd);
  198. Serial.print("en:");Serial.println(cmdbuffer[bufindw]);
  199. bufindw= (bufindw + 1)%BUFSIZE;
  200. buflen += 1;
  201. }
  202. }
  203. void setup()
  204. {
  205. Serial.begin(BAUDRATE);
  206. ECHOLN("Marlin "<<version_string);
  207. Serial.println("start");
  208. #if defined FANCY_LCD || defined SIMPLE_LCD
  209. lcd_init();
  210. #endif
  211. for(int i = 0; i < BUFSIZE; i++){
  212. fromsd[i] = false;
  213. }
  214. RetrieveSettings(); // loads data from EEPROM if available
  215. for(int i=0; i < NUM_AXIS; i++){
  216. axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
  217. }
  218. #ifdef SDSUPPORT
  219. //power to SD reader
  220. #if SDPOWER > -1
  221. SET_OUTPUT(SDPOWER);
  222. WRITE(SDPOWER,HIGH);
  223. #endif //SDPOWER
  224. quickinitsd();
  225. #endif //SDSUPPORT
  226. plan_init(); // Initialize planner;
  227. st_init(); // Initialize stepper;
  228. tp_init(); // Initialize temperature loop
  229. //checkautostart();
  230. }
  231. #ifdef SDSUPPORT
  232. bool autostart_stilltocheck=true;
  233. void checkautostart(bool force)
  234. {
  235. //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
  236. if(!force)
  237. {
  238. if(!autostart_stilltocheck)
  239. return;
  240. if(autostart_atmillis<millis())
  241. return;
  242. }
  243. autostart_stilltocheck=false;
  244. if(!sdactive)
  245. {
  246. initsd();
  247. if(!sdactive) //fail
  248. return;
  249. }
  250. static int lastnr=0;
  251. char autoname[30];
  252. sprintf(autoname,"auto%i.g",lastnr);
  253. for(int i=0;i<(int)strlen(autoname);i++)
  254. autoname[i]=tolower(autoname[i]);
  255. dir_t p;
  256. root.rewind();
  257. //char filename[11];
  258. //int cnt=0;
  259. bool found=false;
  260. while (root.readDir(p) > 0)
  261. {
  262. for(int i=0;i<(int)strlen((char*)p.name);i++)
  263. p.name[i]=tolower(p.name[i]);
  264. //Serial.print((char*)p.name);
  265. //Serial.print(" ");
  266. //Serial.println(autoname);
  267. if(p.name[9]!='~') //skip safety copies
  268. if(strncmp((char*)p.name,autoname,5)==0)
  269. {
  270. char cmd[30];
  271. sprintf(cmd,"M23 %s",autoname);
  272. //sprintf(cmd,"M115");
  273. //enquecommand("G92 Z0");
  274. //enquecommand("G1 Z10 F2000");
  275. //enquecommand("G28 X-105 Y-105");
  276. enquecommand(cmd);
  277. enquecommand("M24");
  278. found=true;
  279. }
  280. }
  281. if(!found)
  282. lastnr=-1;
  283. else
  284. lastnr++;
  285. }
  286. #else
  287. inline void checkautostart(bool x)
  288. {
  289. }
  290. #endif
  291. void loop()
  292. {
  293. if(buflen<3)
  294. get_command();
  295. checkautostart(false);
  296. if(buflen)
  297. {
  298. #ifdef SDSUPPORT
  299. if(savetosd){
  300. if(strstr(cmdbuffer[bufindr],"M29") == NULL){
  301. write_command(cmdbuffer[bufindr]);
  302. Serial.println("ok");
  303. }
  304. else{
  305. file.sync();
  306. file.close();
  307. savetosd = false;
  308. Serial.println("Done saving file.");
  309. }
  310. }
  311. else{
  312. process_commands();
  313. }
  314. #else
  315. process_commands();
  316. #endif //SDSUPPORT
  317. buflen = (buflen-1);
  318. bufindr = (bufindr + 1)%BUFSIZE;
  319. }
  320. //check heater every n milliseconds
  321. manage_heater();
  322. manage_inactivity(1);
  323. LCD_STATUS;
  324. }
  325. inline void get_command()
  326. {
  327. while( Serial.available() > 0 && buflen < BUFSIZE) {
  328. serial_char = Serial.read();
  329. if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) )
  330. {
  331. if(!serial_count) return; //if empty line
  332. cmdbuffer[bufindw][serial_count] = 0; //terminate string
  333. if(!comment_mode){
  334. fromsd[bufindw] = false;
  335. if(strstr(cmdbuffer[bufindw], "N") != NULL)
  336. {
  337. strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
  338. gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));
  339. if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) {
  340. Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:");
  341. Serial.println(gcode_LastN);
  342. //Serial.println(gcode_N);
  343. FlushSerialRequestResend();
  344. serial_count = 0;
  345. return;
  346. }
  347. if(strstr(cmdbuffer[bufindw], "*") != NULL)
  348. {
  349. byte checksum = 0;
  350. byte count = 0;
  351. while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
  352. strchr_pointer = strchr(cmdbuffer[bufindw], '*');
  353. if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) {
  354. Serial.print("Error: checksum mismatch, Last Line:");
  355. Serial.println(gcode_LastN);
  356. FlushSerialRequestResend();
  357. serial_count = 0;
  358. return;
  359. }
  360. //if no errors, continue parsing
  361. }
  362. else
  363. {
  364. Serial.print("Error: No Checksum with line number, Last Line:");
  365. Serial.println(gcode_LastN);
  366. FlushSerialRequestResend();
  367. serial_count = 0;
  368. return;
  369. }
  370. gcode_LastN = gcode_N;
  371. //if no errors, continue parsing
  372. }
  373. else // if we don't receive 'N' but still see '*'
  374. {
  375. if((strstr(cmdbuffer[bufindw], "*") != NULL))
  376. {
  377. Serial.print("Error: No Line Number with checksum, Last Line:");
  378. Serial.println(gcode_LastN);
  379. serial_count = 0;
  380. return;
  381. }
  382. }
  383. if((strstr(cmdbuffer[bufindw], "G") != NULL)){
  384. strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
  385. switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){
  386. case 0:
  387. case 1:
  388. case 2:
  389. case 3:
  390. #ifdef SDSUPPORT
  391. if(savetosd)
  392. break;
  393. #endif //SDSUPPORT
  394. Serial.println("ok");
  395. break;
  396. default:
  397. break;
  398. }
  399. }
  400. bufindw = (bufindw + 1)%BUFSIZE;
  401. buflen += 1;
  402. }
  403. comment_mode = false; //for new command
  404. serial_count = 0; //clear buffer
  405. }
  406. else
  407. {
  408. if(serial_char == ';') comment_mode = true;
  409. if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
  410. }
  411. }
  412. #ifdef SDSUPPORT
  413. if(!sdmode || serial_count!=0){
  414. return;
  415. }
  416. while( filesize > sdpos && buflen < BUFSIZE) {
  417. n = file.read();
  418. serial_char = (char)n;
  419. if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1)
  420. {
  421. sdpos = file.curPosition();
  422. if(sdpos >= filesize){
  423. sdmode = false;
  424. Serial.println("Done printing file");
  425. stoptime=millis();
  426. char time[30];
  427. unsigned long t=(stoptime-starttime)/1000;
  428. int sec,min;
  429. min=t/60;
  430. sec=t%60;
  431. sprintf(time,"%i min, %i sec",min,sec);
  432. Serial.println(time);
  433. LCD_MESSAGE(time);
  434. checkautostart(true);
  435. }
  436. if(!serial_count) return; //if empty line
  437. cmdbuffer[bufindw][serial_count] = 0; //terminate string
  438. if(!comment_mode){
  439. fromsd[bufindw] = true;
  440. buflen += 1;
  441. bufindw = (bufindw + 1)%BUFSIZE;
  442. }
  443. comment_mode = false; //for new command
  444. serial_count = 0; //clear buffer
  445. }
  446. else
  447. {
  448. if(serial_char == ';') comment_mode = true;
  449. if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
  450. }
  451. }
  452. #endif //SDSUPPORT
  453. }
  454. inline float code_value() {
  455. return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL));
  456. }
  457. inline long code_value_long() {
  458. return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10));
  459. }
  460. inline bool code_seen(char code_string[]) {
  461. return (strstr(cmdbuffer[bufindr], code_string) != NULL);
  462. } //Return True if the string was found
  463. inline bool code_seen(char code)
  464. {
  465. strchr_pointer = strchr(cmdbuffer[bufindr], code);
  466. return (strchr_pointer != NULL); //Return True if a character was found
  467. }
  468. inline void process_commands()
  469. {
  470. unsigned long codenum; //throw away variable
  471. char *starpos = NULL;
  472. if(code_seen('G'))
  473. {
  474. switch((int)code_value())
  475. {
  476. case 0: // G0 -> G1
  477. case 1: // G1
  478. get_coordinates(); // For X Y Z E F
  479. prepare_move();
  480. previous_millis_cmd = millis();
  481. //ClearToSend();
  482. return;
  483. //break;
  484. case 2: // G2 - CW ARC
  485. get_arc_coordinates();
  486. prepare_arc_move(true);
  487. previous_millis_cmd = millis();
  488. return;
  489. case 3: // G3 - CCW ARC
  490. get_arc_coordinates();
  491. prepare_arc_move(false);
  492. previous_millis_cmd = millis();
  493. return;
  494. case 4: // G4 dwell
  495. codenum = 0;
  496. if(code_seen('P')) codenum = code_value(); // milliseconds to wait
  497. if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
  498. codenum += millis(); // keep track of when we started waiting
  499. while(millis() < codenum ){
  500. manage_heater();
  501. }
  502. break;
  503. case 28: //G28 Home all Axis one at a time
  504. saved_feedrate = feedrate;
  505. saved_feedmultiply = feedmultiply;
  506. feedmultiply = 100;
  507. for(int i=0; i < NUM_AXIS; i++) {
  508. destination[i] = current_position[i];
  509. }
  510. feedrate = 0.0;
  511. home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2])));
  512. if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) {
  513. if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){
  514. // st_synchronize();
  515. current_position[X_AXIS] = 0;
  516. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  517. destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;
  518. feedrate = homing_feedrate[X_AXIS];
  519. prepare_move();
  520. // st_synchronize();
  521. current_position[X_AXIS] = 0;
  522. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  523. destination[X_AXIS] = -5 * X_HOME_DIR;
  524. prepare_move();
  525. // st_synchronize();
  526. destination[X_AXIS] = 10 * X_HOME_DIR;
  527. feedrate = homing_feedrate[X_AXIS]/2 ;
  528. prepare_move();
  529. // st_synchronize();
  530. current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH;
  531. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  532. destination[X_AXIS] = current_position[X_AXIS];
  533. feedrate = 0.0;
  534. }
  535. }
  536. if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
  537. if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){
  538. current_position[Y_AXIS] = 0;
  539. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  540. destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;
  541. feedrate = homing_feedrate[Y_AXIS];
  542. prepare_move();
  543. // st_synchronize();
  544. current_position[Y_AXIS] = 0;
  545. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  546. destination[Y_AXIS] = -5 * Y_HOME_DIR;
  547. prepare_move();
  548. // st_synchronize();
  549. destination[Y_AXIS] = 10 * Y_HOME_DIR;
  550. feedrate = homing_feedrate[Y_AXIS]/2;
  551. prepare_move();
  552. // st_synchronize();
  553. current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH;
  554. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  555. destination[Y_AXIS] = current_position[Y_AXIS];
  556. feedrate = 0.0;
  557. }
  558. }
  559. if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
  560. if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){
  561. current_position[Z_AXIS] = 0;
  562. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  563. destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR;
  564. feedrate = homing_feedrate[Z_AXIS];
  565. prepare_move();
  566. // st_synchronize();
  567. current_position[Z_AXIS] = 0;
  568. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  569. destination[Z_AXIS] = -2 * Z_HOME_DIR;
  570. prepare_move();
  571. // st_synchronize();
  572. destination[Z_AXIS] = 3 * Z_HOME_DIR;
  573. feedrate = homing_feedrate[Z_AXIS]/2;
  574. prepare_move();
  575. // st_synchronize();
  576. current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH;
  577. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  578. destination[Z_AXIS] = current_position[Z_AXIS];
  579. feedrate = 0.0;
  580. }
  581. }
  582. feedrate = saved_feedrate;
  583. feedmultiply = saved_feedmultiply;
  584. previous_millis_cmd = millis();
  585. break;
  586. case 90: // G90
  587. relative_mode = false;
  588. break;
  589. case 91: // G91
  590. relative_mode = true;
  591. break;
  592. case 92: // G92
  593. if(!code_seen(axis_codes[E_AXIS]))
  594. st_synchronize();
  595. for(int i=0; i < NUM_AXIS; i++) {
  596. if(code_seen(axis_codes[i])) current_position[i] = code_value();
  597. }
  598. plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
  599. break;
  600. }
  601. }
  602. else if(code_seen('M'))
  603. {
  604. switch( (int)code_value() )
  605. {
  606. #ifdef SDSUPPORT
  607. case 20: // M20 - list SD card
  608. Serial.println("Begin file list");
  609. root.ls();
  610. Serial.println("End file list");
  611. break;
  612. case 21: // M21 - init SD card
  613. sdmode = false;
  614. initsd();
  615. break;
  616. case 22: //M22 - release SD card
  617. sdmode = false;
  618. sdactive = false;
  619. break;
  620. case 23: //M23 - Select file
  621. if(sdactive){
  622. sdmode = false;
  623. file.close();
  624. starpos = (strchr(strchr_pointer + 4,'*'));
  625. if(starpos!=NULL)
  626. *(starpos-1)='\0';
  627. if (file.open(&root, strchr_pointer + 4, O_READ)) {
  628. Serial.print("File opened:");
  629. Serial.print(strchr_pointer + 4);
  630. Serial.print(" Size:");
  631. Serial.println(file.fileSize());
  632. sdpos = 0;
  633. filesize = file.fileSize();
  634. Serial.println("File selected");
  635. }
  636. else{
  637. Serial.println("file.open failed");
  638. }
  639. }
  640. break;
  641. case 24: //M24 - Start SD print
  642. if(sdactive){
  643. sdmode = true;
  644. starttime=millis();
  645. }
  646. break;
  647. case 25: //M25 - Pause SD print
  648. if(sdmode){
  649. sdmode = false;
  650. }
  651. break;
  652. case 26: //M26 - Set SD index
  653. if(sdactive && code_seen('S')){
  654. sdpos = code_value_long();
  655. file.seekSet(sdpos);
  656. }
  657. break;
  658. case 27: //M27 - Get SD status
  659. if(sdactive){
  660. Serial.print("SD printing byte ");
  661. Serial.print(sdpos);
  662. Serial.print("/");
  663. Serial.println(filesize);
  664. }
  665. else{
  666. Serial.println("Not SD printing");
  667. }
  668. break;
  669. case 28: //M28 - Start SD write
  670. if(sdactive){
  671. char* npos = 0;
  672. file.close();
  673. sdmode = false;
  674. starpos = (strchr(strchr_pointer + 4,'*'));
  675. if(starpos != NULL){
  676. npos = strchr(cmdbuffer[bufindr], 'N');
  677. strchr_pointer = strchr(npos,' ') + 1;
  678. *(starpos-1) = '\0';
  679. }
  680. if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
  681. {
  682. Serial.print("open failed, File: ");
  683. Serial.print(strchr_pointer + 4);
  684. Serial.print(".");
  685. }
  686. else{
  687. savetosd = true;
  688. Serial.print("Writing to file: ");
  689. Serial.println(strchr_pointer + 4);
  690. }
  691. }
  692. break;
  693. case 29: //M29 - Stop SD write
  694. //processed in write to file routine above
  695. //savetosd = false;
  696. break;
  697. case 30:
  698. {
  699. stoptime=millis();
  700. char time[30];
  701. unsigned long t=(stoptime-starttime)/1000;
  702. int sec,min;
  703. min=t/60;
  704. sec=t%60;
  705. sprintf(time,"%i min, %i sec",min,sec);
  706. Serial.println(time);
  707. LCD_MESSAGE(time);
  708. }
  709. break;
  710. #endif //SDSUPPORT
  711. case 42: //M42 -Change pin status via gcode
  712. if (code_seen('S'))
  713. {
  714. int pin_status = code_value();
  715. if (code_seen('P') && pin_status >= 0 && pin_status <= 255)
  716. {
  717. int pin_number = code_value();
  718. for(int i = 0; i < (int)sizeof(sensitive_pins); i++)
  719. {
  720. if (sensitive_pins[i] == pin_number)
  721. {
  722. pin_number = -1;
  723. break;
  724. }
  725. }
  726. if (pin_number > -1)
  727. {
  728. pinMode(pin_number, OUTPUT);
  729. digitalWrite(pin_number, pin_status);
  730. analogWrite(pin_number, pin_status);
  731. }
  732. }
  733. }
  734. break;
  735. case 104: // M104
  736. if (code_seen('S')) setTargetHotend0(code_value());
  737. setWatch();
  738. break;
  739. case 140: // M140 set bed temp
  740. if (code_seen('S')) setTargetBed(code_value());
  741. break;
  742. case 105: // M105
  743. #if (TEMP_0_PIN > -1) || defined (HEATER_USES_AD595)
  744. tt = degHotend0();
  745. #endif
  746. #if TEMP_1_PIN > -1
  747. bt = degBed();
  748. #endif
  749. #if (TEMP_0_PIN > -1) || defined (HEATER_USES_AD595)
  750. Serial.print("ok T:");
  751. Serial.print(tt);
  752. // Serial.print(", raw:");
  753. // Serial.print(current_raw);
  754. #if TEMP_1_PIN > -1
  755. #ifdef PIDTEMP
  756. Serial.print(" B:");
  757. #if TEMP_1_PIN > -1
  758. Serial.println(bt);
  759. #else
  760. Serial.println(HeaterPower);
  761. #endif
  762. #else
  763. Serial.println();
  764. #endif
  765. #else
  766. Serial.println();
  767. #endif
  768. #else
  769. Serial.println("No thermistors - no temp");
  770. #endif
  771. return;
  772. //break;
  773. case 109: {// M109 - Wait for extruder heater to reach target.
  774. LCD_MESSAGE("Heating...");
  775. if (code_seen('S')) setTargetHotend0(code_value());
  776. setWatch();
  777. codenum = millis();
  778. /* See if we are heating up or cooling down */
  779. bool target_direction = isHeatingHotend0(); // true if heating, false if cooling
  780. #ifdef TEMP_RESIDENCY_TIME
  781. long residencyStart;
  782. residencyStart = -1;
  783. /* continue to loop until we have reached the target temp
  784. _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
  785. while((target_direction ? (isHeatingHotend0()) : (isCoolingHotend0()) ||
  786. (residencyStart > -1 && (millis() - residencyStart) < TEMP_RESIDENCY_TIME*1000) ) {
  787. #else
  788. while ( target_direction ? (isHeatingHotend0()) : (isCoolingHotend0()) ) {
  789. #endif //TEMP_RESIDENCY_TIME
  790. if( (millis() - codenum) > 1000 ) { //Print Temp Reading every 1 second while heating up/cooling down
  791. Serial.print("T:");
  792. Serial.println( degHotend0() );
  793. codenum = millis();
  794. }
  795. manage_heater();
  796. LCD_STATUS;
  797. #ifdef TEMP_RESIDENCY_TIME
  798. /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
  799. or when current temp falls outside the hysteresis after target temp was reached */
  800. if ((residencyStart == -1 && target_direction && !isHeatingHotend0()) ||
  801. (residencyStart == -1 && !target_direction && !isCoolingHotend0()) ||
  802. (residencyStart > -1 && labs(degHotend0() - degTargetHotend0()) > TEMP_HYSTERESIS) ) {
  803. residencyStart = millis();
  804. }
  805. #endif //TEMP_RESIDENCY_TIME
  806. }
  807. LCD_MESSAGE("Marlin ready.");
  808. }
  809. break;
  810. case 190: // M190 - Wait bed for heater to reach target.
  811. #if TEMP_1_PIN > -1
  812. if (code_seen('S')) setTargetBed(code_value());
  813. codenum = millis();
  814. while(isHeatingBed())
  815. {
  816. if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
  817. {
  818. float tt=degHotend0();
  819. Serial.print("T:");
  820. Serial.println( tt );
  821. Serial.print("ok T:");
  822. Serial.print( tt );
  823. Serial.print(" B:");
  824. Serial.println( degBed() );
  825. codenum = millis();
  826. }
  827. manage_heater();
  828. }
  829. #endif
  830. break;
  831. #if FAN_PIN > -1
  832. case 106: //M106 Fan On
  833. if (code_seen('S')){
  834. WRITE(FAN_PIN,HIGH);
  835. fanpwm=constrain(code_value(),0,255);
  836. analogWrite(FAN_PIN, fanpwm);
  837. }
  838. else {
  839. WRITE(FAN_PIN,HIGH);
  840. fanpwm=255;
  841. analogWrite(FAN_PIN, fanpwm);
  842. }
  843. break;
  844. case 107: //M107 Fan Off
  845. WRITE(FAN_PIN,LOW);
  846. analogWrite(FAN_PIN, 0);
  847. break;
  848. #endif
  849. #if (PS_ON_PIN > -1)
  850. case 80: // M80 - ATX Power On
  851. SET_OUTPUT(PS_ON_PIN); //GND
  852. break;
  853. case 81: // M81 - ATX Power Off
  854. SET_INPUT(PS_ON_PIN); //Floating
  855. break;
  856. #endif
  857. case 82:
  858. axis_relative_modes[3] = false;
  859. break;
  860. case 83:
  861. axis_relative_modes[3] = true;
  862. break;
  863. case 18:
  864. case 84:
  865. if(code_seen('S')){
  866. stepper_inactive_time = code_value() * 1000;
  867. }
  868. else{
  869. st_synchronize();
  870. disable_x();
  871. disable_y();
  872. disable_z();
  873. disable_e();
  874. }
  875. break;
  876. case 85: // M85
  877. code_seen('S');
  878. max_inactive_time = code_value() * 1000;
  879. break;
  880. case 92: // M92
  881. for(int i=0; i < NUM_AXIS; i++) {
  882. if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value();
  883. }
  884. break;
  885. case 115: // M115
  886. Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1");
  887. break;
  888. case 114: // M114
  889. Serial.print("X:");
  890. Serial.print(current_position[X_AXIS]);
  891. Serial.print("Y:");
  892. Serial.print(current_position[Y_AXIS]);
  893. Serial.print("Z:");
  894. Serial.print(current_position[Z_AXIS]);
  895. Serial.print("E:");
  896. Serial.print(current_position[E_AXIS]);
  897. #ifdef DEBUG_STEPS
  898. Serial.print(" Count X:");
  899. Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]);
  900. Serial.print("Y:");
  901. Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]);
  902. Serial.print("Z:");
  903. Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]);
  904. #endif
  905. Serial.println("");
  906. break;
  907. case 119: // M119
  908. #if (X_MIN_PIN > -1)
  909. Serial.print("x_min:");
  910. Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  911. #endif
  912. #if (X_MAX_PIN > -1)
  913. Serial.print("x_max:");
  914. Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  915. #endif
  916. #if (Y_MIN_PIN > -1)
  917. Serial.print("y_min:");
  918. Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  919. #endif
  920. #if (Y_MAX_PIN > -1)
  921. Serial.print("y_max:");
  922. Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  923. #endif
  924. #if (Z_MIN_PIN > -1)
  925. Serial.print("z_min:");
  926. Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  927. #endif
  928. #if (Z_MAX_PIN > -1)
  929. Serial.print("z_max:");
  930. Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L ");
  931. #endif
  932. Serial.println("");
  933. break;
  934. //TODO: update for all axis, use for loop
  935. case 201: // M201
  936. for(int i=0; i < NUM_AXIS; i++) {
  937. if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
  938. }
  939. break;
  940. #if 0 // Not used for Sprinter/grbl gen6
  941. case 202: // M202
  942. for(int i=0; i < NUM_AXIS; i++) {
  943. if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
  944. }
  945. break;
  946. #endif
  947. case 203: // M203 max feedrate mm/sec
  948. for(int i=0; i < NUM_AXIS; i++) {
  949. if(code_seen(axis_codes[i])) max_feedrate[i] = code_value()*60 ;
  950. }
  951. break;
  952. case 204: // M204 acclereration S normal moves T filmanent only moves
  953. {
  954. if(code_seen('S')) acceleration = code_value() ;
  955. if(code_seen('T')) retract_acceleration = code_value() ;
  956. }
  957. break;
  958. case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
  959. {
  960. if(code_seen('S')) minimumfeedrate = code_value()*60 ;
  961. if(code_seen('T')) mintravelfeedrate = code_value()*60 ;
  962. if(code_seen('B')) minsegmenttime = code_value() ;
  963. if(code_seen('X')) max_xy_jerk = code_value()*60 ;
  964. if(code_seen('Z')) max_z_jerk = code_value()*60 ;
  965. }
  966. break;
  967. case 220: // M220 S<factor in percent>- set speed factor override percentage
  968. {
  969. if(code_seen('S'))
  970. {
  971. feedmultiply = code_value() ;
  972. feedmultiplychanged=true;
  973. }
  974. }
  975. break;
  976. #ifdef PIDTEMP
  977. case 301: // M301
  978. if(code_seen('P')) Kp = code_value();
  979. if(code_seen('I')) Ki = code_value()*PID_dT;
  980. if(code_seen('D')) Kd = code_value()/PID_dT;
  981. // ECHOLN("Kp "<<_FLOAT(Kp,2));
  982. // ECHOLN("Ki "<<_FLOAT(Ki/PID_dT,2));
  983. // ECHOLN("Kd "<<_FLOAT(Kd*PID_dT,2));
  984. // temp_iState_min = 0.0;
  985. // if (Ki!=0) {
  986. // temp_iState_max = PID_INTEGRAL_DRIVE_MAX / (Ki/100.0);
  987. // }
  988. // else temp_iState_max = 1.0e10;
  989. break;
  990. #endif //PIDTEMP
  991. case 500: // Store settings in EEPROM
  992. {
  993. StoreSettings();
  994. }
  995. break;
  996. case 501: // Read settings from EEPROM
  997. {
  998. RetrieveSettings();
  999. }
  1000. break;
  1001. case 502: // Revert to default settings
  1002. {
  1003. RetrieveSettings(true);
  1004. }
  1005. break;
  1006. }
  1007. }
  1008. else{
  1009. Serial.println("Unknown command:");
  1010. Serial.println(cmdbuffer[bufindr]);
  1011. }
  1012. ClearToSend();
  1013. }
  1014. void FlushSerialRequestResend()
  1015. {
  1016. //char cmdbuffer[bufindr][100]="Resend:";
  1017. Serial.flush();
  1018. Serial.print("Resend:");
  1019. Serial.println(gcode_LastN + 1);
  1020. ClearToSend();
  1021. }
  1022. void ClearToSend()
  1023. {
  1024. previous_millis_cmd = millis();
  1025. #ifdef SDSUPPORT
  1026. if(fromsd[bufindr])
  1027. return;
  1028. #endif //SDSUPPORT
  1029. Serial.println("ok");
  1030. }
  1031. inline void get_coordinates()
  1032. {
  1033. for(int i=0; i < NUM_AXIS; i++) {
  1034. if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i];
  1035. else destination[i] = current_position[i]; //Are these else lines really needed?
  1036. }
  1037. if(code_seen('F')) {
  1038. next_feedrate = code_value();
  1039. if(next_feedrate > 0.0) feedrate = next_feedrate;
  1040. }
  1041. }
  1042. inline void get_arc_coordinates()
  1043. {
  1044. get_coordinates();
  1045. if(code_seen("I")) offset[0] = code_value();
  1046. if(code_seen("J")) offset[1] = code_value();
  1047. }
  1048. void prepare_move()
  1049. {
  1050. plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.0);
  1051. for(int i=0; i < NUM_AXIS; i++) {
  1052. current_position[i] = destination[i];
  1053. }
  1054. }
  1055. void prepare_arc_move(char isclockwise) {
  1056. #if 0
  1057. if (radius_mode) {
  1058. /*
  1059. We need to calculate the center of the circle that has the designated radius and passes
  1060. through both the current position and the target position. This method calculates the following
  1061. set of equations where [x,y] is the vector from current to target position, d == magnitude of
  1062. that vector, h == hypotenuse of the triangle formed by the radius of the circle, the distance to
  1063. the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the
  1064. length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point
  1065. [i,j] at [x/2-y/d*h, y/2+x/d*h] which will be the center of our arc.
  1066. d^2 == x^2 + y^2
  1067. h^2 == r^2 - (d/2)^2
  1068. i == x/2 - y/d*h
  1069. j == y/2 + x/d*h
  1070. O <- [i,j]
  1071. - |
  1072. r - |
  1073. - |
  1074. - | h
  1075. - |
  1076. [0,0] -> C -----------------+--------------- T <- [x,y]
  1077. | <------ d/2 ---->|
  1078. C - Current position
  1079. T - Target position
  1080. O - center of circle that pass through both C and T
  1081. d - distance from C to T
  1082. r - designated radius
  1083. h - distance from center of CT to O
  1084. Expanding the equations:
  1085. d -> sqrt(x^2 + y^2)
  1086. h -> sqrt(4 * r^2 - x^2 - y^2)/2
  1087. i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
  1088. j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
  1089. Which can be written:
  1090. i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
  1091. j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
  1092. Which we for size and speed reasons optimize to:
  1093. h_x2_div_d = sqrt(4 * r^2 - x^2 - y^2)/sqrt(x^2 + y^2)
  1094. i = (x - (y * h_x2_div_d))/2
  1095. j = (y + (x * h_x2_div_d))/2
  1096. */
  1097. // Calculate the change in position along each selected axis
  1098. double x = target[gc.plane_axis_0]-gc.position[gc.plane_axis_0];
  1099. double y = target[gc.plane_axis_1]-gc.position[gc.plane_axis_1];
  1100. clear_vector(offset);
  1101. double h_x2_div_d = -sqrt(4 * r*r - x*x - y*y)/hypot(x,y); // == -(h * 2 / d)
  1102. // If r is smaller than d, the arc is now traversing the complex plane beyond the reach of any
  1103. // real CNC, and thus - for practical reasons - we will terminate promptly:
  1104. if(isnan(h_x2_div_d)) { FAIL(STATUS_FLOATING_POINT_ERROR); return(gc.status_code); }
  1105. // Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below)
  1106. if (gc.motion_mode == MOTION_MODE_CCW_ARC) { h_x2_div_d = -h_x2_div_d; }
  1107. /* The counter clockwise circle lies to the left of the target direction. When offset is positive,
  1108. the left hand circle will be generated - when it is negative the right hand circle is generated.
  1109. T <-- Target position
  1110. ^
  1111. Clockwise circles with this center | Clockwise circles with this center will have
  1112. will have > 180 deg of angular travel | < 180 deg of angular travel, which is a good thing!
  1113. \ | /
  1114. center of arc when h_x2_div_d is positive -> x <----- | -----> x <- center of arc when h_x2_div_d is negative
  1115. |
  1116. |
  1117. C <-- Current position */
  1118. // Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!),
  1119. // even though it is advised against ever generating such circles in a single line of g-code. By
  1120. // inverting the sign of h_x2_div_d the center of the circles is placed on the opposite side of the line of
  1121. // travel and thus we get the unadvisably long arcs as prescribed.
  1122. if (r < 0) {
  1123. h_x2_div_d = -h_x2_div_d;
  1124. r = -r; // Finished with r. Set to positive for mc_arc
  1125. }
  1126. // Complete the operation by calculating the actual center of the arc
  1127. offset[gc.plane_axis_0] = 0.5*(x-(y*h_x2_div_d));
  1128. offset[gc.plane_axis_1] = 0.5*(y+(x*h_x2_div_d));
  1129. } else { // Offset mode specific computations
  1130. #endif
  1131. float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
  1132. // }
  1133. // Set clockwise/counter-clockwise sign for mc_arc computations
  1134. // uint8_t isclockwise = false;
  1135. // if (gc.motion_mode == MOTION_MODE_CW_ARC) { isclockwise = true; }
  1136. // Trace the arc
  1137. mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60.0/100.0, r, isclockwise);
  1138. // }
  1139. // As far as the parser is concerned, the position is now == target. In reality the
  1140. // motion control system might still be processing the action and the real tool position
  1141. // in any intermediate location.
  1142. for(int ii=0; ii < NUM_AXIS; ii++) {
  1143. current_position[ii] = destination[ii];
  1144. }
  1145. }
  1146. void manage_inactivity(byte debug) {
  1147. if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill();
  1148. if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) {
  1149. disable_x();
  1150. disable_y();
  1151. disable_z();
  1152. disable_e();
  1153. }
  1154. check_axes_activity();
  1155. }
  1156. void kill()
  1157. {
  1158. disable_heater();
  1159. disable_x();
  1160. disable_y();
  1161. disable_z();
  1162. disable_e();
  1163. if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT);
  1164. Serial.println("!! Printer halted. kill() called !!");
  1165. while(1); // Wait for reset
  1166. }