cmdqueue.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. #include "cmdqueue.h"
  2. #include "cardreader.h"
  3. #include "ultralcd.h"
  4. extern bool Stopped;
  5. // Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
  6. char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
  7. // Head of the circular buffer, where to read.
  8. int bufindr = 0;
  9. // Tail of the buffer, where to write.
  10. int bufindw = 0;
  11. // Number of lines in cmdbuffer.
  12. int buflen = 0;
  13. // Flag for processing the current command inside the main Arduino loop().
  14. // If a new command was pushed to the front of a command buffer while
  15. // processing another command, this replaces the command on the top.
  16. // Therefore don't remove the command from the queue in the loop() function.
  17. bool cmdbuffer_front_already_processed = false;
  18. int serial_count = 0; //index of character read from serial line
  19. boolean comment_mode = false;
  20. char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
  21. unsigned long TimeSent = millis();
  22. unsigned long TimeNow = millis();
  23. long gcode_N = 0;
  24. long gcode_LastN = 0;
  25. long Stopped_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. bufindr = 0;
  86. bufindw = 0;
  87. buflen = 0;
  88. cmdbuffer_front_already_processed = false;
  89. }
  90. // How long a string could be pushed to the front of the command queue?
  91. // If yes, adjust bufindr to the new position, where the new command could be enqued.
  92. // len_asked does not contain the zero terminator size.
  93. bool cmdqueue_could_enqueue_front(int len_asked)
  94. {
  95. // MAX_CMD_SIZE has to accommodate the zero terminator.
  96. if (len_asked >= MAX_CMD_SIZE)
  97. return false;
  98. // Remove the currently processed command from the queue.
  99. if (! cmdbuffer_front_already_processed) {
  100. cmdqueue_pop_front();
  101. cmdbuffer_front_already_processed = true;
  102. }
  103. if (bufindr == bufindw && buflen > 0)
  104. // Full buffer.
  105. return false;
  106. // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
  107. int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
  108. if (bufindw < bufindr) {
  109. int bufindr_new = bufindr - len_asked - (1 + CMDHDRSIZE);
  110. // Simple case. There is a contiguous space between the write buffer and the read buffer.
  111. if (endw <= bufindr_new) {
  112. bufindr = bufindr_new;
  113. return true;
  114. }
  115. } else {
  116. // Otherwise the free space is split between the start and end.
  117. if (len_asked + (1 + CMDHDRSIZE) <= bufindr) {
  118. // Could fit at the start.
  119. bufindr -= len_asked + (1 + CMDHDRSIZE);
  120. return true;
  121. }
  122. int bufindr_new = sizeof(cmdbuffer) - len_asked - (1 + CMDHDRSIZE);
  123. if (endw <= bufindr_new) {
  124. memset(cmdbuffer, 0, bufindr);
  125. bufindr = bufindr_new;
  126. return true;
  127. }
  128. }
  129. return false;
  130. }
  131. // Could one enqueue a command of length len_asked into the buffer,
  132. // while leaving CMDBUFFER_RESERVE_FRONT at the start?
  133. // If yes, adjust bufindw to the new position, where the new command could be enqued.
  134. // len_asked does not contain the zero terminator size.
  135. // This function may update bufindw, therefore for the power panic to work, this function must be called
  136. // with the interrupts disabled!
  137. bool cmdqueue_could_enqueue_back(int len_asked, bool atomic_update)
  138. {
  139. // MAX_CMD_SIZE has to accommodate the zero terminator.
  140. if (len_asked >= MAX_CMD_SIZE)
  141. return false;
  142. if (bufindr == bufindw && buflen > 0)
  143. // Full buffer.
  144. return false;
  145. if (serial_count > 0) {
  146. // If there is some data stored starting at bufindw, len_asked is certainly smaller than
  147. // the allocated data buffer. Try to reserve a new buffer and to move the already received
  148. // serial data.
  149. // How much memory to reserve for the commands pushed to the front?
  150. // End of the queue, when pushing to the end.
  151. int endw = bufindw + len_asked + (1 + CMDHDRSIZE);
  152. if (bufindw < bufindr)
  153. // Simple case. There is a contiguous space between the write buffer and the read buffer.
  154. return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
  155. // Otherwise the free space is split between the start and end.
  156. if (// Could one fit to the end, including the reserve?
  157. endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
  158. // Could one fit to the end, and the reserve to the start?
  159. (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
  160. return true;
  161. // Could one fit both to the start?
  162. if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
  163. // Mark the rest of the buffer as used.
  164. memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
  165. // and point to the start.
  166. // Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
  167. if (atomic_update)
  168. cli();
  169. bufindw = 0;
  170. if (atomic_update)
  171. sei();
  172. return true;
  173. }
  174. } else {
  175. // How much memory to reserve for the commands pushed to the front?
  176. // End of the queue, when pushing to the end.
  177. int endw = bufindw + len_asked + (1 + CMDHDRSIZE);
  178. if (bufindw < bufindr)
  179. // Simple case. There is a contiguous space between the write buffer and the read buffer.
  180. return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
  181. // Otherwise the free space is split between the start and end.
  182. if (// Could one fit to the end, including the reserve?
  183. endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
  184. // Could one fit to the end, and the reserve to the start?
  185. (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
  186. return true;
  187. // Could one fit both to the start?
  188. if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
  189. // Mark the rest of the buffer as used.
  190. memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
  191. // and point to the start.
  192. // Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
  193. if (atomic_update)
  194. cli();
  195. bufindw = 0;
  196. if (atomic_update)
  197. sei();
  198. return true;
  199. }
  200. }
  201. return false;
  202. }
  203. #ifdef CMDBUFFER_DEBUG
  204. void cmdqueue_dump_to_serial_single_line(int nr, const char *p)
  205. {
  206. SERIAL_ECHOPGM("Entry nr: ");
  207. SERIAL_ECHO(nr);
  208. SERIAL_ECHOPGM(", type: ");
  209. SERIAL_ECHO(int(*p));
  210. SERIAL_ECHOPGM(", cmd: ");
  211. SERIAL_ECHO(p+1);
  212. SERIAL_ECHOLNPGM("");
  213. }
  214. void cmdqueue_dump_to_serial()
  215. {
  216. if (buflen == 0) {
  217. SERIAL_ECHOLNPGM("The command buffer is empty.");
  218. } else {
  219. SERIAL_ECHOPGM("Content of the buffer: entries ");
  220. SERIAL_ECHO(buflen);
  221. SERIAL_ECHOPGM(", indr ");
  222. SERIAL_ECHO(bufindr);
  223. SERIAL_ECHOPGM(", indw ");
  224. SERIAL_ECHO(bufindw);
  225. SERIAL_ECHOLNPGM("");
  226. int nr = 0;
  227. if (bufindr < bufindw) {
  228. for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) {
  229. cmdqueue_dump_to_serial_single_line(nr, p);
  230. // Skip the command.
  231. for (++p; *p != 0; ++ p);
  232. // Skip the gaps.
  233. for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
  234. }
  235. } else {
  236. for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) {
  237. cmdqueue_dump_to_serial_single_line(nr, p);
  238. // Skip the command.
  239. for (++p; *p != 0; ++ p);
  240. // Skip the gaps.
  241. for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p);
  242. }
  243. for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) {
  244. cmdqueue_dump_to_serial_single_line(nr, p);
  245. // Skip the command.
  246. for (++p; *p != 0; ++ p);
  247. // Skip the gaps.
  248. for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
  249. }
  250. }
  251. SERIAL_ECHOLNPGM("End of the buffer.");
  252. }
  253. }
  254. #endif /* CMDBUFFER_DEBUG */
  255. //adds an command to the main command buffer
  256. //thats really done in a non-safe way.
  257. //needs overworking someday
  258. // Currently the maximum length of a command piped through this function is around 20 characters
  259. void enquecommand(const char *cmd, bool from_progmem)
  260. {
  261. int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
  262. // Does cmd fit the queue while leaving sufficient space at the front for the chained commands?
  263. // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd.
  264. if (cmdqueue_could_enqueue_back(len)) {
  265. // This is dangerous if a mixing of serial and this happens
  266. // This may easily be tested: If serial_count > 0, we have a problem.
  267. cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI;
  268. if (from_progmem)
  269. strcpy_P(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
  270. else
  271. strcpy(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
  272. SERIAL_ECHO_START;
  273. SERIAL_ECHORPGM(MSG_Enqueing);
  274. SERIAL_ECHO(cmdbuffer + bufindw + CMDHDRSIZE);
  275. SERIAL_ECHOLNPGM("\"");
  276. bufindw += len + (CMDHDRSIZE + 1);
  277. if (bufindw == sizeof(cmdbuffer))
  278. bufindw = 0;
  279. ++ buflen;
  280. #ifdef CMDBUFFER_DEBUG
  281. cmdqueue_dump_to_serial();
  282. #endif /* CMDBUFFER_DEBUG */
  283. } else {
  284. SERIAL_ERROR_START;
  285. SERIAL_ECHORPGM(MSG_Enqueing);
  286. if (from_progmem)
  287. SERIAL_PROTOCOLRPGM(cmd);
  288. else
  289. SERIAL_ECHO(cmd);
  290. SERIAL_ECHOLNPGM("\" failed: Buffer full!");
  291. #ifdef CMDBUFFER_DEBUG
  292. cmdqueue_dump_to_serial();
  293. #endif /* CMDBUFFER_DEBUG */
  294. }
  295. }
  296. bool cmd_buffer_empty()
  297. {
  298. return (buflen == 0);
  299. }
  300. void enquecommand_front(const char *cmd, bool from_progmem)
  301. {
  302. int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
  303. // Does cmd fit the queue? This call shall move bufindr, so the command may be copied.
  304. if (cmdqueue_could_enqueue_front(len)) {
  305. cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI;
  306. if (from_progmem)
  307. strcpy_P(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
  308. else
  309. strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
  310. ++ buflen;
  311. SERIAL_ECHO_START;
  312. SERIAL_ECHOPGM("Enqueing to the front: \"");
  313. SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE);
  314. SERIAL_ECHOLNPGM("\"");
  315. #ifdef CMDBUFFER_DEBUG
  316. cmdqueue_dump_to_serial();
  317. #endif /* CMDBUFFER_DEBUG */
  318. } else {
  319. SERIAL_ERROR_START;
  320. SERIAL_ECHOPGM("Enqueing to the front: \"");
  321. if (from_progmem)
  322. SERIAL_PROTOCOLRPGM(cmd);
  323. else
  324. SERIAL_ECHO(cmd);
  325. SERIAL_ECHOLNPGM("\" failed: Buffer full!");
  326. #ifdef CMDBUFFER_DEBUG
  327. cmdqueue_dump_to_serial();
  328. #endif /* CMDBUFFER_DEBUG */
  329. }
  330. }
  331. // Mark the command at the top of the command queue as new.
  332. // Therefore it will not be removed from the queue.
  333. void repeatcommand_front()
  334. {
  335. cmdbuffer_front_already_processed = true;
  336. }
  337. bool is_buffer_empty()
  338. {
  339. if (buflen == 0) return true;
  340. else return false;
  341. }
  342. void get_command()
  343. {
  344. // Test and reserve space for the new command string.
  345. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true))
  346. return;
  347. bool rx_buffer_full = false; //flag that serial rx buffer is full
  348. if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
  349. MYSERIAL.flush();
  350. SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed
  351. rx_buffer_full = true; //sets flag that buffer was full
  352. }
  353. while (MYSERIAL.available() > 0) {
  354. char serial_char = MYSERIAL.read();
  355. /* if (selectedSerialPort == 1)
  356. {
  357. selectedSerialPort = 0;
  358. MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode
  359. selectedSerialPort = 1;
  360. } */ //RP - removed
  361. TimeSent = millis();
  362. TimeNow = millis();
  363. if (serial_char < 0)
  364. // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
  365. // and Marlin does not support such file names anyway.
  366. // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading
  367. // to a hang-up of the print process from an SD card.
  368. continue;
  369. if(serial_char == '\n' ||
  370. serial_char == '\r' ||
  371. serial_count >= (MAX_CMD_SIZE - 1) )
  372. {
  373. if(!serial_count) { //if empty line
  374. comment_mode = false; //for new command
  375. return;
  376. }
  377. cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
  378. if(!comment_mode){
  379. // Line numbers must be first in buffer
  380. if ((strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA") == NULL) &&
  381. (cmdbuffer[bufindw+CMDHDRSIZE] == 'N')) {
  382. // Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
  383. // and Marlin tests, whether the successive lines are stamped with an increasing line number ID
  384. gcode_N = (strtol(cmdbuffer+bufindw+CMDHDRSIZE+1, NULL, 10));
  385. if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) {
  386. // M110 - set current line number.
  387. // Line numbers not sent in succession.
  388. SERIAL_ERROR_START;
  389. SERIAL_ERRORRPGM(MSG_ERR_LINE_NO);
  390. SERIAL_ERRORLN(gcode_LastN);
  391. //Serial.println(gcode_N);
  392. FlushSerialRequestResend();
  393. serial_count = 0;
  394. return;
  395. }
  396. if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL)
  397. {
  398. byte checksum = 0;
  399. char *p = cmdbuffer+bufindw+CMDHDRSIZE;
  400. while (p != strchr_pointer)
  401. checksum = checksum^(*p++);
  402. if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
  403. SERIAL_ERROR_START;
  404. SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH);
  405. SERIAL_ERRORLN(gcode_LastN);
  406. FlushSerialRequestResend();
  407. serial_count = 0;
  408. return;
  409. }
  410. // If no errors, remove the checksum and continue parsing.
  411. *strchr_pointer = 0;
  412. }
  413. else
  414. {
  415. SERIAL_ERROR_START;
  416. SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM);
  417. SERIAL_ERRORLN(gcode_LastN);
  418. FlushSerialRequestResend();
  419. serial_count = 0;
  420. return;
  421. }
  422. // Don't parse N again with code_seen('N')
  423. cmdbuffer[bufindw + CMDHDRSIZE] = '$';
  424. //if no errors, continue parsing
  425. gcode_LastN = gcode_N;
  426. }
  427. // if we don't receive 'N' but still see '*'
  428. if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL))
  429. {
  430. SERIAL_ERROR_START;
  431. SERIAL_ERRORRPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
  432. SERIAL_ERRORLN(gcode_LastN);
  433. serial_count = 0;
  434. return;
  435. }
  436. if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) {
  437. if (! IS_SD_PRINTING) {
  438. usb_printing_counter = 10;
  439. is_usb_printing = true;
  440. }
  441. if (Stopped == true) {
  442. int gcode = strtol(strchr_pointer+1, NULL, 10);
  443. if (gcode >= 0 && gcode <= 3) {
  444. SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
  445. LCD_MESSAGERPGM(MSG_STOPPED);
  446. }
  447. }
  448. } // end of 'G' command
  449. //If command was e-stop process now
  450. if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
  451. kill("", 2);
  452. // Store the current line into buffer, move to the next line.
  453. cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_USB;
  454. #ifdef CMDBUFFER_DEBUG
  455. SERIAL_ECHO_START;
  456. SERIAL_ECHOPGM("Storing a command line to buffer: ");
  457. SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE);
  458. SERIAL_ECHOLNPGM("");
  459. #endif /* CMDBUFFER_DEBUG */
  460. bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
  461. if (bufindw == sizeof(cmdbuffer))
  462. bufindw = 0;
  463. ++ buflen;
  464. #ifdef CMDBUFFER_DEBUG
  465. SERIAL_ECHOPGM("Number of commands in the buffer: ");
  466. SERIAL_ECHO(buflen);
  467. SERIAL_ECHOLNPGM("");
  468. #endif /* CMDBUFFER_DEBUG */
  469. } // end of 'not comment mode'
  470. serial_count = 0; //clear buffer
  471. // Don't call cmdqueue_could_enqueue_back if there are no characters waiting
  472. // in the queue, as this function will reserve the memory.
  473. if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
  474. return;
  475. } // end of "end of line" processing
  476. else {
  477. // Not an "end of line" symbol. Store the new character into a buffer.
  478. if(serial_char == ';') comment_mode = true;
  479. if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
  480. }
  481. } // end of serial line processing loop
  482. if(farm_mode){
  483. TimeNow = millis();
  484. if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) {
  485. cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0;
  486. bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
  487. if (bufindw == sizeof(cmdbuffer))
  488. bufindw = 0;
  489. ++ buflen;
  490. serial_count = 0;
  491. SERIAL_ECHOPGM("TIMEOUT:");
  492. //memset(cmdbuffer, 0 , sizeof(cmdbuffer));
  493. return;
  494. }
  495. }
  496. //add comment
  497. /*if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated
  498. rx_buffer_full = false;
  499. bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command
  500. serial_count = 0;
  501. }*/
  502. #ifdef SDSUPPORT
  503. if(!card.sdprinting || serial_count!=0){
  504. // If there is a half filled buffer from serial line, wait until return before
  505. // continuing with the serial line.
  506. return;
  507. }
  508. //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
  509. // if it occurs, stop_buffering is triggered and the buffer is ran dry.
  510. // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
  511. static bool stop_buffering=false;
  512. if(buflen==0) stop_buffering=false;
  513. union {
  514. struct {
  515. char lo;
  516. char hi;
  517. } lohi;
  518. uint16_t value;
  519. } sd_count;
  520. sd_count.value = 0;
  521. // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer.
  522. while( !card.eof() && !stop_buffering) {
  523. int16_t n=card.get();
  524. char serial_char = (char)n;
  525. if(serial_char == '\n' ||
  526. serial_char == '\r' ||
  527. ((serial_char == '#' || serial_char == ':') && comment_mode == false) ||
  528. serial_count >= (MAX_CMD_SIZE - 1) || n==-1)
  529. {
  530. if(card.eof()){
  531. SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED);
  532. stoptime=millis();
  533. char time[30];
  534. unsigned long t=(stoptime-starttime-pause_time)/1000;
  535. pause_time = 0;
  536. int hours, minutes;
  537. minutes=(t/60)%60;
  538. hours=t/60/60;
  539. save_statistics(total_filament_used, t);
  540. sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
  541. SERIAL_ECHO_START;
  542. SERIAL_ECHOLN(time);
  543. lcd_setstatus(time);
  544. card.printingHasFinished();
  545. card.checkautostart(true);
  546. if (farm_mode)
  547. {
  548. prusa_statistics(6);
  549. lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM;
  550. }
  551. }
  552. if(serial_char=='#')
  553. stop_buffering=true;
  554. if(!serial_count)
  555. {
  556. // This is either an empty line, or a line with just a comment.
  557. // Continue to the following line, and continue accumulating the number of bytes
  558. // read from the sdcard into sd_count,
  559. // so that the lenght of the already read empty lines and comments will be added
  560. // to the following non-empty line.
  561. comment_mode = false;
  562. continue; //if empty line
  563. }
  564. // The new command buffer could be updated non-atomically, because it is not yet considered
  565. // to be inside the active queue.
  566. sd_count.value = (card.get_sdpos()+1) - sdpos_atomic;
  567. cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD;
  568. cmdbuffer[bufindw+1] = sd_count.lohi.lo;
  569. cmdbuffer[bufindw+2] = sd_count.lohi.hi;
  570. cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
  571. // Calculate the length before disabling the interrupts.
  572. uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
  573. // SERIAL_ECHOPGM("SD cmd(");
  574. // MYSERIAL.print(sd_count.value, DEC);
  575. // SERIAL_ECHOPGM(") ");
  576. // SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);
  577. // SERIAL_ECHOPGM("cmdbuffer:");
  578. // MYSERIAL.print(cmdbuffer);
  579. // SERIAL_ECHOPGM("buflen:");
  580. // MYSERIAL.print(buflen+1);
  581. sd_count.value = 0;
  582. cli();
  583. ++ buflen;
  584. bufindw += len;
  585. sdpos_atomic = card.get_sdpos()+1;
  586. if (bufindw == sizeof(cmdbuffer))
  587. bufindw = 0;
  588. sei();
  589. comment_mode = false; //for new command
  590. serial_count = 0; //clear buffer
  591. // The following line will reserve buffer space if available.
  592. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
  593. return;
  594. }
  595. else
  596. {
  597. if(serial_char == ';') comment_mode = true;
  598. else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
  599. }
  600. }
  601. #endif //SDSUPPORT
  602. }
  603. uint16_t cmdqueue_calc_sd_length()
  604. {
  605. if (buflen == 0)
  606. return 0;
  607. union {
  608. struct {
  609. char lo;
  610. char hi;
  611. } lohi;
  612. uint16_t value;
  613. } sdlen_single;
  614. uint16_t sdlen = 0;
  615. for (int _buflen = buflen, _bufindr = bufindr;;) {
  616. if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) {
  617. sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1];
  618. sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2];
  619. sdlen += sdlen_single.value;
  620. }
  621. if (-- _buflen == 0)
  622. break;
  623. // First skip the current command ID and iterate up to the end of the string.
  624. for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ;
  625. // Second, skip the end of string null character and iterate until a nonzero command ID is found.
  626. for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
  627. // If the end of the buffer was empty,
  628. if (_bufindr == sizeof(cmdbuffer)) {
  629. // skip to the start and find the nonzero command.
  630. for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
  631. }
  632. }
  633. return sdlen;
  634. }