Lots of re-organization and cleaning-up. Some bug fixes.

- Added a new source and header file called system. These files contain
the system commands and variables, as well as all of the system headers
and standard libraries Grbl uses. Centralizing some of the code.

- Re-organized the include headers throughout the source code.

- ENABLE_M7 define was missing from config.h. Now there.

- SPINDLE_MAX_RPM and SPINDLE_MIN_RPM now defined in config.h. No
uncommenting to prevent user issues. Minimum spindle RPM now provides
the lower, near 0V, scale adjustment, i.e. some spindles can go really
slow so why use up our 256 voltage bins for them?

- Remove some persistent variables from coolant and spindle control.
They were redundant.

- Removed a VARIABLE_SPINDLE define in cpu_map.h that shouldn’t have
been there.

- Changed the DEFAULT_ARC_TOLERANCE to 0.002mm to improve arc tracing.
Before we had issues with performance, no longer.

- Fixed a bug with the hard limits and the software debounce feature
enabled. The invert limit pin setting wasn’t honored.

- Fixed a bug with the homing direction mask. Now is like it used to
be. At least for now.

- Re-organized main.c to serve as only as the reset/initialization
routine. Makes things a little bit clearer in terms of execution
procedures.

- Re-organized protocol.c as the overall master control unit for
execution procedures. Not quite there yet, but starting to make a
little more sense in how things are run.

- Removed updating of old settings records. So many new settings have
been added that it’s not worth adding the code to migrate old user
settings.

- Tweaked spindle_control.c a bit and made it more clear and consistent
with other parts of Grbl.

- Tweaked the stepper disable bit code in stepper.c. Requires less
flash memory.
This commit is contained in:
Sonny Jeon
2014-01-10 20:22:10 -07:00
parent 7a85ab896d
commit cc9afdc195
31 changed files with 636 additions and 583 deletions

View File

@ -1,5 +1,5 @@
/*
protocol.c - the serial protocol master control unit
protocol.c - controls Grbl execution procedures
Part of Grbl
Copyright (c) 2011-2014 Sungeun K. Jeon
@ -19,78 +19,19 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "system.h"
#include "serial.h"
#include "settings.h"
#include "protocol.h"
#include "gcode.h"
#include "serial.h"
#include "print.h"
#include "settings.h"
#include "config.h"
#include "nuts_bolts.h"
#include "stepper.h"
#include "report.h"
#include "motion_control.h"
#include "report.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.
static void protocol_reset_line_buffer()
{
char_counter = 0;
iscomment = false;
}
void protocol_init()
{
protocol_reset_line_buffer(); // Reset line input
report_init_message(); // Welcome message
PINOUT_DDR &= ~(PINOUT_MASK); // Set as input pins
PINOUT_PORT |= PINOUT_MASK; // Enable internal pull-up resistors. Normal high operation.
PINOUT_PCMSK |= PINOUT_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << PINOUT_INT); // Enable Pin Change Interrupt
}
// Executes user startup script, if stored.
void protocol_execute_startup()
{
uint8_t n;
for (n=0; n < N_STARTUP_LINE; n++) {
if (!(settings_read_startup_line(n, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
if (line[0] != 0) {
printString(line); // Echo startup line to indicate execution.
report_status_message(gc_execute_line(line));
}
}
}
}
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the runtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based runtime commands when picked off
// directly from the incoming serial data stream.
ISR(PINOUT_INT_vect)
{
// Enter only if any pinout pin is actively low.
if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) {
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
mc_reset();
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
sys.execute |= EXEC_FEED_HOLD;
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) {
sys.execute |= EXEC_CYCLE_START;
}
}
}
// Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any
// point where the execution time from the last check point may be more than a fraction of a second.
@ -181,188 +122,111 @@ void protocol_execute_runtime()
// 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] == '$') {
uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable
float parameter, value;
switch( line[char_counter] ) {
case '#' : // Print gcode parameters
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_parameters(); }
break;
case 'G' : // Prints gcode parser state
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_modes(); }
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.
default :
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
case '$' : // Prints Grbl settings
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_grbl_settings(); }
break;
case 'C' : // Set check g-code mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent.
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else {
if (sys.state) { return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
}
break;
case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
// Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or alarm.
mc_homing_cycle();
if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
} else { return(STATUS_SETTING_DISABLED); }
break;
case 'I' : // Print or store build info.
if ( line[++char_counter] == 0 ) {
if (!(settings_read_build_info(line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_build_info(line);
}
} else { // Store startup line
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
helper_var = char_counter; // Set helper variable as counter to start of user info line.
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
settings_store_build_info(line);
}
break;
case 'N' : // Startup lines.
if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_startup_line(helper_var,line);
}
}
break;
} else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
default : // Storing setting methods
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
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));
}
}
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
// incoming streaming g-code blocks, this also directs and executes Grbl internal commands,
// such as settings, initiating the homing cycle, and toggling switch states.
// TODO: Eventually re-organize this function to more cleanly organize order of operations,
// which will hopefully reduce some of the current spaghetti logic and dynamic memory usage.
static void protocol_execute_line(char *line)
{
protocol_execute_runtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to calling function upon system abort
uint8_t status;
if (line[0] == 0) {
// Empty or comment line. Send status message for syncing purposes.
status = STATUS_OK;
} else if (line[0] == '$') {
// Grbl '$' system command
status = system_execute_line(line);
} else {
return(gc_execute_line(line)); // Everything else is gcode
// Everything else is gcode. Send to g-code parser!
// TODO: Separate the parsing from the g-code execution. Need to re-write the parser
// completely to do this. First parse the line completely, checking for modal group
// errors and storing all of the g-code words. Then, send the stored g-code words to
// a separate g-code executor. This will be more in-line with actual g-code protocol.
status = gc_execute_line(line);
}
report_status_message(status);
}
// 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()
{
// ------------------------------------------------------------
// Complete initialization procedures upon a power-up or reset.
// ------------------------------------------------------------
// Print welcome message
report_init_message();
// Check for and report alarm state after a reset, error, or an initial power up.
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_LOCK);
} else {
// All systems go!
sys.state = STATE_IDLE; // Set system to ready. Clear all state flags.
system_execute_startup(line); // Execute startup script.
}
// ------------------------------------------------------------------------------
// Main loop! Upon a system abort, this exits back to main() to reset the system.
// ------------------------------------------------------------------------------
uint8_t iscomment = false;
uint8_t char_counter = 0;
uint8_t c;
while((c = serial_read()) != SERIAL_NO_DATA) {
if ((c == '\n') || (c == '\r')) { // End of line reached
for (;;) {
// Runtime command check point before executing line. Prevent any furthur line executions.
// NOTE: If there is no line, this function should quickly return to the main program when
// the buffer empties of non-executable data.
protocol_execute_runtime();
if (sys.abort) { return; } // Bail to main program upon system abort
if (char_counter > 0) {// Line is complete. Then execute!
line[char_counter] = 0; // Terminate string
report_status_message(protocol_execute_line(line));
} else {
// Empty or comment line. Skip block.
report_status_message(STATUS_OK); // Send status message for syncing purposes.
}
protocol_reset_line_buffer();
} else {
if (iscomment) {
// Throw away all comment characters
if (c == ')') {
// End of comment. Resume line.
iscomment = false;
}
// Process one line of incoming serial data, as the data becomes available. Performs an
// initial filtering by removing spaces and comments and capitalizing all letters.
while((c = serial_read()) != SERIAL_NO_DATA) {
if ((c == '\n') || (c == '\r')) { // End of line reached
line[char_counter] = 0; // Set string termination character.
protocol_execute_line(line); // Line is complete. Execute it!
iscomment = false;
char_counter = 0;
} else {
if (c <= ' ') {
// Throw away whitepace and control characters
} else if (c == '/') {
// Block delete not supported. Ignore character.
} else if (c == '(') {
// Enable comments flag and ignore all characters until ')' or EOL.
iscomment = true;
} else if (char_counter >= LINE_BUFFER_SIZE-1) {
// Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW);
protocol_reset_line_buffer();
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase
line[char_counter++] = c-'a'+'A';
if (iscomment) {
// Throw away all comment characters
if (c == ')') {
// End of comment. Resume line.
iscomment = false;
}
} else {
line[char_counter++] = c;
if (c <= ' ') {
// Throw away whitepace and control characters
} else if (c == '/') {
// Block delete not supported. Ignore character.
} else if (c == '(') {
// Enable comments flag and ignore all characters until ')' or EOL.
iscomment = true;
} else if (char_counter >= LINE_BUFFER_SIZE-1) {
// Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW);
iscomment = false;
char_counter = 0;
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase
line[char_counter++] = c-'a'+'A';
} else {
line[char_counter++] = c;
}
}
}
}
protocol_execute_runtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to main() program loop to reset system.
// If there are no more characters in the serial read buffer to be processed and executed,
// this indicates that g-code streaming has either filled the planner buffer or has
// completed. In either case, auto-cycle start, if enabled, any queued moves.
mc_auto_cycle_start();
}
return; /* Never reached */
}