diff --git a/Makefile b/Makefile index cfc0186..58a4d9d 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ # Part of Grbl # # Copyright (c) 2009-2011 Simen Svale Skogsrud +# Copyright (c) 2012 Sungeun K. Jeon # # Grbl is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -31,7 +32,8 @@ DEVICE ?= atmega328p CLOCK = 16000000 PROGRAMMER ?= -c avrisp2 -P usb OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \ - protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o print.o + protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \ + print.o report.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/config.h b/config.h index 6542913..a598b5c 100755 --- a/config.h +++ b/config.h @@ -80,10 +80,6 @@ #define CMD_CYCLE_START '~' #define CMD_RESET 0x18 // ctrl-x -// Specifies the number of work coordinate systems grbl will support (G54 - G59). -// This parameter must be one or greater, currently supporting up to a value of 6. -#define N_COORDINATE_SYSTEM 1 - // The temporal resolution of the acceleration management subsystem. Higher number give smoother // acceleration but may impact performance. // NOTE: Increasing this parameter will help any resolution related issues, especially with machines @@ -106,13 +102,6 @@ // never reach its target. This parameter should always be greater than zero. #define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only -// Number of arc generation iterations by small angle approximation before exact arc trajectory -// correction. This parameter maybe decreased if there are issues with the accuracy of the arc -// generations. In general, the default value is more than enough for the intended CNC applications -// of grbl, and should be on the order or greater than the size of the buffer to help with the -// computational efficiency of generating arcs. -#define N_ARC_CORRECTION 25 // Integer (1-255) - // Time delay increments performed during a dwell. The default value is set at 50ms, which provides // a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing // this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of @@ -172,5 +161,17 @@ // words, the steppers never disable for users that require this. // -> NOW INSTALLED IN SETTINGS #define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer > 0 +// Number of arc generation iterations by small angle approximation before exact arc trajectory +// correction. This parameter maybe decreased if there are issues with the accuracy of the arc +// generations. In general, the default value is more than enough for the intended CNC applications +// of grbl, and should be on the order or greater than the size of the buffer to help with the +// computational efficiency of generating arcs. +// -> NOW INSTALLED IN SETTINGS #define N_ARC_CORRECTION 25 // Integer (1-255) + +// Specifies the number of work coordinate systems grbl will support (G54 - G59). +// This parameter must be one or greater, currently supporting up to a value of 6. +// -> NOW CODED INTO SETTINGS.C #define N_COORDINATE_SYSTEM 6 + +// TODO: Install compile-time option to send numeric status codes rather than strings. #endif diff --git a/gcode.c b/gcode.c index 58bc042..cbda3df 100755 --- a/gcode.c +++ b/gcode.c @@ -32,6 +32,7 @@ #include "coolant_control.h" #include "errno.h" #include "protocol.h" +#include "report.h" // Define modal group internal numbers for checking multiple command violations and tracking the // type of command that is called in the block. A modal group is a group of g-code commands that are @@ -64,9 +65,12 @@ #define NON_MODAL_NONE 0 #define NON_MODAL_DWELL 1 // G4 #define NON_MODAL_SET_COORDINATE_DATA 2 // G10 -#define NON_MODAL_GO_HOME 3 // G28,G30 -#define NON_MODAL_SET_COORDINATE_OFFSET 4 // G92 -#define NON_MODAL_RESET_COORDINATE_OFFSET 5 //G92.1 +#define NON_MODAL_GO_HOME_0 3 // G28 +#define NON_MODAL_SET_HOME_0 4 // G28.1 +#define NON_MODAL_GO_HOME_1 5 // G30 +#define NON_MODAL_SET_HOME_1 6 // G30.1 +#define NON_MODAL_SET_COORDINATE_OFFSET 7 // G92 +#define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1 typedef struct { uint8_t status_code; // Parser status for current block @@ -182,22 +186,20 @@ uint8_t gc_execute_line(char *line) case 19: select_plane(Y_AXIS, Z_AXIS, X_AXIS); break; case 20: gc.inches_mode = true; break; case 21: gc.inches_mode = false; break; + // NOTE: G28.1, G30.1 sets home position parameters. Not currently supported. case 28: case 30: - // NOTE: G28.1, G30.1 sets home position parameters. Not currently supported. - if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { - non_modal_action = NON_MODAL_GO_HOME; - } else { - FAIL(STATUS_SETTING_DISABLED); + int_value = trunc(10*value); // Multiply by 10 to pick up G92.1 + switch(int_value) { + case 280: non_modal_action = NON_MODAL_GO_HOME_0; break; + case 281: non_modal_action = NON_MODAL_SET_HOME_0; break; + case 300: non_modal_action = NON_MODAL_GO_HOME_1; break; + case 301: non_modal_action = NON_MODAL_SET_HOME_1; break; + default: FAIL(STATUS_UNSUPPORTED_STATEMENT); } break; case 53: absolute_override = true; break; case 54: case 55: case 56: case 57: case 58: case 59: - int_value -= 54; // Compute coordinate system row index (0=G54,1=G55,...) - if (int_value < N_COORDINATE_SYSTEM) { - sys.coord_select = int_value; - } else { - FAIL(STATUS_UNSUPPORTED_STATEMENT); - } + sys.coord_select = int_value-54; break; case 80: gc.motion_mode = MOTION_MODE_CANCEL; break; case 90: gc.absolute_mode = true; break; @@ -307,6 +309,13 @@ uint8_t gc_execute_line(char *line) // [*M7,M8,M9]: Update coolant state coolant_run(gc.coolant_mode); + // [G54,G55,...,G59]: Coordinate system selection + if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_12)) ) { // Check if called in block + float coord_data[N_AXIS]; + if (!(settings_read_coord_data(sys.coord_select,coord_data))) { return(STATUS_SETTING_READ_FAIL); } + memcpy(sys.coord_system,coord_data,sizeof(coord_data)); + } + // [G4,G10,G28,G30,G92,G92.1]: Perform dwell, set coordinate system data, homing, or set axis offsets. // NOTE: These commands are in the same modal group, hence are mutually exclusive. G53 is in this // modal group and do not effect these actions. @@ -320,30 +329,41 @@ uint8_t gc_execute_line(char *line) break; case NON_MODAL_SET_COORDINATE_DATA: int_value = trunc(p); // Convert p value to int. - if (l != 2 || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 only. P1=G54, P2=G55, ... + if ((l != 2 && l != 20) || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 and L20. P1=G54, P2=G55, ... FAIL(STATUS_UNSUPPORTED_STATEMENT); - } else if (!axis_words) { // No axis words. + } else if (!axis_words && l==2) { // No axis words. FAIL(STATUS_INVALID_STATEMENT); } else { - int_value--; // Adjust p to be inline with row array index. - // Update axes defined only in block. Always in machine coordinates. Can change non-active system. - uint8_t i; - for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used. - if ( bit_istrue(axis_words,bit(i)) ) { sys.coord_system[int_value][i] = target[i]; } + int_value--; // Adjust P index to EEPROM coordinate data indexing. + if (l == 20) { + settings_write_coord_data(int_value,gc.position); + // Update system coordinate system if currently active. + if (sys.coord_select == int_value) { memcpy(sys.coord_system,gc.position,sizeof(gc.position)); } + } else { + float coord_data[N_AXIS]; + if (!settings_read_coord_data(int_value,coord_data)) { return(STATUS_SETTING_READ_FAIL); } + // Update axes defined only in block. Always in machine coordinates. Can change non-active system. + uint8_t i; + for (i=0; i (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) @@ -75,6 +76,11 @@ // #define bit(6) // #define bit(7) +// Define Grbl system states for sys.state + +// Define position lost in states? + + // Define global system variables typedef struct { uint8_t abort; // System abort flag. Forces exit back to main loop for reset. @@ -86,10 +92,9 @@ typedef struct { // NOTE: This may need to be a volatile variable, if problems arise. uint8_t coord_select; // Active work coordinate system number. Default: 0=G54. - float coord_system[N_COORDINATE_SYSTEM][3]; // Work coordinate systems (G54+). Stores offset from - // absolute machine position in mm. - // Rows: Work system number (0=G54,1=G55,...5=G59), Columns: XYZ Offsets - float coord_offset[3]; // Retains the G92 coordinate offset (work coordinates) relative to + float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine + // position in mm. Loaded from EEPROM when called. + float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to // machine zero in mm. volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program. diff --git a/protocol.c b/protocol.c index e78f4af..439b148 100755 --- a/protocol.c +++ b/protocol.c @@ -31,124 +31,16 @@ #include #include "stepper.h" #include "planner.h" +#include "report.h" +#include "motion_control.h" static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. static uint8_t char_counter; // Last character counter in line variable. static uint8_t iscomment; // Comment/block delete flag for processor to ignore comment characters. -// Method to handle status messages, from an 'ok' to report any 'error' that has occurred. -// Errors can originate from the g-code parser, settings module, or a critical error, such -// as a triggered hard limit. -void protocol_status_message(uint8_t status_code) -{ - // TODO: Compile time option to only return numeric codes for GUIs. - if (status_code == 0) { // STATUS_OK - printPgmString(PSTR("ok\r\n")); - } else { - printPgmString(PSTR("error: ")); - switch(status_code) { - case STATUS_BAD_NUMBER_FORMAT: - printPgmString(PSTR("Bad number format")); break; - case STATUS_EXPECTED_COMMAND_LETTER: - printPgmString(PSTR("Expected command letter")); break; - case STATUS_UNSUPPORTED_STATEMENT: - printPgmString(PSTR("Unsupported statement")); break; - case STATUS_FLOATING_POINT_ERROR: - printPgmString(PSTR("Floating point error")); break; - case STATUS_MODAL_GROUP_VIOLATION: - printPgmString(PSTR("Modal group violation")); break; - case STATUS_INVALID_STATEMENT: - printPgmString(PSTR("Invalid statement")); break; - case STATUS_HARD_LIMIT: - printPgmString(PSTR("Limit triggered")); break; - case STATUS_SETTING_DISABLED: - printPgmString(PSTR("Grbl setting disabled")); break; - case STATUS_SETTING_STEPS_NEG: - printPgmString(PSTR("Steps/mm must be > 0.0")); break; - case STATUS_SETTING_STEP_PULSE_MIN: - printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break; - case STATUS_SETTING_READ_FAIL: - printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break; - } - printPgmString(PSTR("\r\n")); - } -} - - -// Prints miscellaneous messages. This serves as a centralized method to provide additional -// user feedback for things that do not pass through the protocol_execute_line() function -// and are not errors or confirmations, such as setup warnings and how to exit alarms. -void protocol_misc_message(uint8_t message_code) -{ - // TODO: Install silence misc messages option in settings - switch(message_code) { - case MESSAGE_SYSTEM_ALARM: - printPgmString(PSTR("")); break; - case MESSAGE_HOMING_ENABLE: - printPgmString(PSTR("warning: Install all axes limit switches before use")); break; - } - printPgmString(PSTR("\r\n")); -} - - -void protocol_status_report() -{ - // TODO: Status report data is written to the user here. This function should be able to grab a - // real-time snapshot of the stepper subprogram and the actual location of the CNC machine. At a - // minimum, status report should return real-time location information. Other important information - // may be distance to go on block, processed block id, and feed rate. A secondary, non-critical - // status report may include g-code state, i.e. inch mode, plane mode, absolute mode, etc. - // The report generated must be as short as possible, yet still provide the user easily readable - // information, i.e. '[0.23,120.4,2.4]'. This is necessary as it minimizes the computational - // overhead and allows grbl to keep running smoothly, especially with g-code programs with fast, - // short line segments and interface setups that require real-time status reports (5-20Hz). - - // **Under construction** Bare-bones status report. Provides real-time machine position relative to - // the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). - // The following are still needed: user setting of output units (mm|inch), compressed (non-human - // readable) data for interfaces?, save last known position in EEPROM?, code optimizations, solidify - // the reporting schemes, move to a separate .c file for easy user accessibility, and setting the - // home position by the user (likely through '$' setting interface). - // Successfully tested at a query rate of 10-20Hz while running a gauntlet of programs at various - // speeds. - uint8_t i; - int32_t current_position[3]; // Copy current state of the system position variable - memcpy(current_position,sys.position,sizeof(sys.position)); - float print_position[3]; - - // Report machine position - printPgmString(PSTR("MPos:[")); - for (i=0; i<= 2; i++) { - print_position[i] = current_position[i]/settings.steps_per_mm[i]; - if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; } - printFloat(print_position[i]); - if (i < 2) { printPgmString(PSTR(",")); } - else { printPgmString(PSTR("]")); } - } - - // Report work position - printPgmString(PSTR(",WPos:[")); - for (i=0; i<= 2; i++) { - if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { - print_position[i] -= (sys.coord_system[sys.coord_select][i]+sys.coord_offset[i])*INCH_PER_MM; - } else { - print_position[i] -= sys.coord_system[sys.coord_select][i]+sys.coord_offset[i]; - } - printFloat(print_position[i]); - if (i < 2) { printPgmString(PSTR(",")); } - else { printPgmString(PSTR("]")); } - } - - printPgmString(PSTR("\r\n")); -} - void protocol_init() { - // Print grbl initialization message - printPgmString(PSTR("\r\nGrbl " GRBL_VERSION)); - printPgmString(PSTR("\r\n'$' to dump current settings\r\n")); - char_counter = 0; // Reset line input iscomment = false; } @@ -160,29 +52,43 @@ void protocol_init() // This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code // parsing and planning functions. This function also serves as an interface for the interrupts to // set the system runtime flags, where only the main program handles them, removing the need to -// define more computationally-expensive volatile variables. -// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted. +// define more computationally-expensive volatile variables. This also provides a controlled way to +// execute certain tasks without having two or more instances of the same task, such as the planner +// recalculating the buffer upon a feedhold or override. +// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted, +// but may be set by any process, such as a switch pin change interrupt when pinouts are installed. void protocol_execute_runtime() { if (sys.execute) { // Enter only if any bit flag is true uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times - // System alarm. Something has gone wrong. Disable everything until system reset. + // System alarm. Something has gone wrong. Disable everything by entering an infinite + // loop until system reset/abort. if (rt_exec & EXEC_ALARM) { - if (bit_isfalse(sys.execute,EXEC_RESET)) { protocol_misc_message(MESSAGE_SYSTEM_ALARM); } - while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); } + if (bit_isfalse(rt_exec,EXEC_RESET)) { // Ignore loop if reset is already issued + report_feedback_message(MESSAGE_SYSTEM_ALARM); + while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); } + } bit_false(sys.execute,EXEC_ALARM); } // System abort. Steppers have already been force stopped. if (rt_exec & EXEC_RESET) { sys.abort = true; + + // If the cycle is active before killing the motion, the event will likely caused a loss + // of position since there is no controlled deceleration(feed hold) to a stop. + // TODO: Add force home option upon position lost. Need to verify that cycle start isn't + // set false by anything but the stepper module. Also, need to look at a better place for + // this. Main.c? + // if (sys.cycle_start) { protocol_feedback_message(MESSAGE_POSITION_LOST); } + return; // Nothing else to do but exit. } // Execute and serial print status if (rt_exec & EXEC_STATUS_REPORT) { - protocol_status_report(); + report_realtime_status(); bit_false(sys.execute,EXEC_STATUS_REPORT); } @@ -206,41 +112,95 @@ void protocol_execute_runtime() } bit_false(sys.execute,EXEC_CYCLE_START); } - } + } + + // Overrides flag byte (sys.override) and execution should be installed here, since they + // are runtime and require a direct and controlled interface to the main stepper program. } -// Executes one line of input according to protocol +// Directs and executes one line of formatted input from protocol_process. While mostly +// incoming streaming g-code blocks, this also executes Grbl internal commands, such as +// settings, initiating the homing cycle, and toggling switch states. This differs from +// the runtime command module by being susceptible to when Grbl is ready to execute the +// next line during a cycle, so for switches like block delete, the switch only effects +// the lines that are processed afterward, not necessarily real-time during a cycle, +// since there are motions already stored in the buffer. However, this 'lag' should not +// be an issue, since these commands are not typically used during a cycle. uint8_t protocol_execute_line(char *line) -{ +{ + // Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help if(line[0] == '$') { - - // TODO: Re-write this '$' as a way to change runtime settings without having to reset, i.e. - // auto-starting, status query output formatting and type, jog mode (axes, direction, and - // nominal feedrate), toggle block delete, etc. This differs from the EEPROM settings, as they - // are considered defaults and loaded upon startup/reset. - // This use is envisioned where '$' itself dumps settings and help. Defined characters - // proceeding the '$' may be used to setup modes, such as jog mode with a '$J=X100' for X-axis - // motion with a nominal feedrate of 100mm/min. Writing EEPROM settings will likely stay the - // same or similar. Should be worked out in upcoming releases. - return(settings_execute_line(line)); // Delegate lines starting with '$' to the settings module - - // } else if { - // - // JOG MODE - // - // TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be - // susceptible to other runtime commands except for e-stop. The jogging function is intended to - // be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped - // steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would - // start motion and toggle off would initiate a deceleration to stop. One could 'feather' the - // motion by repeatedly toggling to slow the motion to the desired location. Location data would - // need to be updated real-time and supplied to the user through status queries. - // More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are - // handled by the planner. It would be possible for the jog subprogram to insert blocks into the - // block buffer without having the planner plan them. It would need to manage de/ac-celerations - // on its own carefully. This approach could be effective and possibly size/memory efficient. - + + uint8_t char_counter = 1; + float parameter, value; + switch( line[char_counter] ) { + case 0 : + report_grbl_help(); + return(STATUS_OK); + break; +// case '#' : +// if ( line[++char_counter] == 0 ) { +// // Print all parameters +// return(STATUS_OK); +// } else { +// return(STATUS_UNSUPPORTED_STATEMENT); +// } +// case 'G' : // Start up blocks +// if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } +// if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } +// // Extract startup block, execute, and store. +// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) { +// line[char_counter] = line[char_counter+3]; +// } +// uint8_t status = gc_execute_line(line); +// if (status) { return(status); } +// else { settings_store_startup_block(line); } +// break; + case 'H' : // Perform homing cycle + if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { + mc_go_home(); + return(STATUS_OK); + } else { + return(STATUS_SETTING_DISABLED); + } + break; +// // case 'J' : break; // Jogging methods +// // TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be +// // susceptible to other runtime commands except for e-stop. The jogging function is intended to +// // be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped +// // steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would +// // start motion and toggle off would initiate a deceleration to stop. One could 'feather' the +// // motion by repeatedly toggling to slow the motion to the desired location. Location data would +// // need to be updated real-time and supplied to the user through status queries. +// // More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are +// // handled by the planner. It would be possible for the jog subprogram to insert blocks into the +// // block buffer without having the planner plan them. It would need to manage de/ac-celerations +// // on its own carefully. This approach could be effective and possibly size/memory efficient. +// case 'P' : // Print g-code parameters and parser state +// if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } +// +// break; +// case 'S' : // Switch methods +// // Opt stop and block delete are referred to as switches. +// // How to store home position and work offsets real-time?? +// break; +// // Parse $parameter=value settings + default : + if(!read_float(line, &char_counter, ¶meter)) { + return(STATUS_BAD_NUMBER_FORMAT); + } + if(line[char_counter++] != '=') { + return(STATUS_UNSUPPORTED_STATEMENT); + } + if(!read_float(line, &char_counter, &value)) { + return(STATUS_BAD_NUMBER_FORMAT); + } + if(line[char_counter] != 0) { + return(STATUS_UNSUPPORTED_STATEMENT); + } + return(settings_store_global_setting(parameter, value)); + } } else { return(gc_execute_line(line)); // Everything else is gcode // TODO: Install option to set system alarm upon any error code received back from the @@ -250,7 +210,8 @@ uint8_t protocol_execute_line(char *line) } -// Process one line of incoming serial data. Remove unneeded characters and capitalize. +// Process and report status one line of incoming serial data. Performs an initial filtering +// by removing spaces and comments and capitalizing all letters. void protocol_process() { uint8_t c; @@ -265,10 +226,10 @@ void protocol_process() if (char_counter > 0) {// Line is complete. Then execute! line[char_counter] = 0; // Terminate string - protocol_status_message(protocol_execute_line(line)); + report_status_message(protocol_execute_line(line)); } else { // Empty or comment line. Skip block. - protocol_status_message(STATUS_OK); // Send status message for syncing purposes. + report_status_message(STATUS_OK); // Send status message for syncing purposes. } char_counter = 0; // Reset line buffer index iscomment = false; // Reset comment flag diff --git a/protocol.h b/protocol.h index 95fc285..f176fd5 100755 --- a/protocol.h +++ b/protocol.h @@ -29,25 +29,6 @@ // buffer. #define LINE_BUFFER_SIZE 50 -// Define Grbl status codes. -#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 -#define STATUS_MODAL_GROUP_VIOLATION 5 -#define STATUS_INVALID_STATEMENT 6 -#define STATUS_HARD_LIMIT 7 -#define STATUS_SETTING_DISABLED 8 -#define STATUS_SETTING_STEPS_NEG 9 -#define STATUS_SETTING_STEP_PULSE_MIN 10 -#define STATUS_SETTING_READ_FAIL 11 - -// Define Grbl misc message codes -#define MESSAGE_SYSTEM_ALARM 0 -#define MESSAGE_HOMING_ENABLE 1 - - // Initialize the serial protocol void protocol_init(); @@ -61,10 +42,4 @@ uint8_t protocol_execute_line(char *line); // Checks and executes a runtime command at various stop points in main program void protocol_execute_runtime(); -// Prints Grbl's status messages. -void protocol_status_message(uint8_t status_code); - -// Prints any misc messages. -void protocol_misc_message(uint8_t message_code); - #endif diff --git a/readme.textile b/readme.textile index 9bcc8ea..3c5fde6 100755 --- a/readme.textile +++ b/readme.textile @@ -9,19 +9,24 @@ It accepts standards-compliant G-code and has been tested with the output of sev Grbl includes full acceleration management with look ahead. That means the controller will look up to 18 motions into the future and plan its velocities ahead to deliver smooth acceleration and jerk-free cornering. *Changelog for v0.8 from v0.7:* - - *ALPHA status: _Under heavy development. Code state may significantly change with each push as new features are integrated._* + - *BETA status: _Under development. Code state may significantly change with each push as new features are integrated._* - Major structural overhaul to allow for multi-tasking events and new feature sets - New run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting - Controlled feed hold with deceleration to ensure no skipped steps and loss of location. - After feed hold, cycle accelerations are re-planned and may be resumed. + - Advanced homing cycle with direction and speed configuration options. (Requires limit switches.) + - Limit pins are held normal high with an internal pull-up resister. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.) + - Hard limits option and plays nice with homing cycle, so switches can be used for both homing and hard limits. - Re-factored g-code parser with robust error-checking. - - Work coordinate system (G54), offsets(G92), and machine coordinate system support. G10 work coordinate settings support. (Up to 6 work coordinate systems(G54-G59) available as a compile-time option.) + - 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work systems are stored in EEPROM and persistent. + - G10 L2 and L20 work coordinate settings support. L2 sets one or more axes values. L20 sets the current machine position to the specified work origin. - Program stop(M0,M1*,M2,M30) initial support. Optional stop to do. + - Coolant control(M7*,M8,M9) support. (M7 is a compile-time option). - System reset re-initializes grbl without resetting the Arduino and retains machine/home position and work coordinates. - Restructured planner and stepper modules to become independent and ready for future features. - - Reduced serial read buffer to 128 characters and increased write buffer to 64 characters. + - Settings re-factoring to allow configuration without compiling of most features. (Still in progress). - Misc bug fixes and removed deprecated acceleration enabled code. - - Planned features: Jog mode, full-featured status reporting, runtime settings such as toggling block delete. + - Planned features: Axis acceleration and max speed individual settings, full-featured status reporting, runtime settings such as toggling block delete. - Advanced compile-time options: Up to 6 work coordinate systems(G54-G59), XON/XOFF flow control (limited support), direction and step pulse time delay. diff --git a/report.c b/report.c new file mode 100644 index 0000000..9bb3522 --- /dev/null +++ b/report.c @@ -0,0 +1,211 @@ +/* + report.c - reporting and messaging methods + Part of Grbl + + Copyright (c) 2012 Sungeun K. Jeon + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +/* + This file functions as the primary feedback interface for Grbl. Any outgoing data, such + as the protocol status messages, feedback messages, and status reports, are stored here. + For the most part, these functions primarily are called from protocol.c methods. If a + different style feedback is desired (i.e. JSON), then a user can change these following + methods to accomodate their needs. +*/ + +#include +#include "print.h" +#include "settings.h" +#include +#include "nuts_bolts.h" +#include +#include "report.h" +#include "protocol.h" + + +// Handles the primary confirmation protocol response for streaming interfaces and human-feedback. +// For every incoming line, this method responds with an 'ok' for a successful command or an +// 'error:' to indicate some error event with the line or some critical system error during +// operation. Errors events can originate from the g-code parser, settings module, or asynchronously +// from a critical error, such as a triggered hard limit. Interface should always monitor for these +// responses. +// NOTE: In silent mode, all error codes are greater than zero. +// TODO: Install silent mode to return only numeric values, primarily for GUIs. +void report_status_message(uint8_t status_code) +{ + if (status_code == 0) { // STATUS_OK + printPgmString(PSTR("ok\r\n")); + } else { + printPgmString(PSTR("error: ")); + switch(status_code) { + case STATUS_BAD_NUMBER_FORMAT: + printPgmString(PSTR("Bad number format")); break; + case STATUS_EXPECTED_COMMAND_LETTER: + printPgmString(PSTR("Expected command letter")); break; + case STATUS_UNSUPPORTED_STATEMENT: + printPgmString(PSTR("Unsupported statement")); break; + case STATUS_FLOATING_POINT_ERROR: + printPgmString(PSTR("Floating point error")); break; + case STATUS_MODAL_GROUP_VIOLATION: + printPgmString(PSTR("Modal group violation")); break; + case STATUS_INVALID_STATEMENT: + printPgmString(PSTR("Invalid statement")); break; + case STATUS_HARD_LIMIT: + printPgmString(PSTR("Limit triggered")); break; + case STATUS_SETTING_DISABLED: + printPgmString(PSTR("Grbl setting disabled")); break; + case STATUS_SETTING_VALUE_NEG: + printPgmString(PSTR("Set value must be > 0.0")); break; + case STATUS_SETTING_STEP_PULSE_MIN: + printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break; + case STATUS_SETTING_READ_FAIL: + printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break; + } + printPgmString(PSTR("\r\n")); + } +} + + +// Prints feedback messages. This serves as a centralized method to provide additional +// user feedback for things that are not of the status message response protocol. These +// are messages such as setup warnings and how to exit alarms. +// NOTE: For interfaces, messages are always placed within parentheses. And if silent mode +// is installed, the message codes are less than zero. +// TODO: Install silence feedback messages option in settings +void report_feedback_message(int8_t message_code) +{ + printPgmString(PSTR("(")); + switch(message_code) { + case MESSAGE_SYSTEM_ALARM: + printPgmString(PSTR("ALARM: Check and reset Grbl")); break; + case MESSAGE_POSITION_LOST: + printPgmString(PSTR("warning: Position may be lost")); break; + case MESSAGE_HOMING_ENABLE: + printPgmString(PSTR("'$H' to home. Ensure all limit switches are installed")); break; + } + printPgmString(PSTR(")\r\n")); +} + +// Welcome message +void report_init_message() +{ + // Print grbl initialization message + printPgmString(PSTR("\r\nGrbl " GRBL_VERSION)); + printPgmString(PSTR("\r\n'$' for help and to view settings\r\n")); +} + + +void report_grbl_help() { + printPgmString(PSTR("$0 = ")); printFloat(settings.steps_per_mm[X_AXIS]); + printPgmString(PSTR(" (x axis, steps/mm)\r\n$1 = ")); printFloat(settings.steps_per_mm[Y_AXIS]); + printPgmString(PSTR(" (y axis, steps/mm)\r\n$2 = ")); printFloat(settings.steps_per_mm[Z_AXIS]); + printPgmString(PSTR(" (z axis, steps/mm)\r\n$3 = ")); printInteger(settings.pulse_microseconds); + printPgmString(PSTR(" (step pulse, usec)\r\n$4 = ")); printFloat(settings.default_feed_rate); + printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5 = ")); printFloat(settings.default_seek_rate); + printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6 = ")); printFloat(settings.mm_per_arc_segment); + printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7 = ")); printInteger(settings.invert_mask); + printPgmString(PSTR(" (step port invert mask, int:binary = ")); print_uint8_base2(settings.invert_mask); + printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability + printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation); + printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); + printPgmString(PSTR(" (status report inches, bool)\r\n$11 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); + printPgmString(PSTR(" (auto start enable, bool)\r\n$12 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); + printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); + printPgmString(PSTR(" (hard limit enable, bool)\r\n$14 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); + printPgmString(PSTR(" (homing enable, bool)\r\n$15 = ")); printInteger(settings.homing_dir_mask); + printPgmString(PSTR(" (homing direction mask, int:binary = ")); print_uint8_base2(settings.homing_dir_mask); + printPgmString(PSTR(")\r\n$16 = ")); printFloat(settings.homing_feed_rate); + printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17 = ")); printFloat(settings.homing_seek_rate); + printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18 = ")); printInteger(settings.homing_debounce_delay); + printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19 = ")); printFloat(settings.homing_pulloff); + printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20 = ")); printInteger(settings.stepper_idle_lock_time); + printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21 = ")); printInteger(settings.decimal_places); + printPgmString(PSTR(" (decimal places, int)\r\n$22 = ")); printInteger(settings.n_arc_correction); +// char st_line[LINE_BUFFER_SIZE]; +// printPgmString(PSTR("\r\n\r\n Startup\r\n$100 = ")); printString(settings_read_startup(st_line,0)); +// printPgmString(PSTR("\r\n$101 = ")); printString(settings_read_startup(st_line,1)); + +// char buf[4]; +// settings_startup_string((char *)buf); +// printPgmString(PSTR("\r\n Startup: ")); printString(buf); + + printPgmString(PSTR("\r\n'$x=value' to store setting")); +// printPgmString(PSTR("\r\n'$Sx' to toggle switch\r\n")); +} + + + +// void report_gcode_status() +// { +// // Print gcode parser state +// } +// +// void report_gcode_parameters() +// { +// // Print gcode work coordinate offsets? +// } + + +void report_realtime_status() +{ + // TODO: Status report data is written to the user here. This function should be able to grab a + // real-time snapshot of the stepper subprogram and the actual location of the CNC machine. At a + // minimum, status report should return real-time location information. Other important information + // may be distance to go on block, processed block id, and feed rate. A secondary, non-critical + // status report may include g-code state, i.e. inch mode, plane mode, absolute mode, etc. + // The report generated must be as short as possible, yet still provide the user easily readable + // information, i.e. '[0.23,120.4,2.4]'. This is necessary as it minimizes the computational + // overhead and allows grbl to keep running smoothly, especially with g-code programs with fast, + // short line segments and interface setups that require real-time status reports (5-20Hz). + + // **Under construction** Bare-bones status report. Provides real-time machine position relative to + // the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). + // The following are still needed: user setting of output units (mm|inch), compressed (non-human + // readable) data for interfaces?, save last known position in EEPROM?, code optimizations, solidify + // the reporting schemes, move to a separate .c file for easy user accessibility, and setting the + // home position by the user (likely through '$' setting interface). + // Successfully tested at a query rate of 10-20Hz while running a gauntlet of programs at various + // speeds. + uint8_t i; + int32_t current_position[3]; // Copy current state of the system position variable + memcpy(current_position,sys.position,sizeof(sys.position)); + float print_position[3]; + + // Report machine position + printPgmString(PSTR("MPos:[")); + for (i=0; i<= 2; i++) { + print_position[i] = current_position[i]/settings.steps_per_mm[i]; + if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; } + printFloat(print_position[i]); + if (i < 2) { printPgmString(PSTR(",")); } + else { printPgmString(PSTR("]")); } + } + + // Report work position + printPgmString(PSTR(",WPos:[")); + for (i=0; i<= 2; i++) { + if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { + print_position[i] -= (sys.coord_system[i]+sys.coord_offset[i])*INCH_PER_MM; + } else { + print_position[i] -= sys.coord_system[i]+sys.coord_offset[i]; + } + printFloat(print_position[i]); + if (i < 2) { printPgmString(PSTR(",")); } + else { printPgmString(PSTR("]")); } + } + + printPgmString(PSTR("\r\n")); +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..a1b9a4a --- /dev/null +++ b/report.h @@ -0,0 +1,59 @@ +/* + report.h - reporting and messaging methods + Part of Grbl + + Copyright (c) 2012 Sungeun K. Jeon + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ +#ifndef report_h +#define report_h + + +// Define Grbl status codes. +#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 +#define STATUS_MODAL_GROUP_VIOLATION 5 +#define STATUS_INVALID_STATEMENT 6 +#define STATUS_HARD_LIMIT 7 +#define STATUS_SETTING_DISABLED 8 +#define STATUS_SETTING_VALUE_NEG 9 +#define STATUS_SETTING_STEP_PULSE_MIN 10 +#define STATUS_SETTING_READ_FAIL 11 + +// Define Grbl feedback message codes. Less than zero to distinguish message from error. +#define MESSAGE_SYSTEM_ALARM -1 +#define MESSAGE_POSITION_LOST -2 +#define MESSAGE_HOMING_ENABLE -3 + + +// Prints system status messages. +void report_status_message(uint8_t status_code); + +// Prints miscellaneous feedback messages. +void report_feedback_message(int8_t message_code); + +// Prints welcome message +void report_init_message(); + +// Prints Grbl help and current global settings +void report_grbl_help(); + +// Prints realtime status report +void report_realtime_status(); + +#endif diff --git a/serial.c b/serial.c index a0e7916..89c562b 100755 --- a/serial.c +++ b/serial.c @@ -166,7 +166,7 @@ ISR(USART_RX_vect) case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true case CMD_RESET: // Immediately force stepper and spindle subsystem idle at an interrupt level. - if (!(sys.execute & EXEC_RESET)) { mc_alarm(); } // Stop only first time. + mc_alarm(); sys.execute |= EXEC_RESET; // Set as true break; default: // Write character to buffer diff --git a/settings.c b/settings.c old mode 100755 new mode 100644 index 175cf8d..098fc7e --- a/settings.c +++ b/settings.c @@ -1,321 +1,256 @@ -/* - settings.c - eeprom configuration handling - Part of Grbl - - Copyright (c) 2009-2011 Simen Svale Skogsrud - Copyright (c) 2011-2012 Sungeun K. Jeon - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . -*/ - -#include -#include -#include "nuts_bolts.h" -#include "settings.h" -#include "eeprom.h" -#include "print.h" -#include -#include "protocol.h" -#include "config.h" - -settings_t settings; - -// Version 1 outdated settings record -typedef struct { - float steps_per_mm[3]; - uint8_t microsteps; - uint8_t pulse_microseconds; - float default_feed_rate; - float default_seek_rate; - uint8_t invert_mask; - float mm_per_arc_segment; -} settings_v1_t; - -// Version 2,3,4 outdated settings record -typedef struct { - float steps_per_mm[3]; - uint8_t microsteps; - uint8_t pulse_microseconds; - float default_feed_rate; - float default_seek_rate; - uint8_t invert_mask; - float mm_per_arc_segment; - float acceleration; - float junction_deviation; -} settings_v2_v4_t; - -// Default settings (used when resetting eeprom-settings) -#define MICROSTEPS 8 -#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_STEP_PULSE_MICROSECONDS 30 -#define DEFAULT_MM_PER_ARC_SEGMENT 0.1 -#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min -#define DEFAULT_FEEDRATE 500.0 -#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2 -#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm -#define DEFAULT_STEPPING_INVERT_MASK ((1<= 'A' || line[char_counter] <= 'Z') { -// letter = line[char_counter++]; -// if(line[char_counter++] != '=') { -// return(STATUS_UNSUPPORTED_STATEMENT); -// } -// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) { -// line[char_counter] = line[char_counter+3]; -// } -// uint8_t status = gc_execute_line(line); -// if (status) { return(status); } -// else { settings_store_startup_line(line); } -// -// -// // Opt stop and block delete are referred to as switches. -// // How to store home position and work offsets real-time?? -// -// } else { - if(!read_float(line, &char_counter, ¶meter)) { - return(STATUS_BAD_NUMBER_FORMAT); - } - if(line[char_counter++] != '=') { - return(STATUS_UNSUPPORTED_STATEMENT); - } - if(!read_float(line, &char_counter, &value)) { - return(STATUS_BAD_NUMBER_FORMAT); - } - if(line[char_counter] != 0) { - return(STATUS_UNSUPPORTED_STATEMENT); - } - return(settings_store_setting(parameter, value)); -// } -} - -void write_settings() { - eeprom_put_char(0, SETTINGS_VERSION); - memcpy_to_eeprom_with_checksum(1, (char*)&settings, sizeof(settings_t)); -// -// char buf[4]; buf[0] = 'G'; buf[1] = '2'; buf[2] = '0'; buf[3] = 0; -// memcpy_to_eeprom_with_checksum(512, (char*)buf, 4); -// -} - -int read_settings() { - // Check version-byte of eeprom - uint8_t version = eeprom_get_char(0); - - if (version == SETTINGS_VERSION) { - // Read settings-record and check checksum - if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t)))) { - return(false); - } - } else { - // Incrementally update the old versions until up-to-date. - if (version == 1) { - // Migrate from settings version 1 to version 4. - if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v1_t)))) { - return(false); - } - settings.acceleration = DEFAULT_ACCELERATION; - settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; - } else if ((version == 2) || (version == 3)) { - // Migrate from settings version 2 and 3 to version 4. - if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v2_v4_t)))) { - return(false); - } - if (version == 2) { settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; } - settings.acceleration *= 3600; // Convert to mm/min^2 from mm/sec^2 - } - if (version <= 4) { - // Migrate from settings version 4 to current version. - if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v2_v4_t)))) { - return(false); - } - settings_reset(false); - write_settings(); - } else if (version >= 50) { - // Developmental settings. Version numbers greater than or equal to 50 are temporary. - // Currently, this will update the user settings to v4 and the remainder of the settings - // should be re-written to the default value, if the developmental version number changed. - - // Grab settings regardless of error. - memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t)); - settings_reset(false); - write_settings(); - } else { - return(false); - } - } - return(true); -} - -// A helper method to set settings from command line -uint8_t settings_store_setting(int parameter, float value) { - switch(parameter) { - case 0: case 1: case 2: - if (value <= 0.0) { return(STATUS_SETTING_STEPS_NEG); } - settings.steps_per_mm[parameter] = value; break; - case 3: - if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); } - settings.pulse_microseconds = round(value); break; - case 4: settings.default_feed_rate = value; break; - case 5: settings.default_seek_rate = value; break; - case 6: settings.mm_per_arc_segment = value; break; - case 7: settings.invert_mask = trunc(value); break; - case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use. - case 9: settings.junction_deviation = fabs(value); break; - case 10: - if (value) { - settings.flags |= BITFLAG_REPORT_INCHES; - } else { settings.flags &= ~BITFLAG_REPORT_INCHES; } - break; - case 11: - if (value) { - settings.flags |= BITFLAG_AUTO_START; - } else { settings.flags &= ~BITFLAG_AUTO_START; } - break; - case 12: - if (value) { - settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; - } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } - break; - case 13: - if (value) { - settings.flags |= BITFLAG_HOMING_ENABLE; - protocol_misc_message(MESSAGE_HOMING_ENABLE); - } else { settings.flags &= ~BITFLAG_HOMING_ENABLE; } - break; - case 14: settings.homing_dir_mask = trunc(value); break; - case 15: settings.homing_feed_rate = value; break; - case 16: settings.homing_seek_rate = value; break; - case 17: settings.homing_debounce_delay = round(value); break; - case 18: settings.homing_pulloff = value; break; - case 19: - settings.stepper_idle_lock_time = round(value); - // TODO: Immediately check and toggle steppers from always enable or disable? - break; - case 20: settings.decimal_places = round(value); break; - default: - return(STATUS_INVALID_STATEMENT); - } - write_settings(); - return(STATUS_OK); -} - -// Initialize the config subsystem -void settings_init() { - if(!read_settings()) { - protocol_status_message(STATUS_SETTING_READ_FAIL); - settings_reset(true); - write_settings(); - settings_dump(); - } -} - -// int8_t settings_execute_startup() { -// -// char buf[4]; -// settings_startup_string((char *)buf); -// uint8_t i = 0; -// while (i < 4) { -// serial_write(buf[i++]); -// } -// return(gc_execute_line(buf)); -// } +/* + settings.c - eeprom configuration handling + Part of Grbl + + Copyright (c) 2009-2011 Simen Svale Skogsrud + Copyright (c) 2011-2012 Sungeun K. Jeon + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#include +#include +#include "nuts_bolts.h" +#include "settings.h" +#include "eeprom.h" +#include "print.h" +#include +#include "protocol.h" +#include "config.h" +#include "report.h" + +settings_t settings; + +// Version 4 outdated settings record +typedef struct { + float steps_per_mm[3]; + uint8_t microsteps; + uint8_t pulse_microseconds; + float default_feed_rate; + float default_seek_rate; + uint8_t invert_mask; + float mm_per_arc_segment; + float acceleration; + float junction_deviation; +} settings_v4_t; + +// Default settings (used when resetting eeprom-settings) +#define MICROSTEPS 8 +#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_STEP_PULSE_MICROSECONDS 30 +#define DEFAULT_MM_PER_ARC_SEGMENT 0.1 +#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min +#define DEFAULT_FEEDRATE 500.0 +#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2 +#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm +#define DEFAULT_STEPPING_INVERT_MASK ((1<= 50) { + // Developmental settings. Version numbers greater than or equal to 50 are temporary. + // Currently, this will update the user settings to v4 and the remainder of the settings + // should be re-written to the default value, if the developmental version number changed. + + // Grab settings regardless of error. + memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)); + settings_reset(false); + } else { + return(false); + } + } + return(true); +} + + +// A helper method to set settings from command line +uint8_t settings_store_global_setting(int parameter, float value) { + switch(parameter) { + case 0: case 1: case 2: + if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); } + settings.steps_per_mm[parameter] = value; break; + case 3: + if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); } + settings.pulse_microseconds = round(value); break; + case 4: settings.default_feed_rate = value; break; + case 5: settings.default_seek_rate = value; break; + case 6: settings.mm_per_arc_segment = value; break; + case 7: settings.invert_mask = trunc(value); break; + case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use. + case 9: settings.junction_deviation = fabs(value); break; + case 10: + if (value) { + settings.flags |= BITFLAG_REPORT_INCHES; + } else { settings.flags &= ~BITFLAG_REPORT_INCHES; } + break; + case 11: + if (value) { + settings.flags |= BITFLAG_AUTO_START; + } else { settings.flags &= ~BITFLAG_AUTO_START; } + break; + case 12: + if (value) { + settings.flags |= BITFLAG_INVERT_ST_ENABLE; + } else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } + break; + case 13: + if (value) { + settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; + } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } + break; + case 14: + if (value) { + settings.flags |= BITFLAG_HOMING_ENABLE; + report_feedback_message(MESSAGE_HOMING_ENABLE); + } else { settings.flags &= ~BITFLAG_HOMING_ENABLE; } + break; + case 15: settings.homing_dir_mask = trunc(value); break; + case 16: settings.homing_feed_rate = value; break; + case 17: settings.homing_seek_rate = value; break; + case 18: settings.homing_debounce_delay = round(value); break; + case 19: + if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); } + settings.homing_pulloff = value; break; + case 20: + settings.stepper_idle_lock_time = round(value); + // TODO: Immediately check and toggle steppers from always enable or disable? + break; + case 21: settings.decimal_places = round(value); break; + case 22: settings.n_arc_correction = round(value); break; + default: + return(STATUS_INVALID_STATEMENT); + } + write_global_settings(); + return(STATUS_OK); +} + +// Initialize the config subsystem +void settings_init() { + if(!read_global_settings()) { + report_status_message(STATUS_SETTING_READ_FAIL); + settings_reset(true); + report_grbl_help(); + } +} + +// int8_t settings_execute_startup() { +// +// char buf[4]; +// settings_startup_string((char *)buf); +// uint8_t i = 0; +// while (i < 4) { +// serial_write(buf[i++]); +// } +// return(gc_execute_line(buf)); +// } diff --git a/settings.h b/settings.h index 635911b..3af5ba5 100755 --- a/settings.h +++ b/settings.h @@ -24,20 +24,35 @@ #include #include +#include "nuts_bolts.h" #define GRBL_VERSION "0.8b" // Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl // when firmware is upgraded. Always stored in byte 0 of eeprom -#define SETTINGS_VERSION 55 +#define SETTINGS_VERSION 56 // Define bit flag masks for the boolean settings in settings.flag. #define BITFLAG_REPORT_INCHES bit(0) #define BITFLAG_AUTO_START bit(1) -#define BITFLAG_HARD_LIMIT_ENABLE bit(2) -#define BITFLAG_HOMING_ENABLE bit(3) +#define BITFLAG_INVERT_ST_ENABLE bit(2) +#define BITFLAG_HARD_LIMIT_ENABLE bit(3) +#define BITFLAG_HOMING_ENABLE bit(4) -// Current global settings (persisted in EEPROM from byte 1 onwards) +// Define EEPROM memory address location values for on-demand settings and parameters +#define EEPROM_ADDR_GLOBAL 1 +#define EEPROM_ADDR_PARAMETERS 512 +#define EEPROM_ADDR_STARTUP_SCRIPT 768 + +// Define EEPROM address indexing for coordinate parameters +#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1) +#define SETTING_INDEX_NCOORD N_COORDINATE_SYSTEM+2 // Total number of system stored (from index 0) +// NOTE: Work coordinate indices are (0=G54, 1=G55, ... , 6=G59) +#define SETTING_INDEX_G28 N_COORDINATE_SYSTEM // Home position 1 +#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2 +#define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset + +// Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards) typedef struct { float steps_per_mm[3]; uint8_t microsteps; @@ -55,21 +70,22 @@ typedef struct { uint16_t homing_debounce_delay; float homing_pulloff; uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable. - uint8_t decimal_places; + uint8_t decimal_places; + uint8_t n_arc_correction; } settings_t; extern settings_t settings; // Initialize the configuration subsystem (load settings from EEPROM) 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 -uint8_t settings_store_setting(int parameter, float value); +uint8_t settings_store_global_setting(int parameter, float value); + +// Writes selected coordinate data to EEPROM +void settings_write_coord_data(uint8_t coord_select, float *coord_data); + +// Reads selected coordinate data from EEPROM +uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data); // int8_t settings_execute_startup(); diff --git a/stepper.c b/stepper.c index 117c7a2..97e6e4b 100755 --- a/stepper.c +++ b/stepper.c @@ -84,25 +84,32 @@ static volatile uint8_t busy; // True when SIG_OUTPUT_COMPARE1A is being servi static void set_step_events_per_minute(uint32_t steps_per_minute); -// Stepper state initialization -static void st_wake_up() +// Stepper state initialization. Cycle should only start if the st.cycle_start flag is +// enabled. Startup init and limits call this function but shouldn't start the cycle. +void st_wake_up() { - // Initialize stepper output bits - out_bits = (0) ^ (settings.invert_mask); - // Initialize step pulse timing from settings. Here to ensure updating after re-writing. - #ifdef STEP_PULSE_DELAY - // Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope. - step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3); - // Set delay between direction pin write and step command. - OCR2A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); - #else // Normal operation - // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. - step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); - #endif // Enable steppers by resetting the stepper disable port - STEPPERS_DISABLE_PORT &= ~(1<> 3); + // Set delay between direction pin write and step command. + OCR2A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); + #else // Normal operation + // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. + step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); + #endif + // Enable stepper driver interrupt + TIMSK1 |= (1<