From 9105de073c754c6ebeb00d466f0ffe3825868de0 Mon Sep 17 00:00:00 2001 From: Robert Pelnar Date: Thu, 14 Sep 2017 16:19:49 +0200 Subject: [PATCH] Cmdqueue code in separate files, debug codes for read/write eeprom and ram, PWM amplitude for Y axis stealtchop mode increased to 210. --- Firmware/Dcodes.cpp | 192 +++++ Firmware/Dcodes.h | 11 + Firmware/Marlin_main.cpp | 713 +----------------- Firmware/cmdqueue.cpp | 603 +++++++++++++++ Firmware/cmdqueue.h | 85 +++ Firmware/tmc2130.cpp | 8 +- .../variants/1_75mm_MK3-EINY03-E3Dv6full.h | 13 +- .../variants/1_75mm_MK3-EINY04-E3Dv6full.h | 13 +- 8 files changed, 939 insertions(+), 699 deletions(-) create mode 100644 Firmware/Dcodes.cpp create mode 100644 Firmware/Dcodes.h create mode 100644 Firmware/cmdqueue.cpp create mode 100644 Firmware/cmdqueue.h diff --git a/Firmware/Dcodes.cpp b/Firmware/Dcodes.cpp new file mode 100644 index 00000000..05977b5f --- /dev/null +++ b/Firmware/Dcodes.cpp @@ -0,0 +1,192 @@ +#include "Dcodes.h" +#include "Marlin.h" +#include "cmdqueue.h" + +inline void serial_print_hex_nibble(uint8_t val) +{ + MYSERIAL.write((val > 9)?(val - 10 + 'a'):(val + '0')); +} + +void serial_print_hex_byte(uint8_t val) +{ + serial_print_hex_nibble(val >> 4); + serial_print_hex_nibble(val & 15); +} + +void serial_print_hex_word(uint16_t val) +{ + serial_print_hex_byte(val >> 8); + serial_print_hex_byte(val & 255); +} + +int parse_hex(char* hex, uint8_t* data, int count) +{ + int parsed = 0; + while (*hex) + { + if (count && (parsed >= count)) break; + char c = *(hex++); + if (c == ' ') continue; + if (c == '\n') break; + uint8_t val = 0x00; + if ((c >= '0') && (c <= '9')) val |= ((c - '0') << 4); + else if ((c >= 'a') && (c <= 'f')) val |= ((c - 'a' + 10) << 4); + else return -parsed; + c = *(hex++); + if ((c >= '0') && (c <= '9')) val |= (c - '0'); + else if ((c >= 'a') && (c <= 'f')) val |= (c - 'a' + 10); + else return -parsed; + data[parsed] = val; + parsed++; + } + return parsed; +} + +void dcode_0() +{ + if (*(strchr_pointer + 1) == 0) return; + MYSERIAL.println("D0 - Reset"); + if (code_seen('B')) //bootloader + asm volatile("jmp 0x1e000"); + else //reset + asm volatile("jmp 0x00000"); +/* + cli(); //disable interrupts + wdt_reset(); //reset watchdog + WDTCSR = (1< 0x2000) count = 0x2000; + if ((address + count) > 0x2000) count = 0x2000 - address; + if (code_seen('X')) // Data + { + uint8_t data[16]; + count = parse_hex(strchr_pointer + 1, data, 16); + if (count > 0) + { + for (int i = 0; i < count; i++) + *((uint8_t*)(address + i)) = data[i]; + MYSERIAL.print(count, DEC); + MYSERIAL.println(" bytes written to RAM at addres "); + serial_print_hex_word(address); + MYSERIAL.write('\n'); + } + else + count = 0; + } + while (count) + { + serial_print_hex_word(address); + MYSERIAL.write(' '); + uint8_t countperline = 16; + while (count && countperline) + { + uint8_t data = *((uint8_t*)address++); + MYSERIAL.write(' '); + serial_print_hex_byte(data); + countperline--; + count--; + } + MYSERIAL.write('\n'); + } +} +void dcode_3() +{ + MYSERIAL.println("D3 - Read/Write EEPROM"); + uint16_t address = 0x0000; //default 0x0000 + uint16_t count = 0x2000; //default 0x2000 (entire eeprom) + if (code_seen('A')) // Address (0x0000-0x1fff) + address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); + if (code_seen('C')) // Count (0x0001-0x2000) + count = (int)code_value(); + address &= 0x1fff; + if (count > 0x2000) count = 0x2000; + if ((address + count) > 0x2000) count = 0x2000 - address; + if (code_seen('X')) // Data + { + uint8_t data[16]; + count = parse_hex(strchr_pointer + 1, data, 16); + if (count > 0) + { + for (int i = 0; i < count; i++) + eeprom_write_byte((uint8_t*)(address + i), data[i]); + MYSERIAL.print(count, DEC); + MYSERIAL.println(" bytes written to EEPROM at addres "); + serial_print_hex_word(address); + MYSERIAL.write('\n'); + } + else + count = 0; + } + while (count) + { + serial_print_hex_word(address); + MYSERIAL.write(' '); + uint8_t countperline = 16; + while (count && countperline) + { + uint8_t data = eeprom_read_byte((uint8_t*)address++); + MYSERIAL.write(' '); + serial_print_hex_byte(data); + countperline--; + count--; + } + MYSERIAL.write('\n'); + } +} + +void dcode_4() +{ + MYSERIAL.println("D4 - Read/Write PIN"); + if (code_seen('P')) // Pin (0-255) + { + int pin = (int)code_value(); + if ((pin >= 0) && (pin <= 255)) + { + if (code_seen('F')) // Function in/out (0/1) + { + int fnc = (int)code_value(); + if (fnc == 0) pinMode(pin, INPUT); + else if (fnc == 1) pinMode(pin, OUTPUT); + } + if (code_seen('V')) // Value (0/1) + { + int val = (int)code_value(); + if (val == 0) digitalWrite(pin, LOW); + else if (val == 1) digitalWrite(pin, HIGH); + } + else + { + int val = (digitalRead(pin) != LOW)?1:0; + MYSERIAL.print("PIN"); + MYSERIAL.print(pin); + MYSERIAL.print("="); + MYSERIAL.println(val); + } + } + } +} + + diff --git a/Firmware/Dcodes.h b/Firmware/Dcodes.h new file mode 100644 index 00000000..2f8a53f4 --- /dev/null +++ b/Firmware/Dcodes.h @@ -0,0 +1,11 @@ +#ifndef DCODES_H +#define DCODES_H + +extern void dcode_0(); +extern void dcode_1(); +extern void dcode_2(); +extern void dcode_3(); +extern void dcode_4(); + + +#endif //DCODES_H diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 90694b20..c8bca937 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -57,6 +57,9 @@ #include +#include "Dcodes.h" + + #ifdef SWSPI #include "swspi.h" #endif //SWSPI @@ -96,6 +99,8 @@ #include "ultralcd.h" +#include "cmdqueue.h" + // Macros for bit masks #define BIT(b) (1<<(b)) #define TEST(n,b) (((n)&BIT(b))!=0) @@ -240,8 +245,6 @@ CardReader card; #endif -unsigned long TimeSent = millis(); -unsigned long TimeNow = millis(); unsigned long PingTime = millis(); union Data { @@ -417,58 +420,11 @@ static float delta[3] = {0.0, 0.0, 0.0}; static float offset[3] = {0.0, 0.0, 0.0}; static bool home_all_axis = true; static float feedrate = 1500.0, next_feedrate, saved_feedrate; -static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0; // Determines Absolute or Relative Coordinates. // Also there is bool axis_relative_modes[] per axis flag. static bool relative_mode = false; -// String circular buffer. Commands may be pushed to the buffer from both sides: -// Chained commands will be pushed to the front, interactive (from LCD menu) -// and printing commands (from serial line or from SD card) are pushed to the tail. -// First character of each entry indicates the type of the entry: -#define CMDBUFFER_CURRENT_TYPE_UNKNOWN 0 -// Command in cmdbuffer was sent over USB. -#define CMDBUFFER_CURRENT_TYPE_USB 1 -// Command in cmdbuffer was read from SDCARD. -#define CMDBUFFER_CURRENT_TYPE_SDCARD 2 -// Command in cmdbuffer was generated by the UI. -#define CMDBUFFER_CURRENT_TYPE_UI 3 -// Command in cmdbuffer was generated by another G-code. -#define CMDBUFFER_CURRENT_TYPE_CHAINED 4 - -// How much space to reserve for the chained commands -// of type CMDBUFFER_CURRENT_TYPE_CHAINED, -// which are pushed to the front of the queue? -// Maximum 5 commands of max length 20 + null terminator. -#define CMDBUFFER_RESERVE_FRONT (5*21) -// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT. -static char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT]; -// Head of the circular buffer, where to read. -static int bufindr = 0; -// Tail of the buffer, where to write. -static int bufindw = 0; -// Number of lines in cmdbuffer. -static int buflen = 0; -// Flag for processing the current command inside the main Arduino loop(). -// If a new command was pushed to the front of a command buffer while -// processing another command, this replaces the command on the top. -// Therefore don't remove the command from the queue in the loop() function. -static bool cmdbuffer_front_already_processed = false; - -// Type of a command, which is to be executed right now. -#define CMDBUFFER_CURRENT_TYPE (cmdbuffer[bufindr]) -// String of a command, which is to be executed right now. -#define CMDBUFFER_CURRENT_STRING (cmdbuffer+bufindr+CMDHDRSIZE) - -// Enable debugging of the command buffer. -// Debugging information will be sent to serial line. -//#define CMDBUFFER_DEBUG - -static int serial_count = 0; //index of character read from serial line -static boolean comment_mode = false; -static char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc - const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42 //static float tt = 0; @@ -537,315 +493,6 @@ void serial_echopair_P(const char *s_P, unsigned long v) } #endif //!SDSUPPORT -// Pop the currently processed command from the queue. -// It is expected, that there is at least one command in the queue. -bool cmdqueue_pop_front() -{ - if (buflen > 0) { -#ifdef CMDBUFFER_DEBUG - SERIAL_ECHOPGM("Dequeing "); - SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("Old indices: buflen "); - SERIAL_ECHO(buflen); - SERIAL_ECHOPGM(", bufindr "); - SERIAL_ECHO(bufindr); - SERIAL_ECHOPGM(", bufindw "); - SERIAL_ECHO(bufindw); - SERIAL_ECHOPGM(", serial_count "); - SERIAL_ECHO(serial_count); - SERIAL_ECHOPGM(", bufsize "); - SERIAL_ECHO(sizeof(cmdbuffer)); - SERIAL_ECHOLNPGM(""); -#endif /* CMDBUFFER_DEBUG */ - if (-- buflen == 0) { - // Empty buffer. - if (serial_count == 0) - // No serial communication is pending. Reset both pointers to zero. - bufindw = 0; - bufindr = bufindw; - } else { - // There is at least one ready line in the buffer. - // First skip the current command ID and iterate up to the end of the string. -// for (++ bufindr; cmdbuffer[bufindr] != 0; ++ bufindr) ; - for (bufindr += CMDHDRSIZE; cmdbuffer[bufindr] != 0; ++ bufindr) ; - // Second, skip the end of string null character and iterate until a nonzero command ID is found. - for (++ bufindr; bufindr < sizeof(cmdbuffer) && cmdbuffer[bufindr] == 0; ++ bufindr) ; - // If the end of the buffer was empty, - if (bufindr == sizeof(cmdbuffer)) { - // skip to the start and find the nonzero command. - for (bufindr = 0; cmdbuffer[bufindr] == 0; ++ bufindr) ; - } -#ifdef CMDBUFFER_DEBUG - SERIAL_ECHOPGM("New indices: buflen "); - SERIAL_ECHO(buflen); - SERIAL_ECHOPGM(", bufindr "); - SERIAL_ECHO(bufindr); - SERIAL_ECHOPGM(", bufindw "); - SERIAL_ECHO(bufindw); - SERIAL_ECHOPGM(", serial_count "); - SERIAL_ECHO(serial_count); - SERIAL_ECHOPGM(" new command on the top: "); - SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); - SERIAL_ECHOLNPGM(""); -#endif /* CMDBUFFER_DEBUG */ - } - return true; - } - return false; -} - -void cmdqueue_reset() -{ - while (cmdqueue_pop_front()) ; -} - -// How long a string could be pushed to the front of the command queue? -// If yes, adjust bufindr to the new position, where the new command could be enqued. -// len_asked does not contain the zero terminator size. -bool cmdqueue_could_enqueue_front(int len_asked) -{ - // MAX_CMD_SIZE has to accommodate the zero terminator. - if (len_asked >= MAX_CMD_SIZE) - return false; - // Remove the currently processed command from the queue. - if (! cmdbuffer_front_already_processed) { - cmdqueue_pop_front(); - cmdbuffer_front_already_processed = true; - } - if (bufindr == bufindw && buflen > 0) - // Full buffer. - return false; - // Adjust the end of the write buffer based on whether a partial line is in the receive buffer. - int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw; - if (bufindw < bufindr) { - int bufindr_new = bufindr - len_asked - (1 + CMDHDRSIZE); - // Simple case. There is a contiguous space between the write buffer and the read buffer. - if (endw <= bufindr_new) { - bufindr = bufindr_new; - return true; - } - } else { - // Otherwise the free space is split between the start and end. - if (len_asked + (1 + CMDHDRSIZE) <= bufindr) { - // Could fit at the start. - bufindr -= len_asked + (1 + CMDHDRSIZE); - return true; - } - int bufindr_new = sizeof(cmdbuffer) - len_asked - (1 + CMDHDRSIZE); - if (endw <= bufindr_new) { - memset(cmdbuffer, 0, bufindr); - bufindr = bufindr_new; - return true; - } - } - return false; -} - -// Could one enqueue a command of lenthg len_asked into the buffer, -// while leaving CMDBUFFER_RESERVE_FRONT at the start? -// If yes, adjust bufindw to the new position, where the new command could be enqued. -// len_asked does not contain the zero terminator size. -bool cmdqueue_could_enqueue_back(int len_asked) -{ - // MAX_CMD_SIZE has to accommodate the zero terminator. - if (len_asked >= MAX_CMD_SIZE) - return false; - - if (bufindr == bufindw && buflen > 0) - // Full buffer. - return false; - - if (serial_count > 0) { - // If there is some data stored starting at bufindw, len_asked is certainly smaller than - // the allocated data buffer. Try to reserve a new buffer and to move the already received - // serial data. - // How much memory to reserve for the commands pushed to the front? - // End of the queue, when pushing to the end. - int endw = bufindw + len_asked + (1 + CMDHDRSIZE); - if (bufindw < bufindr) - // Simple case. There is a contiguous space between the write buffer and the read buffer. - return endw + CMDBUFFER_RESERVE_FRONT <= bufindr; - // Otherwise the free space is split between the start and end. - if (// Could one fit to the end, including the reserve? - endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) || - // Could one fit to the end, and the reserve to the start? - (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr)) - return true; - // Could one fit both to the start? - if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) { - // Mark the rest of the buffer as used. - memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); - // and point to the start. - bufindw = 0; - return true; - } - } else { - // How much memory to reserve for the commands pushed to the front? - // End of the queue, when pushing to the end. - int endw = bufindw + len_asked + (1 + CMDHDRSIZE); - if (bufindw < bufindr) - // Simple case. There is a contiguous space between the write buffer and the read buffer. - return endw + CMDBUFFER_RESERVE_FRONT <= bufindr; - // Otherwise the free space is split between the start and end. - if (// Could one fit to the end, including the reserve? - endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) || - // Could one fit to the end, and the reserve to the start? - (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr)) - return true; - // Could one fit both to the start? - if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) { - // Mark the rest of the buffer as used. - memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); - // and point to the start. - bufindw = 0; - return true; - } - } - return false; -} - -#ifdef CMDBUFFER_DEBUG -static void cmdqueue_dump_to_serial_single_line(int nr, const char *p) -{ - SERIAL_ECHOPGM("Entry nr: "); - SERIAL_ECHO(nr); - SERIAL_ECHOPGM(", type: "); - SERIAL_ECHO(int(*p)); - SERIAL_ECHOPGM(", cmd: "); - SERIAL_ECHO(p+1); - SERIAL_ECHOLNPGM(""); -} - -static void cmdqueue_dump_to_serial() -{ - if (buflen == 0) { - SERIAL_ECHOLNPGM("The command buffer is empty."); - } else { - SERIAL_ECHOPGM("Content of the buffer: entries "); - SERIAL_ECHO(buflen); - SERIAL_ECHOPGM(", indr "); - SERIAL_ECHO(bufindr); - SERIAL_ECHOPGM(", indw "); - SERIAL_ECHO(bufindw); - SERIAL_ECHOLNPGM(""); - int nr = 0; - if (bufindr < bufindw) { - for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) { - cmdqueue_dump_to_serial_single_line(nr, p); - // Skip the command. - for (++p; *p != 0; ++ p); - // Skip the gaps. - for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p); - } - } else { - for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) { - cmdqueue_dump_to_serial_single_line(nr, p); - // Skip the command. - for (++p; *p != 0; ++ p); - // Skip the gaps. - for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p); - } - for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) { - cmdqueue_dump_to_serial_single_line(nr, p); - // Skip the command. - for (++p; *p != 0; ++ p); - // Skip the gaps. - for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p); - } - } - SERIAL_ECHOLNPGM("End of the buffer."); - } -} -#endif /* CMDBUFFER_DEBUG */ - -//adds an command to the main command buffer -//thats really done in a non-safe way. -//needs overworking someday -// Currently the maximum length of a command piped through this function is around 20 characters -void enquecommand(const char *cmd, bool from_progmem) -{ - int len = from_progmem ? strlen_P(cmd) : strlen(cmd); - // Does cmd fit the queue while leaving sufficient space at the front for the chained commands? - // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd. - if (cmdqueue_could_enqueue_back(len)) { - // This is dangerous if a mixing of serial and this happens - // This may easily be tested: If serial_count > 0, we have a problem. - cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI; - if (from_progmem) - strcpy_P(cmdbuffer + bufindw + CMDHDRSIZE, cmd); - else - strcpy(cmdbuffer + bufindw + CMDHDRSIZE, cmd); - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_Enqueing); - SERIAL_ECHO(cmdbuffer + bufindw + CMDHDRSIZE); - SERIAL_ECHOLNPGM("\""); - bufindw += len + (CMDHDRSIZE + 1); - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - ++ buflen; -#ifdef CMDBUFFER_DEBUG - cmdqueue_dump_to_serial(); -#endif /* CMDBUFFER_DEBUG */ - } else { - SERIAL_ERROR_START; - SERIAL_ECHORPGM(MSG_Enqueing); - if (from_progmem) - SERIAL_PROTOCOLRPGM(cmd); - else - SERIAL_ECHO(cmd); - SERIAL_ECHOLNPGM("\" failed: Buffer full!"); -#ifdef CMDBUFFER_DEBUG - cmdqueue_dump_to_serial(); -#endif /* CMDBUFFER_DEBUG */ - } -} - -void enquecommand_front(const char *cmd, bool from_progmem) -{ - int len = from_progmem ? strlen_P(cmd) : strlen(cmd); - // Does cmd fit the queue? This call shall move bufindr, so the command may be copied. - if (cmdqueue_could_enqueue_front(len)) { - cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI; - if (from_progmem) - strcpy_P(cmdbuffer + bufindr + CMDHDRSIZE, cmd); - else - strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd); - ++ buflen; - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Enqueing to the front: \""); - SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE); - SERIAL_ECHOLNPGM("\""); -#ifdef CMDBUFFER_DEBUG - cmdqueue_dump_to_serial(); -#endif /* CMDBUFFER_DEBUG */ - } else { - SERIAL_ERROR_START; - SERIAL_ECHOPGM("Enqueing to the front: \""); - if (from_progmem) - SERIAL_PROTOCOLRPGM(cmd); - else - SERIAL_ECHO(cmd); - SERIAL_ECHOLNPGM("\" failed: Buffer full!"); -#ifdef CMDBUFFER_DEBUG - cmdqueue_dump_to_serial(); -#endif /* CMDBUFFER_DEBUG */ - } -} - -// Mark the command at the top of the command queue as new. -// Therefore it will not be removed from the queue. -void repeatcommand_front() -{ - cmdbuffer_front_already_processed = true; -} - -bool is_buffer_empty() -{ - if (buflen == 0) return true; - else return false; -} - void setup_killpin() { #if defined(KILL_PIN) && KILL_PIN > -1 @@ -1520,287 +1167,6 @@ void loop() #endif //TMC2130 } -void get_command() -{ - // Test and reserve space for the new command string. - if (!cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1)) - return; - - bool rx_buffer_full = false; //flag that serial rx buffer is full - - while (MYSERIAL.available() > 0) { - if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size - SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed - rx_buffer_full = true; //sets flag that buffer was full - } - char serial_char = MYSERIAL.read(); - if (selectedSerialPort == 1) - { - selectedSerialPort = 0; - MYSERIAL.write(serial_char); - selectedSerialPort = 1; - } - TimeSent = millis(); - TimeNow = millis(); - - if (serial_char < 0) - // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names - // and Marlin does not support such file names anyway. - // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading - // to a hang-up of the print process from an SD card. - continue; - if(serial_char == '\n' || - serial_char == '\r' || - (serial_char == ':' && comment_mode == false) || - serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) { //if empty line - comment_mode = false; //for new command - return; - } - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string - if(!comment_mode){ - comment_mode = false; //for new command - if ((strchr_pointer = strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA")) == NULL && (strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL) { - if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL) - { - // Line number met. When sending a G-code over a serial line, each line may be stamped with its index, - // and Marlin tests, whether the successive lines are stamped with an increasing line number ID. - gcode_N = (strtol(strchr_pointer+1, NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) { - // M110 - set current line number. - // Line numbers not sent in succession. - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(MSG_ERR_LINE_NO); - SERIAL_ERRORLN(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL) - { - byte checksum = 0; - char *p = cmdbuffer+bufindw+CMDHDRSIZE; - while (p != strchr_pointer) - checksum = checksum^(*p++); - if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH); - SERIAL_ERRORLN(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - // If no errors, remove the checksum and continue parsing. - *strchr_pointer = 0; - } - else - { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM); - SERIAL_ERRORLN(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } // end of 'N' command - } - else // if we don't receive 'N' but still see '*' - { - if((strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL)) - { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM); - SERIAL_ERRORLN(gcode_LastN); - serial_count = 0; - return; - } - } // end of '*' command - if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { - if (! IS_SD_PRINTING) { - usb_printing_counter = 10; - is_usb_printing = true; - } - if (Stopped == true) { - int gcode = strtol(strchr_pointer+1, NULL, 10); - if (gcode >= 0 && gcode <= 3) { - SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED); - LCD_MESSAGERPGM(MSG_STOPPED); - } - } - } // end of 'G' command - - //If command was e-stop process now - if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0) - kill("", 2); - - // Store the current line into buffer, move to the next line. - cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_USB; -#ifdef CMDBUFFER_DEBUG - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Storing a command line to buffer: "); - SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE); - SERIAL_ECHOLNPGM(""); -#endif /* CMDBUFFER_DEBUG */ - bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - ++ buflen; -#ifdef CMDBUFFER_DEBUG - SERIAL_ECHOPGM("Number of commands in the buffer: "); - SERIAL_ECHO(buflen); - SERIAL_ECHOLNPGM(""); -#endif /* CMDBUFFER_DEBUG */ - } // end of 'not comment mode' - serial_count = 0; //clear buffer - // Don't call cmdqueue_could_enqueue_back if there are no characters waiting - // in the queue, as this function will reserve the memory. - if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) - return; - } // end of "end of line" processing - else { - // Not an "end of line" symbol. Store the new character into a buffer. - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; - } - } // end of serial line processing loop - - if(farm_mode){ - TimeNow = millis(); - if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) { - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; - - bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - ++ buflen; - - serial_count = 0; - - SERIAL_ECHOPGM("TIMEOUT:"); - //memset(cmdbuffer, 0 , sizeof(cmdbuffer)); - return; - } - } - - //add comment - if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated - rx_buffer_full = false; - bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command - serial_count = 0; - } - - #ifdef SDSUPPORT - if(!card.sdprinting || serial_count!=0){ - // If there is a half filled buffer from serial line, wait until return before - // continuing with the serial line. - return; - } - - //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible - // if it occurs, stop_buffering is triggered and the buffer is ran dry. - // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing - - static bool stop_buffering=false; - if(buflen==0) stop_buffering=false; - unsigned char sd_count = 0; - // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. - while( !card.eof() && !stop_buffering) { - int16_t n=card.get(); - sd_count++; - char serial_char = (char)n; - if(serial_char == '\n' || - serial_char == '\r' || - (serial_char == '#' && comment_mode == false) || - (serial_char == ':' && comment_mode == false) || - serial_count >= (MAX_CMD_SIZE - 1)||n==-1) - { - if(card.eof()){ - SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED); - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime-pause_time)/1000; - pause_time = 0; - int hours, minutes; - minutes=(t/60)%60; - hours=t/60/60; - save_statistics(total_filament_used, t); - sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); - SERIAL_ECHO_START; - SERIAL_ECHOLN(time); - lcd_setstatus(time); - card.printingHasFinished(); - card.checkautostart(true); - - if (farm_mode) - { - prusa_statistics(6); - lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; - } - - } - if(serial_char=='#') - stop_buffering=true; - - if(!serial_count) - { - comment_mode = false; //for new command - return; //if empty line - } - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string - cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; - cmdbuffer[bufindw+1] = sd_count; -/* SERIAL_ECHOPGM("SD cmd("); - MYSERIAL.print(sd_count, DEC); - SERIAL_ECHOPGM(") "); - SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/ -// SERIAL_ECHOPGM("cmdbuffer:"); -// MYSERIAL.print(cmdbuffer); - ++ buflen; -// SERIAL_ECHOPGM("buflen:"); -// MYSERIAL.print(buflen); - bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - comment_mode = false; //for new command - serial_count = 0; //clear buffer - // The following line will reserve buffer space if available. - if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) - return; - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; - } - } - - #endif //SDSUPPORT -} - - -// Return True if a character was found -static inline bool code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } -static inline bool code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } -static inline float code_value() { return strtod(strchr_pointer+1, NULL);} -static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); } -static inline int16_t code_value_short() { return int16_t(strtol(strchr_pointer+1, NULL, 10)); }; -static inline uint8_t code_value_uint8() { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); }; - -static inline float code_value_float() { - char* e = strchr(strchr_pointer, 'E'); - if (!e) return strtod(strchr_pointer + 1, NULL); - *e = 0; - float ret = strtod(strchr_pointer + 1, NULL); - *e = 'E'; - return ret; -} - #define DEFINE_PGM_READ_ANY(type, reader) \ static inline type pgm_read_any(const type *p) \ { return pgm_read_##reader##_near(p); } @@ -6207,57 +5573,30 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp switch((int)code_value()) { case 0: // D0 - Reset - if (*(strchr_pointer + 1) == 0) break; - MYSERIAL.println("D0 - Reset"); - asm volatile("jmp 0x00000"); - break; -/* MYSERIAL.println("D0 - Reset"); - cli(); //disable interrupts - wdt_reset(); //reset watchdog - WDTCSR = (1<= 0) && (pin <= 255)) - { - if (code_seen('F')) // Function in/out (0/1) - { - int fnc = (int)code_value(); - if (fnc == 0) pinMode(pin, INPUT); - else if (fnc == 1) pinMode(pin, OUTPUT); - } - if (code_seen('V')) // Value (0/1) - { - int val = (int)code_value(); - if (val == 0) digitalWrite(pin, LOW); - else if (val == 1) digitalWrite(pin, HIGH); - } - else - { - int val = (digitalRead(pin) != LOW)?1:0; - MYSERIAL.print("PIN"); - MYSERIAL.print(pin); - MYSERIAL.print("="); - MYSERIAL.println(val); - } - } + serial_print_hex_byte(data[i]); + MYSERIAL.write(' '); } + MYSERIAL.write('\n'); } break; - case 3: +/* case 3: if (code_seen('L')) // lcd pwm (0-255) { lcdSoftPwm = (int)code_value(); @@ -6272,14 +5611,14 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp fsensor_enable(); #endif*/ break; - case 4: +// case 4: // lcdBlinkDelay = 10; /* MYSERIAL.print("fsensor_disable()"); #ifdef PAT9125 fsensor_disable(); #endif break;*/ - break; +// break; case 5: { /* MYSERIAL.print("tmc2130_rd_MSCNT(0)="); @@ -7352,7 +6691,7 @@ void serialecho_temperatures() { void uvlo_() { - //SERIAL_ECHOLNPGM("UVLO"); + //SERIAL_ECHOLNPGM("UVLO"); save_print_to_eeprom(); float current_position_bckp[2]; int feedrate_bckp = feedrate; diff --git a/Firmware/cmdqueue.cpp b/Firmware/cmdqueue.cpp new file mode 100644 index 00000000..c32b65b1 --- /dev/null +++ b/Firmware/cmdqueue.cpp @@ -0,0 +1,603 @@ +#include "cmdqueue.h" +#include "cardreader.h" +#include "ultralcd.h" + +extern bool Stopped; + +// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT. +char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT]; +// Head of the circular buffer, where to read. +int bufindr = 0; +// Tail of the buffer, where to write. +int bufindw = 0; +// Number of lines in cmdbuffer. +int buflen = 0; +// Flag for processing the current command inside the main Arduino loop(). +// If a new command was pushed to the front of a command buffer while +// processing another command, this replaces the command on the top. +// Therefore don't remove the command from the queue in the loop() function. +bool cmdbuffer_front_already_processed = false; + +int serial_count = 0; //index of character read from serial line +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc + +unsigned long TimeSent = millis(); +unsigned long TimeNow = millis(); + +long gcode_N = 0; +long gcode_LastN = 0; +long Stopped_gcode_LastN = 0; + + +// Pop the currently processed command from the queue. +// It is expected, that there is at least one command in the queue. +bool cmdqueue_pop_front() +{ + if (buflen > 0) { +#ifdef CMDBUFFER_DEBUG + SERIAL_ECHOPGM("Dequeing "); + SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Old indices: buflen "); + SERIAL_ECHO(buflen); + SERIAL_ECHOPGM(", bufindr "); + SERIAL_ECHO(bufindr); + SERIAL_ECHOPGM(", bufindw "); + SERIAL_ECHO(bufindw); + SERIAL_ECHOPGM(", serial_count "); + SERIAL_ECHO(serial_count); + SERIAL_ECHOPGM(", bufsize "); + SERIAL_ECHO(sizeof(cmdbuffer)); + SERIAL_ECHOLNPGM(""); +#endif /* CMDBUFFER_DEBUG */ + if (-- buflen == 0) { + // Empty buffer. + if (serial_count == 0) + // No serial communication is pending. Reset both pointers to zero. + bufindw = 0; + bufindr = bufindw; + } else { + // There is at least one ready line in the buffer. + // First skip the current command ID and iterate up to the end of the string. +// for (++ bufindr; cmdbuffer[bufindr] != 0; ++ bufindr) ; + for (bufindr += CMDHDRSIZE; cmdbuffer[bufindr] != 0; ++ bufindr) ; + // Second, skip the end of string null character and iterate until a nonzero command ID is found. + for (++ bufindr; bufindr < sizeof(cmdbuffer) && cmdbuffer[bufindr] == 0; ++ bufindr) ; + // If the end of the buffer was empty, + if (bufindr == sizeof(cmdbuffer)) { + // skip to the start and find the nonzero command. + for (bufindr = 0; cmdbuffer[bufindr] == 0; ++ bufindr) ; + } +#ifdef CMDBUFFER_DEBUG + SERIAL_ECHOPGM("New indices: buflen "); + SERIAL_ECHO(buflen); + SERIAL_ECHOPGM(", bufindr "); + SERIAL_ECHO(bufindr); + SERIAL_ECHOPGM(", bufindw "); + SERIAL_ECHO(bufindw); + SERIAL_ECHOPGM(", serial_count "); + SERIAL_ECHO(serial_count); + SERIAL_ECHOPGM(" new command on the top: "); + SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); + SERIAL_ECHOLNPGM(""); +#endif /* CMDBUFFER_DEBUG */ + } + return true; + } + return false; +} + +void cmdqueue_reset() +{ + while (cmdqueue_pop_front()) ; +} + +// How long a string could be pushed to the front of the command queue? +// If yes, adjust bufindr to the new position, where the new command could be enqued. +// len_asked does not contain the zero terminator size. +bool cmdqueue_could_enqueue_front(int len_asked) +{ + // MAX_CMD_SIZE has to accommodate the zero terminator. + if (len_asked >= MAX_CMD_SIZE) + return false; + // Remove the currently processed command from the queue. + if (! cmdbuffer_front_already_processed) { + cmdqueue_pop_front(); + cmdbuffer_front_already_processed = true; + } + if (bufindr == bufindw && buflen > 0) + // Full buffer. + return false; + // Adjust the end of the write buffer based on whether a partial line is in the receive buffer. + int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw; + if (bufindw < bufindr) { + int bufindr_new = bufindr - len_asked - (1 + CMDHDRSIZE); + // Simple case. There is a contiguous space between the write buffer and the read buffer. + if (endw <= bufindr_new) { + bufindr = bufindr_new; + return true; + } + } else { + // Otherwise the free space is split between the start and end. + if (len_asked + (1 + CMDHDRSIZE) <= bufindr) { + // Could fit at the start. + bufindr -= len_asked + (1 + CMDHDRSIZE); + return true; + } + int bufindr_new = sizeof(cmdbuffer) - len_asked - (1 + CMDHDRSIZE); + if (endw <= bufindr_new) { + memset(cmdbuffer, 0, bufindr); + bufindr = bufindr_new; + return true; + } + } + return false; +} + +// Could one enqueue a command of lenthg len_asked into the buffer, +// while leaving CMDBUFFER_RESERVE_FRONT at the start? +// If yes, adjust bufindw to the new position, where the new command could be enqued. +// len_asked does not contain the zero terminator size. +bool cmdqueue_could_enqueue_back(int len_asked) +{ + // MAX_CMD_SIZE has to accommodate the zero terminator. + if (len_asked >= MAX_CMD_SIZE) + return false; + + if (bufindr == bufindw && buflen > 0) + // Full buffer. + return false; + + if (serial_count > 0) { + // If there is some data stored starting at bufindw, len_asked is certainly smaller than + // the allocated data buffer. Try to reserve a new buffer and to move the already received + // serial data. + // How much memory to reserve for the commands pushed to the front? + // End of the queue, when pushing to the end. + int endw = bufindw + len_asked + (1 + CMDHDRSIZE); + if (bufindw < bufindr) + // Simple case. There is a contiguous space between the write buffer and the read buffer. + return endw + CMDBUFFER_RESERVE_FRONT <= bufindr; + // Otherwise the free space is split between the start and end. + if (// Could one fit to the end, including the reserve? + endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) || + // Could one fit to the end, and the reserve to the start? + (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr)) + return true; + // Could one fit both to the start? + if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) { + // Mark the rest of the buffer as used. + memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); + // and point to the start. + bufindw = 0; + return true; + } + } else { + // How much memory to reserve for the commands pushed to the front? + // End of the queue, when pushing to the end. + int endw = bufindw + len_asked + (1 + CMDHDRSIZE); + if (bufindw < bufindr) + // Simple case. There is a contiguous space between the write buffer and the read buffer. + return endw + CMDBUFFER_RESERVE_FRONT <= bufindr; + // Otherwise the free space is split between the start and end. + if (// Could one fit to the end, including the reserve? + endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) || + // Could one fit to the end, and the reserve to the start? + (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr)) + return true; + // Could one fit both to the start? + if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) { + // Mark the rest of the buffer as used. + memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); + // and point to the start. + bufindw = 0; + return true; + } + } + return false; +} + +#ifdef CMDBUFFER_DEBUG +void cmdqueue_dump_to_serial_single_line(int nr, const char *p) +{ + SERIAL_ECHOPGM("Entry nr: "); + SERIAL_ECHO(nr); + SERIAL_ECHOPGM(", type: "); + SERIAL_ECHO(int(*p)); + SERIAL_ECHOPGM(", cmd: "); + SERIAL_ECHO(p+1); + SERIAL_ECHOLNPGM(""); +} + +void cmdqueue_dump_to_serial() +{ + if (buflen == 0) { + SERIAL_ECHOLNPGM("The command buffer is empty."); + } else { + SERIAL_ECHOPGM("Content of the buffer: entries "); + SERIAL_ECHO(buflen); + SERIAL_ECHOPGM(", indr "); + SERIAL_ECHO(bufindr); + SERIAL_ECHOPGM(", indw "); + SERIAL_ECHO(bufindw); + SERIAL_ECHOLNPGM(""); + int nr = 0; + if (bufindr < bufindw) { + for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) { + cmdqueue_dump_to_serial_single_line(nr, p); + // Skip the command. + for (++p; *p != 0; ++ p); + // Skip the gaps. + for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p); + } + } else { + for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) { + cmdqueue_dump_to_serial_single_line(nr, p); + // Skip the command. + for (++p; *p != 0; ++ p); + // Skip the gaps. + for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p); + } + for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) { + cmdqueue_dump_to_serial_single_line(nr, p); + // Skip the command. + for (++p; *p != 0; ++ p); + // Skip the gaps. + for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p); + } + } + SERIAL_ECHOLNPGM("End of the buffer."); + } +} +#endif /* CMDBUFFER_DEBUG */ + +//adds an command to the main command buffer +//thats really done in a non-safe way. +//needs overworking someday +// Currently the maximum length of a command piped through this function is around 20 characters +void enquecommand(const char *cmd, bool from_progmem) +{ + int len = from_progmem ? strlen_P(cmd) : strlen(cmd); + // Does cmd fit the queue while leaving sufficient space at the front for the chained commands? + // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd. + if (cmdqueue_could_enqueue_back(len)) { + // This is dangerous if a mixing of serial and this happens + // This may easily be tested: If serial_count > 0, we have a problem. + cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI; + if (from_progmem) + strcpy_P(cmdbuffer + bufindw + CMDHDRSIZE, cmd); + else + strcpy(cmdbuffer + bufindw + CMDHDRSIZE, cmd); + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_Enqueing); + SERIAL_ECHO(cmdbuffer + bufindw + CMDHDRSIZE); + SERIAL_ECHOLNPGM("\""); + bufindw += len + (CMDHDRSIZE + 1); + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + ++ buflen; +#ifdef CMDBUFFER_DEBUG + cmdqueue_dump_to_serial(); +#endif /* CMDBUFFER_DEBUG */ + } else { + SERIAL_ERROR_START; + SERIAL_ECHORPGM(MSG_Enqueing); + if (from_progmem) + SERIAL_PROTOCOLRPGM(cmd); + else + SERIAL_ECHO(cmd); + SERIAL_ECHOLNPGM("\" failed: Buffer full!"); +#ifdef CMDBUFFER_DEBUG + cmdqueue_dump_to_serial(); +#endif /* CMDBUFFER_DEBUG */ + } +} + +void enquecommand_front(const char *cmd, bool from_progmem) +{ + int len = from_progmem ? strlen_P(cmd) : strlen(cmd); + // Does cmd fit the queue? This call shall move bufindr, so the command may be copied. + if (cmdqueue_could_enqueue_front(len)) { + cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI; + if (from_progmem) + strcpy_P(cmdbuffer + bufindr + CMDHDRSIZE, cmd); + else + strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd); + ++ buflen; + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Enqueing to the front: \""); + SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE); + SERIAL_ECHOLNPGM("\""); +#ifdef CMDBUFFER_DEBUG + cmdqueue_dump_to_serial(); +#endif /* CMDBUFFER_DEBUG */ + } else { + SERIAL_ERROR_START; + SERIAL_ECHOPGM("Enqueing to the front: \""); + if (from_progmem) + SERIAL_PROTOCOLRPGM(cmd); + else + SERIAL_ECHO(cmd); + SERIAL_ECHOLNPGM("\" failed: Buffer full!"); +#ifdef CMDBUFFER_DEBUG + cmdqueue_dump_to_serial(); +#endif /* CMDBUFFER_DEBUG */ + } +} + +// Mark the command at the top of the command queue as new. +// Therefore it will not be removed from the queue. +void repeatcommand_front() +{ + cmdbuffer_front_already_processed = true; +} + +bool is_buffer_empty() +{ + if (buflen == 0) return true; + else return false; +} + +void get_command() +{ + // Test and reserve space for the new command string. + if (!cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1)) + return; + + bool rx_buffer_full = false; //flag that serial rx buffer is full + + while (MYSERIAL.available() > 0) { + if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size + SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed + rx_buffer_full = true; //sets flag that buffer was full + } + char serial_char = MYSERIAL.read(); + if (selectedSerialPort == 1) + { + selectedSerialPort = 0; + MYSERIAL.write(serial_char); + selectedSerialPort = 1; + } + TimeSent = millis(); + TimeNow = millis(); + + if (serial_char < 0) + // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names + // and Marlin does not support such file names anyway. + // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading + // to a hang-up of the print process from an SD card. + continue; + if(serial_char == '\n' || + serial_char == '\r' || + (serial_char == ':' && comment_mode == false) || + serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) { //if empty line + comment_mode = false; //for new command + return; + } + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string + if(!comment_mode){ + comment_mode = false; //for new command + if ((strchr_pointer = strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA")) == NULL && (strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL) { + if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL) + { + // Line number met. When sending a G-code over a serial line, each line may be stamped with its index, + // and Marlin tests, whether the successive lines are stamped with an increasing line number ID. + gcode_N = (strtol(strchr_pointer+1, NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) { + // M110 - set current line number. + // Line numbers not sent in succession. + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(MSG_ERR_LINE_NO); + SERIAL_ERRORLN(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL) + { + byte checksum = 0; + char *p = cmdbuffer+bufindw+CMDHDRSIZE; + while (p != strchr_pointer) + checksum = checksum^(*p++); + if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) { + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH); + SERIAL_ERRORLN(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + // If no errors, remove the checksum and continue parsing. + *strchr_pointer = 0; + } + else + { + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM); + SERIAL_ERRORLN(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } // end of 'N' command + } + else // if we don't receive 'N' but still see '*' + { + if((strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL)) + { + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM); + SERIAL_ERRORLN(gcode_LastN); + serial_count = 0; + return; + } + } // end of '*' command + if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { + if (! IS_SD_PRINTING) { + usb_printing_counter = 10; + is_usb_printing = true; + } + if (Stopped == true) { + int gcode = strtol(strchr_pointer+1, NULL, 10); + if (gcode >= 0 && gcode <= 3) { + SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED); + LCD_MESSAGERPGM(MSG_STOPPED); + } + } + } // end of 'G' command + + //If command was e-stop process now + if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0) + kill("", 2); + + // Store the current line into buffer, move to the next line. + cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_USB; +#ifdef CMDBUFFER_DEBUG + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Storing a command line to buffer: "); + SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE); + SERIAL_ECHOLNPGM(""); +#endif /* CMDBUFFER_DEBUG */ + bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + ++ buflen; +#ifdef CMDBUFFER_DEBUG + SERIAL_ECHOPGM("Number of commands in the buffer: "); + SERIAL_ECHO(buflen); + SERIAL_ECHOLNPGM(""); +#endif /* CMDBUFFER_DEBUG */ + } // end of 'not comment mode' + serial_count = 0; //clear buffer + // Don't call cmdqueue_could_enqueue_back if there are no characters waiting + // in the queue, as this function will reserve the memory. + if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) + return; + } // end of "end of line" processing + else { + // Not an "end of line" symbol. Store the new character into a buffer. + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + } + } // end of serial line processing loop + + if(farm_mode){ + TimeNow = millis(); + if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) { + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; + + bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + ++ buflen; + + serial_count = 0; + + SERIAL_ECHOPGM("TIMEOUT:"); + //memset(cmdbuffer, 0 , sizeof(cmdbuffer)); + return; + } + } + + //add comment + if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated + rx_buffer_full = false; + bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command + serial_count = 0; + } + + #ifdef SDSUPPORT + if(!card.sdprinting || serial_count!=0){ + // If there is a half filled buffer from serial line, wait until return before + // continuing with the serial line. + return; + } + + //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible + // if it occurs, stop_buffering is triggered and the buffer is ran dry. + // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing + + static bool stop_buffering=false; + if(buflen==0) stop_buffering=false; + unsigned char sd_count = 0; + // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. + while( !card.eof() && !stop_buffering) { + int16_t n=card.get(); + sd_count++; + char serial_char = (char)n; + if(serial_char == '\n' || + serial_char == '\r' || + (serial_char == '#' && comment_mode == false) || + (serial_char == ':' && comment_mode == false) || + serial_count >= (MAX_CMD_SIZE - 1)||n==-1) + { + if(card.eof()){ + SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED); + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime-pause_time)/1000; + pause_time = 0; + int hours, minutes; + minutes=(t/60)%60; + hours=t/60/60; + save_statistics(total_filament_used, t); + sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); + SERIAL_ECHO_START; + SERIAL_ECHOLN(time); + lcd_setstatus(time); + card.printingHasFinished(); + card.checkautostart(true); + + if (farm_mode) + { + prusa_statistics(6); + lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; + } + + } + if(serial_char=='#') + stop_buffering=true; + + if(!serial_count) + { + comment_mode = false; //for new command + return; //if empty line + } + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string + cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; + cmdbuffer[bufindw+1] = sd_count; +/* SERIAL_ECHOPGM("SD cmd("); + MYSERIAL.print(sd_count, DEC); + SERIAL_ECHOPGM(") "); + SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/ +// SERIAL_ECHOPGM("cmdbuffer:"); +// MYSERIAL.print(cmdbuffer); + ++ buflen; +// SERIAL_ECHOPGM("buflen:"); +// MYSERIAL.print(buflen); + bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + comment_mode = false; //for new command + serial_count = 0; //clear buffer + // The following line will reserve buffer space if available. + if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) + return; + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + } + } + + #endif //SDSUPPORT +} diff --git a/Firmware/cmdqueue.h b/Firmware/cmdqueue.h new file mode 100644 index 00000000..f029d43a --- /dev/null +++ b/Firmware/cmdqueue.h @@ -0,0 +1,85 @@ +#ifndef CMDQUEUE_H +#define CMDQUEUE_H + +#include "Marlin.h" +#include "language_all.h" + + +// String circular buffer. Commands may be pushed to the buffer from both sides: +// Chained commands will be pushed to the front, interactive (from LCD menu) +// and printing commands (from serial line or from SD card) are pushed to the tail. +// First character of each entry indicates the type of the entry: +#define CMDBUFFER_CURRENT_TYPE_UNKNOWN 0 +// Command in cmdbuffer was sent over USB. +#define CMDBUFFER_CURRENT_TYPE_USB 1 +// Command in cmdbuffer was read from SDCARD. +#define CMDBUFFER_CURRENT_TYPE_SDCARD 2 +// Command in cmdbuffer was generated by the UI. +#define CMDBUFFER_CURRENT_TYPE_UI 3 +// Command in cmdbuffer was generated by another G-code. +#define CMDBUFFER_CURRENT_TYPE_CHAINED 4 + +// How much space to reserve for the chained commands +// of type CMDBUFFER_CURRENT_TYPE_CHAINED, +// which are pushed to the front of the queue? +// Maximum 5 commands of max length 20 + null terminator. +#define CMDBUFFER_RESERVE_FRONT (5*21) + +extern char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT]; +extern int bufindr; +extern int bufindw; +extern int buflen; +extern bool cmdbuffer_front_already_processed; + +// Type of a command, which is to be executed right now. +#define CMDBUFFER_CURRENT_TYPE (cmdbuffer[bufindr]) +// String of a command, which is to be executed right now. +#define CMDBUFFER_CURRENT_STRING (cmdbuffer+bufindr+CMDHDRSIZE) + +// Enable debugging of the command buffer. +// Debugging information will be sent to serial line. +//#define CMDBUFFER_DEBUG + +extern int serial_count; +extern boolean comment_mode; +extern char *strchr_pointer; + +extern unsigned long TimeSent; +extern unsigned long TimeNow; + +extern long gcode_N; +extern long gcode_LastN; +extern long Stopped_gcode_LastN; + +extern bool cmdqueue_pop_front(); +extern void cmdqueue_reset(); +extern bool cmdqueue_could_enqueue_front(int len_asked); +extern bool cmdqueue_could_enqueue_back(int len_asked); +extern void cmdqueue_dump_to_serial_single_line(int nr, const char *p); +extern void cmdqueue_dump_to_serial(); +extern void enquecommand(const char *cmd, bool from_progmem); +extern void enquecommand_front(const char *cmd, bool from_progmem); +extern void repeatcommand_front(); +extern bool is_buffer_empty(); +extern void get_command(); + +// Return True if a character was found +static inline bool code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } +static inline bool code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } +static inline float code_value() { return strtod(strchr_pointer+1, NULL);} +static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); } +static inline int16_t code_value_short() { return int16_t(strtol(strchr_pointer+1, NULL, 10)); }; +static inline uint8_t code_value_uint8() { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); }; + +static inline float code_value_float() +{ + char* e = strchr(strchr_pointer, 'E'); + if (!e) return strtod(strchr_pointer + 1, NULL); + *e = 0; + float ret = strtod(strchr_pointer + 1, NULL); + *e = 'E'; + return ret; +} + + +#endif //CMDQUEUE_H diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp index 8dcc225b..503404a4 100644 --- a/Firmware/tmc2130.cpp +++ b/Firmware/tmc2130.cpp @@ -28,13 +28,13 @@ uint8_t tmc2130_current_r[4] = TMC2130_CURRENTS_R; uint8_t tmc2130_axis_stalled[3] = {0, 0, 0}; //pwm_ampl -uint8_t tmc2130_pwm_ampl[2] = {TMC2130_PWM_AMPL_XY, TMC2130_PWM_AMPL_XY}; +uint8_t tmc2130_pwm_ampl[2] = {TMC2130_PWM_AMPL_X, TMC2130_PWM_AMPL_Y}; //pwm_grad -uint8_t tmc2130_pwm_grad[2] = {TMC2130_PWM_GRAD_XY, TMC2130_PWM_GRAD_XY}; +uint8_t tmc2130_pwm_grad[2] = {TMC2130_PWM_GRAD_X, TMC2130_PWM_GRAD_Y}; //pwm_auto -uint8_t tmc2130_pwm_auto[2] = {TMC2130_PWM_AUTO_XY, TMC2130_PWM_AUTO_XY}; +uint8_t tmc2130_pwm_auto[2] = {TMC2130_PWM_AUTO_X, TMC2130_PWM_AUTO_Y}; //pwm_freq -uint8_t tmc2130_pwm_freq[2] = {TMC2130_PWM_FREQ_XY, TMC2130_PWM_FREQ_XY}; +uint8_t tmc2130_pwm_freq[2] = {TMC2130_PWM_FREQ_X, TMC2130_PWM_FREQ_Y}; uint8_t tmc2131_axis_sg_thr[3] = {TMC2130_SG_THRS_X, TMC2130_SG_THRS_Y, TMC2130_SG_THRS_Z}; diff --git a/Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h index 2fee06c6..a6a6fb47 100644 --- a/Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h @@ -109,10 +109,15 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define TMC2130_INTPOL_Z 1 // extrapolate 256 for Z axis #define TMC2130_INTPOL_E 1 // extrapolate 256 for E axis -#define TMC2130_PWM_GRAD_XY 4 // PWMCONF -#define TMC2130_PWM_AMPL_XY 200 // PWMCONF -#define TMC2130_PWM_AUTO_XY 1 // PWMCONF -#define TMC2130_PWM_FREQ_XY 2 // PWMCONF +#define TMC2130_PWM_GRAD_X 4 // PWMCONF +#define TMC2130_PWM_AMPL_X 200 // PWMCONF +#define TMC2130_PWM_AUTO_X 1 // PWMCONF +#define TMC2130_PWM_FREQ_X 2 // PWMCONF + +#define TMC2130_PWM_GRAD_Y 4 // PWMCONF +#define TMC2130_PWM_AMPL_Y 210 // PWMCONF +#define TMC2130_PWM_AUTO_Y 1 // PWMCONF +#define TMC2130_PWM_FREQ_Y 2 // PWMCONF /* //not used #define TMC2130_PWM_GRAD_Z 4 // PWMCONF diff --git a/Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h index 8c901bd5..f134bb68 100644 --- a/Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h @@ -109,10 +109,15 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define TMC2130_INTPOL_Z 1 // extrapolate 256 for Z axis #define TMC2130_INTPOL_E 1 // extrapolate 256 for E axis -#define TMC2130_PWM_GRAD_XY 4 // PWMCONF -#define TMC2130_PWM_AMPL_XY 200 // PWMCONF -#define TMC2130_PWM_AUTO_XY 1 // PWMCONF -#define TMC2130_PWM_FREQ_XY 2 // PWMCONF +#define TMC2130_PWM_GRAD_X 4 // PWMCONF +#define TMC2130_PWM_AMPL_X 200 // PWMCONF +#define TMC2130_PWM_AUTO_X 1 // PWMCONF +#define TMC2130_PWM_FREQ_X 2 // PWMCONF + +#define TMC2130_PWM_GRAD_Y 4 // PWMCONF +#define TMC2130_PWM_AMPL_Y 210 // PWMCONF +#define TMC2130_PWM_AUTO_Y 1 // PWMCONF +#define TMC2130_PWM_FREQ_Y 2 // PWMCONF /* //not used #define TMC2130_PWM_GRAD_Z 4 // PWMCONF