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 41KB

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