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

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