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.

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