cmdqueue.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. #include <util/atomic.h>
  2. #include "cmdqueue.h"
  3. #include "cardreader.h"
  4. #include "ultralcd.h"
  5. #include "Prusa_farm.h"
  6. // Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
  7. char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
  8. // Head of the circular buffer, where to read.
  9. size_t bufindr = 0;
  10. // Tail of the buffer, where to write.
  11. static size_t bufindw = 0;
  12. // Number of lines in cmdbuffer.
  13. int buflen = 0;
  14. // Flag for processing the current command inside the main Arduino loop().
  15. // If a new command was pushed to the front of a command buffer while
  16. // processing another command, this replaces the command on the top.
  17. // Therefore don't remove the command from the queue in the loop() function.
  18. bool cmdbuffer_front_already_processed = false;
  19. // Used for temporarely preventing accidental adding of Serial commands to the queue.
  20. // For now only check_file and the fancheck pause use this.
  21. bool cmdqueue_serial_disabled = false;
  22. int serial_count = 0; //index of character read from serial line
  23. bool comment_mode = false;
  24. char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
  25. ShortTimer serialTimeoutTimer;
  26. long gcode_LastN = 0;
  27. uint32_t sdpos_atomic = 0;
  28. // Pop the currently processed command from the queue.
  29. // It is expected, that there is at least one command in the queue.
  30. bool cmdqueue_pop_front()
  31. {
  32. if (buflen > 0) {
  33. #ifdef CMDBUFFER_DEBUG
  34. SERIAL_ECHOPGM("Dequeing ");
  35. SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE);
  36. SERIAL_ECHOLNPGM("");
  37. SERIAL_ECHOPGM("Old indices: buflen ");
  38. SERIAL_ECHO(buflen);
  39. SERIAL_ECHOPGM(", bufindr ");
  40. SERIAL_ECHO(bufindr);
  41. SERIAL_ECHOPGM(", bufindw ");
  42. SERIAL_ECHO(bufindw);
  43. SERIAL_ECHOPGM(", serial_count ");
  44. SERIAL_ECHO(serial_count);
  45. SERIAL_ECHOPGM(", bufsize ");
  46. SERIAL_ECHO(sizeof(cmdbuffer));
  47. SERIAL_ECHOLNPGM("");
  48. #endif /* CMDBUFFER_DEBUG */
  49. if (-- buflen == 0) {
  50. // Empty buffer.
  51. if (serial_count == 0)
  52. // No serial communication is pending. Reset both pointers to zero.
  53. bufindw = 0;
  54. bufindr = bufindw;
  55. } else {
  56. // There is at least one ready line in the buffer.
  57. // First skip the current command ID and iterate up to the end of the string.
  58. for (bufindr += CMDHDRSIZE; cmdbuffer[bufindr] != 0; ++ bufindr) ;
  59. // Second, skip the end of string null character and iterate until a nonzero command ID is found.
  60. for (++ bufindr; bufindr < sizeof(cmdbuffer) && cmdbuffer[bufindr] == 0; ++ bufindr) ;
  61. // If the end of the buffer was empty,
  62. if (bufindr == sizeof(cmdbuffer)) {
  63. // skip to the start and find the nonzero command.
  64. for (bufindr = 0; cmdbuffer[bufindr] == 0; ++ bufindr) ;
  65. }
  66. #ifdef CMDBUFFER_DEBUG
  67. SERIAL_ECHOPGM("New indices: buflen ");
  68. SERIAL_ECHO(buflen);
  69. SERIAL_ECHOPGM(", bufindr ");
  70. SERIAL_ECHO(bufindr);
  71. SERIAL_ECHOPGM(", bufindw ");
  72. SERIAL_ECHO(bufindw);
  73. SERIAL_ECHOPGM(", serial_count ");
  74. SERIAL_ECHO(serial_count);
  75. SERIAL_ECHOPGM(" new command on the top: ");
  76. SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE);
  77. SERIAL_ECHOLNPGM("");
  78. #endif /* CMDBUFFER_DEBUG */
  79. }
  80. return true;
  81. }
  82. return false;
  83. }
  84. void cmdqueue_reset()
  85. {
  86. while (buflen)
  87. {
  88. // printf_P(PSTR("dumping: \"%s\" of type %u\n"), cmdbuffer+bufindr+CMDHDRSIZE, CMDBUFFER_CURRENT_TYPE);
  89. ClearToSend();
  90. cmdqueue_pop_front();
  91. }
  92. bufindr = 0;
  93. bufindw = 0;
  94. //commands are removed from command queue after process_command() function is finished
  95. //reseting command queue and enqueing new commands during some (usually long running) command processing would cause that new commands are immediately removed from queue (or damaged)
  96. //this will ensure that all new commands which are enqueued after cmdqueue reset, will be always executed
  97. cmdbuffer_front_already_processed = true;
  98. }
  99. // How long a string could be pushed to the front of the command queue?
  100. // If yes, adjust bufindr to the new position, where the new command could be enqued.
  101. // len_asked does not contain the zero terminator size.
  102. static bool cmdqueue_could_enqueue_front(size_t len_asked)
  103. {
  104. // MAX_CMD_SIZE has to accommodate the zero terminator.
  105. if (len_asked >= MAX_CMD_SIZE)
  106. return false;
  107. // Remove the currently processed command from the queue.
  108. if (! cmdbuffer_front_already_processed) {
  109. cmdqueue_pop_front();
  110. cmdbuffer_front_already_processed = true;
  111. }
  112. if (bufindr == bufindw && buflen > 0)
  113. // Full buffer.
  114. return false;
  115. // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
  116. int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
  117. if (bufindw < bufindr) {
  118. int bufindr_new = bufindr - len_asked - (1 + CMDHDRSIZE);
  119. // Simple case. There is a contiguous space between the write buffer and the read buffer.
  120. if (endw <= bufindr_new) {
  121. bufindr = bufindr_new;
  122. return true;
  123. }
  124. } else {
  125. // Otherwise the free space is split between the start and end.
  126. if (len_asked + (1 + CMDHDRSIZE) <= bufindr) {
  127. // Could fit at the start.
  128. bufindr -= len_asked + (1 + CMDHDRSIZE);
  129. return true;
  130. }
  131. int bufindr_new = sizeof(cmdbuffer) - len_asked - (1 + CMDHDRSIZE);
  132. if (endw <= bufindr_new) {
  133. memset(cmdbuffer, 0, bufindr);
  134. bufindr = bufindr_new;
  135. return true;
  136. }
  137. }
  138. return false;
  139. }
  140. // Could one enqueue a command of length len_asked into the buffer,
  141. // while leaving CMDBUFFER_RESERVE_FRONT at the start?
  142. // If yes, adjust bufindw to the new position, where the new command could be enqued.
  143. // len_asked does not contain the zero terminator size.
  144. // This function may update bufindw, therefore for the power panic to work, this function must be called
  145. // with the interrupts disabled!
  146. static bool __attribute__((noinline)) cmdqueue_could_enqueue_back(size_t len_asked)
  147. {
  148. // MAX_CMD_SIZE has to accommodate the zero terminator.
  149. if (len_asked >= MAX_CMD_SIZE)
  150. return false;
  151. if (bufindr == bufindw && buflen > 0)
  152. // Full buffer.
  153. return false;
  154. // If there is some data stored starting at bufindw, len_asked is certainly smaller than
  155. // the allocated data buffer. Try to reserve a new buffer and to move the already received
  156. // serial data.
  157. // How much memory to reserve for the commands pushed to the front?
  158. // End of the queue, when pushing to the end.
  159. size_t endw = bufindw + len_asked + (1 + CMDHDRSIZE);
  160. if (bufindw < bufindr)
  161. // Simple case. There is a contiguous space between the write buffer and the read buffer.
  162. return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
  163. // Otherwise the free space is split between the start and end.
  164. if (// Could one fit to the end, including the reserve?
  165. endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
  166. // Could one fit to the end, and the reserve to the start?
  167. (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
  168. return true;
  169. // Could one fit both to the start?
  170. if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
  171. // Mark the rest of the buffer as used.
  172. memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
  173. // and point to the start.
  174. // Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
  175. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { bufindw = 0; }
  176. return true;
  177. }
  178. return false;
  179. }
  180. #ifdef CMDBUFFER_DEBUG
  181. void cmdqueue_dump_to_serial_single_line(int nr, const char *p)
  182. {
  183. SERIAL_ECHOPGM("Entry nr: ");
  184. SERIAL_ECHO(nr);
  185. SERIAL_ECHOPGM(", type: ");
  186. int type = *p;
  187. SERIAL_ECHO(type);
  188. SERIAL_ECHOPGM(", size: ");
  189. unsigned int size = *(unsigned int*)(p + 1);
  190. SERIAL_ECHO(size);
  191. SERIAL_ECHOPGM(", cmd: ");
  192. SERIAL_ECHO(p + CMDHDRSIZE);
  193. SERIAL_ECHOLNPGM("");
  194. }
  195. void cmdqueue_dump_to_serial()
  196. {
  197. if (buflen == 0) {
  198. SERIAL_ECHOLNPGM("The command buffer is empty.");
  199. } else {
  200. SERIAL_ECHOPGM("Content of the buffer: entries ");
  201. SERIAL_ECHO(buflen);
  202. SERIAL_ECHOPGM(", indr ");
  203. SERIAL_ECHO(bufindr);
  204. SERIAL_ECHOPGM(", indw ");
  205. SERIAL_ECHO(bufindw);
  206. SERIAL_ECHOLNPGM("");
  207. int nr = 0;
  208. if (bufindr < bufindw) {
  209. for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) {
  210. cmdqueue_dump_to_serial_single_line(nr, p);
  211. // Skip the command.
  212. for (p += CMDHDRSIZE; *p != 0; ++ p);
  213. // Skip the gaps.
  214. for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
  215. }
  216. } else {
  217. for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) {
  218. cmdqueue_dump_to_serial_single_line(nr, p);
  219. // Skip the command.
  220. for (p += CMDHDRSIZE; *p != 0; ++ p);
  221. // Skip the gaps.
  222. for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p);
  223. }
  224. for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) {
  225. cmdqueue_dump_to_serial_single_line(nr, p);
  226. // Skip the command.
  227. for (p += CMDHDRSIZE; *p != 0; ++ p);
  228. // Skip the gaps.
  229. for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
  230. }
  231. }
  232. SERIAL_ECHOLNPGM("End of the buffer.");
  233. }
  234. }
  235. #endif /* CMDBUFFER_DEBUG */
  236. //adds an command to the main command buffer
  237. //thats really done in a non-safe way.
  238. //needs overworking someday
  239. // Currently the maximum length of a command piped through this function is around 20 characters
  240. void enquecommand(const char *cmd, bool from_progmem)
  241. {
  242. size_t len = from_progmem ? strlen_P(cmd) : strlen(cmd);
  243. // Does cmd fit the queue while leaving sufficient space at the front for the chained commands?
  244. // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd.
  245. if (cmdqueue_could_enqueue_back(len)) {
  246. // This is dangerous if a mixing of serial and this happens
  247. // This may easily be tested: If serial_count > 0, we have a problem.
  248. cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI;
  249. if (from_progmem)
  250. strcpy_P(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
  251. else
  252. strcpy(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
  253. SERIAL_ECHO_START;
  254. SERIAL_ECHORPGM(MSG_Enqueing);
  255. SERIAL_ECHO(cmdbuffer + bufindw + CMDHDRSIZE);
  256. SERIAL_ECHOLNPGM("\"");
  257. bufindw += len + (CMDHDRSIZE + 1);
  258. if (bufindw == sizeof(cmdbuffer))
  259. bufindw = 0;
  260. ++ buflen;
  261. #ifdef CMDBUFFER_DEBUG
  262. cmdqueue_dump_to_serial();
  263. #endif /* CMDBUFFER_DEBUG */
  264. } else {
  265. SERIAL_ERROR_START;
  266. SERIAL_ECHORPGM(MSG_Enqueing);
  267. if (from_progmem)
  268. SERIAL_PROTOCOLRPGM(cmd);
  269. else
  270. SERIAL_ECHO(cmd);
  271. SERIAL_ECHOLNPGM("\" failed: Buffer full!");
  272. #ifdef CMDBUFFER_DEBUG
  273. cmdqueue_dump_to_serial();
  274. #endif /* CMDBUFFER_DEBUG */
  275. }
  276. }
  277. bool cmd_buffer_empty()
  278. {
  279. return (buflen == 0);
  280. }
  281. void enquecommand_front(const char *cmd, bool from_progmem)
  282. {
  283. size_t len = from_progmem ? strlen_P(cmd) : strlen(cmd);
  284. // Does cmd fit the queue? This call shall move bufindr, so the command may be copied.
  285. if (cmdqueue_could_enqueue_front(len)) {
  286. cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI;
  287. if (from_progmem)
  288. strcpy_P(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
  289. else
  290. strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
  291. ++ buflen;
  292. SERIAL_ECHO_START;
  293. SERIAL_ECHOPGM("Enqueing to the front: \"");
  294. SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE);
  295. SERIAL_ECHOLNPGM("\"");
  296. #ifdef CMDBUFFER_DEBUG
  297. cmdqueue_dump_to_serial();
  298. #endif /* CMDBUFFER_DEBUG */
  299. } else {
  300. SERIAL_ERROR_START;
  301. SERIAL_ECHOPGM("Enqueing to the front: \"");
  302. if (from_progmem)
  303. SERIAL_PROTOCOLRPGM(cmd);
  304. else
  305. SERIAL_ECHO(cmd);
  306. SERIAL_ECHOLNPGM("\" failed: Buffer full!");
  307. #ifdef CMDBUFFER_DEBUG
  308. cmdqueue_dump_to_serial();
  309. #endif /* CMDBUFFER_DEBUG */
  310. }
  311. }
  312. // Mark the command at the top of the command queue as new.
  313. // Therefore it will not be removed from the queue.
  314. void repeatcommand_front()
  315. {
  316. cmdbuffer_front_already_processed = true;
  317. }
  318. void get_command()
  319. {
  320. // Test and reserve space for the new command string.
  321. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1))
  322. return;
  323. if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
  324. MYSERIAL.flush();
  325. SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed
  326. }
  327. // start of serial line processing loop
  328. while (((MYSERIAL.available() > 0 && !saved_printing) || (MYSERIAL.available() > 0 && isPrintPaused)) && !cmdqueue_serial_disabled) { //is print is saved (crash detection or filament detection), dont process data from serial line
  329. char serial_char = MYSERIAL.read();
  330. serialTimeoutTimer.start();
  331. if (serial_char < 0)
  332. // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
  333. // and Marlin does not support such file names anyway.
  334. // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading
  335. // to a hang-up of the print process from an SD card.
  336. continue;
  337. if(serial_char == '\n' ||
  338. serial_char == '\r' ||
  339. serial_count >= (MAX_CMD_SIZE - 1) )
  340. {
  341. if(!serial_count) { //if empty line
  342. comment_mode = false; //for new command
  343. return;
  344. }
  345. cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; // terminate string
  346. char* cmd_head = cmdbuffer+bufindw+CMDHDRSIZE; // current command pointer
  347. char* cmd_start = cmd_head; // pointer past the line number (if any)
  348. if(!comment_mode){
  349. long gcode_N = -1; // seen line number
  350. // Line numbers must be first in buffer
  351. if (*cmd_head == 'N') {
  352. // Line number met: decode the number, then move cmd_start past all spaces.
  353. gcode_N = (strtol(cmd_head+1, &cmd_start, 10));
  354. while (*cmd_start == ' ') ++cmd_start;
  355. // Test whether the successive lines are stamped with an increasing line number ID.
  356. if(gcode_N != gcode_LastN+1 && strncmp_P(cmd_start, PSTR("M110"), 4)) {
  357. // Line numbers not sent in succession and M110 not seen.
  358. SERIAL_ERROR_START;
  359. SERIAL_ERRORRPGM(_n("Line Number is not Last Line Number+1, Last Line: "));////MSG_ERR_LINE_NO
  360. SERIAL_ERRORLN(gcode_LastN);
  361. //Serial.println(gcode_N);
  362. FlushSerialRequestResend();
  363. serial_count = 0;
  364. return;
  365. }
  366. if((strchr_pointer = strchr(cmd_start, '*')) != NULL)
  367. {
  368. byte checksum = 0;
  369. char *p = cmd_head;
  370. while (p != strchr_pointer)
  371. checksum = checksum^(*p++);
  372. if (code_value_short() != (int16_t)checksum) {
  373. SERIAL_ERROR_START;
  374. SERIAL_ERRORRPGM(_n("checksum mismatch, Last Line: "));////MSG_ERR_CHECKSUM_MISMATCH
  375. SERIAL_ERRORLN(gcode_LastN);
  376. FlushSerialRequestResend();
  377. serial_count = 0;
  378. return;
  379. }
  380. // If no errors, remove the checksum and continue parsing.
  381. *strchr_pointer = 0;
  382. }
  383. else
  384. {
  385. SERIAL_ERROR_START;
  386. SERIAL_ERRORRPGM(_n("No Checksum with line number, Last Line: "));////MSG_ERR_NO_CHECKSUM
  387. SERIAL_ERRORLN(gcode_LastN);
  388. FlushSerialRequestResend();
  389. serial_count = 0;
  390. return;
  391. }
  392. }
  393. // if we don't receive 'N' but still see '*'
  394. if (*(cmd_head != 'N') && (strchr(cmd_start, '*') != NULL))
  395. {
  396. SERIAL_ERROR_START;
  397. SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM
  398. SERIAL_ERRORLN(gcode_LastN);
  399. FlushSerialRequestResend();
  400. serial_count = 0;
  401. return;
  402. }
  403. // Handle KILL early, even when Stopped
  404. if(strcmp_P(cmd_start, PSTR("M112")) == 0)
  405. kill(MSG_M112_KILL, 2);
  406. // Bypass Stopped for some commands
  407. bool allow_when_stopped = false;
  408. if(strncmp_P(cmd_start, PSTR("M310"), 4) == 0)
  409. allow_when_stopped = true;
  410. // Handle the USB timer
  411. if ((*cmd_start == 'G') && !(IS_SD_PRINTING))
  412. usb_timer.start();
  413. if (allow_when_stopped == false && Stopped == true) {
  414. // Stopped can be set either during error states (thermal error: cannot continue), or
  415. // when a printer-initiated action is processed. In such case the printer will send to
  416. // the host an action, but cannot know if the action has been processed while new
  417. // commands are being sent. In this situation we just drop the command while issuing
  418. // periodic "busy" messages in the main loop. Since we're not incrementing the received
  419. // line number, a request for resend will happen (if necessary), ensuring we don't skip
  420. // commands whenever Stopped is cleared and processing resumes.
  421. serial_count = 0;
  422. return;
  423. }
  424. // Command is complete: store the current line into buffer, move to the next line.
  425. // Store type of entry
  426. cmdbuffer[bufindw] = gcode_N >= 0 ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB;
  427. #ifdef CMDBUFFER_DEBUG
  428. SERIAL_ECHO_START;
  429. SERIAL_ECHOPGM("Storing a command line to buffer: ");
  430. SERIAL_ECHO(cmd_start);
  431. SERIAL_ECHOLNPGM("");
  432. #endif /* CMDBUFFER_DEBUG */
  433. // Store the command itself (without line number or checksum)
  434. size_t cmd_len;
  435. if (cmd_head == cmd_start)
  436. cmd_len = strlen(cmd_start) + 1;
  437. else {
  438. // strip the line number
  439. cmd_len = 0;
  440. do { cmd_head[cmd_len] = cmd_start[cmd_len]; }
  441. while (cmd_head[cmd_len++]);
  442. }
  443. bufindw += cmd_len + CMDHDRSIZE;
  444. if (bufindw == sizeof(cmdbuffer))
  445. bufindw = 0;
  446. ++ buflen;
  447. // Update the processed gcode line
  448. if (gcode_N >= 0)
  449. gcode_LastN = gcode_N;
  450. #ifdef CMDBUFFER_DEBUG
  451. SERIAL_ECHOPGM("Number of commands in the buffer: ");
  452. SERIAL_ECHO(buflen);
  453. SERIAL_ECHOLNPGM("");
  454. #endif /* CMDBUFFER_DEBUG */
  455. } // end of 'not comment mode'
  456. serial_count = 0; //clear buffer
  457. // Don't call cmdqueue_could_enqueue_back if there are no characters waiting
  458. // in the queue, as this function will reserve the memory.
  459. if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
  460. return;
  461. } // end of "end of line" processing
  462. else {
  463. // Not an "end of line" symbol. Store the new character into a buffer.
  464. if(serial_char == ';') comment_mode = true;
  465. if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
  466. }
  467. } // end of serial line processing loop
  468. if (serial_count > 0 && serialTimeoutTimer.expired(farm_mode ? 800 : 2000)) {
  469. comment_mode = false;
  470. serial_count = 0;
  471. SERIAL_ECHOLNPGM("RX timeout");
  472. return;
  473. }
  474. #ifdef SDSUPPORT
  475. if(!card.sdprinting || !card.isFileOpen() || serial_count!=0){
  476. // If there is a half filled buffer from serial line, wait until return before
  477. // continuing with the serial line.
  478. return;
  479. }
  480. //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
  481. // if it occurs, stop_buffering is triggered and the buffer is ran dry.
  482. // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
  483. static bool stop_buffering=false;
  484. if(buflen==0) stop_buffering=false;
  485. union {
  486. struct {
  487. char lo;
  488. char hi;
  489. } lohi;
  490. uint16_t value;
  491. } sd_count;
  492. sd_count.value = 0;
  493. // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer.
  494. while( !card.eof() && !stop_buffering) {
  495. int16_t n=card.getFilteredGcodeChar();
  496. char serial_char = (char)n;
  497. if( serial_char == '\n'
  498. || serial_char == '\r'
  499. || ((serial_char == '#' || serial_char == ':') )
  500. || serial_count >= (MAX_CMD_SIZE - 1)
  501. || n==-1
  502. ){
  503. if(serial_char=='#')
  504. stop_buffering=true;
  505. if(!serial_count)
  506. {
  507. // This is either an empty line, or a line with just a comment.
  508. // Continue to the following line, and continue accumulating the number of bytes
  509. // read from the sdcard into sd_count,
  510. // so that the length of the already read empty lines and comments will be added
  511. // to the following non-empty line.
  512. return; // prevent cycling indefinitely - let manage_heaters do their job
  513. }
  514. // The new command buffer could be updated non-atomically, because it is not yet considered
  515. // to be inside the active queue.
  516. sd_count.value = card.get_sdpos() - sdpos_atomic;
  517. cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD;
  518. cmdbuffer[bufindw+1] = sd_count.lohi.lo;
  519. cmdbuffer[bufindw+2] = sd_count.lohi.hi;
  520. cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
  521. // Calculate the length before disabling the interrupts.
  522. uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
  523. // SERIAL_ECHOPGM("SD cmd(");
  524. // MYSERIAL.print(sd_count.value, DEC);
  525. // SERIAL_ECHOPGM(") ");
  526. // SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);
  527. // SERIAL_ECHOPGM("cmdbuffer:");
  528. // MYSERIAL.print(cmdbuffer);
  529. // SERIAL_ECHOPGM("buflen:");
  530. // MYSERIAL.print(buflen+1);
  531. sd_count.value = 0;
  532. cli();
  533. // This block locks the interrupts globally for 3.56 us,
  534. // which corresponds to a maximum repeat frequency of 280.70 kHz.
  535. // This blocking is safe in the context of a 10kHz stepper driver interrupt
  536. // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz.
  537. ++ buflen;
  538. bufindw += len;
  539. sdpos_atomic = card.get_sdpos();
  540. if (bufindw == sizeof(cmdbuffer))
  541. bufindw = 0;
  542. sei();
  543. comment_mode = false; //for new command
  544. serial_count = 0; //clear buffer
  545. if(card.eof()) break;
  546. // The following line will reserve buffer space if available.
  547. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
  548. return;
  549. }
  550. else
  551. {
  552. // there are no comments coming from the filtered file
  553. cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
  554. }
  555. }
  556. if(card.eof())
  557. {
  558. // file was fully buffered, but commands might still need to be planned!
  559. // do *not* clear sdprinting until all SD commands are consumed to ensure
  560. // SD state can be resumed from a saved printing state. sdprinting is only
  561. // cleared by printingHasFinished after peforming all remaining moves.
  562. if(!cmdqueue_calc_sd_length())
  563. {
  564. // queue is complete, but before we process EOF commands prevent
  565. // re-entry by disabling SD processing from any st_synchronize call
  566. card.closefile();
  567. SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED
  568. stoptime=_millis();
  569. char time[30];
  570. unsigned long t=(stoptime-starttime-pause_time)/1000;
  571. pause_time = 0;
  572. int hours, minutes;
  573. minutes=(t/60)%60;
  574. hours=t/60/60;
  575. save_statistics(total_filament_used, t);
  576. sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
  577. SERIAL_ECHO_START;
  578. SERIAL_ECHOLN(time);
  579. lcd_setstatus(time);
  580. card.printingHasFinished();
  581. card.checkautostart(true);
  582. if (farm_mode)
  583. prusa_statistics(6);
  584. }
  585. }
  586. #endif //SDSUPPORT
  587. }
  588. uint16_t cmdqueue_calc_sd_length()
  589. {
  590. if (buflen == 0)
  591. return 0;
  592. union {
  593. struct {
  594. char lo;
  595. char hi;
  596. } lohi;
  597. uint16_t value;
  598. } sdlen_single;
  599. uint16_t sdlen = 0;
  600. for (size_t _buflen = buflen, _bufindr = bufindr;;) {
  601. if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) {
  602. sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1];
  603. sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2];
  604. sdlen += sdlen_single.value;
  605. }
  606. if (-- _buflen == 0)
  607. break;
  608. // First skip the current command ID and iterate up to the end of the string.
  609. for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ;
  610. // Second, skip the end of string null character and iterate until a nonzero command ID is found.
  611. for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
  612. // If the end of the buffer was empty,
  613. if (_bufindr == sizeof(cmdbuffer)) {
  614. // skip to the start and find the nonzero command.
  615. for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
  616. }
  617. }
  618. return sdlen;
  619. }