diff --git a/Makefile b/Makefile index 06be840..ae641fc 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ DEVICE = atmega328p CLOCK = 16000000 PROGRAMMER = -c avrisp2 -P usb OBJECTS = main.o motion_control.o gcode.o spindle_control.o wiring_serial.o protocol.o stepper.o \ - eeprom.o settings.o planner.o + eeprom.o settings.o planner.o nuts_bolts.o # FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m # update that line with this when programmer is back up: diff --git a/gcode.c b/gcode.c index 320ac0b..d4f38b7 100644 --- a/gcode.c +++ b/gcode.c @@ -22,7 +22,6 @@ by Kramer, Proctor and Messina. */ #include "gcode.h" -#include #include #include "nuts_bolts.h" #include @@ -63,7 +62,7 @@ typedef struct { uint8_t inches_mode; /* 0 = millimeter mode, 1 = inches mode {G20, G21} */ uint8_t absolute_mode; /* 0 = relative motion, 1 = absolute motion {G90, G91} */ uint8_t program_flow; - int spindle_direction; + int8_t spindle_direction; double feed_rate, seek_rate; /* Millimeters/second */ double position[3]; /* Where the interpreter considers the tool to be at this point in the code */ uint8_t tool; @@ -76,11 +75,7 @@ static parser_state_t gc; #define FAIL(status) gc.status_code = status; -int read_double(char *line, // <- string: line of RS274/NGC code being processed - int *char_counter, // <- pointer to a counter for position on the line - double *double_ptr); // <- pointer to double to be read - -int next_statement(char *letter, double *double_ptr, char *line, int *char_counter); +int next_statement(char *letter, double *double_ptr, char *line, uint8_t *char_counter); void select_plane(uint8_t axis_0, uint8_t axis_1, uint8_t axis_2) @@ -122,7 +117,7 @@ double theta(double x, double y) // Executes one line of 0-terminated G-Code. The line is assumed to contain only uppercase // characters and signed floating point values (no whitespace). uint8_t gc_execute_line(char *line) { - int char_counter = 0; + uint8_t char_counter = 0; char letter; double value; double unit_converted_value; @@ -140,27 +135,12 @@ uint8_t gc_execute_line(char *line) { clear_vector(target); clear_vector(offset); - gc.status_code = GCSTATUS_OK; + gc.status_code = STATUS_OK; // Disregard comments and block delete if (line[0] == '(') { return(gc.status_code); } if (line[0] == '/') { char_counter++; } // ignore block delete - // If the line starts with an '$' it is a configuration-command - if (line[0] == '$') { - // Parameter lines are on the form '$4=374.3' or '$' to dump current settings - char_counter = 1; - if(line[char_counter] == 0) { settings_dump(); return(GCSTATUS_OK); } - read_double(line, &char_counter, &p); - if(line[char_counter++] != '=') { return(GCSTATUS_UNSUPPORTED_STATEMENT); } - read_double(line, &char_counter, &value); - if(line[char_counter] != 0) { return(GCSTATUS_UNSUPPORTED_STATEMENT); } - settings_store_setting(p, value); - return(gc.status_code); - } - - /* We'll handle this as g-code. First: parse all statements */ - // Pass 1: Commands while(next_statement(&letter, &value, line, &char_counter)) { int_value = trunc(value); @@ -184,7 +164,7 @@ uint8_t gc_execute_line(char *line) { case 91: gc.absolute_mode = FALSE; break; case 93: gc.inverse_feed_rate_mode = TRUE; break; case 94: gc.inverse_feed_rate_mode = FALSE; break; - default: FAIL(GCSTATUS_UNSUPPORTED_STATEMENT); + default: FAIL(STATUS_UNSUPPORTED_STATEMENT); } break; @@ -195,7 +175,7 @@ uint8_t gc_execute_line(char *line) { case 3: gc.spindle_direction = 1; break; case 4: gc.spindle_direction = -1; break; case 5: gc.spindle_direction = 0; break; - default: FAIL(GCSTATUS_UNSUPPORTED_STATEMENT); + default: FAIL(STATUS_UNSUPPORTED_STATEMENT); } break; case 'T': gc.tool = trunc(value); break; @@ -324,7 +304,7 @@ uint8_t gc_execute_line(char *line) { double h_x2_div_d = -sqrt(4 * r*r - x*x - y*y)/hypot(x,y); // == -(h * 2 / d) // If r is smaller than d, the arc is now traversing the complex plane beyond the reach of any // real CNC, and thus - for practical reasons - we will terminate promptly: - if(isnan(h_x2_div_d)) { FAIL(GCSTATUS_FLOATING_POINT_ERROR); return(gc.status_code); } + if(isnan(h_x2_div_d)) { FAIL(STATUS_FLOATING_POINT_ERROR); return(gc.status_code); } // Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below) if (gc.motion_mode == MOTION_MODE_CCW_ARC) { h_x2_div_d = -h_x2_div_d; } @@ -407,40 +387,24 @@ uint8_t gc_execute_line(char *line) { // Parses the next statement and leaves the counter on the first character following // the statement. Returns 1 if there was a statements, 0 if end of string was reached // or there was an error (check state.status_code). -int next_statement(char *letter, double *double_ptr, char *line, int *char_counter) { +int next_statement(char *letter, double *double_ptr, char *line, uint8_t *char_counter) { if (line[*char_counter] == 0) { return(0); // No more statements } *letter = line[*char_counter]; if((*letter < 'A') || (*letter > 'Z')) { - FAIL(GCSTATUS_EXPECTED_COMMAND_LETTER); + FAIL(STATUS_EXPECTED_COMMAND_LETTER); return(0); } (*char_counter)++; if (!read_double(line, char_counter, double_ptr)) { + FAIL(STATUS_BAD_NUMBER_FORMAT); return(0); }; return(1); } -int read_double(char *line, //!< string: line of RS274/NGC code being processed - int *char_counter, //!< pointer to a counter for position on the line - double *double_ptr) //!< pointer to double to be read -{ - char *start = line + *char_counter; - char *end; - - *double_ptr = strtod(start, &end); - if(end == start) { - FAIL(GCSTATUS_BAD_NUMBER_FORMAT); - return(0); - }; - - *char_counter = end - line; - return(1); -} - /* Intentionally not supported: diff --git a/gcode.h b/gcode.h index 8adb836..7ad4e0e 100644 --- a/gcode.h +++ b/gcode.h @@ -23,12 +23,6 @@ #define gcode_h #include -#define GCSTATUS_OK 0 -#define GCSTATUS_BAD_NUMBER_FORMAT 1 -#define GCSTATUS_EXPECTED_COMMAND_LETTER 2 -#define GCSTATUS_UNSUPPORTED_STATEMENT 3 -#define GCSTATUS_FLOATING_POINT_ERROR 4 - // Initialize the parser void gc_init(); diff --git a/nuts_bolts.c b/nuts_bolts.c new file mode 100644 index 0000000..614f3cd --- /dev/null +++ b/nuts_bolts.c @@ -0,0 +1,18 @@ +#include "nuts_bolts.h" +#include +#include + +int read_double(char *line, uint8_t *char_counter, double *double_ptr) +{ + char *start = line + *char_counter; + char *end; + + *double_ptr = strtod(start, &end); + if(end == start) { + return(0); + }; + + *char_counter = end - line; + return(1); +} + diff --git a/nuts_bolts.h b/nuts_bolts.h index ca4ecf5..614cc12 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -21,6 +21,7 @@ #ifndef nuts_bolts_h #define nuts_bolts_h #include +#include #define FALSE 0 #define TRUE 1 @@ -32,4 +33,6 @@ #define clear_vector(a) memset(a, 0, sizeof(a)) #define max(a,b) (((a) > (b)) ? (a) : (b)) +int read_double(char *line, uint8_t *char_counter, double *double_ptr); + #endif diff --git a/protocol.c b/protocol.c index bdd5cfc..aaed597 100644 --- a/protocol.c +++ b/protocol.c @@ -33,21 +33,23 @@ static char line[LINE_BUFFER_SIZE]; static uint8_t char_counter; void status_message(int status_code) { - switch(status_code) { - case GCSTATUS_OK: - printPgmString(PSTR("ok\n\r")); break; - case GCSTATUS_BAD_NUMBER_FORMAT: - printPgmString(PSTR("error: Bad number format\n\r")); break; - case GCSTATUS_EXPECTED_COMMAND_LETTER: - printPgmString(PSTR("error: Expected command letter\n\r")); break; - case GCSTATUS_UNSUPPORTED_STATEMENT: - printPgmString(PSTR("error: Unsupported statement\n\r")); break; - case GCSTATUS_FLOATING_POINT_ERROR: - printPgmString(PSTR("error: Floating point error\n\r")); break; - default: + if (status_code == 0) { + printPgmString(PSTR("ok\n\r")); + } else { printPgmString(PSTR("error: ")); - printInteger(status_code); - printPgmString(PSTR("\n\r")); + switch(status_code) { + case STATUS_BAD_NUMBER_FORMAT: + printPgmString(PSTR("Bad number format\n\r")); break; + case STATUS_EXPECTED_COMMAND_LETTER: + printPgmString(PSTR("Expected command letter\n\r")); break; + case STATUS_UNSUPPORTED_STATEMENT: + printPgmString(PSTR("Unsupported statement\n\r")); break; + case STATUS_FLOATING_POINT_ERROR: + printPgmString(PSTR("Floating point error\n\r")); break; + default: + printInteger(status_code); + printPgmString(PSTR("\n\r")); + } } } @@ -58,6 +60,15 @@ void protocol_init() printPgmString(PSTR("\r\n")); } +// Executes one line of input according to protocol +uint8_t protocol_execute_line(char *line) { + if(line[0] == '$') { + return(settings_execute_line(line)); // Delegate lines starting with '$' to the settings module + } else { + return(gc_execute_line(line)); // Everything else is gcode + } +} + void protocol_process() { char c; @@ -65,7 +76,7 @@ void protocol_process() { if((char_counter > 0) && ((c == '\n') || (c == '\r'))) { // Line is complete. Then execute! line[char_counter] = 0; // treminate string - status_message(gc_execute_line(line)); + status_message(protocol_execute_line(line)); char_counter = 0; // reset line buffer index } else if (c <= ' ') { // Throw away whitepace and control characters } else if (c >= 'a' && c <= 'z') { // Upcase lowercase diff --git a/protocol.h b/protocol.h index 318adcf..7fa7704 100644 --- a/protocol.h +++ b/protocol.h @@ -20,6 +20,12 @@ #ifndef serial_h #define serial_h +#define STATUS_OK 0 +#define STATUS_BAD_NUMBER_FORMAT 1 +#define STATUS_EXPECTED_COMMAND_LETTER 2 +#define STATUS_UNSUPPORTED_STATEMENT 3 +#define STATUS_FLOATING_POINT_ERROR 4 + // Initialize the serial protocol void protocol_init(); @@ -27,4 +33,7 @@ void protocol_init(); // come in. Blocks until the serial buffer is emptied. void protocol_process(); +// Executes one line of input according to protocol +uint8_t protocol_execute_line(char *line); + #endif diff --git a/settings.c b/settings.c index 2f50564..e5b2583 100644 --- a/settings.c +++ b/settings.c @@ -25,6 +25,7 @@ #include "eeprom.h" #include "wiring_serial.h" #include +#include "protocol.h" settings_t settings; @@ -81,6 +82,28 @@ void settings_dump() { printPgmString(PSTR("\r\n'$x=value' to set parameter or just '$' to dump current settings\r\n")); } +// Parameter lines are on the form '$4=374.3' or '$' to dump current settings +uint8_t settings_execute_line(char *line) { + uint8_t char_counter = 1; + double parameter, value; + if(line[0] != '$') { + return(STATUS_UNSUPPORTED_STATEMENT); + } + if(line[char_counter] == 0) { + settings_dump(); return(STATUS_OK); + } + read_double(line, &char_counter, ¶meter); + if(line[char_counter++] != '=') { + return(STATUS_UNSUPPORTED_STATEMENT); + } + read_double(line, &char_counter, &value); + if(line[char_counter] != 0) { + return(STATUS_UNSUPPORTED_STATEMENT); + } + settings_store_setting(parameter, value); + return(STATUS_OK); +} + void write_settings() { eeprom_put_char(0, SETTINGS_VERSION); memcpy_to_eeprom_with_checksum(1, (char*)&settings, sizeof(settings_t)); diff --git a/settings.h b/settings.h index 505cc3b..93feede 100644 --- a/settings.h +++ b/settings.h @@ -51,6 +51,9 @@ void settings_init(); // Print current settings void settings_dump(); +// Handle settings command +uint8_t settings_execute_line(char *line); + // A helper method to set new settings from command line void settings_store_setting(int parameter, double value);