diff --git a/attic/input-float.tar.gz b/attic/input-float.tar.gz new file mode 100644 index 0000000..a2a3b1b Binary files /dev/null and b/attic/input-float.tar.gz differ diff --git a/attic/input-float/apply-to-fc4bfca06ae6c21b3103b9a721bf19ca4cf33a25.patch b/attic/input-float/apply-to-fc4bfca06ae6c21b3103b9a721bf19ca4cf33a25.patch deleted file mode 100644 index d5a2f75..0000000 --- a/attic/input-float/apply-to-fc4bfca06ae6c21b3103b9a721bf19ca4cf33a25.patch +++ /dev/null @@ -1,672 +0,0 @@ -From cb05c9dda6bb8da6dbf6bbbbc64e79b069d8b2a0 Mon Sep 17 00:00:00 2001 -From: Michael Moon -Date: Sat, 5 Feb 2011 18:39:35 +1100 -Subject: big gcode_parse update- wait for whole line to ease processing, use - floats to receive numerical data, plugs into existing gcode_process.c. TODO: - revamp gcode_process to use new gcode_parse data structures - ---- - func.sh | 32 ++++ - gcode_parse.c | 563 +++++++++++++++++++++++----------------------------------- - gcode_parse.h | 4 +- - 3 files changed, 256 insertions(+), 343 deletions(-) - -diff --git a/func.sh b/func.sh -index e59b7a5..18827e0 100755 ---- a/func.sh -+++ b/func.sh -@@ -322,6 +322,38 @@ ENDPERL - } - - # Read status of PID routines. -+mendel_readsym_nexttarget() { -+ local val=$(mendel_readsym next_target) -+ perl - <<'ENDPERL' -- $val -+ $i = -1; -+ @a = qw/flags 2 G 1 M 1 X 4 Y 4 Z 4 E 4 F 4 S 2 P 2 T 1 N 4 eN 4 cr 1 cc 1/; -+ $c = 1234567; -+ while (length $ARGV[1]) { -+ if ($c > ($#a / 2)) { -+ $i++; -+ $c = 0; -+ } -+ if ($a[$c * 2 + 1] & 8) { -+ printf "\n"; -+ } -+ if (($a[$c * 2 + 1] & 7) == 4) { -+ $ARGV[1] =~ s#^(..)(..)(..)(..)##; -+ printf "%s: %d\t", $a[$c * 2], eval "0x$4$3$2$1"; -+ } -+ if (($a[$c * 2 + 1] & 7) == 2) { -+ $ARGV[1] =~ s#^(..)(..)##; -+ printf "%s: %d\t", $a[$c * 2], eval "0x$2$1"; -+ } -+ elsif (($a[$c * 2 + 1] & 7) == 1) { -+ $ARGV[1] =~ s#^(..)##; -+ printf "%s: %d\t", $a[$c * 2], eval "0x$1"; -+ } -+ $c++; -+ } -+ printf "\n"; -+ENDPERL -+} -+ - mendel_heater_pid() { - local P=$(mendel_readsym_int16 heater_p) - local I=$(mendel_readsym_int16 heater_i) -diff --git a/gcode_parse.c b/gcode_parse.c -index 1eb4eb0..626b694 100644 ---- a/gcode_parse.c -+++ b/gcode_parse.c -@@ -4,15 +4,12 @@ - \brief Parse received G-Codes - */ - --#include -+#include - -+#include "config.h" -+#include "sersendf.h" - #include "serial.h" - #include "sermsg.h" --#include "dda_queue.h" --#include "debug.h" --#include "heater.h" --#include "sersendf.h" -- - #include "gcode_process.h" - - /// current or previous gcode word -@@ -22,64 +19,232 @@ uint8_t last_field = 0; - /// crude crc macro - #define crc(a, b) (a ^ b) - --/// crude floating point data storage --decfloat read_digit __attribute__ ((__section__ (".bss"))); -- --/// this is where we store all the data for the current command before we work out what to do with it --GCODE_COMMAND next_target __attribute__ ((__section__ (".bss"))); -- --/* -- decfloat_to_int() is the weakest subject to variable overflow. For evaluation, we assume a build room of +-1000 mm and STEPS_PER_MM_x between 1.000 and 4096. Accordingly for metric units: -- -- df->mantissa: +-0..1048075 (20 bit - 500 for rounding) -- df->exponent: 0, 2, 3, 4 or 5 (10 bit) -- multiplicand: 1000 (10 bit) -- -- imperial units: -- -- df->mantissa: +-0..32267 (15 bit - 500 for rounding) -- df->exponent: 0, 2, 3, 4 or 5 (10 bit) -- multiplicand: 25400 (15 bit) --*/ --// decfloat_to_int() can handle a bit more: --#define DECFLOAT_EXP_MAX 3 // more is pointless, as 1 um is our presision --// (2^^32 - 1) / multiplicand - powers[DECFLOAT_EXP_MAX] / 2 = --// 4294967295 / 1000 - 5000 = --#define DECFLOAT_MANT_MM_MAX 4289967 // = 4290 mm --// 4294967295 / 25400 - 5000 = --#define DECFLOAT_MANT_IN_MAX 164093 // = 164 inches = 4160 mm -+#define GCODE_LINE_BUFFER_LEN 64 -+ -+#define iA 0 -+#define iB 1 -+#define iC 2 -+#define iD 3 -+#define iE 4 -+#define iF 5 -+#define iG 6 -+#define iH 7 -+#define iI 8 -+#define iJ 9 -+#define iK 10 -+#define iL 11 -+#define iM 12 -+#define iN 13 -+#define iO 14 -+#define iP 15 -+#define iQ 16 -+#define iR 17 -+#define iS 18 -+#define iT 19 -+#define iU 20 -+#define iV 21 -+#define iW 22 -+#define iX 23 -+#define iY 24 -+#define iZ 25 -+#define iAsterisk 26 -+ -+GCODE_COMMAND next_target; -+ -+uint8_t gcode_line[GCODE_LINE_BUFFER_LEN]; -+uint8_t gcode_line_pointer = 0; -+ -+float words[32]; -+uint32_t seen_mask = 0; -+ -+#define SEEN(c) (seen_mask & (1L << (c))) -+ -+uint32_t line_number = 0; -+ -+const uint8_t char2index(uint8_t c) __attribute__ ((pure)); -+const uint8_t char2index(uint8_t c) { -+ if (c >= 'a' && c <= 'z') -+ return c - 'a'; -+ if (c >= 'A' && c <= 'Z') -+ return c - 'A'; -+ if (c == '*') -+ return 26; -+ return 255; -+} - --/* -- utility functions --*/ --extern const uint32_t powers[]; // defined in sermsg.c -+void gcode_parse_char(uint8_t c) { -+ if (gcode_line_pointer < (GCODE_LINE_BUFFER_LEN - 1)) -+ gcode_line[gcode_line_pointer++] = c; -+ if ((c == 13) || (c == 10)) { -+ uint8_t i; -+ for (i = gcode_line_pointer; i < GCODE_LINE_BUFFER_LEN; i++) -+ gcode_line[i] = 0; -+ if (gcode_line_pointer > 2) -+ gcode_parse_line(gcode_line); -+ gcode_line_pointer = 0; -+ } -+} - --/// convert a floating point input value into an integer with appropriate scaling. --/// \param *df pointer to floating point structure that holds fp value to convert --/// \param multiplicand multiply by this amount during conversion to integer --/// --/// Tested for up to 42'000 mm (accurate), 420'000 mm (precision 10 um) and --/// 4'200'000 mm (precision 100 um). --static int32_t decfloat_to_int(decfloat *df, uint16_t multiplicand) { -- uint32_t r = df->mantissa; -- uint8_t e = df->exponent; -+void gcode_parse_line(uint8_t *c) { -+ enum { -+ STATE_FIND_WORD, -+ STATE_FIND_VALUE, -+ STATE_SEMICOLON_COMMENT, -+ STATE_BRACKET_COMMENT, -+ } state = STATE_FIND_WORD; -+ -+ uint8_t i; // string index -+ uint8_t w = 0; // current gcode word -+ uint8_t checksum = 0; -+ -+ seen_mask = 0; -+ -+ // calculate checksum -+ for(i = 0; c[i] != '*' && c[i] != 0; i++) -+ checksum = checksum ^ c[i]; -+ -+ // extract gcode words from line -+ for (i = 0; c[i] != 0 && c[i] != 13 && c[i] != 10; i++) { -+ switch (state) { -+ case STATE_FIND_WORD: -+ // start of word -+ if (char2index(c[i]) < 255) { -+ w = char2index(c[i]); -+ state = STATE_FIND_VALUE; -+ } -+ // comment until end of line -+ if (c[i] == ';') -+ state = STATE_SEMICOLON_COMMENT; -+ // comment until close bracket -+ if (c[i] == '(') -+ state = STATE_BRACKET_COMMENT; -+ break; -+ case STATE_FIND_VALUE: -+ if ((c[i] >= '0' && c[i] <= '9') || c[i] == '-') { -+ uint8_t *ep; -+ float v = strtod((const char *) &c[i], (char **) &ep); -+ state = STATE_FIND_WORD; -+ if (ep > &c[i]) { -+// sersendf_P(PSTR("[seen %c: %lx->"), w + 'A', seen_mask); -+ seen_mask |= (1L << w); -+// sersendf_P(PSTR("%lx]"), seen_mask); -+ words[w] = v; -+ i = ep - c - 1; -+ } -+ } -+ break; -+ case STATE_BRACKET_COMMENT: -+ if (c[i] == ')') -+ state = STATE_FIND_WORD; -+ break; -+ case STATE_SEMICOLON_COMMENT: -+ // dummy entry to suppress compiler warning -+ break; -+ } // switch (state) -+ } // for i=0 .. newline -+ -+ // TODO: process line just read -+ -+ if (SEEN(iAsterisk)) { -+ if (checksum != words[iAsterisk]) { -+ if (seen_mask & iAsterisk) -+ sersendf_P(PSTR("rs %d "), ((uint8_t) words[iAsterisk])); -+ sersendf_P(PSTR("Bad checksum, received %d, expected %d\n"), ((uint8_t) words[iAsterisk]), checksum); -+ seen_mask = 0; -+ return; -+ } -+ } -+ -+ if (SEEN(iN)) { -+ if (((uint32_t) words[iN]) != line_number) { -+ sersendf_P(PSTR("Bad line number, received %ld, expected %ld\n"), ((uint32_t) words[iN]), line_number); -+ seen_mask = 0; -+ return; -+ } -+ line_number++; -+ } -+ -+ serial_writestr_P(PSTR("ok ")); - -- // e=1 means we've seen a decimal point but no digits after it, and e=2 means we've seen a decimal point with one digit so it's too high by one if not zero -- if (e) -- e--; -+ // patch words into next_target struct -+ // TODO: eliminate next_target, update gcode_process to use words[] directly - -- // This raises range for mm by factor 1000 and for inches by factor 100. -- // It's a bit expensive, but we should have the time while parsing. -- while (e && multiplicand % 10 == 0) { -- multiplicand /= 10; -- e--; -+ next_target.flags = 0; -+ if (SEEN(iG)) { -+ next_target.seen_G = 1; -+ next_target.G = words[iG]; -+// sersendf_P(PSTR("G:%d/"), next_target.G); -+ } -+ if (SEEN(iM)) { -+ next_target.seen_M = 1; -+ next_target.M = words[iM]; -+// sersendf_P(PSTR("M:%d/"), next_target.M); -+ } -+ if (SEEN(iX)) { -+ next_target.seen_X = 1; -+ next_target.target.X = words[iX] * STEPS_PER_MM_X; -+// sersendf_P(PSTR("X:%ld/"), next_target.target.X); -+ } -+ if (SEEN(iY)) { -+ next_target.seen_Y = 1; -+ next_target.target.Y = words[iY] * STEPS_PER_MM_Y; -+// sersendf_P(PSTR("Y:%ld/"), next_target.target.Y); -+ } -+ if (SEEN(iZ)) { -+ next_target.seen_Z = 1; -+ next_target.target.Z = words[iZ] * STEPS_PER_MM_Z; -+// sersendf_P(PSTR("Z:%ld/"), next_target.target.Z); -+ } -+ if (SEEN(iE)) { -+ next_target.seen_E = 1; -+ next_target.target.E = words[iE] * STEPS_PER_MM_E; -+// sersendf_P(PSTR("E:%ld/"), next_target.target.E); -+ } -+ if (SEEN(iF)) { -+ next_target.seen_F = 1; -+ next_target.target.F = words[iF]; -+// sersendf_P(PSTR("F:%ld/"), next_target.target.F); -+ } -+ if (SEEN(iS)) { -+ next_target.seen_S = 1; -+ // if this is temperature, multiply by 4 to convert to quarter-degree units -+ // cosmetically this should be done in the temperature section, -+ // but it takes less code, less memory and loses no precision if we do it here instead -+ if ((next_target.M == 104) || (next_target.M == 109)) -+ next_target.S = words[iS] * 4.0; -+ // if this is heater PID stuff, multiply by PID_SCALE because we divide by PID_SCALE later on -+ else if ((next_target.M >= 130) && (next_target.M <= 132)) -+ next_target.S = words[iS] * PID_SCALE; -+ else -+ next_target.S = words[iS]; -+// sersendf_P(PSTR("S:%d/"), next_target.S); -+ } -+ if (SEEN(iP)) { -+ next_target.seen_P = 1; -+ next_target.P = words[iP]; -+// sersendf_P(PSTR("P:%u/"), next_target.P); -+ } -+ if (SEEN(iT)) { -+ next_target.seen_T = 1; -+ next_target.T = words[iT]; -+// sersendf_P(PSTR("T:%d/"), next_target.T); -+ } -+ if (SEEN(iN)) { -+ next_target.seen_N = 1; -+ next_target.N = words[iN]; -+// sersendf_P(PSTR("N:%lu/"), next_target.N); - } -+ next_target.N_expected = line_number; -+ if (SEEN(iAsterisk)) { -+ next_target.seen_checksum = 1; -+ next_target.checksum_read = words[iAsterisk]; -+ } -+ next_target.checksum_calculated = checksum; - -- r *= multiplicand; -- if (e) -- r = (r + powers[e] / 2) / powers[e]; -+ process_gcode_command(); -+ serial_writechar('\n'); - -- return df->sign ? -(int32_t)r : (int32_t)r; -+ seen_mask = 0; - } - - void gcode_init(void) { -@@ -94,290 +259,6 @@ void gcode_init(void) { - #endif - } - --/// Character Received - add it to our command --/// \param c the next character to process --void gcode_parse_char(uint8_t c) { -- uint8_t checksum_char = c; -- -- // uppercase -- if (c >= 'a' && c <= 'z') -- c &= ~32; -- -- // process previous field -- if (last_field) { -- // check if we're seeing a new field or end of line -- // any character will start a new field, even invalid/unknown ones -- if ((c >= 'A' && c <= 'Z') || c == '*' || (c == 10) || (c == 13)) { -- switch (last_field) { -- case 'G': -- next_target.G = read_digit.mantissa; -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint8(next_target.G); -- break; -- case 'M': -- next_target.M = read_digit.mantissa; -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint8(next_target.M); -- break; -- case 'X': -- if (next_target.option_inches) -- next_target.target.X = decfloat_to_int(&read_digit, 25400); -- else -- next_target.target.X = decfloat_to_int(&read_digit, 1000); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_int32(next_target.target.X); -- break; -- case 'Y': -- if (next_target.option_inches) -- next_target.target.Y = decfloat_to_int(&read_digit, 25400); -- else -- next_target.target.Y = decfloat_to_int(&read_digit, 1000); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_int32(next_target.target.Y); -- break; -- case 'Z': -- if (next_target.option_inches) -- next_target.target.Z = decfloat_to_int(&read_digit, 25400); -- else -- next_target.target.Z = decfloat_to_int(&read_digit, 1000); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_int32(next_target.target.Z); -- break; -- case 'E': -- if (next_target.option_inches) -- next_target.target.E = decfloat_to_int(&read_digit, 25400); -- else -- next_target.target.E = decfloat_to_int(&read_digit, 1000); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint32(next_target.target.E); -- break; -- case 'F': -- // just use raw integer, we need move distance and n_steps to convert it to a useful value, so wait until we have those to convert it -- if (next_target.option_inches) -- next_target.target.F = decfloat_to_int(&read_digit, 25400); -- else -- next_target.target.F = decfloat_to_int(&read_digit, 1); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint32(next_target.target.F); -- break; -- case 'S': -- // if this is temperature, multiply by 4 to convert to quarter-degree units -- // cosmetically this should be done in the temperature section, -- // but it takes less code, less memory and loses no precision if we do it here instead -- if ((next_target.M == 104) || (next_target.M == 109) || (next_target.M == 140)) -- next_target.S = decfloat_to_int(&read_digit, 4); -- // if this is heater PID stuff, multiply by PID_SCALE because we divide by PID_SCALE later on -- else if ((next_target.M >= 130) && (next_target.M <= 132)) -- next_target.S = decfloat_to_int(&read_digit, PID_SCALE); -- else -- next_target.S = decfloat_to_int(&read_digit, 1); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint16(next_target.S); -- break; -- case 'P': -- next_target.P = decfloat_to_int(&read_digit, 1); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint16(next_target.P); -- break; -- case 'T': -- next_target.T = read_digit.mantissa; -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint8(next_target.T); -- break; -- case 'N': -- next_target.N = decfloat_to_int(&read_digit, 1); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint32(next_target.N); -- break; -- case '*': -- next_target.checksum_read = decfloat_to_int(&read_digit, 1); -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serwrite_uint8(next_target.checksum_read); -- break; -- } -- // reset for next field -- last_field = 0; -- read_digit.sign = read_digit.mantissa = read_digit.exponent = 0; -- } -- } -- -- // skip comments -- if (next_target.seen_semi_comment == 0 && next_target.seen_parens_comment == 0) { -- // new field? -- if ((c >= 'A' && c <= 'Z') || c == '*') { -- last_field = c; -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serial_writechar(c); -- } -- -- // process character -- // Can't do ranges in switch..case, so process actual digits here. -- // Do it early, as there are many more digits than characters expected. -- if (c >= '0' && c <= '9') { -- if (read_digit.exponent < DECFLOAT_EXP_MAX + 1 && -- ((next_target.option_inches == 0 && -- read_digit.mantissa < DECFLOAT_MANT_MM_MAX) || -- (next_target.option_inches && -- read_digit.mantissa < DECFLOAT_MANT_IN_MAX))) { -- // this is simply mantissa = (mantissa * 10) + atoi(c) in different clothes -- read_digit.mantissa = (read_digit.mantissa << 3) + -- (read_digit.mantissa << 1) + (c - '0'); -- if (read_digit.exponent) -- read_digit.exponent++; -- } -- } -- else { -- switch (c) { -- // Each currently known command is either G or M, so preserve -- // previous G/M unless a new one has appeared. -- // FIXME: same for T command -- case 'G': -- next_target.seen_G = 1; -- next_target.seen_M = 0; -- next_target.M = 0; -- break; -- case 'M': -- next_target.seen_M = 1; -- next_target.seen_G = 0; -- next_target.G = 0; -- break; -- case 'X': -- next_target.seen_X = 1; -- break; -- case 'Y': -- next_target.seen_Y = 1; -- break; -- case 'Z': -- next_target.seen_Z = 1; -- break; -- case 'E': -- next_target.seen_E = 1; -- break; -- case 'F': -- next_target.seen_F = 1; -- break; -- case 'S': -- next_target.seen_S = 1; -- break; -- case 'P': -- next_target.seen_P = 1; -- break; -- case 'T': -- next_target.seen_T = 1; -- break; -- case 'N': -- next_target.seen_N = 1; -- break; -- case '*': -- next_target.seen_checksum = 1; -- break; -- -- // comments -- case ';': -- next_target.seen_semi_comment = 1; -- break; -- case '(': -- next_target.seen_parens_comment = 1; -- break; -- -- // now for some numeracy -- case '-': -- read_digit.sign = 1; -- // force sign to be at start of number, so 1-2 = -2 instead of -12 -- read_digit.exponent = 0; -- read_digit.mantissa = 0; -- break; -- case '.': -- if (read_digit.exponent == 0) -- read_digit.exponent = 1; -- break; -- #ifdef DEBUG -- case ' ': -- case '\t': -- case 10: -- case 13: -- // ignore -- break; -- #endif -- -- default: -- #ifdef DEBUG -- // invalid -- serial_writechar('?'); -- serial_writechar(c); -- serial_writechar('?'); -- #endif -- break; -- } -- } -- } else if ( next_target.seen_parens_comment == 1 && c == ')') -- next_target.seen_parens_comment = 0; // recognize stuff after a (comment) -- -- if (next_target.seen_checksum == 0) -- next_target.checksum_calculated = -- crc(next_target.checksum_calculated, checksum_char); -- -- // end of line -- if ((c == 10) || (c == 13)) { -- if (DEBUG_ECHO && (debug_flags & DEBUG_ECHO)) -- serial_writechar(c); -- -- if ( -- #ifdef REQUIRE_LINENUMBER -- ((next_target.N >= next_target.N_expected) && (next_target.seen_N == 1)) || -- (next_target.seen_M && (next_target.M == 110)) -- #else -- 1 -- #endif -- ) { -- if ( -- #ifdef REQUIRE_CHECKSUM -- ((next_target.checksum_calculated == next_target.checksum_read) && (next_target.seen_checksum == 1)) -- #else -- ((next_target.checksum_calculated == next_target.checksum_read) || (next_target.seen_checksum == 0)) -- #endif -- ) { -- // process -- serial_writestr_P(PSTR("ok ")); -- process_gcode_command(); -- serial_writechar('\n'); -- -- // expect next line number -- if (next_target.seen_N == 1) -- next_target.N_expected = next_target.N + 1; -- } -- else { -- sersendf_P(PSTR("rs N%ld Expected checksum %d\n"), next_target.N_expected, next_target.checksum_calculated); --// request_resend(); -- } -- } -- else { -- sersendf_P(PSTR("rs N%ld Expected line number %ld\n"), next_target.N_expected, next_target.N_expected); --// request_resend(); -- } -- -- // reset variables -- next_target.seen_X = next_target.seen_Y = next_target.seen_Z = \ -- next_target.seen_E = next_target.seen_F = next_target.seen_S = \ -- next_target.seen_P = next_target.seen_T = next_target.seen_N = \ -- next_target.seen_M = next_target.seen_checksum = next_target.seen_semi_comment = \ -- next_target.seen_parens_comment = next_target.checksum_read = \ -- next_target.checksum_calculated = 0; -- // last_field and read_digit are reset above already -- -- // assume a G1 by default -- next_target.seen_G = 1; -- next_target.G = 1; -- -- if (next_target.option_all_relative) { -- next_target.target.X = next_target.target.Y = next_target.target.Z = 0; -- } -- if (next_target.option_all_relative || next_target.option_e_relative) { -- next_target.target.E = 0; -- } -- } --} -- - /***************************************************************************\ - * * - * Request a resend of the current line - used from various places. * -diff --git a/gcode_parse.h b/gcode_parse.h -index 825bbbc..73e44c1 100644 ---- a/gcode_parse.h -+++ b/gcode_parse.h -@@ -64,8 +64,8 @@ extern GCODE_COMMAND next_target; - - void gcode_init(void); - --/// accept the next character and process it --void gcode_parse_char(uint8_t c); -+// once we have a whole line, process it -+void gcode_parse_line(uint8_t *c); - - // uses the global variable next_target.N - void request_resend(void); --- -1.8.1.2 - diff --git a/attic/input-float/gcode_parse.c b/attic/input-float/gcode_parse.c deleted file mode 100644 index 626b694..0000000 --- a/attic/input-float/gcode_parse.c +++ /dev/null @@ -1,274 +0,0 @@ -#include "gcode_parse.h" - -/** \file - \brief Parse received G-Codes -*/ - -#include - -#include "config.h" -#include "sersendf.h" -#include "serial.h" -#include "sermsg.h" -#include "gcode_process.h" - -/// current or previous gcode word -/// for working out what to do with data just received -uint8_t last_field = 0; - -/// crude crc macro -#define crc(a, b) (a ^ b) - -#define GCODE_LINE_BUFFER_LEN 64 - -#define iA 0 -#define iB 1 -#define iC 2 -#define iD 3 -#define iE 4 -#define iF 5 -#define iG 6 -#define iH 7 -#define iI 8 -#define iJ 9 -#define iK 10 -#define iL 11 -#define iM 12 -#define iN 13 -#define iO 14 -#define iP 15 -#define iQ 16 -#define iR 17 -#define iS 18 -#define iT 19 -#define iU 20 -#define iV 21 -#define iW 22 -#define iX 23 -#define iY 24 -#define iZ 25 -#define iAsterisk 26 - -GCODE_COMMAND next_target; - -uint8_t gcode_line[GCODE_LINE_BUFFER_LEN]; -uint8_t gcode_line_pointer = 0; - -float words[32]; -uint32_t seen_mask = 0; - -#define SEEN(c) (seen_mask & (1L << (c))) - -uint32_t line_number = 0; - -const uint8_t char2index(uint8_t c) __attribute__ ((pure)); -const uint8_t char2index(uint8_t c) { - if (c >= 'a' && c <= 'z') - return c - 'a'; - if (c >= 'A' && c <= 'Z') - return c - 'A'; - if (c == '*') - return 26; - return 255; -} - -void gcode_parse_char(uint8_t c) { - if (gcode_line_pointer < (GCODE_LINE_BUFFER_LEN - 1)) - gcode_line[gcode_line_pointer++] = c; - if ((c == 13) || (c == 10)) { - uint8_t i; - for (i = gcode_line_pointer; i < GCODE_LINE_BUFFER_LEN; i++) - gcode_line[i] = 0; - if (gcode_line_pointer > 2) - gcode_parse_line(gcode_line); - gcode_line_pointer = 0; - } -} - -void gcode_parse_line(uint8_t *c) { - enum { - STATE_FIND_WORD, - STATE_FIND_VALUE, - STATE_SEMICOLON_COMMENT, - STATE_BRACKET_COMMENT, - } state = STATE_FIND_WORD; - - uint8_t i; // string index - uint8_t w = 0; // current gcode word - uint8_t checksum = 0; - - seen_mask = 0; - - // calculate checksum - for(i = 0; c[i] != '*' && c[i] != 0; i++) - checksum = checksum ^ c[i]; - - // extract gcode words from line - for (i = 0; c[i] != 0 && c[i] != 13 && c[i] != 10; i++) { - switch (state) { - case STATE_FIND_WORD: - // start of word - if (char2index(c[i]) < 255) { - w = char2index(c[i]); - state = STATE_FIND_VALUE; - } - // comment until end of line - if (c[i] == ';') - state = STATE_SEMICOLON_COMMENT; - // comment until close bracket - if (c[i] == '(') - state = STATE_BRACKET_COMMENT; - break; - case STATE_FIND_VALUE: - if ((c[i] >= '0' && c[i] <= '9') || c[i] == '-') { - uint8_t *ep; - float v = strtod((const char *) &c[i], (char **) &ep); - state = STATE_FIND_WORD; - if (ep > &c[i]) { -// sersendf_P(PSTR("[seen %c: %lx->"), w + 'A', seen_mask); - seen_mask |= (1L << w); -// sersendf_P(PSTR("%lx]"), seen_mask); - words[w] = v; - i = ep - c - 1; - } - } - break; - case STATE_BRACKET_COMMENT: - if (c[i] == ')') - state = STATE_FIND_WORD; - break; - case STATE_SEMICOLON_COMMENT: - // dummy entry to suppress compiler warning - break; - } // switch (state) - } // for i=0 .. newline - - // TODO: process line just read - - if (SEEN(iAsterisk)) { - if (checksum != words[iAsterisk]) { - if (seen_mask & iAsterisk) - sersendf_P(PSTR("rs %d "), ((uint8_t) words[iAsterisk])); - sersendf_P(PSTR("Bad checksum, received %d, expected %d\n"), ((uint8_t) words[iAsterisk]), checksum); - seen_mask = 0; - return; - } - } - - if (SEEN(iN)) { - if (((uint32_t) words[iN]) != line_number) { - sersendf_P(PSTR("Bad line number, received %ld, expected %ld\n"), ((uint32_t) words[iN]), line_number); - seen_mask = 0; - return; - } - line_number++; - } - - serial_writestr_P(PSTR("ok ")); - - // patch words into next_target struct - // TODO: eliminate next_target, update gcode_process to use words[] directly - - next_target.flags = 0; - if (SEEN(iG)) { - next_target.seen_G = 1; - next_target.G = words[iG]; -// sersendf_P(PSTR("G:%d/"), next_target.G); - } - if (SEEN(iM)) { - next_target.seen_M = 1; - next_target.M = words[iM]; -// sersendf_P(PSTR("M:%d/"), next_target.M); - } - if (SEEN(iX)) { - next_target.seen_X = 1; - next_target.target.X = words[iX] * STEPS_PER_MM_X; -// sersendf_P(PSTR("X:%ld/"), next_target.target.X); - } - if (SEEN(iY)) { - next_target.seen_Y = 1; - next_target.target.Y = words[iY] * STEPS_PER_MM_Y; -// sersendf_P(PSTR("Y:%ld/"), next_target.target.Y); - } - if (SEEN(iZ)) { - next_target.seen_Z = 1; - next_target.target.Z = words[iZ] * STEPS_PER_MM_Z; -// sersendf_P(PSTR("Z:%ld/"), next_target.target.Z); - } - if (SEEN(iE)) { - next_target.seen_E = 1; - next_target.target.E = words[iE] * STEPS_PER_MM_E; -// sersendf_P(PSTR("E:%ld/"), next_target.target.E); - } - if (SEEN(iF)) { - next_target.seen_F = 1; - next_target.target.F = words[iF]; -// sersendf_P(PSTR("F:%ld/"), next_target.target.F); - } - if (SEEN(iS)) { - next_target.seen_S = 1; - // if this is temperature, multiply by 4 to convert to quarter-degree units - // cosmetically this should be done in the temperature section, - // but it takes less code, less memory and loses no precision if we do it here instead - if ((next_target.M == 104) || (next_target.M == 109)) - next_target.S = words[iS] * 4.0; - // if this is heater PID stuff, multiply by PID_SCALE because we divide by PID_SCALE later on - else if ((next_target.M >= 130) && (next_target.M <= 132)) - next_target.S = words[iS] * PID_SCALE; - else - next_target.S = words[iS]; -// sersendf_P(PSTR("S:%d/"), next_target.S); - } - if (SEEN(iP)) { - next_target.seen_P = 1; - next_target.P = words[iP]; -// sersendf_P(PSTR("P:%u/"), next_target.P); - } - if (SEEN(iT)) { - next_target.seen_T = 1; - next_target.T = words[iT]; -// sersendf_P(PSTR("T:%d/"), next_target.T); - } - if (SEEN(iN)) { - next_target.seen_N = 1; - next_target.N = words[iN]; -// sersendf_P(PSTR("N:%lu/"), next_target.N); - } - next_target.N_expected = line_number; - if (SEEN(iAsterisk)) { - next_target.seen_checksum = 1; - next_target.checksum_read = words[iAsterisk]; - } - next_target.checksum_calculated = checksum; - - process_gcode_command(); - serial_writechar('\n'); - - seen_mask = 0; -} - -void gcode_init(void) { - // gcc guarantees us all variables are initialised to 0. - - // assume a G1 by default - next_target.seen_G = 1; - next_target.G = 1; - - #ifndef E_ABSOLUTE - next_target.option_e_relative = 1; - #endif -} - -/***************************************************************************\ -* * -* Request a resend of the current line - used from various places. * -* * -* Relies on the global variable next_target.N being valid. * -* * -\***************************************************************************/ - -void request_resend(void) { - serial_writestr_P(PSTR("rs ")); - serwrite_uint8(next_target.N); - serial_writechar('\n'); -} diff --git a/attic/input-float/gcode_parse.h b/attic/input-float/gcode_parse.h deleted file mode 100644 index 73e44c1..0000000 --- a/attic/input-float/gcode_parse.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _GCODE_PARSE_H -#define _GCODE_PARSE_H - -#include - -#include "dda.h" - -// wether to insist on N line numbers -// if not defined, N's are completely ignored -//#define REQUIRE_LINENUMBER - -// wether to insist on a checksum -//#define REQUIRE_CHECKSUM - -/// this is a very crude decimal-based floating point structure. -/// a real floating point would at least have signed exponent.\n -/// resulting value is \f$ mantissa * 10^{-(exponent - 1)} * ((sign * 2) - 1)\f$ -typedef struct { - uint32_t mantissa; ///< the actual digits of our floating point number - uint8_t exponent :7; ///< scale mantissa by \f$10^{-exponent}\f$ - uint8_t sign :1; ///< positive or negative? -} decfloat; - -/// this holds all the possible data from a received command -typedef struct { - struct { - uint8_t seen_G :1; - uint8_t seen_M :1; - uint8_t seen_X :1; - uint8_t seen_Y :1; - uint8_t seen_Z :1; - uint8_t seen_E :1; - uint8_t seen_F :1; - uint8_t seen_S :1; - uint8_t seen_P :1; - uint8_t seen_T :1; - uint8_t seen_N :1; - uint8_t seen_checksum :1; ///< seen a checksum? - uint8_t seen_semi_comment :1; ///< seen a semicolon? - uint8_t seen_parens_comment :1; ///< seen an open parenthesis - uint8_t option_all_relative :1; ///< relative or absolute coordinates? - uint8_t option_e_relative :1; ///< same for e axis (M82/M83) - uint8_t option_inches :1; ///< inches or millimeters? - }; - - uint8_t G; ///< G command number - uint8_t M; ///< M command number - TARGET target; ///< target position: X, Y, Z, E and F - - int16_t S; ///< S word (various uses) - uint16_t P; ///< P word (various uses) - - uint8_t T; ///< T word (tool index) - - uint32_t N; ///< line number - uint32_t N_expected; ///< expected line number - - uint8_t checksum_read; ///< checksum in gcode command - uint8_t checksum_calculated; ///< checksum we calculated -} GCODE_COMMAND; - -/// the command being processed -extern GCODE_COMMAND next_target; - -void gcode_init(void); - -// once we have a whole line, process it -void gcode_parse_line(uint8_t *c); - -// uses the global variable next_target.N -void request_resend(void); - -#endif /* _GCODE_PARSE_H */