cmdqueue.cpp 27 KB

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