diff --git a/.cproject b/.cproject
new file mode 100644
index 000000000..ddced78d3
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 000000000..94ec9251a
--- /dev/null
+++ b/.project
@@ -0,0 +1,26 @@
+
+
+ grbl_atmega
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/atmega328p.ld b/atmega328p.ld
new file mode 100644
index 000000000..5b8c238c8
--- /dev/null
+++ b/atmega328p.ld
@@ -0,0 +1,228 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+MEMORY
+{
+ text (rx) : ORIGIN = 0, LENGTH = 32K
+ data (rw!x) : ORIGIN = 0x800060, LENGTH = 2K
+ eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 1K
+ fuse (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
+ lock (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
+ signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
+}
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.text :
+ {
+ *(.rel.text)
+ *(.rel.text.*)
+ *(.rel.gnu.linkonce.t*)
+ }
+ .rela.text :
+ {
+ *(.rela.text)
+ *(.rela.text.*)
+ *(.rela.gnu.linkonce.t*)
+ }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.rodata :
+ {
+ *(.rel.rodata)
+ *(.rel.rodata.*)
+ *(.rel.gnu.linkonce.r*)
+ }
+ .rela.rodata :
+ {
+ *(.rela.rodata)
+ *(.rela.rodata.*)
+ *(.rela.gnu.linkonce.r*)
+ }
+ .rel.data :
+ {
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.gnu.linkonce.d*)
+ }
+ .rela.data :
+ {
+ *(.rela.data)
+ *(.rela.data.*)
+ *(.rela.gnu.linkonce.d*)
+ }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ /* Internal text space or external memory. */
+ .text :
+ {
+ *(.vectors)
+ KEEP(*(.vectors))
+ /* For data that needs to reside in the lower 64k of progmem. */
+ *(.progmem.gcc*)
+ *(.progmem*)
+ . = ALIGN(2);
+ __trampolines_start = . ;
+ /* The jump trampolines for the 16-bit limited relocs will reside here. */
+ *(.trampolines)
+ *(.trampolines*)
+ __trampolines_end = . ;
+ /* For future tablejump instruction arrays for 3 byte pc devices.
+ We don't relax jump/call instructions within these sections. */
+ *(.jumptables)
+ *(.jumptables*)
+ /* For code that needs to reside in the lower 128k progmem. */
+ *(.lowtext)
+ *(.lowtext*)
+ __ctors_start = . ;
+ *(.ctors)
+ __ctors_end = . ;
+ __dtors_start = . ;
+ *(.dtors)
+ __dtors_end = . ;
+ KEEP(SORT(*)(.ctors))
+ KEEP(SORT(*)(.dtors))
+ /* From this point on, we don't bother about wether the insns are
+ below or above the 16 bits boundary. */
+ *(.init0) /* Start here after reset. */
+ KEEP (*(.init0))
+ *(.init1)
+ KEEP (*(.init1))
+ *(.init2) /* Clear __zero_reg__, set up stack pointer. */
+ KEEP (*(.init2))
+ *(.init3)
+ KEEP (*(.init3))
+ *(.init4) /* Initialize data and BSS. */
+ KEEP (*(.init4))
+ *(.init5)
+ KEEP (*(.init5))
+ *(.init6) /* C++ constructors. */
+ KEEP (*(.init6))
+ *(.init7)
+ KEEP (*(.init7))
+ *(.init8)
+ KEEP (*(.init8))
+ *(.init9) /* Call main(). */
+ KEEP (*(.init9))
+ *(.text)
+ . = ALIGN(2);
+ *(.text.*)
+ . = ALIGN(2);
+ *(.fini9) /* _exit() starts here. */
+ KEEP (*(.fini9))
+ *(.fini8)
+ KEEP (*(.fini8))
+ *(.fini7)
+ KEEP (*(.fini7))
+ *(.fini6) /* C++ destructors. */
+ KEEP (*(.fini6))
+ *(.fini5)
+ KEEP (*(.fini5))
+ *(.fini4)
+ KEEP (*(.fini4))
+ *(.fini3)
+ KEEP (*(.fini3))
+ *(.fini2)
+ KEEP (*(.fini2))
+ *(.fini1)
+ KEEP (*(.fini1))
+ *(.fini0) /* Infinite loop after program termination. */
+ KEEP (*(.fini0))
+ _etext = . ;
+ } > text
+ .data : AT (ADDR (.text) + SIZEOF (.text))
+ {
+ PROVIDE (__data_start = .) ;
+ *(.data)
+ *(.data*)
+ *(.rodata) /* We need to include .rodata here if gcc is used */
+ *(.rodata*) /* with -fdata-sections. */
+ *(.gnu.linkonce.d*)
+ . = ALIGN(2);
+ _edata = . ;
+ PROVIDE (__data_end = .) ;
+ } > data
+ .bss : AT (ADDR (.bss))
+ {
+ PROVIDE (__bss_start = .) ;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ PROVIDE (__bss_end = .) ;
+ } > data
+ __data_load_start = LOADADDR(.data);
+ __data_load_end = __data_load_start + SIZEOF(.data);
+ /* Global data not cleared after reset. */
+ .noinit :
+ {
+ PROVIDE (__noinit_start = .) ;
+ *(.noinit*)
+ PROVIDE (__noinit_end = .) ;
+ _end = . ;
+ PROVIDE (__heap_start = .) ;
+ } > data
+ .eeprom :
+ {
+ *(.eeprom*)
+ __eeprom_end = . ;
+ } > eeprom
+ .fuse :
+ {
+ KEEP(*(.fuse))
+ KEEP(*(.lfuse))
+ KEEP(*(.hfuse))
+ KEEP(*(.efuse))
+ } > fuse
+ .lock :
+ {
+ KEEP(*(.lock*))
+ } > lock
+ .signature :
+ {
+ KEEP(*(.signature*))
+ } > signature
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+}
diff --git a/config.h b/config.h
index e345bdd82..29a5b1094 100644
--- a/config.h
+++ b/config.h
@@ -33,7 +33,6 @@
#define BAUD_RATE 57600
// #define DEBUG_IGNORE_SENSORS // set for debugging
-
#define CONFIG_X_STEPS_PER_MM 32.80839895 //microsteps/mm
#ifndef NANOTEC_STEPPER_09
#define CONFIG_Y_STEPS_PER_MM 32.80839895 //microsteps/mm
@@ -195,3 +194,4 @@
//
// x = ~x; // toggles ALL the bits in x.
+#define MM_PER_INCH 25.4
diff --git a/gcode.c b/gcode.c
index 20401529b..c7c9ed045 100644
--- a/gcode.c
+++ b/gcode.c
@@ -32,27 +32,34 @@
#include "planner.h"
#include "stepper.h"
-#define MM_PER_INCH (25.4)
-
-#define NEXT_ACTION_NONE 0
-#define NEXT_ACTION_SEEK 1
-#define NEXT_ACTION_FEED 2
-#define NEXT_ACTION_DWELL 3
-#define NEXT_ACTION_HOMING_CYCLE 4
-#define NEXT_ACTION_SET_COORDINATE_OFFSET 5
-#define NEXT_ACTION_AIR_ASSIST_ENABLE 6
-#define NEXT_ACTION_AIR_ASSIST_DISABLE 7
-#define NEXT_ACTION_AUX1_ASSIST_ENABLE 8
-#define NEXT_ACTION_AUX1_ASSIST_DISABLE 9
+enum {
+ NEXT_ACTION_NONE = 0,
+ NEXT_ACTION_SEEK,
+ NEXT_ACTION_FEED,
+ NEXT_ACTION_CW_ARC,
+ NEXT_ACTION_CCW_ARC,
+ NEXT_ACTION_RASTER,
+ NEXT_ACTION_DWELL,
+ NEXT_ACTION_STOP,
+ NEXT_ACTION_HOMING_CYCLE,
+ NEXT_ACTION_SET_COORDINATE_OFFSET,
+ NEXT_ACTION_AIR_ASSIST_ENABLE,
+ NEXT_ACTION_AIR_ASSIST_DISABLE,
+ NEXT_ACTION_AUX1_ASSIST_ENABLE,
+ NEXT_ACTION_AUX1_ASSIST_DISABLE,
#ifdef DRIVEBOARD
- #define NEXT_ACTION_AUX2_ASSIST_ENABLE 10
- #define NEXT_ACTION_AUX2_ASSIST_DISABLE 11
+ NEXT_ACTION_AUX2_ASSIST_ENABLE,
+ NEXT_ACTION_AUX2_ASSIST_DISABLE,
#endif
+ NEXT_ACTION_SET_ACCELERATION,
+ NEXT_ACTION_SET_PPI,
+};
#define OFFSET_G54 0
#define OFFSET_G55 1
#define BUFFER_LINE_SIZE 80
+
char rx_line[BUFFER_LINE_SIZE];
char *rx_line_cursor;
@@ -61,7 +68,7 @@ uint8_t line_checksum_ok_already;
#define FAIL(status) gc.status_code = status;
typedef struct {
- uint8_t status_code; // return codes
+ GCODE_STATUS status_code; // return codes
uint8_t motion_mode; // {G0, G1}
bool inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21}
bool absolute_mode; // 0 = relative motion, 1 = absolute motion {G90, G91}
@@ -71,6 +78,7 @@ typedef struct {
double offsets[6]; // coord system offsets {G54_X,G54_Y,G54_Z,G55_X,G55_Y,G55_Z}
uint8_t offselect; // currently active offset, 0 -> G54, 1 -> G55
uint8_t nominal_laser_intensity; // 0-255 percentage
+ raster_info_t raster; // Raster State
} parser_state_t;
static parser_state_t gc;
@@ -107,7 +115,7 @@ void gcode_init() {
void gcode_process_line() {
uint8_t chr = '\0';
int numChars = 0;
- int status_code = STATUS_OK;
+ int status_code = GCODE_STATUS_OK;
uint8_t skip_line = false;
uint8_t print_extended_status = false;
@@ -115,7 +123,7 @@ void gcode_process_line() {
chr = serial_read(); // blocks until there is data
if (numChars + 1 >= BUFFER_LINE_SIZE) { // +1 for \0
// reached line size, other side sent too long lines
- stepper_request_stop(STATUS_LINE_BUFFER_OVERFLOW);
+ stepper_request_stop(GCODE_STATUS_LINE_BUFFER_OVERFLOW);
break;
} else if (chr <= ' ') {
// ignore control characters and space
@@ -142,21 +150,35 @@ void gcode_process_line() {
printString("!"); // report harware is in stop mode
status_code = stepper_stop_status();
// report stop conditions
- if ( status_code == STATUS_POWER_OFF) {
- printString("P"); // Stop: Power Off
- } else if (status_code == STATUS_LIMIT_HIT) {
- printString("L"); // Stop: Limit Hit
- } else if (status_code == STATUS_SERIAL_STOP_REQUEST) {
- printString("R"); // Stop: Serial Request
- } else if (status_code == STATUS_RX_BUFFER_OVERFLOW) {
- printString("B"); // Stop: Rx Buffer Overflow
- } else if (status_code == STATUS_LINE_BUFFER_OVERFLOW) {
- printString("I"); // Stop: Line Buffer Overflow
- } else if (status_code == STATUS_TRANSMISSION_ERROR) {
- printString("T"); // Stop: Serial Transmission Error
- } else {
- printString("O"); // Stop: Other error
- printInteger(status_code);
+ switch (status_code) {
+ case GCODE_STATUS_POWER_OFF:
+ printString("P"); // Stop: Power Off
+ break;
+
+ case GCODE_STATUS_LIMIT_HIT:
+ printString("L"); // Stop: Limit Hit
+ break;
+
+ case GCODE_STATUS_SERIAL_STOP_REQUEST:
+ printString("R"); // Stop: Serial Request
+ break;
+
+ case GCODE_STATUS_RX_BUFFER_OVERFLOW:
+ printString("B"); // Stop: Rx Buffer Overflow
+ break;
+
+ case GCODE_STATUS_LINE_BUFFER_OVERFLOW:
+ printString("I"); // Stop: Line Buffer Overflow
+ break;
+
+ case GCODE_STATUS_TRANSMISSION_ERROR:
+ printString("T"); // Stop: Serial Transmission Error
+ break;
+
+ default:
+ printString("O"); // Stop: Other error
+ printInteger(status_code);
+ break;
}
} else {
if (rx_line[0] == '*' || rx_line[0] == '^') {
@@ -169,7 +191,7 @@ void gcode_process_line() {
if (rx_checksum < 128) {
printString(rx_line);
printString(" -> checksum outside [128,255]");
- stepper_request_stop(STATUS_TRANSMISSION_ERROR);
+ stepper_request_stop(GCODE_STATUS_TRANSMISSION_ERROR);
}
char *itr = rx_line_cursor;
uint16_t checksum = 0;
@@ -191,7 +213,7 @@ void gcode_process_line() {
printString("^");
} else { // '*'
printString(rx_line);
- stepper_request_stop(STATUS_TRANSMISSION_ERROR);
+ stepper_request_stop(GCODE_STATUS_TRANSMISSION_ERROR);
// line_checksum_ok_already = false;
}
} else { // we got a good line
@@ -216,19 +238,27 @@ void gcode_process_line() {
if (rx_line_cursor[0] != '?') {
// process the next line of G-code
status_code = gcode_execute_line(rx_line_cursor);
- // report parse errors
- if (status_code == STATUS_OK) {
- // pass
- } else if (status_code == STATUS_BAD_NUMBER_FORMAT) {
- printString("N"); // Warning: Bad number format
- } else if (status_code == STATUS_EXPECTED_COMMAND_LETTER) {
- printString("E"); // Warning: Expected command letter
- } else if (status_code == STATUS_UNSUPPORTED_STATEMENT) {
- printString("U"); // Warning: Unsupported statement
- } else {
- printString("W"); // Warning: Other error
- printInteger(status_code);
- }
+ switch (status_code) {
+ case GCODE_STATUS_OK:
+ break;
+
+ case GCODE_STATUS_BAD_NUMBER_FORMAT:
+ printString("N"); // Warning: Bad number format
+ break;
+
+ case GCODE_STATUS_EXPECTED_COMMAND_LETTER:
+ printString("E"); // Warning: Expected command letter
+ break;
+
+ case GCODE_STATUS_UNSUPPORTED_STATEMENT:
+ printString("U"); // Warning: Unsupported statement
+ break;
+
+ default:
+ printString("W"); // Warning: Other error
+ printInteger(status_code);
+ break;
+ }
} else {
print_extended_status = true;
}
@@ -294,11 +324,13 @@ uint8_t gcode_execute_line(char *line) {
double unit_converted_value;
uint8_t next_action = NEXT_ACTION_NONE;
double target[3];
+ double vector[3] = {0.0, 0.0, 0.0};
+ double n = -1.0;
double p = 0.0;
int cs = 0;
int l = 0;
bool got_actual_line_command = false; // as opposed to just e.g. G1 F1200
- gc.status_code = STATUS_OK;
+ gc.status_code = GCODE_STATUS_OK;
//// Pass 1: Commands
while(next_statement(&letter, &value, line, &char_counter)) {
@@ -309,6 +341,29 @@ uint8_t gcode_execute_line(char *line) {
case 0: gc.motion_mode = next_action = NEXT_ACTION_SEEK; break;
case 1: gc.motion_mode = next_action = NEXT_ACTION_FEED; break;
case 4: next_action = NEXT_ACTION_DWELL; break;
+ case 8:
+ // Special case to append raster data
+ if (line[char_counter] == 'D') {
+ uint32_t len;
+ char_counter++;
+
+ len = strlen(line) - char_counter;
+
+ if (len >= RASTER_BUFFER_SIZE || len > 70)
+ {
+ gc.status_code = GCODE_STATUS_RX_BUFFER_OVERFLOW;
+ stepper_request_stop(gc.status_code);
+ }
+ else
+ {
+ planner_raster_data(&line[char_counter], len, false);
+ }
+
+ return gc.status_code;
+ } else {
+ next_action = NEXT_ACTION_RASTER;
+ }
+ break;
case 10: next_action = NEXT_ACTION_SET_COORDINATE_OFFSET; break;
case 20: gc.inches_mode = true; break;
case 21: gc.inches_mode = false; break;
@@ -317,7 +372,7 @@ uint8_t gcode_execute_line(char *line) {
case 55: gc.offselect = OFFSET_G55; break;
case 90: gc.absolute_mode = true; break;
case 91: gc.absolute_mode = false; break;
- default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
+ default: FAIL(GCODE_STATUS_UNSUPPORTED_STATEMENT); break;
}
break;
case 'M':
@@ -330,7 +385,7 @@ uint8_t gcode_execute_line(char *line) {
case 84: next_action = NEXT_ACTION_AUX2_ASSIST_ENABLE;break;
case 85: next_action = NEXT_ACTION_AUX2_ASSIST_DISABLE;break;
#endif
- default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
+ default: FAIL(GCODE_STATUS_UNSUPPORTED_STATEMENT); break;
}
break;
}
@@ -352,7 +407,7 @@ uint8_t gcode_execute_line(char *line) {
}
switch(letter) {
case 'F':
- if (unit_converted_value <= 0) { FAIL(STATUS_BAD_NUMBER_FORMAT); }
+ if (unit_converted_value <= 0) { FAIL(GCODE_STATUS_BAD_NUMBER_FORMAT); }
if (gc.motion_mode == NEXT_ACTION_SEEK) {
gc.seek_rate = unit_converted_value;
} else {
@@ -367,6 +422,7 @@ uint8_t gcode_execute_line(char *line) {
}
got_actual_line_command = true;
break;
+ case 'N': n = value; break;
case 'P': // dwelling seconds or CS selector
if (next_action == NEXT_ACTION_SET_COORDINATE_OFFSET) {
cs = trunc(value);
@@ -404,6 +460,37 @@ uint8_t gcode_execute_line(char *line) {
gc.feed_rate, gc.nominal_laser_intensity );
}
break;
+ case NEXT_ACTION_RASTER:
+ if (p > 0.0) {
+ gc.raster.dot_size = p;
+ }
+ if (got_actual_line_command) {
+ gc.raster.x_off = vector[X_AXIS];
+ gc.raster.y_off = vector[Y_AXIS];
+ if (vector[Z_AXIS] < 0) {
+ gc.raster.invert = 1;
+ } else {
+ gc.raster.invert = 0;
+ }
+
+ // Setup the raster...
+ planner_raster(target[X_AXIS] + gc.offsets[3 * gc.offselect + X_AXIS],
+ target[Y_AXIS] + gc.offsets[3 * gc.offselect + Y_AXIS],
+ target[Z_AXIS] + gc.offsets[3 * gc.offselect + Z_AXIS],
+ gc.feed_rate, gc.nominal_laser_intensity, &gc.raster);
+ }
+
+ if (n >= 0.0) {
+ // End of the raster.
+ planner_raster_data(NULL, 0, true);
+
+ // Always increment on N regardless of D.
+ if (gc.raster.x_off != 0.0)
+ target[Y_AXIS] += gc.raster.dot_size;
+ else if (gc.raster.y_off != 0.0)
+ target[X_AXIS] -= gc.raster.dot_size;
+ }
+ break;
case NEXT_ACTION_DWELL:
planner_dwell(p, gc.nominal_laser_intensity);
break;
@@ -507,12 +594,12 @@ static int next_statement(char *letter, double *double_ptr, char *line, uint8_t
*letter = line[*char_counter];
if((*letter < 'A') || (*letter > 'Z')) {
- FAIL(STATUS_EXPECTED_COMMAND_LETTER);
+ FAIL(GCODE_STATUS_EXPECTED_COMMAND_LETTER);
return(0);
}
(*char_counter)++;
if (!read_double(line, char_counter, double_ptr)) {
- FAIL(STATUS_BAD_NUMBER_FORMAT);
+ FAIL(GCODE_STATUS_BAD_NUMBER_FORMAT);
return(0);
};
return(1);
@@ -525,19 +612,35 @@ static int next_statement(char *letter, double *double_ptr, char *line, uint8_t
static int read_double(char *line, uint8_t *char_counter, double *double_ptr) {
char *start = line + *char_counter;
char *end;
-
- *double_ptr = strtod(start, &end);
- if(end == start) {
- return(false);
- };
-
- *char_counter = end - line;
- return(true);
-}
+ char *search;
+ char mod_char = 0;
+
+ // Quick search for any X's (don't want G0X0Y0 interpreting as a hex value!).
+ // The alternative was sscanf, but that adds 15K of code.
+ for (search = line + *char_counter; *search != 0x00; search++)
+ {
+ if (*search == 'X' || *search == 'Y' || *search == 'Z' || *search == 'E') {
+ // Temporarily replace this with string terminator
+ mod_char = *search;
+ *search = 0;
+ break;
+ }
+ }
+ *double_ptr = strtod(start, &end);
+ // Revert the string (if needed)
+ if (mod_char != 0)
+ *search = mod_char;
+ // Nothing found
+ if (end == start)
+ return (false);
+ // Update our char counter
+ *char_counter = end - line;
+ return (true);
+}
/*
diff --git a/gcode.h b/gcode.h
index f3c2d815e..644866664 100644
--- a/gcode.h
+++ b/gcode.h
@@ -25,19 +25,21 @@
#include
#include
-#define STATUS_OK 0
-#define STATUS_RX_BUFFER_OVERFLOW 1
-#define STATUS_LINE_BUFFER_OVERFLOW 2
-#define STATUS_TRANSMISSION_ERROR 3
-#define STATUS_BAD_NUMBER_FORMAT 4
-#define STATUS_EXPECTED_COMMAND_LETTER 5
-#define STATUS_UNSUPPORTED_STATEMENT 6
-#define STATUS_SERIAL_STOP_REQUEST 7
-#define STATUS_LIMIT_HIT 8
-#define STATUS_POWER_OFF 9
-// #define STATUS_DOOR_OPEN 10
-// #define STATUS_CHILLER_OFF 11
-
+typedef enum {
+ GCODE_STATUS_OK = 0,
+ GCODE_STATUS_RX_BUFFER_OVERFLOW,
+ GCODE_STATUS_LINE_BUFFER_OVERFLOW,
+ GCODE_STATUS_TRANSMISSION_ERROR,
+ GCODE_STATUS_BAD_NUMBER_FORMAT,
+ GCODE_STATUS_EXPECTED_COMMAND_LETTER,
+ GCODE_STATUS_UNSUPPORTED_STATEMENT,
+ GCODE_STATUS_SERIAL_STOP_REQUEST,
+ GCODE_STATUS_LIMIT_HIT,
+ GCODE_STATUS_POWER_OFF,
+ GCODE_STATUS_DOOR_OPEN,
+ GCODE_STATUS_CHILLER_OFF,
+ GCODE_STATUS_ARC_RADIUS_ERROR,
+} GCODE_STATUS;
// Initialize the parser
void gcode_init();
diff --git a/planner.c b/planner.c
index 99629fc07..065b669a0 100644
--- a/planner.c
+++ b/planner.c
@@ -28,12 +28,20 @@
// The number of linear motions that can be in the plan at any give time
-#define BLOCK_BUFFER_SIZE 16 // do not make bigger than uint8_t
+#define BLOCK_BUFFER_SIZE 15 // do not make bigger than uint8_t
+#define RASTER_BUFFER_COUNT 2
static block_t block_buffer[BLOCK_BUFFER_SIZE]; // ring buffer for motion instructions
static volatile uint8_t block_buffer_head; // index of the next block to be pushed
static volatile uint8_t block_buffer_tail; // index of the block to process now
+// Raster buffer.
+// We are severely memory constrained, so each (gcode) line of raster data is queued as a new
+// planner block rather than waiting for the end of the raster. The raster buffers are grabbed
+// on an "is free" basis and a pointer to it stored in the planner block.
+static raster_t raster_buffer[RASTER_BUFFER_COUNT];
+static raster_info_t raster_current;
+
static int32_t position[3]; // The current position of the tool in absolute steps
static volatile bool position_update_requested; // make sure to update to stepper position on next occasion
static double previous_unit_vec[3]; // Unit vector of previous path line segment
@@ -51,8 +59,8 @@ static void reduce_entry_speed_forward(block_t *previous, block_t *current);
static void planner_recalculate();
-
void planner_init() {
+ int i;
block_buffer_head = 0;
block_buffer_tail = 0;
clear_vector(position);
@@ -62,13 +70,20 @@ void planner_init() {
position_update_requested = false;
clear_vector_double(previous_unit_vec);
previous_nominal_speed = 0.0;
+
+ // Mark the raster buffers as free.
+ for (i=0; itype = TYPE_LINE;
+ // Setup the block type
+ if (raster == NULL) {
+ block->block_type = BLOCK_TYPE_LINE;
+ } else {
+ block->block_type = BLOCK_TYPE_RASTER_LINE;
+ block->raster = raster;
+ }
// set nominal laser intensity
block->nominal_laser_intensity = nominal_laser_intensity;
@@ -119,7 +139,7 @@ void planner_line(double x, double y, double z, double feed_rate, uint8_t nomina
block->millimeters = sqrt( (delta_mm[X_AXIS]*delta_mm[X_AXIS]) +
(delta_mm[Y_AXIS]*delta_mm[Y_AXIS]) +
(delta_mm[Z_AXIS]*delta_mm[Z_AXIS]) );
- double inverse_millimeters = 1.0/block->millimeters; // store for efficency
+ double inverse_millimeters = 1.0/block->millimeters; // store for efficency
// calculate nominal_speed (mm/min) and nominal_rate (step/min)
// minimum stepper speed is limited by MINIMUM_STEPS_PER_MINUTE in stepper.c
@@ -197,6 +217,84 @@ void planner_line(double x, double y, double z, double feed_rate, uint8_t nomina
stepper_wake_up();
}
+// Process a raster.
+// Rasters can be +/- in the x or y directions (not z).
+// The sign of x_off/y_off specify the raster direction.
+// The value of x_off/y_off specify the offset (acceleration margin) before the actual raster.
+void planner_raster(double x, double y, double z,
+ double feed_rate,
+ uint8_t nominal_laser_intensity,
+ raster_info_t *info) {
+
+ memcpy(&raster_current, info, sizeof(raster_info_t));
+
+ // Store the parameters
+ raster_current.x = x;
+ raster_current.y = y;
+ raster_current.z = z;
+ raster_current.feed_rate = feed_rate;
+
+ // Move to the starting point. (Assumes we have space before the limits are hit)
+ // then accelerate to operating feed_rate.
+ // Hopefully by then we'll have the first block of raster data...
+ if (raster_current.x_off > 0) {
+ planner_movement(x - raster_current.x_off, y, z, CONFIG_SEEKRATE, 0, NULL);
+ planner_movement(x, y, z, feed_rate, 0, NULL);
+ } else if (raster_current.y_off > 0) {
+ planner_movement(x, y - raster_current.y_off, z, CONFIG_SEEKRATE, 0, NULL);
+ planner_movement(x, y, z, feed_rate, 0, NULL);
+ }
+
+ raster_current.intensity = nominal_laser_intensity;
+}
+
+// There isn't enough RAM to buffer a whole raster, so take and process piecemeal.
+void planner_raster_data(char *data, uint8_t len, bool last) {
+ int i;
+
+ if (len > 0) {
+ raster_t* raster = NULL;
+ for (i=0; ifree = false;
+ break;
+ }
+ }
+
+ // Append the data to the inactive buffer.
+ memcpy(raster->data, data, len);
+ raster->data_length = len;
+ raster->intensity = raster_current.intensity;
+ raster->invert = raster_current.invert;
+
+ // Shuffle the stepper along.
+ if (raster_current.x_off > 0) {
+ planner_movement(raster_current.x + raster_current.length, raster_current.y, raster_current.z, raster_current.feed_rate, 0, raster);
+ } else if (raster_current.y_off > 0) {
+ planner_movement(raster_current.x, raster_current.y + raster_current.length, raster_current.z, raster_current.feed_rate, 0, raster);
+ }
+ }
+
+ // If this is the last one, end properly.
+ if (last) {
+ if (raster_current.x_off > 0) {
+ planner_movement(raster_current.x + raster_current.length + raster_current.x_off, raster_current.y, raster_current.z, CONFIG_SEEKRATE, 0, NULL);
+ } else if (raster_current.y_off > 0) {
+ planner_movement(raster_current.x, raster_current.y + raster_current.length + raster_current.y_off, raster_current.z, CONFIG_SEEKRATE, 0, NULL);
+ }
+ }
+}
+
+// Add a new linear movement to the buffer. x, y and z is
+// the signed, absolute target position in millimeters. Feed rate specifies the speed of the motion.
+void planner_line(double x, double y, double z,
+ double feed_rate,
+ uint8_t laser_pwm) {
+ planner_movement(x, y, z, feed_rate, laser_pwm, NULL);
+}
+
void planner_dwell(double seconds, uint8_t nominal_laser_intensity) {
// // Execute dwell in seconds. Maximum time delay is > 18 hours, more than enough for any application.
@@ -214,7 +312,7 @@ void planner_dwell(double seconds, uint8_t nominal_laser_intensity) {
void planner_command(uint8_t type) {
// calculate the buffer head and check for space
- int next_buffer_head = next_block_index( block_buffer_head );
+ int next_buffer_head = next_block_index( block_buffer_head );
while(block_buffer_tail == next_buffer_head) { // buffer full condition
// good! We are well ahead of the robot. Rest here until buffer has room.
// sleep_mode();
@@ -224,7 +322,7 @@ void planner_command(uint8_t type) {
block_t *block = &block_buffer[block_buffer_head];
// set block type command
- block->type = type;
+ block->block_type = type;
// Move buffer head
block_buffer_head = next_buffer_head;
diff --git a/planner.h b/planner.h
index 96e49fc98..a9dae1255 100644
--- a/planner.h
+++ b/planner.h
@@ -23,29 +23,61 @@
#include "config.h"
-
-// Command types the planner and stepper can schedule for execution
-#define TYPE_LINE 0
-#define TYPE_AIR_ASSIST_ENABLE 1
-#define TYPE_AIR_ASSIST_DISABLE 2
-#define TYPE_AUX1_ASSIST_ENABLE 3
-#define TYPE_AUX1_ASSIST_DISABLE 4
-#define TYPE_AUX2_ASSIST_ENABLE 5
-#define TYPE_AUX2_ASSIST_DISABLE 6
-
-#define planner_control_air_assist_enable() planner_command(TYPE_AIR_ASSIST_ENABLE)
-#define planner_control_air_assist_disable() planner_command(TYPE_AIR_ASSIST_DISABLE)
-#define planner_control_aux1_assist_enable() planner_command(TYPE_AUX1_ASSIST_ENABLE)
-#define planner_control_aux1_assist_disable() planner_command(TYPE_AUX1_ASSIST_DISABLE)
+#define RASTER_BUFFER_SIZE 70
+
+// Command types the planner and stepper can schedule for execution
+typedef enum {
+ BLOCK_TYPE_LINE,
+ BLOCK_TYPE_RASTER_LINE,
+ BLOCK_TYPE_AIR_ASSIST_ENABLE,
+ BLOCK_TYPE_AIR_ASSIST_DISABLE,
+ BLOCK_TYPE_AUX1_ASSIST_ENABLE,
+ BLOCK_TYPE_AUX1_ASSIST_DISABLE,
+ BLOCK_TYPE_AUX2_ASSIST_ENABLE,
+ BLOCK_TYPE_AUX2_ASSIST_DISABLE,
+} BLOCK_TYPE;
+
+typedef struct _raster_info {
+ uint8_t intensity;
+ uint8_t invert;
+
+ double dot_size;
+ double x_off;
+ double y_off;
+
+ double x;
+ double y;
+ double z;
+ double feed_rate;
+
+ uint32_t length;
+} raster_info_t;
+
+// Raster structure, used by gcode, planner and stepper.
+typedef struct _raster {
+ bool free;
+
+ uint8_t data[RASTER_BUFFER_SIZE];
+ uint32_t data_length;
+
+ uint8_t intensity;
+ uint8_t invert;
+} raster_t;
+
+
+#define planner_control_air_assist_enable() planner_command(BLOCK_TYPE_AIR_ASSIST_ENABLE)
+#define planner_control_air_assist_disable() planner_command(BLOCK_TYPE_AIR_ASSIST_DISABLE)
+#define planner_control_aux1_assist_enable() planner_command(BLOCK_TYPE_AUX1_ASSIST_ENABLE)
+#define planner_control_aux1_assist_disable() planner_command(BLOCK_TYPE_AUX1_ASSIST_DISABLE)
#ifdef DRIVEBOARD
- #define planner_control_aux2_assist_enable() planner_command(TYPE_AUX2_ASSIST_ENABLE)
- #define planner_control_aux2_assist_disable() planner_command(TYPE_AUX2_ASSIST_DISABLE)
+ #define planner_control_aux2_assist_enable() planner_command(BLOCK_TYPE_AUX2_ASSIST_ENABLE)
+ #define planner_control_aux2_assist_disable() planner_command(BLOCK_TYPE_AUX2_ASSIST_DISABLE)
#endif
// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in
// the source g-code and may never actually be reached if acceleration management is active.
typedef struct {
- uint8_t type; // Type of command, eg: TYPE_LINE, TYPE_AIR_ASSIST_ENABLE
+ BLOCK_TYPE block_type; // Type of command, eg: TYPE_LINE, TYPE_AIR_ASSIST_ENABLE
// Fields used by the bresenham algorithm for tracing the line
uint32_t steps_x, steps_y, steps_z; // Step count along each axis
uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
@@ -65,12 +97,24 @@ typedef struct {
int32_t rate_delta; // The steps/minute to add or subtract when changing speed (must be positive)
uint32_t accelerate_until; // The index of the step event on which to stop acceleration
uint32_t decelerate_after; // The index of the step event on which to start decelerating
-
+ raster_t *raster; // Which raster buffer we're using.
} block_t;
-
+
// Initialize the motion plan subsystem
void planner_init();
+// Process a raster.
+// Rasters can be +/- in the x or y directions (not z).
+// The sign of x_off/y_off specifies the raster direction.
+// The value of x_off/y_off specifies the offset (acceleration margin) before the actual raster.
+// raster and raster_len contain the pointer and length of buffer containing 0-255 PWM values for each dot.
+void planner_raster(double x, double y, double z,
+ double feed_rate,
+ uint8_t nominal_laser_intensity,
+ raster_info_t *info);
+
+void planner_raster_data(char *data, uint8_t len, bool last);
+
// Add a new linear movement to the buffer.
// x, y and z is the signed, absolute target position in millimaters.
// Feed rate specifies the speed of the motion.
diff --git a/serial.c b/serial.c
index 9210bfed0..2f1e56eb7 100644
--- a/serial.c
+++ b/serial.c
@@ -162,7 +162,7 @@ SIGNAL(USART_RX_vect) {
uint8_t data = UDR0;
if (data == CHAR_STOP) {
// special stop character, bypass buffer
- stepper_request_stop(STATUS_SERIAL_STOP_REQUEST);
+ stepper_request_stop(GCODE_STATUS_SERIAL_STOP_REQUEST);
} else if (data == CHAR_RESUME) {
// special resume character, bypass buffer
stepper_stop_resume();
@@ -181,7 +181,7 @@ SIGNAL(USART_RX_vect) {
if (next_head == rx_buffer_tail) {
// buffer is full, other side sent too much data
- stepper_request_stop(STATUS_RX_BUFFER_OVERFLOW);
+ stepper_request_stop(GCODE_STATUS_RX_BUFFER_OVERFLOW);
} else {
rx_buffer[head] = data;
rx_buffer_head = next_head;
diff --git a/stepper.c b/stepper.c
index e055b41ee..156f318dc 100644
--- a/stepper.c
+++ b/stepper.c
@@ -58,7 +58,6 @@
#define CYCLES_PER_MICROSECOND (F_CPU/1000000) //16000000/1000000 = 16
#define CYCLES_PER_ACCELERATION_TICK (F_CPU/ACCELERATION_TICKS_PER_SECOND) // 16MHz/100 = 160000
-
static int32_t stepper_position[3]; // real-time position in absolute steps
static block_t *current_block; // A pointer to the block currently being traced
@@ -116,7 +115,7 @@ void stepper_init() {
acceleration_tick_counter = 0;
current_block = NULL;
stop_requested = false;
- stop_status = STATUS_OK;
+ stop_status = GCODE_STATUS_OK;
busy = false;
// start in the idle state
@@ -210,6 +209,8 @@ ISR(TIMER2_OVF_vect) {
// config_step_timer. It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
// The bresenham line tracer algorithm controls all three stepper outputs simultaneously.
ISR(TIMER1_COMPA_vect) {
+ uint32_t raster_index;
+ uint8_t intensity;
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
busy = true;
if (stop_requested) {
@@ -225,13 +226,13 @@ ISR(TIMER1_COMPA_vect) {
#ifndef DEBUG_IGNORE_SENSORS
// stop program when any limit is hit or the e-stop turned the power off
if (SENSE_LIMITS) {
- stepper_request_stop(STATUS_LIMIT_HIT);
+ stepper_request_stop(GCODE_STATUS_LIMIT_HIT);
busy = false;
return;
}
#ifndef DRIVEBOARD
else if (SENSE_POWER_OFF) {
- stepper_request_stop(STATUS_POWER_OFF);
+ stepper_request_stop(GCODE_STATUS_POWER_OFF);
busy = false;
return;
}
@@ -261,7 +262,8 @@ ISR(TIMER1_COMPA_vect) {
busy = false;
return;
}
- if (current_block->type == TYPE_LINE) { // starting on new line block
+ if (current_block->block_type == BLOCK_TYPE_LINE
+ || current_block->block_type == BLOCK_TYPE_RASTER_LINE) { // starting on new line block
adjusted_rate = current_block->initial_rate;
acceleration_tick_counter = CYCLES_PER_ACCELERATION_TICK/2; // start halfway, midpoint rule.
adjust_speed( adjusted_rate ); // initialize cycles_per_step_event
@@ -273,8 +275,22 @@ ISR(TIMER1_COMPA_vect) {
}
// process current block, populate out_bits (or handle other commands)
- switch (current_block->type) {
- case TYPE_LINE:
+ switch (current_block->block_type) {
+ case BLOCK_TYPE_RASTER_LINE:
+ raster_index = (step_events_completed * current_block->raster->data_length) / current_block->step_event_count;
+
+ intensity = 0;
+ if (current_block->raster->invert == 0 && current_block->raster->data[raster_index] == '1')
+ intensity = current_block->raster->intensity;
+ else if (current_block->raster->invert != 0 && current_block->raster->data[raster_index] == '0')
+ intensity = current_block->raster->intensity;
+
+ if (intensity != current_block->nominal_laser_intensity) {
+ current_block->nominal_laser_intensity = intensity;
+ control_laser_intensity(intensity);
+ }
+ //break;
+ case BLOCK_TYPE_LINE:
////// Execute step displacement profile by bresenham line algorithm
out_bits = current_block->direction_bits;
counter_x += current_block->steps_x;
@@ -335,11 +351,14 @@ ISR(TIMER1_COMPA_vect) {
// reset counter, midpoint rule
// makes sure deceleration is performed the same every time
acceleration_tick_counter = CYCLES_PER_ACCELERATION_TICK/2;
-
+
// decelerating
} else if (step_events_completed >= current_block->decelerate_after) {
if ( acceleration_tick() ) { // scheduled speed change
- adjusted_rate -= current_block->rate_delta;
+ if (adjusted_rate > current_block->rate_delta)
+ adjusted_rate -= current_block->rate_delta;
+ else
+ adjusted_rate = 0;
if (adjusted_rate < current_block->final_rate) { // overshot
adjusted_rate = current_block->final_rate;
}
@@ -362,38 +381,38 @@ ISR(TIMER1_COMPA_vect) {
break;
- case TYPE_AIR_ASSIST_ENABLE:
+ case BLOCK_TYPE_AIR_ASSIST_ENABLE:
control_air_assist(true);
current_block = NULL;
planner_discard_current_block();
break;
- case TYPE_AIR_ASSIST_DISABLE:
+ case BLOCK_TYPE_AIR_ASSIST_DISABLE:
control_air_assist(false);
current_block = NULL;
planner_discard_current_block();
break;
- case TYPE_AUX1_ASSIST_ENABLE:
+ case BLOCK_TYPE_AUX1_ASSIST_ENABLE:
control_aux1_assist(true);
current_block = NULL;
planner_discard_current_block();
break;
- case TYPE_AUX1_ASSIST_DISABLE:
+ case BLOCK_TYPE_AUX1_ASSIST_DISABLE:
control_aux1_assist(false);
current_block = NULL;
planner_discard_current_block();
break;
#ifdef DRIVEBOARD
- case TYPE_AUX2_ASSIST_ENABLE:
+ case BLOCK_TYPE_AUX2_ASSIST_ENABLE:
control_aux2_assist(true);
current_block = NULL;
planner_discard_current_block();
break;
- case TYPE_AUX2_ASSIST_DISABLE:
+ case BLOCK_TYPE_AUX2_ASSIST_DISABLE:
control_aux2_assist(false);
current_block = NULL;
planner_discard_current_block();
@@ -464,7 +483,12 @@ static uint32_t config_step_timer(uint32_t cycles) {
static void adjust_speed( uint32_t steps_per_minute ) {
// steps_per_minute is typicaly just adjusted_rate
if (steps_per_minute < MINIMUM_STEPS_PER_MINUTE) { steps_per_minute = MINIMUM_STEPS_PER_MINUTE; }
- cycles_per_step_event = config_step_timer((CYCLES_PER_MICROSECOND*1000000*60)/steps_per_minute);
+ cycles_per_step_event = config_step_timer( (CYCLES_PER_MICROSECOND*1000000/steps_per_minute) * 60 );
+
+ if (cycles_per_step_event == 0)
+ {
+ stepper_request_stop(GCODE_STATUS_BAD_NUMBER_FORMAT);
+ }
// beam dynamics
uint8_t adjusted_intensity = current_block->nominal_laser_intensity *
((float)steps_per_minute/(float)current_block->nominal_rate);