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

Marlin.pde 40KB

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