diff --git a/config.h b/config.h
index 56f4b9d..ac68acb 100644
--- a/config.h
+++ b/config.h
@@ -27,37 +27,38 @@
#define BAUD_RATE 9600
// Define pin-assignments
-#define STEPPERS_DISABLE_DDR DDRB
-#define STEPPERS_DISABLE_PORT PORTB
-#define STEPPERS_DISABLE_BIT 0
-
#define STEPPING_DDR DDRD
#define STEPPING_PORT PORTD
-#define X_STEP_BIT 2
-#define Y_STEP_BIT 3
-#define Z_STEP_BIT 4
-#define X_DIRECTION_BIT 5
-#define Y_DIRECTION_BIT 6
-#define Z_DIRECTION_BIT 7
+#define X_STEP_BIT 2 // Uno Digital Pin 2
+#define Y_STEP_BIT 3 // Uno Digital Pin 3
+#define Z_STEP_BIT 4 // Uno Digital Pin 4
+#define X_DIRECTION_BIT 5 // Uno Digital Pin 5
+#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
+#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
-#define LIMIT_DDR DDRB
+#define STEPPERS_DISABLE_DDR DDRB
+#define STEPPERS_DISABLE_PORT PORTB
+#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8
+
+#define LIMIT_DDR DDRB
#define LIMIT_PIN PINB
-#define X_LIMIT_BIT 1
-#define Y_LIMIT_BIT 2
-#define Z_LIMIT_BIT 3
+#define X_LIMIT_BIT 1 // Uno Digital Pin 9
+#define Y_LIMIT_BIT 2 // Uno Digital Pin 10
+#define Z_LIMIT_BIT 3 // Uno Digital Pin 11
#define SPINDLE_ENABLE_DDR DDRB
#define SPINDLE_ENABLE_PORT PORTB
-#define SPINDLE_ENABLE_BIT 4
+#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
#define SPINDLE_DIRECTION_DDR DDRB
#define SPINDLE_DIRECTION_PORT PORTB
-#define SPINDLE_DIRECTION_BIT 5
+#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13
// Define runtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters
// that do not and must not exist in the streamed g-code program. ASCII control characters may be
-// used, if they are available per user setup.
+// used, if they are available per user setup. Also, extended ASCII codes (>127), which are never in
+// g-code programs, maybe selected for interface programs.
// TODO: Solidify these default characters. Temporary for now.
#define CMD_STATUS_REPORT '?'
#define CMD_FEED_HOLD '!'
@@ -70,8 +71,8 @@
// entering g-code into grbl, i.e. locating part zero or simple manual machining. If the axes drift,
// grbl has no way to know this has happened, since stepper motors are open-loop control. Depending
// on the machine, this parameter may need to be larger or smaller than the default time.
-// NOTE: If defined 0, the delay will not be compiled.
-#define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer >= 0
+// NOTE: If commented out, the delay will not be compiled.
+#define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer > 0
// The temporal resolution of the acceleration management subsystem. Higher number give smoother
// acceleration but may impact performance.
@@ -109,4 +110,20 @@
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
#define DWELL_TIME_STEP 50 // Integer (milliseconds)
+
+// -----------------------------------------------
+
+// TODO: The following options are set as compile-time options for now, until the next EEPROM
+// settings version has solidified.
+#define CYCLE_AUTO_START 1 // Cycle auto-start boolean flag for the planner.
+#define BLOCK_DELETE_ENABLE 0 // Block delete enable/disable flag during g-code parsing
+#define REPORT_INCH_MODE 0 // Status reporting unit mode (1 = inch, 0 = mm)
+#if REPORT_INCH_MODE
+ #define DECIMAL_PLACES 3
+ #define DECIMAL_MULTIPLIER 1000 // 10^DECIMAL_PLACES
+#else
+ #define DECIMAL_PLACES 2 // mm-mode
+ #define DECIMAL_MULTIPLIER 100
+#endif
+
#endif
diff --git a/gcode.c b/gcode.c
index 1936015..b9ca1f4 100644
--- a/gcode.c
+++ b/gcode.c
@@ -32,8 +32,6 @@
#include "errno.h"
#include "protocol.h"
-#define MM_PER_INCH (25.4)
-
#define NEXT_ACTION_DEFAULT 0
#define NEXT_ACTION_DWELL 1
#define NEXT_ACTION_GO_HOME 2
diff --git a/main.c b/main.c
index a1b0b1d..17732ac 100644
--- a/main.c
+++ b/main.c
@@ -4,8 +4,7 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
- Copyright (c) 2011 Jens Geisler
-
+
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
@@ -20,11 +19,8 @@
along with Grbl. If not, see .
*/
-#include
-#include
#include
#include
-#include
#include "config.h"
#include "planner.h"
#include "nuts_bolts.h"
@@ -34,15 +30,11 @@
#include "gcode.h"
#include "protocol.h"
#include "limits.h"
-
#include "settings.h"
#include "serial.h"
-#include "print.h"
-
-// Declare system global variables
-uint8_t sys_abort; // Global system abort flag
-volatile uint8_t sys_state; // Global system state variable
+// Declare system global variable structure
+system_t sys;
int main(void)
{
@@ -50,17 +42,18 @@ int main(void)
sei(); // Enable interrupts
serial_init(BAUD_RATE); // Setup serial baud rate and interrupts
st_init(); // Setup stepper pins and interrupt timers
- sys_abort = true; // Set abort to complete initialization
+
+ sys.abort = true; // Set abort to complete initialization
while(1) {
- // Upon a system abort, the main program will return to this loop. Once here, it is safe to
- // re-initialize the system. Upon startup, the system will automatically reset to finish the
- // initialization process.
- if (sys_abort) {
- // Execute system reset
- sys_state = 0; // Reset system state
- sys_abort = false; // Release system abort
+ // Execute system reset upon a system abort, where the main program will return to this loop.
+ // Once here, it is safe to re-initialize the system. At startup, the system will automatically
+ // reset to finish the initialization process.
+ if (sys.abort) {
+
+ // Clear all system variables
+ memset(&sys, 0, sizeof(sys));
// Reset system.
serial_reset_read_buffer(); // Clear serial read buffer
@@ -70,19 +63,14 @@ int main(void)
gc_init(); // Set g-code parser to default state
spindle_init();
limits_init();
-
- // TODO: For now, the stepper subsystem tracks the absolute stepper position from the point
- // of power up or hard reset. This reset is a soft reset, where the information of the current
- // position is not lost after a system abort. This is not guaranteed to be correct, since
- // during an abort, the steppers can lose steps in the immediate stop. However, if a feed
- // hold is performed before a system abort, this position should be correct. In the next few
- // updates, this soft reset feature will be fleshed out along with the status reporting and
- // jogging features.
- st_reset(); // Clear stepper subsystem variables. Machine position variable is not reset.
-
- // Print grbl initialization message
- printPgmString(PSTR("\r\nGrbl " GRBL_VERSION));
- printPgmString(PSTR("\r\n'$' to dump current settings\r\n"));
+ st_reset(); // Clear stepper subsystem variables.
+
+ // Set system runtime defaults
+ // TODO: Eventual move to EEPROM from config.h when all of the new settings are worked out.
+ // Mainly to avoid having to maintain several different versions.
+ #ifdef CYCLE_AUTO_START
+ sys.auto_start = true;
+ #endif
}
protocol_execute_runtime();
diff --git a/motion_control.c b/motion_control.c
index a5985c4..12c929e 100644
--- a/motion_control.c
+++ b/motion_control.c
@@ -33,8 +33,6 @@
#include "limits.h"
#include "protocol.h"
-#include "print.h"
-
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
// (1 minute)/feed_rate time.
@@ -56,17 +54,19 @@ void mc_line(double x, double y, double z, double feed_rate, uint8_t invert_feed
// Remain in this loop until there is room in the buffer.
do {
protocol_execute_runtime(); // Check for any run-time commands
- if (sys_abort) { return; } // Bail, if system abort.
+ if (sys.abort) { return; } // Bail, if system abort.
} while ( plan_check_full_buffer() );
plan_buffer_line(x, y, z, feed_rate, invert_feed_rate);
- // Auto-cycle start.
- // TODO: Determine a more efficient and robust way of implementing the auto-starting the cycle.
- // For example, only auto-starting when the buffer is full; if there was only one g-code command
- // sent during manual operation; or if there is buffer starvation, making sure it minimizes any
- // dwelling/motion hiccups. Additionally, these situations must not auto-start during a feed hold.
- // Only the cycle start runtime command should be able to restart the cycle after a feed hold.
- st_cycle_start();
+ // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
+ // a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start
+ // runtime command.
+ // NOTE: This is allows the user to decide to exclusively use the cycle start runtime command to
+ // begin motion or let grbl auto-start it for them. This is useful when: manually cycle-starting
+ // when the buffer is completely full and primed; auto-starting, if there was only one g-code
+ // command sent during manual operation; or if a system is prone to buffer starvation, auto-start
+ // helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going.
+ if (sys.auto_start) { st_cycle_start(); }
}
@@ -167,7 +167,7 @@ void mc_arc(double *position, double *target, double *offset, uint8_t axis_0, ui
mc_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], feed_rate, invert_feed_rate);
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
- if (sys_abort) { return; }
+ if (sys.abort) { return; }
}
// Ensure last segment arrives at target location.
mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], feed_rate, invert_feed_rate);
@@ -183,7 +183,7 @@ void mc_dwell(double seconds)
while (i > 0) {
// NOTE: Check and execute runtime commands during dwell every <= DWELL_TIME_STEP milliseconds.
protocol_execute_runtime();
- if (sys_abort) { return; }
+ if (sys.abort) { return; }
_delay_ms(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
i--;
}
diff --git a/nuts_bolts.h b/nuts_bolts.h
index 665de25..edbb96c 100644
--- a/nuts_bolts.h
+++ b/nuts_bolts.h
@@ -32,27 +32,50 @@
#define Y_AXIS 1
#define Z_AXIS 2
+#define MM_PER_INCH (25.4)
+
+// Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
#define clear_vector_double(a) memset(a, 0.0, sizeof(a))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
-// Define system state bit map. Used internally by runtime protocol as runtime command flags.
-// NOTE: The system state is an unsigned 8-bit volatile variable and has a 8 flag limit. The default
-// flags are always false, so the runtime protocol only needs to check for a non-zero state value to
+// Bit field and masking macros
+#define bit(n) (1 << n)
+#define bit_true(x,mask) (x |= mask)
+#define bit_false(x,mask) (x &= ~mask)
+#define bit_toggle(x,mask) (x ^= mask)
+#define bit_istrue(x,mask) ((x & mask) != 0)
+#define bit_isfalse(x,mask) ((x & mask) == 0)
+
+// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
+// which notifies the main program to execute the specified runtime command asynchronously.
+// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
+// flags are always false, so the runtime protocol only needs to check for a non-zero value to
// know when there is a runtime command to execute.
-#define BIT_STATUS_REPORT 1 // bit 00000001
-#define BIT_CYCLE_START 2 // bit 00000010
-#define BIT_FEED_HOLD 4 // bit 00000100
-#define BIT_RESET 8 // bit 00001000
-#define BIT_REPLAN_CYCLE 16 // bit 00010000
-// #define 32 // bit 00100000
-// #define 64 // bit 01000000
-// #define 128 // bit 10000000
+#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
+#define EXEC_CYCLE_START bit(1) // bitmask 00000010
+#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
+#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
+#define EXEC_RESET bit(4) // bitmask 00010000
+// #define bit(5) // bitmask 00100000
+// #define bit(6) // bitmask 01000000
+// #define bit(7) // bitmask 10000000
// Define global system variables
-extern uint8_t sys_abort; // Global system abort flag
-extern volatile uint8_t sys_state; // Global system state variable
+typedef struct {
+ uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
+ uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume.
+ uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
+
+ int32_t position[3]; // Real-time machine position vector in steps. This may need to be a volatile
+ // variable, if problems arise. Subject to change. Need to add coordinate offset
+ // functionality to correctly track part zero and machine zero.
+
+ volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
+ volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
+} system_t;
+extern system_t sys;
// Read a floating point value from a string. Line points to the input buffer, char_counter
// is the indexer pointing to the current character of the line, while double_ptr is
diff --git a/planner.c b/planner.c
index aeba0cd..772e168 100644
--- a/planner.c
+++ b/planner.c
@@ -34,7 +34,7 @@
#include "protocol.h"
// The number of linear motions that can be in the plan at any give time
-#define BLOCK_BUFFER_SIZE 20
+#define BLOCK_BUFFER_SIZE 18
static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions
static volatile uint8_t block_buffer_head; // Index of the next block to be pushed
@@ -336,7 +336,7 @@ void plan_synchronize()
{
while(plan_get_current_block()) {
protocol_execute_runtime(); // Check and execute run-time commands
- if (sys_abort) { return; } // Check for system abort
+ if (sys.abort) { return; } // Check for system abort
}
}
diff --git a/planner.h b/planner.h
index fc692b5..451fdf9 100644
--- a/planner.h
+++ b/planner.h
@@ -35,7 +35,7 @@ typedef struct {
// Fields used by the motion planner to manage acceleration
double nominal_speed; // The nominal speed for this block in mm/min
- double entry_speed; // Entry speed at previous-current junction in mm/min
+ double entry_speed; // Entry speed at previous-current block junction in mm/min
double max_entry_speed; // Maximum allowable junction entry speed in mm/min
double millimeters; // The total travel of this block in mm
uint8_t recalculate_flag; // Planner flag to recalculate trapezoids on entry junction
diff --git a/print.c b/print.c
index 05524a3..f509e88 100644
--- a/print.c
+++ b/print.c
@@ -3,6 +3,7 @@
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
+ Copyright (c) 2011 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
@@ -24,72 +25,107 @@
#include
#include
+#include "config.h"
#include "serial.h"
-#ifndef DECIMAL_PLACES
-#define DECIMAL_PLACES 3
-#endif
-
void printString(const char *s)
{
- while (*s)
- serial_write(*s++);
+ while (*s)
+ serial_write(*s++);
}
// Print a string stored in PGM-memory
void printPgmString(const char *s)
{
char c;
- while ((c = pgm_read_byte_near(s++)))
- serial_write(c);
+ while ((c = pgm_read_byte_near(s++)))
+ serial_write(c);
}
-void printIntegerInBase(unsigned long n, unsigned long base)
+// void printIntegerInBase(unsigned long n, unsigned long base)
+// {
+// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
+// unsigned long i = 0;
+//
+// if (n == 0) {
+// serial_write('0');
+// return;
+// }
+//
+// while (n > 0) {
+// buf[i++] = n % base;
+// n /= base;
+// }
+//
+// for (; i > 0; i--)
+// serial_write(buf[i - 1] < 10 ?
+// '0' + buf[i - 1] :
+// 'A' + buf[i - 1] - 10);
+// }
+
+void print_uint8_base2(uint8_t n)
{
- unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
- unsigned long i = 0;
+ unsigned char buf[8];
+ uint8_t i = 0;
- if (n == 0) {
- serial_write('0');
- return;
- }
-
- while (n > 0) {
- buf[i++] = n % base;
- n /= base;
+ for (; i < 8; i++) {
+ buf[i] = n & 1;
+ n >>= 1;
}
for (; i > 0; i--)
- serial_write(buf[i - 1] < 10 ?
- '0' + buf[i - 1] :
- 'A' + buf[i - 1] - 10);
+ serial_write('0' + buf[i - 1]);
+}
+
+static void print_uint32_base10(unsigned long n)
+{
+ unsigned char buf[32];
+ uint8_t i = 0;
+
+ if (n == 0) {
+ serial_write('0');
+ return;
+ }
+
+ while (n > 0) {
+ buf[i++] = n % 10;
+ n /= 10;
+ }
+
+ for (; i > 0; i--)
+ serial_write('0' + buf[i - 1]);
}
void printInteger(long n)
{
- if (n < 0) {
- serial_write('-');
- n = -n;
- }
-
- printIntegerInBase(n, 10);
+ if (n < 0) {
+ serial_write('-');
+ n = -n;
+ }
+ print_uint32_base10(n);
}
-// A very simple
void printFloat(double n)
{
- double integer_part, fractional_part;
- uint8_t decimal_part;
- fractional_part = modf(n, &integer_part);
- printInteger(integer_part);
+ if (n < 0) {
+ serial_write('-');
+ n = -n;
+ }
+ n += 0.5/DECIMAL_MULTIPLIER; // Add rounding factor
+
+ long integer_part;
+ integer_part = (int)n;
+ print_uint32_base10(integer_part);
+
serial_write('.');
- fractional_part *= 10;
+
+ n -= integer_part;
int decimals = DECIMAL_PLACES;
+ uint8_t decimal_part;
while(decimals-- > 0) {
- decimal_part = floor(fractional_part);
+ n *= 10;
+ decimal_part = (int) n;
serial_write('0'+decimal_part);
- fractional_part -= decimal_part;
- fractional_part *= 10;
+ n -= decimal_part;
}
}
-
diff --git a/print.h b/print.h
index b2581ba..ff4ea99 100644
--- a/print.h
+++ b/print.h
@@ -3,6 +3,7 @@
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
+ Copyright (c) 2011 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
@@ -30,7 +31,7 @@ void printPgmString(const char *s);
void printInteger(long n);
-void printIntegerInBase(unsigned long n, unsigned long base);
+void print_uint8_base2(uint8_t n);
void printFloat(double n);
diff --git a/protocol.c b/protocol.c
index da31da8..7b812f3 100644
--- a/protocol.c
+++ b/protocol.c
@@ -69,15 +69,39 @@ void protocol_status_report()
// 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. 'x0.23 y120.4 z2.4'. This is necessary as it minimizes the computational
+ // information, i.e. 'x0.23,y120.4,z2.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 (10-20Hz).
- printString("Query Received.\r\n"); // Notify that it's working.
+ // short line segments and interface setups that require real-time status reports (5-20Hz).
+ // Additionally, during an abort, the steppers are immediately stopped regardless of what they
+ // are doing. If they are moving, the abort stop can cause grbl to lose steps. However, if a feed
+ // hold is performed before a system abort, the steppers will steadily decelerate at the max
+ // acceleration rate, hence the stopped machine position will be maintained and correct.
+
+
+ // Bare-bones status report. Provides real-time machine position relative to the initialization
+ // or system reset location (0,0,0), not a home position. This section is under construction and
+ // the following are needed: coordinate offsets/updating of machine position relative to home, work
+ // coordinate position?, user setting of output units (mm|inch), compressed (non-human readable)
+ // data for interfaces?, save last known position in EEPROM?
+ #if REPORT_INCH_MODE
+ printString("x"); printFloat(sys.position[X_AXIS]/(settings.steps_per_mm[X_AXIS]*MM_PER_INCH));
+ printString(",y"); printFloat(sys.position[Y_AXIS]/(settings.steps_per_mm[Y_AXIS]*MM_PER_INCH));
+ printString(",z"); printFloat(sys.position[Z_AXIS]/(settings.steps_per_mm[Z_AXIS]*MM_PER_INCH));
+ #else
+ printString("x"); printFloat(sys.position[X_AXIS]/(settings.steps_per_mm[X_AXIS]));
+ printString(",y"); printFloat(sys.position[Y_AXIS]/(settings.steps_per_mm[Y_AXIS]));
+ printString(",z"); printFloat(sys.position[Z_AXIS]/(settings.steps_per_mm[Z_AXIS]));
+ #endif
+ printString("\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;
}
@@ -87,40 +111,46 @@ void protocol_init()
// 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.
// This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code
-// parsing and planning functions.
-// NOTE: The sys_state variable flags are set by the serial read subprogram, except where noted.
+// 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 to 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.
void protocol_execute_runtime()
{
- if (sys_state) { // Enter only if any bit flag is enabled
+ if (sys.execute) { // Enter only if any bit flag is true
+ uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
// System abort. Steppers have already been force stopped.
- if (sys_state & BIT_RESET) {
- sys_abort = true;
+ if (rt_exec & EXEC_RESET) {
+ sys.abort = true;
return; // Nothing else to do but exit.
}
// Execute and serial print status
- if (sys_state & BIT_STATUS_REPORT) {
+ if (rt_exec & EXEC_STATUS_REPORT) {
+ bit_false(sys.execute,EXEC_STATUS_REPORT);
protocol_status_report();
- sys_state ^= BIT_STATUS_REPORT; // Toggle off
}
// Initiate stepper feed hold
- if (sys_state & BIT_FEED_HOLD) {
- st_feed_hold();
- sys_state ^= BIT_FEED_HOLD; // Toggle off
+ if (rt_exec & EXEC_FEED_HOLD) {
+ st_feed_hold(); // Initiate feed hold.
+ bit_false(sys.execute,EXEC_FEED_HOLD);
}
- // Re-plans the buffer after a feed hold completes
- // NOTE: BIT_REPLAN_CYCLE is set by the stepper subsystem when the feed hold is complete.
- if (sys_state & BIT_REPLAN_CYCLE) {
+ // Reinitializes the stepper module running flags and re-plans the buffer after a feed hold.
+ // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
+ if (rt_exec & EXEC_CYCLE_STOP) {
st_cycle_reinitialize();
- sys_state ^= BIT_REPLAN_CYCLE; // Toggle off
+ bit_false(sys.execute,EXEC_CYCLE_STOP);
}
- if (sys_state & BIT_CYCLE_START) {
+ if (rt_exec & EXEC_CYCLE_START) {
st_cycle_start(); // Issue cycle start command to stepper subsystem
- sys_state ^= BIT_CYCLE_START; // Toggle off
+ #ifdef CYCLE_AUTO_START
+ sys.auto_start = true; // Re-enable auto start after feed hold.
+ #endif
+ bit_false(sys.execute,EXEC_CYCLE_START);
}
}
}
@@ -130,6 +160,15 @@ void protocol_execute_runtime()
uint8_t protocol_execute_line(char *line)
{
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 {
@@ -165,7 +204,7 @@ void protocol_process()
// 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 (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
@@ -176,6 +215,7 @@ void protocol_process()
}
char_counter = 0; // Reset line buffer index
iscomment = false; // Reset comment flag
+
} else {
if (iscomment) {
// Throw away all comment characters
@@ -187,9 +227,10 @@ void protocol_process()
if (c <= ' ') {
// Throw away whitepace and control characters
} else if (c == '/') {
- // Disable block delete and throw away character
- // To enable block delete, uncomment following line. Will ignore until EOL.
- // iscomment = true;
+ // Disable block delete and throw away characters. Will ignore until EOL.
+ #if BLOCK_DELETE_ENABLE
+ iscomment = true;
+ #endif
} else if (c == '(') {
// Enable comments flag and ignore all characters until ')' or EOL.
iscomment = true;
diff --git a/script/console b/script/Obsolete/console
similarity index 100%
rename from script/console
rename to script/Obsolete/console
diff --git a/script/proxy b/script/Obsolete/proxy
similarity index 100%
rename from script/proxy
rename to script/Obsolete/proxy
diff --git a/script/stream b/script/Obsolete/stream
similarity index 100%
rename from script/stream
rename to script/Obsolete/stream
diff --git a/script/stream.rb b/script/Obsolete/stream.rb
similarity index 100%
rename from script/stream.rb
rename to script/Obsolete/stream.rb
diff --git a/script/trapezoid_simulator.rb b/script/Obsolete/trapezoid_simulator.rb
similarity index 100%
rename from script/trapezoid_simulator.rb
rename to script/Obsolete/trapezoid_simulator.rb
diff --git a/script/simple_stream.py b/script/simple_stream.py
index 8bd4b3b..5119db4 100755
--- a/script/simple_stream.py
+++ b/script/simple_stream.py
@@ -1,6 +1,15 @@
#!/usr/bin/env python
"""\
Simple g-code streaming script for grbl
+
+Provided as an illustration of the basic communication interface
+for grbl. When grbl has finished parsing the g-code block, it will
+return an 'ok' or 'error' response. When the planner buffer is full,
+grbl will not send a response until the planner buffer clears space.
+
+G02/03 arcs are special exceptions, where they inject short line
+segments directly into the planner. So there may not be a response
+from grbl for the duration of the arc.
"""
import serial
diff --git a/script/stream.py b/script/stream.py
new file mode 100755
index 0000000..32971ff
--- /dev/null
+++ b/script/stream.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+"""\
+Stream g-code to grbl controller
+
+This script differs from the simple_stream.py script by
+tracking the number of characters in grbl's serial read
+buffer. This allows grbl to fetch the next line directly
+from the serial buffer and does not have to wait for a
+response from the computer. This effectively adds another
+buffer layer to prevent buffer starvation.
+
+TODO: - Add runtime command capabilities
+
+Version: SKJ.20120104
+"""
+
+import serial
+import re
+import time
+import sys
+import argparse
+
+RX_BUFFER_SIZE = 128
+
+# Define command line argument interface
+parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial library required)')
+parser.add_argument('gcode', type=argparse.FileType('r'),
+ help='g-code filename to be streamed')
+parser.add_argument('device',
+ help='serial device path')
+parser.add_argument('-q','--quiet',action='store_true', default=False,
+ help='suppress output text')
+args = parser.parse_args()
+
+# Initialize
+s = serial.Serial(args.device_file,9600)
+f = args.gcode_file
+verbose = True
+if args.quiet : verbose = False
+
+# Wake up grbl
+print "Initializing grbl..."
+s.write("\r\n\r\n")
+
+# Wait for grbl to initialize and flush startup text in serial input
+time.sleep(2)
+s.flushInput()
+
+# Stream g-code to grbl
+print "Streaming ", args.gcode_file.name, " to ", args.device_file
+l_count = 0
+g_count = 0
+c_line = []
+for line in f:
+ l_count += 1 # Iterate line counter
+# l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
+ l_block = line.strip()
+ c_line.append(len(l_block)) # Track number of characters in grbl serial read buffer
+ grbl_out = ''
+ while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
+ out_temp = s.readline().strip() # Wait for grbl response
+ if out_temp not in ['ok','error'] :
+ print " Debug: ",out_temp # Debug response
+ else :
+ grbl_out += out_temp;
+ g_count += 1 # Iterate g-code counter
+ grbl_out += str(g_count); # Add line finished indicator
+ del c_line[0]
+ if verbose: print "SND: " + str(l_count) + " : " + l_block,
+ s.write(l_block + '\n') # Send block to grbl
+ if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
+
+# Wait for user input after streaming is completed
+print "G-code streaming finished!\n"
+print "WARNING: Wait until grbl completes buffered g-code blocks before exiting."
+raw_input(" Press to exit and disable grbl.")
+
+# Close file and serial port
+f.close()
+s.close()
\ No newline at end of file
diff --git a/serial.c b/serial.c
index 8aa9419..87aab50 100644
--- a/serial.c
+++ b/serial.c
@@ -31,7 +31,7 @@
#include "protocol.h"
#define RX_BUFFER_SIZE 128
-#define TX_BUFFER_SIZE 32
+#define TX_BUFFER_SIZE 64
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_buffer_head = 0;
@@ -72,7 +72,7 @@ void serial_write(uint8_t data) {
// Wait until there is space in the buffer
while (next_head == tx_buffer_tail) {
protocol_execute_runtime(); // Check for any run-time commands
- if (sys_abort) { return; } // Bail, if system abort.
+ if (sys.abort) { return; } // Bail, if system abort.
}
// Store data and advance head
@@ -124,15 +124,15 @@ ISR(USART_RX_vect)
// Pick off runtime command characters directly from the serial stream. These characters are
// not passed into the buffer, but these set system state flag bits for runtime execution.
switch (data) {
- case CMD_STATUS_REPORT: sys_state |= BIT_STATUS_REPORT; break; // Set as true
- case CMD_CYCLE_START: sys_state |= BIT_CYCLE_START; break; // Set as true
- case CMD_FEED_HOLD: sys_state |= BIT_FEED_HOLD; break; // Set as true
+ case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
+ case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true
+ case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
case CMD_RESET:
// Immediately force stepper subsystem idle at an interrupt level.
- if (!(sys_state & BIT_RESET)) { // Force stop only first time.
+ if (!(sys.execute & EXEC_RESET)) { // Force stop only first time.
st_go_idle();
}
- sys_state |= BIT_RESET; // Set as true
+ sys.execute |= EXEC_RESET; // Set as true
break;
default : // Write character to buffer
rx_buffer[rx_buffer_head] = data;
diff --git a/settings.c b/settings.c
index 9d2c173..5cc3b16 100644
--- a/settings.c
+++ b/settings.c
@@ -54,6 +54,7 @@ typedef struct {
#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<
#include
diff --git a/stepper.c b/stepper.c
index f48cf77..3278c89 100644
--- a/stepper.c
+++ b/stepper.c
@@ -4,7 +4,6 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
- Copyright (c) 2011 Jens Geisler
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,8 +33,6 @@
#include "planner.h"
#include "limits.h"
-#include "print.h"
-
// Some useful constants
#define STEP_MASK ((1<initial_rate;
set_step_events_per_minute(st.trapezoid_adjusted_rate); // Initialize cycles_per_step_event
st.trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
@@ -177,9 +172,9 @@ ISR(TIMER1_COMPA_vect,ISR_NOBLOCK)
st.event_count = current_block->step_event_count;
st.step_events_completed = 0;
} else {
- st.cycle_start = false;
- st.feed_hold = false;
st_go_idle();
+ sys.cycle_start = false;
+ bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program for cycle end
}
}
@@ -190,29 +185,29 @@ ISR(TIMER1_COMPA_vect,ISR_NOBLOCK)
if (st.counter_x > 0) {
out_bits |= (1<steps_y;
if (st.counter_y > 0) {
out_bits |= (1<steps_z;
if (st.counter_z > 0) {
out_bits |= (1<step_event_count) {
- if (st.feed_hold) {
+ if (sys.feed_hold) {
// Check for and execute feed hold by enforcing a steady deceleration from the moment of
// execution. The rate of deceleration is limited by rate_delta and will never decelerate
// faster or slower than in normal operation. If the distance required for the feed hold
@@ -225,10 +220,11 @@ ISR(TIMER1_COMPA_vect,ISR_NOBLOCK)
// If deceleration complete, set system flags and shutdown steppers.
if (st.trapezoid_adjusted_rate <= current_block->rate_delta) {
// Just go idle. Do not NULL current block. The bresenham algorithm variables must
- // remain intact to ensure the stepper path is exactly the same.
- st.cycle_start = false;
+ // remain intact to ensure the stepper path is exactly the same. Feed hold is still
+ // active and is released after the buffer has been reinitialized.
st_go_idle();
- sys_state |= BIT_REPLAN_CYCLE; // Flag main program that feed hold is complete.
+ sys.cycle_start = false;
+ bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program that feed hold is complete.
} else {
st.trapezoid_adjusted_rate -= current_block->rate_delta;
set_step_events_per_minute(st.trapezoid_adjusted_rate);
@@ -339,9 +335,6 @@ void st_init()
TCCR2A = 0; // Normal operation
TCCR2B = (1<step_event_count - st.step_events_completed);
- // Update initial rate and timers after feed hold.
- st.trapezoid_adjusted_rate = 0; // Resumes from rest
- set_step_events_per_minute(st.trapezoid_adjusted_rate);
- st.trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
- st.step_events_completed = 0;
- st.feed_hold = false; // Release feed hold. Cycle is ready to re-start.
+ if (current_block != NULL) {
+ // Replan buffer from the feed hold stop location.
+ plan_cycle_reinitialize(current_block->step_event_count - st.step_events_completed);
+ // Update initial rate and timers after feed hold.
+ st.trapezoid_adjusted_rate = 0; // Resumes from rest
+ set_step_events_per_minute(st.trapezoid_adjusted_rate);
+ st.trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
+ st.step_events_completed = 0;
+ }
+ sys.feed_hold = false; // Release feed hold. Cycle is ready to re-start.
}
+
+