1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-20 13:21:49 +02:00

Merge pull request #29 from bdring/dev

Merge dev to master
This commit is contained in:
bdring
2018-09-15 17:59:10 -05:00
committed by GitHub
23 changed files with 709 additions and 422 deletions

View File

@@ -101,7 +101,7 @@ void loop() {
sys_rt_exec_accessory_override = 0; sys_rt_exec_accessory_override = 0;
// Reset Grbl primary systems. // Reset Grbl primary systems.
serial_reset_read_buffer(); // Clear serial read buffer serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer
gc_init(); // Set g-code parser to default state gc_init(); // Set g-code parser to default state
@@ -119,7 +119,7 @@ void loop() {
// put your main code here, to run repeatedly: // put your main code here, to run repeatedly:
report_init_message(); report_init_message(CLIENT_ALL);
// Start Grbl main loop. Processes program inputs and executes them. // Start Grbl main loop. Processes program inputs and executes them.
protocol_main_loop(); protocol_main_loop();

View File

@@ -107,13 +107,13 @@ Some features should not be changed. See notes below.
// pull-off motion to disengage the limit switches. The following HOMING_CYCLE_x defines are executed // pull-off motion to disengage the limit switches. The following HOMING_CYCLE_x defines are executed
// in order starting with suffix 0 and completes the homing routine for the specified-axes only. If // in order starting with suffix 0 and completes the homing routine for the specified-axes only. If
// an axis is omitted from the defines, it will not home, nor will the system update its position. // an axis is omitted from the defines, it will not home, nor will the system update its position.
// Meaning that this allows for users with non-standard cartesian machines, such as a lathe (x then z, // Meaning that this allows for users with non-standard Cartesian machines, such as a lathe (x then z,
// with no y), to configure the homing cycle behavior to their needs. // with no y), to configure the homing cycle behavior to their needs.
// NOTE: The homing cycle is designed to allow sharing of limit pins, if the axes are not in the same // NOTE: The homing cycle is designed to allow sharing of limit pins, if the axes are not in the same
// cycle, but this requires some pin settings changes in cpu_map.h file. For example, the default homing // cycle, but this requires some pin settings changes in cpu_map.h file. For example, the default homing
// cycle can share the Z limit pin with either X or Y limit pins, since they are on different cycles. // cycle can share the Z limit pin with either X or Y limit pins, since they are on different cycles.
// By sharing a pin, this frees up a precious IO pin for other purposes. In theory, all axes limit pins // By sharing a pin, this frees up a precious IO pin for other purposes. In theory, all axes limit pins
// may be reduced to one pin, if all axes are homed with seperate cycles, or vice versa, all three axes // may be reduced to one pin, if all axes are homed with separate cycles, or vice versa, all three axes
// on separate pin, but homed in one cycle. Also, it should be noted that the function of hard limits // on separate pin, but homed in one cycle. Also, it should be noted that the function of hard limits
// will not be affected by pin sharing. // will not be affected by pin sharing.
// NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y. // NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y.
@@ -185,7 +185,9 @@ Some features should not be changed. See notes below.
// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno // Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
// analog pin 4. Only use this option if you require a second coolant control pin. // analog pin 4. Only use this option if you require a second coolant control pin.
// NOTE: The M8 flood coolant control pin on analog pin 3 will still be functional regardless. // NOTE: The M8 flood coolant control pin on analog pin 3 will still be functional regardless.
//#define ENABLE_M7 // Disabled by default. Uncomment to enable. // ESP32 NOTE! This is here for reference only. You enable both M7 and M8 by assigning them a GPIO Pin
// in cpu_map.h
//#define ENABLE_M7 // Don't uncomment...see above!
// This option causes the feed hold input to act as a safety door switch. A safety door, when triggered, // This option causes the feed hold input to act as a safety door switch. A safety door, when triggered,
// immediately forces a feed hold and then safely de-energizes the machine. Resuming is blocked until // immediately forces a feed hold and then safely de-energizes the machine. Resuming is blocked until

View File

@@ -26,8 +26,12 @@
void coolant_init() void coolant_init()
{ {
#ifdef COOLANT_FLOOD_PIN
pinMode(COOLANT_FLOOD_PIN, OUTPUT); pinMode(COOLANT_FLOOD_PIN, OUTPUT);
#ifdef ENABLE_M7 #endif
#ifdef COOLANT_MIST_PIN
pinMode(COOLANT_MIST_PIN, OUTPUT); pinMode(COOLANT_MIST_PIN, OUTPUT);
#endif #endif
coolant_stop(); coolant_stop();
@@ -39,6 +43,7 @@ uint8_t coolant_get_state()
{ {
uint8_t cl_state = COOLANT_STATE_DISABLE; uint8_t cl_state = COOLANT_STATE_DISABLE;
#ifdef COOLANT_FLOOD_PIN
#ifdef INVERT_COOLANT_FLOOD_PIN #ifdef INVERT_COOLANT_FLOOD_PIN
if (! digitalRead(COOLANT_FLOOD_PIN)) { if (! digitalRead(COOLANT_FLOOD_PIN)) {
#else #else
@@ -46,7 +51,10 @@ uint8_t coolant_get_state()
#endif #endif
cl_state |= COOLANT_STATE_FLOOD; cl_state |= COOLANT_STATE_FLOOD;
} }
#ifdef ENABLE_M7 #endif
#ifdef COOLANT_MIST_PIN
#ifdef INVERT_COOLANT_MIST_PIN #ifdef INVERT_COOLANT_MIST_PIN
if (! digitalRead(COOLANT_MIST_PIN)) { if (! digitalRead(COOLANT_MIST_PIN)) {
#else #else
@@ -65,12 +73,15 @@ uint8_t coolant_get_state()
// an interrupt-level. No report flag set, but only called by routines that don't need it. // an interrupt-level. No report flag set, but only called by routines that don't need it.
void coolant_stop() void coolant_stop()
{ {
#ifdef COOLANT_FLOOD_PIN
#ifdef INVERT_COOLANT_FLOOD_PIN #ifdef INVERT_COOLANT_FLOOD_PIN
digitalWrite(COOLANT_FLOOD_PIN, 1); digitalWrite(COOLANT_FLOOD_PIN, 1);
#else #else
digitalWrite(COOLANT_FLOOD_PIN, 0); digitalWrite(COOLANT_FLOOD_PIN, 0);
#endif #endif
#ifdef ENABLE_M7 #endif
#ifdef COOLANT_MIST_PIN
#ifdef INVERT_COOLANT_MIST_PIN #ifdef INVERT_COOLANT_MIST_PIN
digitalWrite(COOLANT_MIST_PIN, 1); digitalWrite(COOLANT_MIST_PIN, 1);
#else #else
@@ -94,6 +105,7 @@ void coolant_set_state(uint8_t mode)
} else { } else {
#ifdef COOLANT_FLOOD_PIN
if (mode & COOLANT_FLOOD_ENABLE) { if (mode & COOLANT_FLOOD_ENABLE) {
#ifdef INVERT_COOLANT_FLOOD_PIN #ifdef INVERT_COOLANT_FLOOD_PIN
digitalWrite(COOLANT_FLOOD_PIN, 0); digitalWrite(COOLANT_FLOOD_PIN, 0);
@@ -101,8 +113,9 @@ void coolant_set_state(uint8_t mode)
digitalWrite(COOLANT_FLOOD_PIN, 1); digitalWrite(COOLANT_FLOOD_PIN, 1);
#endif #endif
} }
#endif
#ifdef ENABLE_M7 #ifdef COOLANT_MIST_PIN
if (mode & COOLANT_MIST_ENABLE) { if (mode & COOLANT_MIST_ENABLE) {
#ifdef INVERT_COOLANT_MIST_PIN #ifdef INVERT_COOLANT_MIST_PIN
digitalWrite(COOLANT_MIST_PIN, 0); digitalWrite(COOLANT_MIST_PIN, 0);

View File

@@ -34,34 +34,43 @@
changed. They are just preserved right now to make it easy to stay in sync changed. They are just preserved right now to make it easy to stay in sync
with AVR grbl with AVR grbl
*/ */
// This is the CPU Map for the ESP32 CNC Controller R2 // This is the CPU Map for the ESP32 CNC Controller R2
// It is OK to comment out any step and direction pins. This
// won't affect operation except that there will be no output
// form the pins. Grbl will virtually move the axis. This could
// be handy if you are using a servo, etc. for another axis.
#define X_STEP_PIN GPIO_NUM_12 #define X_STEP_PIN GPIO_NUM_12
#define Y_STEP_PIN GPIO_NUM_14 #define Y_STEP_PIN GPIO_NUM_14
#define Z_STEP_PIN GPIO_NUM_27 #define Z_STEP_PIN GPIO_NUM_27
#define STEP_MASK B111 // don't change #define STEP_MASK B111 // don't change
#define X_STEP_BIT 0 #define X_STEP_BIT 0 // don't change
#define Y_STEP_BIT 1 #define Y_STEP_BIT 1 // don't change
#define Z_STEP_BIT 2 #define Z_STEP_BIT 2 // don't change
#define X_DIRECTION_BIT 0 #define X_DIRECTION_BIT 0 // don't change
#define Y_DIRECTION_BIT 1 #define Y_DIRECTION_BIT 1 // don't change
#define Z_DIRECTION_BIT 2 #define Z_DIRECTION_BIT 2 // don't change
#define X_DIRECTION_PIN GPIO_NUM_26 #define X_DIRECTION_PIN GPIO_NUM_26
#define Y_DIRECTION_PIN GPIO_NUM_25 #define Y_DIRECTION_PIN GPIO_NUM_25
#define Z_DIRECTION_PIN GPIO_NUM_33 #define Z_DIRECTION_PIN GPIO_NUM_33
// OK to comment out to use pin for other features
#define STEPPERS_DISABLE_PIN GPIO_NUM_13 #define STEPPERS_DISABLE_PIN GPIO_NUM_13
#define COOLANT_FLOOD_PIN GPIO_NUM_16
#define COOLANT_MIST_PIN GPIO_NUM_19
// *** the flood coolant feature code is activated by defining this pins
// *** Comment it out to use the pin for other features
#define COOLANT_FLOOD_PIN GPIO_NUM_16
//#define COOLANT_MIST_PIN GPIO_NUM_21
// If SPINDLE_PWM_PIN is commented out, this frees up the pin, but Grbl will still
// use a virtual spindle. Do not comment out the other parameters for the spindle.
#define SPINDLE_PWM_PIN GPIO_NUM_17 #define SPINDLE_PWM_PIN GPIO_NUM_17
#define SPINDLE_PWM_CHANNEL 0 #define SPINDLE_PWM_CHANNEL 0
#define SPINDLE_PWM_BASE_FREQ 5000 // Hz #define SPINDLE_PWM_BASE_FREQ 5000 // Hz
@@ -70,9 +79,14 @@
#define SPINDLE_PWM_MAX_VALUE 255 // TODO ESP32 Calc from resolution #define SPINDLE_PWM_MAX_VALUE 255 // TODO ESP32 Calc from resolution
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE) #define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)
#define X_LIMIT_BIT 0 // if these spindle function pins are defined, they will be activated in the code
#define Y_LIMIT_BIT 1 // comment them out to use the pins for other functions
#define Z_LIMIT_BIT 2 //#define SPINDLE_ENABLE_PIN GPIO_NUM_16
//#define SPINDLE_DIR_PIN GPIO_NUM_16
#define X_LIMIT_BIT 0 // don't change
#define Y_LIMIT_BIT 1 // don't change
#define Z_LIMIT_BIT 2 // don't change
#define X_LIMIT_PIN GPIO_NUM_2 #define X_LIMIT_PIN GPIO_NUM_2
#define Y_LIMIT_PIN GPIO_NUM_4 #define Y_LIMIT_PIN GPIO_NUM_4

View File

@@ -48,7 +48,7 @@ void gc_init()
// Load default G54 coordinate system. // Load default G54 coordinate system.
if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) { if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) {
report_status_message(STATUS_SETTING_READ_FAIL); report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
} }
} }
@@ -66,7 +66,7 @@ void gc_sync_position()
// characters have been removed. In this function, all units and positions are converted and // characters have been removed. In this function, all units and positions are converted and
// exported to grbl's internal functions in terms of (mm, mm/min) and absolute machine // exported to grbl's internal functions in terms of (mm, mm/min) and absolute machine
// coordinates, respectively. // coordinates, respectively.
uint8_t gc_execute_line(char *line) uint8_t gc_execute_line(char *line, uint8_t client)
{ {
/* ------------------------------------------------------------------------------------- /* -------------------------------------------------------------------------------------
STEP 1: Initialize parser block struct and copy current g-code state modes. The parser STEP 1: Initialize parser block struct and copy current g-code state modes. The parser
@@ -255,34 +255,38 @@ uint8_t gc_execute_line(char *line)
default: gc_block.modal.program_flow = int_value; // Program end and reset default: gc_block.modal.program_flow = int_value; // Program end and reset
} }
break; break;
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
case 4: case 3: case 4: case 5:
#endif
case 3: case 5:
word_bit = MODAL_GROUP_M7; word_bit = MODAL_GROUP_M7;
switch(int_value) { switch(int_value) {
case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break; case 3:
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN gc_block.modal.spindle = SPINDLE_ENABLE_CW;
case 4: gc_block.modal.spindle = SPINDLE_ENABLE_CCW; break; break;
case 4:
#ifdef SPINDLE_DIR_PIN
gc_block.modal.spindle = SPINDLE_ENABLE_CCW;
#else
FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND);
#endif #endif
break;
case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break; case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break;
} }
break; break;
#ifdef ENABLE_M7
case 7: case 8: case 9: case 7: case 8: case 9:
#else
case 8: case 9:
#endif
word_bit = MODAL_GROUP_M8; word_bit = MODAL_GROUP_M8;
switch(int_value) { switch(int_value) {
#ifdef ENABLE_M7 #ifdef COOLANT_MIST_PIN
case 7: gc_block.modal.coolant = COOLANT_MIST_ENABLE; break; case 7: gc_block.modal.coolant = COOLANT_MIST_ENABLE; break;
#endif #endif
#ifdef COOLANT_FLOOD_PIN
case 8: gc_block.modal.coolant = COOLANT_FLOOD_ENABLE; break; case 8: gc_block.modal.coolant = COOLANT_FLOOD_ENABLE; break;
#endif
case 9: gc_block.modal.coolant = COOLANT_DISABLE; break; case 9: gc_block.modal.coolant = COOLANT_DISABLE; break;
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command]
} }
break; break;
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command] default:
FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command]
} }
// Check for more than one command per modal group violations in the current block // Check for more than one command per modal group violations in the current block

View File

@@ -238,7 +238,7 @@ typedef struct {
void gc_init(); void gc_init();
// Execute one block of rs275/ngc/g-code // Execute one block of rs275/ngc/g-code
uint8_t gc_execute_line(char *line); uint8_t gc_execute_line(char *line, uint8_t client);
// Set g-code parser position. Input in steps. // Set g-code parser position. Input in steps.
void gc_sync_position(); void gc_sync_position();

View File

@@ -20,7 +20,7 @@
// Grbl versioning system // Grbl versioning system
#define GRBL_VERSION "1.1f" #define GRBL_VERSION "1.1f"
#define GRBL_VERSION_BUILD "20180906" #define GRBL_VERSION_BUILD "20180910"
//#include <sdkconfig.h> //#include <sdkconfig.h>
#include <arduino.h> #include <arduino.h>

View File

@@ -1,11 +1,15 @@
#include "grbl.h" #include "grbl.h"
#ifdef ENABLE_BLUETOOTH
BluetoothSerial SerialBT; BluetoothSerial SerialBT;
void bluetooth_init(char *name) void bluetooth_init(char *name)
{ {
if (!SerialBT.begin(name)) if (!SerialBT.begin(name))
{ {
report_status_message(STATUS_BT_FAIL_BEGIN); report_status_message(STATUS_BT_FAIL_BEGIN, CLIENT_SERIAL);
} }
} }
#endif

View File

@@ -29,13 +29,13 @@
File myFile; File myFile;
char fileTypes[FILE_TYPE_COUNT][8] = {".NC", ".TXT", ".GCODE"}; // filter out files not of these types (s/b UPPERCASE) char fileTypes[FILE_TYPE_COUNT][8] = {".NC", ".TXT", ".GCODE"}; // filter out files not of these types (s/b UPPERCASE)
bool SD_file_running = false; // a file has started but not completed
bool SD_ready_next = false; // Grbl has processed a line and is waiting for another bool SD_ready_next = false; // Grbl has processed a line and is waiting for another
// attempt to mount the SD card // attempt to mount the SD card
bool sd_mount() { bool sd_mount() {
if(!SD.begin()){ if(!SD.begin()){
report_status_message(STATUS_SD_FAILED_MOUNT); report_status_message(STATUS_SD_FAILED_MOUNT, CLIENT_SERIAL);
return false; return false;
} }
return true; return true;
@@ -46,11 +46,11 @@ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
File root = fs.open(dirname); File root = fs.open(dirname);
if(!root){ if(!root){
report_status_message(STATUS_SD_FAILED_OPEN_DIR); report_status_message(STATUS_SD_FAILED_OPEN_DIR, CLIENT_SERIAL);
return; return;
} }
if(!root.isDirectory()){ if(!root.isDirectory()){
report_status_message(STATUS_SD_DIR_NOT_FOUND); report_status_message(STATUS_SD_DIR_NOT_FOUND, CLIENT_SERIAL);
return; return;
} }
@@ -72,7 +72,7 @@ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
for (uint8_t i=0; i < FILE_TYPE_COUNT; i++) // make sure it is a valid file type for (uint8_t i=0; i < FILE_TYPE_COUNT; i++) // make sure it is a valid file type
{ {
if (strstr(temp_filename, fileTypes[i])) { if (strstr(temp_filename, fileTypes[i])) {
grbl_sendf("[FILE:%s,SIZE:%d]\r\n", file.name(), file.size()); grbl_sendf(CLIENT_ALL, "[FILE:%s,SIZE:%d]\r\n", file.name(), file.size());
break; break;
} }
} }
@@ -83,12 +83,13 @@ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
boolean openFile(fs::FS &fs, const char * path){ boolean openFile(fs::FS &fs, const char * path){
myFile = fs.open(path); myFile = fs.open(path);
if(!myFile){ if(!myFile){
report_status_message(STATUS_SD_FAILED_READ); report_status_message(STATUS_SD_FAILED_READ, CLIENT_SERIAL);
return false; return false;
} }
SD_file_running = true; set_sd_state(SDCARD_BUSY_PRINTING);
SD_ready_next = false; // this will get set to true when Grbl issues "ok" message SD_ready_next = false; // this will get set to true when Grbl issues "ok" message
return true; return true;
} }
@@ -98,7 +99,7 @@ boolean closeFile(){
return false; return false;
} }
SD_file_running = false; set_sd_state(SDCARD_IDLE);
SD_ready_next = false; SD_ready_next = false;
myFile.close(); myFile.close();
return true; return true;
@@ -117,7 +118,7 @@ boolean readFileLine(char *line) {
uint8_t line_flags = 0; uint8_t line_flags = 0;
if (!myFile) { if (!myFile) {
report_status_message(STATUS_SD_FAILED_READ); report_status_message(STATUS_SD_FAILED_READ, CLIENT_SERIAL);
return false; return false;
} }
@@ -156,7 +157,7 @@ boolean readFileLine(char *line) {
if (index == 255) // name is too long so return false if (index == 255) // name is too long so return false
{ {
line[index] = '\0'; line[index] = '\0';
report_status_message(STATUS_OVERFLOW); report_status_message(STATUS_OVERFLOW, CLIENT_SERIAL);
return false; return false;
} }
} }
@@ -177,18 +178,47 @@ float sd_report_perc_complete() {
return ((float)myFile.position() / (float)myFile.size() * 100.0); return ((float)myFile.position() / (float)myFile.size() * 100.0);
} }
/*
void readFile(fs::FS &fs, const char * path){
File file = fs.open(path); uint8_t sd_state = SDCARD_IDLE;
if(!file){
report_status_message(STATUS_SD_FAILED_READ);
return;
}
while(file.available()){ uint8_t get_sd_state(bool refresh){
Serial.write(file.read()); #if defined(SDCARD_DET_PIN) && SDCARD_SD_PIN != -1
//no need to go further if SD detect is not correct
if (!((digitalRead (SDCARD_DET_PIN) == SDCARD_DET_VAL) ? true : false)){
sd_state = SDCARD_NOT_PRESENT;
return sd_state;
} }
file.close(); #endif
//if busy doing something return state
if (!((sd_state == SDCARD_NOT_PRESENT) || (sd_state == SDCARD_IDLE))) return sd_state;
if (!refresh) return sd_state; //to avoid refresh=true + busy to reset SD and waste time
//SD is idle or not detected, let see if still the case
if (sd_state == SDCARD_IDLE) {
SD.end();
//using default value for speed ? should be parameter
//refresh content if card was removed
if (!SD.begin()) sd_state = SDCARD_NOT_PRESENT;
else {
if ( !(SD.cardSize() > 0 )) sd_state = SDCARD_NOT_PRESENT;
}
}
return sd_state;
} }
*/
uint8_t set_sd_state(uint8_t flag){
sd_state = flag;
return sd_state;
}
void sd_get_current_filename(char* name) {
if (myFile != NULL)
{
strcpy(name, myFile.name());
}
else
name[0] = 0;
}

View File

@@ -24,10 +24,22 @@
#define FILE_TYPE_COUNT 3 // number of acceptable gcode file types in array #define FILE_TYPE_COUNT 3 // number of acceptable gcode file types in array
extern bool SD_file_running; // a file has started but not completed #define SDCARD_DET_PIN -1
#define SDCARD_DET_VAL 0
#define SDCARD_IDLE 0
#define SDCARD_NOT_PRESENT 1
#define SDCARD_BUSY_PRINTING 2
#define SDCARD_BUSY_UPLOADING 4
#define SDCARD_BUSY_PARSING 8
extern bool SD_ready_next; // Grbl has processed a line and is waiting for another extern bool SD_ready_next; // Grbl has processed a line and is waiting for another
bool sd_mount(); bool sd_mount();
uint8_t get_sd_state(bool refresh);
uint8_t set_sd_state(uint8_t flag);
void listDir(fs::FS &fs, const char * dirname, uint8_t levels); void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
boolean openFile(fs::FS &fs, const char * path); boolean openFile(fs::FS &fs, const char * path);
boolean closeFile(); boolean closeFile();
@@ -35,4 +47,6 @@ boolean readFileLine(char *line);
void readFile(fs::FS &fs, const char * path); void readFile(fs::FS &fs, const char * path);
float sd_report_perc_complete(); float sd_report_perc_complete();
void sd_get_current_filename(char* name);
#endif #endif

View File

@@ -318,7 +318,7 @@ uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_
#ifdef MESSAGE_PROBE_COORDINATES #ifdef MESSAGE_PROBE_COORDINATES
// All done! Output the probe position as message. // All done! Output the probe position as message.
report_probe_parameters(); report_probe_parameters(CLIENT_ALL);
#endif #endif
if (sys.probe_succeeded) { return(GC_PROBE_FOUND); } // Successful probe cycle. if (sys.probe_succeeded) { return(GC_PROBE_FOUND); } // Successful probe cycle.

View File

@@ -23,6 +23,7 @@
*/ */
#include "grbl.h" #include "grbl.h"
#include "config.h"
// Define line flags. Includes comment type tracking and line overflow detection. // Define line flags. Includes comment type tracking and line overflow detection.
#define LINE_FLAG_OVERFLOW bit(0) #define LINE_FLAG_OVERFLOW bit(0)
@@ -40,6 +41,8 @@ static void protocol_exec_rt_suspend();
*/ */
void protocol_main_loop() void protocol_main_loop()
{ {
//uint8_t client = CLIENT_SERIAL; // default client
// Perform some machine checks to make sure everything is good to go. // Perform some machine checks to make sure everything is good to go.
#ifdef CHECK_LIMITS_AT_INIT #ifdef CHECK_LIMITS_AT_INIT
if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) { if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
@@ -74,14 +77,17 @@ void protocol_main_loop()
uint8_t line_flags = 0; uint8_t line_flags = 0;
uint8_t char_counter = 0; uint8_t char_counter = 0;
uint8_t c; uint8_t c;
for (;;) { for (;;) {
// serialCheck(); // un comment this if you do this here rather than in a separate task
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
if (SD_ready_next) { if (SD_ready_next) {
char fileLine[255]; char fileLine[255];
if (readFileLine(fileLine)) { if (readFileLine(fileLine)) {
SD_ready_next = false; SD_ready_next = false;
report_status_message(gc_execute_line(fileLine)); report_status_message(gc_execute_line(fileLine, CLIENT_SERIAL), CLIENT_SERIAL);
} }
else { else {
closeFile(); // close file and clear SD ready/running flags closeFile(); // close file and clear SD ready/running flags
@@ -93,7 +99,11 @@ void protocol_main_loop()
// Process one line of incoming serial data, as the data becomes available. Performs an // 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. // initial filtering by removing spaces and comments and capitalizing all letters.
while((c = serial_read()) != SERIAL_NO_DATA) {
uint8_t client = CLIENT_SERIAL;
for (client = 1; client <= CLIENT_COUNT; client++)
{
while((c = serial_read(client)) != SERIAL_NO_DATA) {
if ((c == '\n') || (c == '\r')) { // End of line reached if ((c == '\n') || (c == '\r')) { // End of line reached
protocol_execute_realtime(); // Runtime command check point. protocol_execute_realtime(); // Runtime command check point.
@@ -101,25 +111,25 @@ void protocol_main_loop()
line[char_counter] = 0; // Set string termination character. line[char_counter] = 0; // Set string termination character.
#ifdef REPORT_ECHO_LINE_RECEIVED #ifdef REPORT_ECHO_LINE_RECEIVED
report_echo_line_received(line); report_echo_line_received(line, client);
#endif #endif
// Direct and execute one line of formatted input, and report status of execution. // Direct and execute one line of formatted input, and report status of execution.
if (line_flags & LINE_FLAG_OVERFLOW) { if (line_flags & LINE_FLAG_OVERFLOW) {
// Report line overflow error. // Report line overflow error.
report_status_message(STATUS_OVERFLOW); report_status_message(STATUS_OVERFLOW, client);
} else if (line[0] == 0) { } else if (line[0] == 0) {
// Empty or comment line. For syncing purposes. // Empty or comment line. For syncing purposes.
report_status_message(STATUS_OK); report_status_message(STATUS_OK, client);
} else if (line[0] == '$') { } else if (line[0] == '$') {
// Grbl '$' system command // Grbl '$' system command
report_status_message(system_execute_line(line)); report_status_message(system_execute_line(line, client), client);
} else if (sys.state & (STATE_ALARM | STATE_JOG)) { } else if (sys.state & (STATE_ALARM | STATE_JOG)) {
// Everything else is gcode. Block if in alarm or jog mode. // Everything else is gcode. Block if in alarm or jog mode.
report_status_message(STATUS_SYSTEM_GC_LOCK); report_status_message(STATUS_SYSTEM_GC_LOCK, client);
} else { } else {
// Parse and execute g-code block. // Parse and execute g-code block.
report_status_message(gc_execute_line(line)); report_status_message(gc_execute_line(line, client), client);
} }
// Reset tracking data for next line. // Reset tracking data for next line.
@@ -171,7 +181,10 @@ void protocol_main_loop()
} }
} }
} } // while serial read
} // for clients
// If there are no more characters in the serial read buffer to be processed and executed, // 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 // this indicates that g-code streaming has either filled the planner buffer or has
@@ -189,7 +202,9 @@ void protocol_main_loop()
set_stepper_disable(true); set_stepper_disable(true);
} }
} }
#ifdef ENABLE_WIFI
wifi_config.handle();
#endif
} }
return; /* Never reached */ return; /* Never reached */
@@ -280,7 +295,7 @@ void protocol_exec_rt_system()
// Execute and serial print status // Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) { if (rt_exec & EXEC_STATUS_REPORT) {
report_realtime_status(); report_realtime_status(CLIENT_ALL);
system_clear_exec_state_flag(EXEC_STATUS_REPORT); system_clear_exec_state_flag(EXEC_STATUS_REPORT);
} }
@@ -496,19 +511,28 @@ void protocol_exec_rt_system()
if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) { if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) { if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) {
uint8_t coolant_state = gc_state.modal.coolant; uint8_t coolant_state = gc_state.modal.coolant;
#ifdef ENABLE_M7 #ifdef COOLANT_FLOOD_PIN
if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) { if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE)
if (coolant_state & COOLANT_MIST_ENABLE) { bit_false(coolant_state,COOLANT_MIST_ENABLE); } {
else { coolant_state |= COOLANT_MIST_ENABLE; } if (coolant_state & COOLANT_FLOOD_ENABLE) {
bit_false(coolant_state,COOLANT_FLOOD_ENABLE);
}
else {
coolant_state |= COOLANT_FLOOD_ENABLE;
} }
if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE) {
if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
else { coolant_state |= COOLANT_FLOOD_ENABLE; }
} }
#else
if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
else { coolant_state |= COOLANT_FLOOD_ENABLE; }
#endif #endif
#ifdef COOLANT_MIST_PIN
if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
if (coolant_state & COOLANT_MIST_ENABLE) {
bit_false(coolant_state,COOLANT_MIST_ENABLE);
}
else {
coolant_state |= COOLANT_MIST_ENABLE;
}
}
#endif
coolant_set_state(coolant_state); // Report counter set in coolant_set_state(). coolant_set_state(coolant_state); // Report counter set in coolant_set_state().
gc_state.modal.coolant = coolant_state; gc_state.modal.coolant = coolant_state;
} }

View File

@@ -4,7 +4,7 @@
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
2018 - Bart Dring This file was modifed for use on the ESP32 2018 - Bart Dring This file was modified for use on the ESP32
CPU. Do not use this with Grbl for atMega328P CPU. Do not use this with Grbl for atMega328P
Grbl is free software: you can redistribute it and/or modify Grbl is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@
as the protocol status messages, feedback messages, and status reports, are stored here. 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 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 different style feedback is desired (i.e. JSON), then a user can change these following
methods to accomodate their needs. methods to accommodate their needs.
ESP32 Notes: ESP32 Notes:
@@ -50,21 +50,28 @@
// this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc) // this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc)
void grbl_send(char *text) void grbl_send(uint8_t client, char *text)
{ {
#ifdef ENABLE_BLUETOOTH #ifdef ENABLE_BLUETOOTH
if (SerialBT.hasClient()) if (SerialBT.hasClient() && ( client == CLIENT_BT || client == CLIENT_ALL ) )
{ {
SerialBT.print(text); SerialBT.print(text);
//delay(10); // possible fix for dropped characters //delay(10); // possible fix for dropped characters
} }
#endif #endif
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
if ( client == CLIENT_WEBUI || client == CLIENT_ALL )
Serial2Socket.write((const uint8_t*)text, strlen(text));
#endif
if ( client == CLIENT_SERIAL || client == CLIENT_ALL )
Serial.print(text); Serial.print(text);
} }
// This is a formating version of the grbl_send(...) function that work like printf // This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
void grbl_sendf(const char *format, ...) void grbl_sendf(uint8_t client, const char *format, ...)
{ {
char loc_buf[64]; char loc_buf[64];
char * temp = loc_buf; char * temp = loc_buf;
@@ -81,7 +88,7 @@ void grbl_sendf(const char *format, ...)
} }
} }
len = vsnprintf(temp, len+1, format, arg); len = vsnprintf(temp, len+1, format, arg);
grbl_send(temp); grbl_send(client, temp);
va_end(arg); va_end(arg);
if(len > 64){ if(len > 64){
delete[] temp; delete[] temp;
@@ -128,21 +135,21 @@ void get_state(char *foo)
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously // 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 // from a critical error, such as a triggered hard limit. Interface should always monitor for these
// responses. // responses.
void report_status_message(uint8_t status_code) void report_status_message(uint8_t status_code, uint8_t client)
{ {
switch(status_code) { switch(status_code) {
case STATUS_OK: // STATUS_OK case STATUS_OK: // STATUS_OK
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
if (SD_file_running) if (get_sd_state(false) == SDCARD_BUSY_PRINTING)
SD_ready_next = true; // flag so system_execute_line() will send the next line SD_ready_next = true; // flag so system_execute_line() will send the next line
else else
grbl_send("ok\r\n"); grbl_send(client,"ok\r\n");
#else #else
grbl_send("ok\r\n"); grbl_send(client,"ok\r\n");
#endif #endif
break; break;
default: default:
grbl_sendf("error:%d\r\n", status_code); grbl_sendf(client, "error:%d\r\n", status_code);
} }
} }
@@ -151,7 +158,7 @@ void report_status_message(uint8_t status_code)
// Prints alarm messages. // Prints alarm messages.
void report_alarm_message(uint8_t alarm_code) void report_alarm_message(uint8_t alarm_code)
{ {
grbl_sendf("ALARM:%d\r\n", alarm_code); grbl_sendf(CLIENT_ALL, "ALARM:%d\r\n", alarm_code); // OK to send to all clients
delay_ms(500); // Force delay to ensure message clears serial write buffer. delay_ms(500); // Force delay to ensure message clears serial write buffer.
} }
@@ -160,56 +167,50 @@ void report_alarm_message(uint8_t alarm_code)
// messages such as setup warnings, switch toggling, and how to exit alarms. // messages such as setup warnings, switch toggling, and how to exit alarms.
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode // NOTE: For interfaces, messages are always placed within brackets. And if silent mode
// is installed, the message number codes are less than zero. // is installed, the message number codes are less than zero.
void report_feedback_message(uint8_t message_code) void report_feedback_message(uint8_t message_code) // OK to send to all clients
{ {
switch(message_code) { switch(message_code) {
case MESSAGE_CRITICAL_EVENT: case MESSAGE_CRITICAL_EVENT:
grbl_sendf("[MSG:%s]\r\n", "Reset to continue"); break; grbl_send(CLIENT_ALL,"[MSG:Reset to continue]\r\n"); break;
case MESSAGE_ALARM_LOCK: case MESSAGE_ALARM_LOCK:
grbl_sendf("[MSG:%s]\r\n", "'$H'|'$X' to unlock"); break; grbl_send(CLIENT_ALL, "[MSG:'$H'|'$X' to unlock]\r\n"); break;
case MESSAGE_ALARM_UNLOCK: case MESSAGE_ALARM_UNLOCK:
grbl_sendf("[MSG:%s]\r\n", "Caution: Unlocked"); break; grbl_send(CLIENT_ALL, "[MSG:Caution: Unlocked]\r\n"); break;
case MESSAGE_ENABLED: case MESSAGE_ENABLED:
grbl_sendf("[MSG:%s]\r\n", "Enabled"); break; grbl_send(CLIENT_ALL, "[MSG:Enabled]\r\n"); break;
case MESSAGE_DISABLED: case MESSAGE_DISABLED:
grbl_sendf("[MSG:%s]\r\n", "Disabled"); break; grbl_send(CLIENT_ALL, "[MSG:Disabled]\r\n"); break;
case MESSAGE_SAFETY_DOOR_AJAR: case MESSAGE_SAFETY_DOOR_AJAR:
grbl_sendf("[MSG:%s]\r\n", "Check Door"); break; grbl_send(CLIENT_ALL, "[MSG:Check Door]\r\n"); break;
case MESSAGE_CHECK_LIMITS: case MESSAGE_CHECK_LIMITS:
grbl_sendf("[MSG:%s]\r\n", "Check Limits"); break; grbl_send(CLIENT_ALL, "[MSG:Check Limits]\r\n"); break;
case MESSAGE_PROGRAM_END: case MESSAGE_PROGRAM_END:
grbl_sendf("[MSG:%s]\r\n", "Pgm End"); break; grbl_send(CLIENT_ALL, "[MSG:Pgm End]\r\n"); break;
case MESSAGE_RESTORE_DEFAULTS: case MESSAGE_RESTORE_DEFAULTS:
grbl_sendf("[MSG:%s]\r\n", "Restoring defaults"); break; grbl_send(CLIENT_ALL, "[MSG:Restoring defaults]\r\n"); break;
case MESSAGE_SPINDLE_RESTORE: case MESSAGE_SPINDLE_RESTORE:
grbl_sendf("[MSG:%s]\r\n", "Restoring spindle"); break; grbl_send(CLIENT_ALL, "[MSG:Restoring spindle]\r\n"); break;
case MESSAGE_SLEEP_MODE: case MESSAGE_SLEEP_MODE:
grbl_sendf("[MSG:%s]\r\n", "Sleeping"); break; grbl_send(CLIENT_ALL, "[MSG:Sleeping]\r\n"); break;
} }
} }
// Welcome message // Welcome message
void report_init_message() void report_init_message(uint8_t client)
{ {
grbl_send("\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n"); grbl_send(client,"\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n");
} }
// Grbl help message // Grbl help message
void report_grbl_help() { void report_grbl_help(uint8_t client) {
grbl_send("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H $F ~ ! ? ctrl-x]\r\n"); grbl_send(client,"[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H $F ~ ! ? ctrl-x]\r\n");
#ifdef VERBOSE_HELP
#ifdef ENABLE_BLUETOOTH
return; // to much data for BT until fixed
#endif
settings_help();
#endif
} }
// Grbl global settings print out. // Grbl global settings print out.
// NOTE: The numbering scheme here must correlate to storing in settings.c // NOTE: The numbering scheme here must correlate to storing in settings.c
void report_grbl_settings() { void report_grbl_settings(uint8_t client) {
// Print Grbl settings. // Print Grbl settings.
char setting[20]; char setting[20];
char rpt[800]; char rpt[800];
@@ -264,7 +265,7 @@ void report_grbl_settings() {
val += AXIS_SETTINGS_INCREMENT; val += AXIS_SETTINGS_INCREMENT;
} }
grbl_send(rpt); grbl_send(client,rpt);
} }
@@ -275,7 +276,7 @@ void report_grbl_settings() {
// Prints current probe parameters. Upon a probe command, these parameters are updated upon a // Prints current probe parameters. Upon a probe command, these parameters are updated upon a
// successful probe or upon a failed probe with the G38.3 without errors command (if supported). // successful probe or upon a failed probe with the G38.3 without errors command (if supported).
// These values are retained until Grbl is power-cycled, whereby they will be re-zeroed. // These values are retained until Grbl is power-cycled, whereby they will be re-zeroed.
void report_probe_parameters() void report_probe_parameters(uint8_t client)
{ {
// Report in terms of machine position. // Report in terms of machine position.
float print_position[N_AXIS]; float print_position[N_AXIS];
@@ -293,14 +294,14 @@ void report_probe_parameters()
sprintf(temp, ":%d]\r\n", sys.probe_succeeded); sprintf(temp, ":%d]\r\n", sys.probe_succeeded);
strcat(probe_rpt, temp); strcat(probe_rpt, temp);
grbl_send(probe_rpt); // send the report grbl_send(client, probe_rpt); // send the report
} }
// Prints Grbl NGC parameters (coordinate offsets, probing) // Prints Grbl NGC parameters (coordinate offsets, probing)
void report_ngc_parameters() void report_ngc_parameters(uint8_t client)
{ {
float coord_data[N_AXIS]; float coord_data[N_AXIS];
uint8_t coord_select; uint8_t coord_select;
@@ -311,7 +312,7 @@ void report_ngc_parameters()
for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) { for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
if (!(settings_read_coord_data(coord_select,coord_data))) { if (!(settings_read_coord_data(coord_select,coord_data))) {
report_status_message(STATUS_SETTING_READ_FAIL); report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
return; return;
} }
strcat(ngc_rpt, "[G"); strcat(ngc_rpt, "[G");
@@ -342,15 +343,15 @@ void report_ngc_parameters()
} }
strcat(ngc_rpt, temp); strcat(ngc_rpt, temp);
grbl_send(ngc_rpt); grbl_send(client, ngc_rpt);
report_probe_parameters(); // TDO ======================= Print probe parameters. Not persistent in memory. report_probe_parameters(client);
} }
// Print current gcode parser mode state // Print current gcode parser mode state
void report_gcode_modes() void report_gcode_modes(uint8_t client)
{ {
char temp[20]; char temp[20];
char modes_rpt[75]; char modes_rpt[75];
@@ -402,16 +403,14 @@ void report_gcode_modes()
case SPINDLE_DISABLE : strcat(modes_rpt, " M5"); break; case SPINDLE_DISABLE : strcat(modes_rpt, " M5"); break;
} }
//report_util_gcode_modes_M(); //report_util_gcode_modes_M(); // optional M7 and M8 should have been dealt with by here
#ifdef ENABLE_M7
if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time. if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time.
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { strcat(modes_rpt, " M7"); } if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { strcat(modes_rpt, " M7"); }
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { strcat(modes_rpt, " M8"); } if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { strcat(modes_rpt, " M8"); }
} else { strcat(modes_rpt, " M9"); } }
#else else {
if (gc_state.modal.coolant) { strcat(modes_rpt, " M8"); } strcat(modes_rpt, " M9");
else { strcat(modes_rpt, " M9"); } }
#endif
sprintf(temp, " T%d", gc_state.tool); sprintf(temp, " T%d", gc_state.tool);
strcat(modes_rpt, temp); strcat(modes_rpt, temp);
@@ -426,28 +425,25 @@ void report_gcode_modes()
strcat(modes_rpt, "]\r\n"); strcat(modes_rpt, "]\r\n");
grbl_send(modes_rpt); grbl_send(client, modes_rpt);
} }
// Prints specified startup line // Prints specified startup line
void report_startup_line(uint8_t n, char *line) void report_startup_line(uint8_t n, char *line, uint8_t client)
{ {
grbl_sendf("$N%d=%s\r\n", n, line); grbl_sendf(client, "$N%d=%s\r\n", n, line); // OK to send to all
} }
void report_execute_startup_message(char *line, uint8_t status_code) void report_execute_startup_message(char *line, uint8_t status_code, uint8_t client)
{ {
char temp[80]; grbl_sendf(client, ">%s:", line); // OK to send to all
report_status_message(status_code, client);
grbl_sendf(">%s:", line);
report_status_message(status_code); // TODO reduce number of back to back BT sends
} }
// Prints build info line // Prints build info line
void report_build_info(char *line) void report_build_info(char *line, uint8_t client)
{ {
char build_info[50]; char build_info[50];
@@ -461,8 +457,8 @@ void report_build_info(char *line)
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
strcat(build_info,"N"); strcat(build_info,"N");
#endif #endif
#ifdef ENABLE_M7 #ifdef COOLANT_MIST_PIN
strcat(build_info,"M"); strcat(build_info,"M"); // TODO Need to deal with M8...it could be disabled
#endif #endif
#ifdef COREXY #ifdef COREXY
strcat(build_info,"C"); strcat(build_info,"C");
@@ -510,7 +506,7 @@ void report_build_info(char *line)
// These will likely have a comma delimiter to separate them. // These will likely have a comma delimiter to separate them.
strcat(build_info,"]\r\n"); strcat(build_info,"]\r\n");
grbl_send(build_info); grbl_send(client, build_info); // ok to send to all
} }
@@ -518,23 +514,17 @@ void report_build_info(char *line)
// Prints the character string line Grbl has received from the user, which has been pre-parsed, // Prints the character string line Grbl has received from the user, which has been pre-parsed,
// and has been sent into protocol_execute_line() routine to be executed by Grbl. // and has been sent into protocol_execute_line() routine to be executed by Grbl.
void report_echo_line_received(char *line) void report_echo_line_received(char *line, uint8_t client)
{ {
char temp[80]; grbl_sendf(client, "[echo: %s]\r\n", line);
sprintf(temp, "[echo: %s]\r\n", line);
} }
//--------------------------------------------- Converted up to here ---------------------------------------------------------------------
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
// and the actual location of the CNC machine. Users may change the following function to their // and the actual location of the CNC machine. Users may change the following function to their
// specific needs, but the desired real-time data report must be as short as possible. This is // specific needs, but the desired real-time data report must be as short as possible. This is
// requires as it minimizes the computational overhead and allows grbl to keep running smoothly, // requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz). // especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status() void report_realtime_status(uint8_t client)
{ {
uint8_t idx; uint8_t idx;
int32_t current_position[N_AXIS]; // Copy current state of the system position variable int32_t current_position[N_AXIS]; // Copy current state of the system position variable
@@ -607,7 +597,7 @@ void report_realtime_status()
// Returns planner and serial read buffer states. // Returns planner and serial read buffer states.
#ifdef REPORT_FIELD_BUFFER_STATE #ifdef REPORT_FIELD_BUFFER_STATE
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) { if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) {
sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), serial_get_rx_buffer_available()); sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), serial_get_rx_buffer_available(CLIENT_SERIAL));
strcat(status, temp); strcat(status, temp);
} }
#endif #endif
@@ -711,7 +701,7 @@ void report_realtime_status()
#endif #endif
} }
if (cl_state & COOLANT_STATE_FLOOD) { strcat(status, "F"); } if (cl_state & COOLANT_STATE_FLOOD) { strcat(status, "F"); }
#ifdef ENABLE_M7 #ifdef COOLANT_MIST_PIN // TODO Deal with M8 - Flood
if (cl_state & COOLANT_STATE_MIST) { strcat(status, "M"); } if (cl_state & COOLANT_STATE_MIST) { strcat(status, "M"); }
#endif #endif
} }
@@ -719,61 +709,24 @@ void report_realtime_status()
#endif #endif
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
if (SD_file_running) { if (get_sd_state(false) == SDCARD_BUSY_PRINTING) {
sprintf(temp, "|SD:%4.2f", sd_report_perc_complete()); sprintf(temp, "|SD:%4.2f,", sd_report_perc_complete());
strcat(status, temp);
sd_get_current_filename(temp);
strcat(status, temp); strcat(status, temp);
} }
#endif #endif
strcat(status, ">\r\n"); strcat(status, ">\r\n");
grbl_send(status); grbl_send(client, status);
} }
void report_realtime_steps() void report_realtime_steps()
{ {
uint8_t idx; uint8_t idx;
for (idx=0; idx< N_AXIS; idx++) { for (idx=0; idx< N_AXIS; idx++) {
Serial.println(sys_position[idx]); grbl_sendf(CLIENT_ALL, "%ld\n", sys_position[idx]); // OK to send to all ... debug stuff
} }
} }
void settings_help()
{
Serial.println("[HLP ----------- Setting Descriptions -----------]");
Serial.println("[HLP $0=Step Pulse Delay (3-255)]");
Serial.println("[HLP $1=Step Idle Delay (0-254, 255 keeps motors on)]");
Serial.println("[HLP $2=Step Pulse Invert Mask(00000ZYZ)]");
Serial.println("[HLP $3=Direction Invert Mask(00000XYZ)]");
Serial.println("[HLP $4=Step Enable Invert (boolean)]");
Serial.println("[HLP $6=Invert Probe Pin (boolean)]");
Serial.println("[HLP $10Status Report Options (See Wiki)]");
Serial.println("[HLP $11=Junction Deviation (float millimeters)]");
Serial.println("[HLP $12=Arc Tolerance (float millimeters)]");
Serial.println("[HLP $13=Report in Inches (boolean)]");
Serial.println("[HLP $20=Soft Limits Enable (boolean)]");
Serial.println("[HLP $21=Hard Limits Enable (boolean)]");
Serial.println("[HLP $22=Homing Enable (boolean)]");
Serial.println("[HLP $23=Homing Direction Invert (00000ZYX)]");
Serial.println("[HLP $24=Homing Feed Rate (mm/min)]");
Serial.println("[HLP $25=Homing Seek Rate (mm/min)]");
Serial.println("[HLP $26=Homing Switch Debounce Delay (milliseconds)]");
Serial.println("[HLP $27=Homing Switch Pull-off Distance (millimeters)]");
Serial.println("[HLP $30=Max Spindle Speed (RPM)]");
Serial.println("[HLP $31=Min Spindle Speed (RPM)]");
Serial.println("[HLP $32=Laser Mode Enable (boolean)]");
Serial.println("[HLP $100-102= XYZ Axis Resolution (step/mm)]");
Serial.println("[HLP $110-112= XYZ Axis Max Rate (mm/min)]");
Serial.println("[HLP $120-122= XYZ Axis Acceleration (step/mm^2)]");
Serial.println("[HLP $130-132= XYZ Axis max Travel (step/mm)]");
}
#ifdef DEBUG
void report_realtime_debug()
{
}
#endif

View File

@@ -97,12 +97,18 @@
#define MESSAGE_SPINDLE_RESTORE 10 #define MESSAGE_SPINDLE_RESTORE 10
#define MESSAGE_SLEEP_MODE 11 #define MESSAGE_SLEEP_MODE 11
#define CLIENT_SERIAL 1
#define CLIENT_BT 2
#define CLIENT_WEBUI 3
#define CLIENT_ALL 0xFF
#define CLIENT_COUNT 3 // total number of client types regardless if they are used
// functions to send data to the user. // functions to send data to the user.
void grbl_send(char *text); void grbl_send(uint8_t client, char *text);
void grbl_sendf(const char *format, ...); void grbl_sendf(uint8_t client, const char *format, ...);
// Prints system status messages. // Prints system status messages.
void report_status_message(uint8_t status_code); void report_status_message(uint8_t status_code, uint8_t client);
void report_realtime_steps(); void report_realtime_steps();
// Prints system alarm messages. // Prints system alarm messages.
@@ -112,40 +118,40 @@ void report_alarm_message(uint8_t alarm_code);
void report_feedback_message(uint8_t message_code); void report_feedback_message(uint8_t message_code);
// Prints welcome message // Prints welcome message
void report_init_message(); void report_init_message(uint8_t client);
// Prints Grbl help and current global settings // Prints Grbl help and current global settings
void report_grbl_help(); void report_grbl_help(uint8_t client);
// Prints Grbl global settings // Prints Grbl global settings
void report_grbl_settings(); void report_grbl_settings(uint8_t client);
// Prints an echo of the pre-parsed line received right before execution. // Prints an echo of the pre-parsed line received right before execution.
void report_echo_line_received(char *line); void report_echo_line_received(char *line, uint8_t client);
// Prints realtime status report // Prints realtime status report
void report_realtime_status(); void report_realtime_status(uint8_t client);
// Prints recorded probe position // Prints recorded probe position
void report_probe_parameters(); void report_probe_parameters(uint8_t client);
// Prints Grbl NGC parameters (coordinate offsets, probe) // Prints Grbl NGC parameters (coordinate offsets, probe)
void report_ngc_parameters(); void report_ngc_parameters(uint8_t client);
// Prints current g-code parser mode state // Prints current g-code parser mode state
void report_gcode_modes(); void report_gcode_modes(uint8_t client);
// Prints startup line when requested and executed. // Prints startup line when requested and executed.
void report_startup_line(uint8_t n, char *line); void report_startup_line(uint8_t n, char *line, uint8_t client);
void report_execute_startup_message(char *line, uint8_t status_code); void report_execute_startup_message(char *line, uint8_t status_code, uint8_t client);
// Prints build info and user info // Prints build info and user info
void report_build_info(char *line); void report_build_info(char *line, uint8_t client);
#ifdef DEBUG #ifdef DEBUG
void report_realtime_debug(); void report_realtime_debug();
#endif #endif
void settings_help();
#endif #endif

View File

@@ -25,17 +25,19 @@
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
uint8_t serial_rx_buffer[RX_RING_BUFFER]; uint8_t serial_rx_buffer[CLIENT_COUNT][RX_RING_BUFFER];
uint8_t serial_rx_buffer_head = 0; uint8_t serial_rx_buffer_head[CLIENT_COUNT] = {0};
volatile uint8_t serial_rx_buffer_tail = 0; volatile uint8_t serial_rx_buffer_tail[CLIENT_COUNT] = {0};
// Returns the number of bytes available in the RX serial buffer. // Returns the number of bytes available in the RX serial buffer.
uint8_t serial_get_rx_buffer_available() uint8_t serial_get_rx_buffer_available(uint8_t client)
{ {
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile uint8_t client_idx = client - 1;
if (serial_rx_buffer_head >= rtail) { return(RX_BUFFER_SIZE - (serial_rx_buffer_head-rtail)); }
return((rtail-serial_rx_buffer_head-1)); uint8_t rtail = serial_rx_buffer_tail[client_idx]; // Copy to limit multiple calls to volatile
if (serial_rx_buffer_head[client_idx] >= rtail) { return(RX_BUFFER_SIZE - (serial_rx_buffer_head[client_idx]-rtail)); }
return((rtail-serial_rx_buffer_head[client_idx]-1));
} }
void serial_init() void serial_init()
@@ -51,43 +53,66 @@ void serial_init()
&serialCheckTaskHandle, &serialCheckTaskHandle,
0 // core 0 // core
); );
} }
// this task runs and checks for data on all interfaces, currently // this task runs and checks for data on all interfaces
// only hardware serial port is checked // REaltime stuff is acted upon, then characters are added to the appropriate buffer
// This was normally done in an interrupt on 8-bit Grbl
void serialCheckTask(void *pvParameters) void serialCheckTask(void *pvParameters)
{ {
uint8_t data; uint8_t data;
uint8_t next_head; uint8_t next_head;
uint8_t client; // who send the data
uint8_t client_idx = 0; // index of data buffer
while(true) // run continuously while(true) // run continuously
{ {
while (Serial.available()
#ifdef ENABLE_BLUETOOTH #ifdef ENABLE_BLUETOOTH
while (Serial.available() || (SerialBT.hasClient() && SerialBT.available())) || (SerialBT.hasClient() && SerialBT.available())
#else
while (Serial.available())
#endif #endif
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|| Serial2Socket.available()
#endif
)
{ {
if (Serial.available()) if (Serial.available())
data = Serial.read();
else
{ {
client = CLIENT_SERIAL;
data = Serial.read();
}
else
{ //currently is wifi or BT but better to prepare both can be live
#ifdef ENABLE_BLUETOOTH #ifdef ENABLE_BLUETOOTH
if(SerialBT.hasClient() && SerialBT.available()){
client = CLIENT_BT;
data = SerialBT.read(); data = SerialBT.read();
Serial.write(data); // echo all data to serial //Serial.write(data); // echo all data to serial
} else {
#endif
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
client = CLIENT_WEBUI;
data = Serial2Socket.read();
#endif
#ifdef ENABLE_BLUETOOTH
}
#endif #endif
} }
client_idx = client - 1; // for zero based array
// Pick off realtime command characters directly from the serial stream. These characters are // Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the main buffer, but these set system state flag bits for realtime execution. // not passed into the main buffer, but these set system state flag bits for realtime execution.
switch (data) { switch (data) {
case CMD_RESET: mc_reset(); break; // Call motion control reset routine. case CMD_RESET:
case CMD_STATUS_REPORT: report_realtime_status(); break; // direct call instead of setting flag mc_reset(); // Call motion control reset routine.
//report_init_message(client); // fool senders into thinking a reset happened.
break;
case CMD_STATUS_REPORT:
report_realtime_status(client);
break; // direct call instead of setting flag
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
default : default :
@@ -116,8 +141,10 @@ void serialCheckTask(void *pvParameters)
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break; case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break; case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break;
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break; case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
#ifdef COOLANT_FLOOD_PIN
case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break; case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break;
#ifdef ENABLE_M7 #endif
#ifdef COOLANT_MIST_PIN
case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break; case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break;
#endif #endif
} }
@@ -125,28 +152,135 @@ void serialCheckTask(void *pvParameters)
} else { // Write character to buffer } else { // Write character to buffer
vTaskEnterCritical(&myMutex); vTaskEnterCritical(&myMutex);
next_head = serial_rx_buffer_head + 1; next_head = serial_rx_buffer_head[client_idx] + 1;
if (next_head == RX_RING_BUFFER) { next_head = 0; } if (next_head == RX_RING_BUFFER) { next_head = 0; }
// Write data to buffer unless it is full. // Write data to buffer unless it is full.
if (next_head != serial_rx_buffer_tail) { if (next_head != serial_rx_buffer_tail[client_idx]) {
serial_rx_buffer[serial_rx_buffer_head] = data; serial_rx_buffer[client_idx][serial_rx_buffer_head[client_idx]] = data;
serial_rx_buffer_head = next_head; serial_rx_buffer_head[client_idx] = next_head;
} }
vTaskExitCritical(&myMutex); vTaskExitCritical(&myMutex);
} }
} // switch data } // switch data
} // if something available } // if something available
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
} // while(true) } // while(true)
} }
void serial_reset_read_buffer() // ==================== call this in main protocol loop if you want it in the main task =========
// be sure to stop task.
// Realtime stuff is acted upon, then characters are added to the appropriate buffer
void serialCheck()
{ {
serial_rx_buffer_tail = serial_rx_buffer_head; uint8_t data;
uint8_t next_head;
uint8_t client; // who send the data
uint8_t client_idx = 0; // index of data buffer
while (Serial.available()
#ifdef ENABLE_BLUETOOTH
|| (SerialBT.hasClient() && SerialBT.available())
#endif
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|| Serial2Socket.available()
#endif
)
{
if (Serial.available())
{
client = CLIENT_SERIAL;
data = Serial.read();
}
else
{ //currently is wifi or BT but better to prepare both can be live
#ifdef ENABLE_BLUETOOTH
if(SerialBT.hasClient() && SerialBT.available()){
client = CLIENT_BT;
data = SerialBT.read();
} else {
#endif
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
client = CLIENT_WEBUI;
data = Serial2Socket.read();
#endif
#ifdef ENABLE_BLUETOOTH
}
#endif
}
client_idx = client - 1; // for zero based array
// Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the main buffer, but these set system state flag bits for realtime execution.
switch (data) {
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
case CMD_STATUS_REPORT:
report_realtime_status(client);
break; // direct call instead of setting flag
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
default :
if (data > 0x7F) { // Real-time control characters are extended ACSII only.
switch(data) {
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
case CMD_JOG_CANCEL:
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
}
break;
#ifdef DEBUG
case CMD_DEBUG_REPORT: {uint8_t sreg = SREG; cli(); bit_true(sys_rt_exec_debug,EXEC_DEBUG_REPORT); SREG = sreg;} break;
#endif
case CMD_FEED_OVR_RESET: system_set_exec_motion_override_flag(EXEC_FEED_OVR_RESET); break;
case CMD_FEED_OVR_COARSE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_PLUS); break;
case CMD_FEED_OVR_COARSE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_MINUS); break;
case CMD_FEED_OVR_FINE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_PLUS); break;
case CMD_FEED_OVR_FINE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_MINUS); break;
case CMD_RAPID_OVR_RESET: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_RESET); break;
case CMD_RAPID_OVR_MEDIUM: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_MEDIUM); break;
case CMD_RAPID_OVR_LOW: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_LOW); break;
case CMD_SPINDLE_OVR_RESET: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_RESET); break;
case CMD_SPINDLE_OVR_COARSE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_PLUS); break;
case CMD_SPINDLE_OVR_COARSE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_MINUS); break;
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break;
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
#ifdef COOLANT_FLOOD_PIN
case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break;
#endif
#ifdef COOLANT_MIST_PIN
case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break;
#endif
}
// Throw away any unfound extended-ASCII character by not passing it to the serial buffer.
} else { // Write character to buffer
next_head = serial_rx_buffer_head[client_idx] + 1;
if (next_head == RX_RING_BUFFER) { next_head = 0; }
// Write data to buffer unless it is full.
if (next_head != serial_rx_buffer_tail[client_idx]) {
serial_rx_buffer[client_idx][serial_rx_buffer_head[client_idx]] = data;
serial_rx_buffer_head[client_idx] = next_head;
}
}
} // switch data
} // if something available
}
void serial_reset_read_buffer(uint8_t client)
{
for (uint8_t client_num = 1; client_num <= CLIENT_COUNT; client_num++)
{
if (client == client_num || client == CLIENT_ALL)
{
serial_rx_buffer_tail[client_num-1] = serial_rx_buffer_head[client_num-1];
}
}
} }
// Writes one byte to the TX serial buffer. Called by main program. // Writes one byte to the TX serial buffer. Called by main program.
@@ -154,18 +288,20 @@ void serial_write(uint8_t data) {
Serial.write((char)data); Serial.write((char)data);
} }
// Fetches the first byte in the serial read buffer. Called by main program. // Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read() uint8_t serial_read(uint8_t client)
{ {
uint8_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile) uint8_t client_idx = client - 1;
if (serial_rx_buffer_head == tail) {
uint8_t tail = serial_rx_buffer_tail[client_idx]; // Temporary serial_rx_buffer_tail (to optimize for volatile)
if (serial_rx_buffer_head[client_idx] == tail) {
return SERIAL_NO_DATA; return SERIAL_NO_DATA;
} else { } else {
vTaskEnterCritical(&myMutex); // make sure buffer is not modified while reading by newly read chars from the serial when we are here vTaskEnterCritical(&myMutex); // make sure buffer is not modified while reading by newly read chars from the serial when we are here
uint8_t data = serial_rx_buffer[tail]; uint8_t data = serial_rx_buffer[client_idx][tail];
tail++; tail++;
if (tail == RX_RING_BUFFER) { tail = 0; } if (tail == RX_RING_BUFFER) { tail = 0; }
serial_rx_buffer_tail = tail; serial_rx_buffer_tail[client_idx] = tail;
vTaskExitCritical(&myMutex); vTaskExitCritical(&myMutex);
return data; return data;
} }

View File

@@ -40,17 +40,19 @@
static TaskHandle_t serialCheckTaskHandle = 0; static TaskHandle_t serialCheckTaskHandle = 0;
void serialCheckTask(void *pvParameters); void serialCheckTask(void *pvParameters);
void serialCheck();
void serial_write(uint8_t data); void serial_write(uint8_t data);
// Fetches the first byte in the serial read buffer. Called by main program. // Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read(); uint8_t serial_read(uint8_t client);
// See if the character is an action command like feedhold or jogging. If so, do the action and return true // See if the character is an action command like feedhold or jogging. If so, do the action and return true
uint8_t check_action_command(uint8_t data); uint8_t check_action_command(uint8_t data);
void serial_init(); void serial_init();
void serial_reset_read_buffer(); void serial_reset_read_buffer(uint8_t client);
// Returns the number of bytes available in the RX serial buffer. // Returns the number of bytes available in the RX serial buffer.
uint8_t serial_get_rx_buffer_available(); uint8_t serial_get_rx_buffer_available(uint8_t client);
#endif #endif

View File

@@ -41,9 +41,9 @@ void settings_init()
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
if(!read_global_settings()) { if(!read_global_settings()) {
report_status_message(STATUS_SETTING_READ_FAIL); report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data. settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
report_grbl_settings(); report_grbl_settings(CLIENT_SERIAL); // only the serial could be working at this point
} }
} }
@@ -332,8 +332,6 @@ uint8_t get_step_pin_mask(uint8_t axis_idx)
// Returns direction pin mask according to Grbl internal axis indexing. // Returns direction pin mask according to Grbl internal axis indexing.
uint8_t get_direction_pin_mask(uint8_t axis_idx) uint8_t get_direction_pin_mask(uint8_t axis_idx)
{ {
if ( axis_idx == X_AXIS ) { return((1<<X_DIRECTION_BIT)); } return(1<<axis_idx);
if ( axis_idx == Y_AXIS ) { return((1<<Y_DIRECTION_BIT)); }
return((1<<Z_DIRECTION_BIT));
} }

View File

@@ -3,7 +3,7 @@
Part of Grbl Part of Grbl
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
2018 - Bart Dring This file was modifed for use on the ESP32 2018 - Bart Dring This file was modified for use on the ESP32
CPU. Do not use this with Grbl for atMega328P CPU. Do not use this with Grbl for atMega328P
Grbl is free software: you can redistribute it and/or modify Grbl is free software: you can redistribute it and/or modify
@@ -23,30 +23,66 @@
void spindle_init() void spindle_init()
{ {
// Use DIR and Enable if pins are defined
#ifdef SPINDLE_ENABLE_PIN
pinMode(SPINDLE_ENABLE_PIN, OUTPUT);
#endif
#ifdef SPINDLE_DIR_PIN
pinMode(SPINDLE_DIR_PIN, OUTPUT);
#endif
#ifdef SPINDLE_PWM_PIN
// use the LED control feature to setup PWM https://esp-idf.readthedocs.io/en/v1.0/api/ledc.html // use the LED control feature to setup PWM https://esp-idf.readthedocs.io/en/v1.0/api/ledc.html
ledcSetup(SPINDLE_PWM_CHANNEL, SPINDLE_PWM_BASE_FREQ, SPINDLE_PWM_BIT_PRECISION); // setup the channel ledcSetup(SPINDLE_PWM_CHANNEL, SPINDLE_PWM_BASE_FREQ, SPINDLE_PWM_BIT_PRECISION); // setup the channel
ledcAttachPin(SPINDLE_PWM_PIN, SPINDLE_PWM_CHANNEL); // attach the PWM to the pin ledcAttachPin(SPINDLE_PWM_PIN, SPINDLE_PWM_CHANNEL); // attach the PWM to the pin
#endif
// Start with PWM off // Start with spindle off off
spindle_stop(); spindle_stop();
} }
void spindle_stop() void spindle_stop()
{ {
spindle_set_enable(false);
#ifdef SPINDLE_PWM_PIN
grbl_analogWrite(SPINDLE_PWM_CHANNEL, 0); grbl_analogWrite(SPINDLE_PWM_CHANNEL, 0);
#endif
} }
uint8_t spindle_get_state() uint8_t spindle_get_state() // returns SPINDLE_STATE_DISABLE, SPINDLE_STATE_CW or SPINDLE_STATE_CCW
{ {
// TODO Update this when direction and enable pin are added // TODO Update this when direction and enable pin are added
#ifndef SPINDLE_PWM_PIN
return(SPINDLE_STATE_DISABLE);
#endif
if (ledcRead(SPINDLE_PWM_CHANNEL) == 0) // Check the PWM value if (ledcRead(SPINDLE_PWM_CHANNEL) == 0) // Check the PWM value
return(SPINDLE_STATE_DISABLE); return(SPINDLE_STATE_DISABLE);
else else
return(SPINDLE_STATE_CW); // only CW is supported right now. {
#ifdef SPINDLE_DIR_PIN
if (digitalRead(SPINDLE_DIR_PIN))
return (SPINDLE_STATE_CW);
else
return(SPINDLE_STATE_CCW);
#else
return(SPINDLE_STATE_CW);
#endif
}
} }
void spindle_set_speed(uint8_t pwm_value) void spindle_set_speed(uint8_t pwm_value)
{ {
#ifndef SPINDLE_PWM_PIN
return;
#endif
#ifndef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
spindle_set_enable(true);
#else
spindle_set_enable(pwm_value != 0);
#endif
grbl_analogWrite(SPINDLE_PWM_CHANNEL, pwm_value); grbl_analogWrite(SPINDLE_PWM_CHANNEL, pwm_value);
} }
@@ -54,6 +90,9 @@ void spindle_set_speed(uint8_t pwm_value)
uint8_t spindle_compute_pwm_value(float rpm) uint8_t spindle_compute_pwm_value(float rpm)
{ {
uint8_t pwm_value; uint8_t pwm_value;
rpm *= (0.010*sys.spindle_speed_ovr);
pwm_value = map(rpm, settings.rpm_min, settings.rpm_max, SPINDLE_PWM_OFF_VALUE, SPINDLE_PWM_MAX_VALUE); pwm_value = map(rpm, settings.rpm_min, settings.rpm_max, SPINDLE_PWM_OFF_VALUE, SPINDLE_PWM_MAX_VALUE);
// TODO_ESP32 .. make it 16 bit // TODO_ESP32 .. make it 16 bit
@@ -70,12 +109,15 @@ void spindle_set_state(uint8_t state, float rpm)
} else { } else {
// TODO ESP32 Enable and direction control // TODO ESP32 Enable and direction control
#ifdef SPINDLE_DIR_PIN
digitalWrite(SPINDLE_DIR_PIN, state == SPINDLE_ENABLE_CW);
#endif
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off. // NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
if (settings.flags & BITFLAG_LASER_MODE) { if (settings.flags & BITFLAG_LASER_MODE) {
if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE); if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
} }
spindle_set_speed(spindle_compute_pwm_value(rpm)); spindle_set_speed(spindle_compute_pwm_value(rpm));
} }
sys.report_ovr_counter = 0; // Set to report change immediately sys.report_ovr_counter = 0; // Set to report change immediately
@@ -98,4 +140,14 @@ void grbl_analogWrite(uint8_t chan, uint32_t duty)
} }
} }
void spindle_set_enable(bool enable)
{
#ifdef SPINDLE_ENABLE_PIN
#ifndef INVERT_SPINDLE_ENABLE_PIN
digitalWrite(SPINDLE_ENABLE_PIN, enable); // turn off (low) with zero speed
#else
digitalWrite(SPINDLE_ENABLE_PIN, !enable); // turn off (high) with zero speed
#endif
#endif
}

View File

@@ -30,7 +30,6 @@
#define SPINDLE_STATE_CW bit(0) #define SPINDLE_STATE_CW bit(0)
#define SPINDLE_STATE_CCW bit(1) #define SPINDLE_STATE_CCW bit(1)
void spindle_init(); void spindle_init();
void spindle_stop(); void spindle_stop();
uint8_t spindle_get_state(); uint8_t spindle_get_state();
@@ -38,7 +37,7 @@
uint8_t spindle_compute_pwm_value(float rpm); uint8_t spindle_compute_pwm_value(float rpm);
void spindle_set_state(uint8_t state, float rpm); void spindle_set_state(uint8_t state, float rpm);
void spindle_sync(uint8_t state, float rpm); void spindle_sync(uint8_t state, float rpm);
void grbl_analogWrite(uint8_t chan, uint32_t duty); void grbl_analogWrite(uint8_t chan, uint32_t duty);
void spindle_set_enable(bool enable);
#endif #endif

View File

@@ -341,17 +341,31 @@ void stepper_init()
{ {
// make the direction pins outputs // make the direction pins outputs
#ifdef X_DIRECTION_PIN
pinMode(X_DIRECTION_PIN, OUTPUT); pinMode(X_DIRECTION_PIN, OUTPUT);
#endif
#ifdef Y_DIRECTION_PIN
pinMode(Y_DIRECTION_PIN, OUTPUT); pinMode(Y_DIRECTION_PIN, OUTPUT);
#endif
#ifdef Z_DIRECTION_PIN
pinMode(Z_DIRECTION_PIN, OUTPUT); pinMode(Z_DIRECTION_PIN, OUTPUT);
#endif
// make the step pins outputs // make the step pins outputs
#ifdef X_STEP_PIN
pinMode(X_STEP_PIN, OUTPUT); pinMode(X_STEP_PIN, OUTPUT);
#endif
#ifdef Y_STEP_PIN
pinMode(Y_STEP_PIN, OUTPUT); pinMode(Y_STEP_PIN, OUTPUT);
#endif
#ifdef Z_STEP_PIN
pinMode(Z_STEP_PIN, OUTPUT); pinMode(Z_STEP_PIN, OUTPUT);
#endif
// make the stepper disable pin an output // make the stepper disable pin an output
#ifdef STEPPERS_DISABLE_PIN
pinMode(STEPPERS_DISABLE_PIN, OUTPUT); pinMode(STEPPERS_DISABLE_PIN, OUTPUT);
#endif
// setup stepper timer interrupt // setup stepper timer interrupt
@@ -444,17 +458,30 @@ void st_reset()
void set_direction_pins_on(uint8_t onMask) void set_direction_pins_on(uint8_t onMask)
{ {
// inverts are applied in step generation // inverts are applied in step generation
#ifdef X_DIRECTION_PIN
digitalWrite(X_DIRECTION_PIN, (onMask & (1<<X_AXIS))); digitalWrite(X_DIRECTION_PIN, (onMask & (1<<X_AXIS)));
#endif
#ifdef Y_DIRECTION_PIN
digitalWrite(Y_DIRECTION_PIN, (onMask & (1<<Y_AXIS))); digitalWrite(Y_DIRECTION_PIN, (onMask & (1<<Y_AXIS)));
#endif
#ifdef Z_DIRECTION_PIN
digitalWrite(Z_DIRECTION_PIN, (onMask & (1<<Z_AXIS))); digitalWrite(Z_DIRECTION_PIN, (onMask & (1<<Z_AXIS)));
#endif
} }
void set_stepper_pins_on(uint8_t onMask) void set_stepper_pins_on(uint8_t onMask)
{ {
onMask ^= settings.step_invert_mask; // invert pins as required by invert mask onMask ^= settings.step_invert_mask; // invert pins as required by invert mask
#ifdef X_STEP_PIN
digitalWrite(X_STEP_PIN, (onMask & (1<<X_AXIS))); digitalWrite(X_STEP_PIN, (onMask & (1<<X_AXIS)));
#endif
#ifdef Y_STEP_PIN
digitalWrite(Y_STEP_PIN, (onMask & (1<<Y_AXIS))); digitalWrite(Y_STEP_PIN, (onMask & (1<<Y_AXIS)));
#endif
#ifdef Z_STEP_PIN
digitalWrite(Z_STEP_PIN, (onMask & (1<<Z_AXIS))); digitalWrite(Z_STEP_PIN, (onMask & (1<<Z_AXIS)));
#endif
} }
@@ -1027,7 +1054,10 @@ void IRAM_ATTR Stepper_Timer_Stop()
void set_stepper_disable(uint8_t isOn) // isOn = true // to disable void set_stepper_disable(uint8_t isOn) // isOn = true // to disable
{ {
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { isOn = !isOn; } // Apply pin invert. if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { isOn = !isOn; } // Apply pin invert.
#ifdef STEPPERS_DISABLE_PIN
digitalWrite(STEPPERS_DISABLE_PIN, isOn ); digitalWrite(STEPPERS_DISABLE_PIN, isOn );
#endif
} }

View File

@@ -70,11 +70,11 @@ void system_execute_startup(char *line)
for (n=0; n < N_STARTUP_LINE; n++) { for (n=0; n < N_STARTUP_LINE; n++) {
if (!(settings_read_startup_line(n, line))) { if (!(settings_read_startup_line(n, line))) {
line[0] = 0; line[0] = 0;
report_execute_startup_message(line,STATUS_SETTING_READ_FAIL); report_execute_startup_message(line,STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
} else { } else {
if (line[0] != 0) { if (line[0] != 0) {
uint8_t status_code = gc_execute_line(line); uint8_t status_code = gc_execute_line(line, CLIENT_SERIAL);
report_execute_startup_message(line,status_code); report_execute_startup_message(line,status_code, CLIENT_SERIAL);
} }
} }
} }
@@ -88,30 +88,30 @@ void system_execute_startup(char *line)
// the lines that are processed afterward, not necessarily real-time during a cycle, // 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 // 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. // be an issue, since these commands are not typically used during a cycle.
uint8_t system_execute_line(char *line) uint8_t system_execute_line(char *line, uint8_t client)
{ {
uint8_t char_counter = 1; uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable uint8_t helper_var = 0; // Helper variable
float parameter, value; float parameter, value;
switch( line[char_counter] ) { switch( line[char_counter] ) {
case 0 : report_grbl_help(); break; case 0 : report_grbl_help(client); break;
case 'J' : // Jogging case 'J' : // Jogging
// Execute only if in IDLE or JOG states. // Execute only if in IDLE or JOG states.
if (sys.state != STATE_IDLE && sys.state != STATE_JOG) { return(STATUS_IDLE_ERROR); } if (sys.state != STATE_IDLE && sys.state != STATE_JOG) { return(STATUS_IDLE_ERROR); }
if(line[2] != '=') { return(STATUS_INVALID_STATEMENT); } if(line[2] != '=') { return(STATUS_INVALID_STATEMENT); }
return(gc_execute_line(line)); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions. return(gc_execute_line(line, client)); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
break; break;
case '$': case 'G': case 'C': case 'X': case '$': case 'G': case 'C': case 'X':
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); } if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
switch( line[1] ) { switch( line[1] ) {
case '$' : // Prints Grbl settings case '$' : // Prints Grbl settings
if ( sys.state & (STATE_CYCLE | STATE_HOLD) ) { return(STATUS_IDLE_ERROR); } // Block during cycle. Takes too long to print. if ( sys.state & (STATE_CYCLE | STATE_HOLD) ) { return(STATUS_IDLE_ERROR); } // Block during cycle. Takes too long to print.
else { report_grbl_settings(); } else { report_grbl_settings(client); }
break; break;
case 'G' : // Prints gcode parser state case 'G' : // Prints gcode parser state
// TODO: Move this to realtime commands for GUIs to request this data during suspend-state. // TODO: Move this to realtime commands for GUIs to request this data during suspend-state.
report_gcode_modes(); report_gcode_modes(client);
break; break;
case 'C' : // Set check g-code mode [IDLE/CHECK] case 'C' : // Set check g-code mode [IDLE/CHECK]
// Perform reset when toggling off. Check g-code mode should only work if Grbl // Perform reset when toggling off. Check g-code mode should only work if Grbl
@@ -143,7 +143,7 @@ uint8_t system_execute_line(char *line)
switch( line[1] ) { switch( line[1] ) {
case '#' : // Print Grbl NGC parameters case '#' : // Print Grbl NGC parameters
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); } if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
else { report_ngc_parameters(); } else { report_ngc_parameters(client); }
break; break;
case 'H' : // Perform homing cycle [IDLE/ALARM] case 'H' : // Perform homing cycle [IDLE/ALARM]
if (bit_isfalse(settings.flags,BITFLAG_HOMING_ENABLE)) {return(STATUS_SETTING_DISABLED); } if (bit_isfalse(settings.flags,BITFLAG_HOMING_ENABLE)) {return(STATUS_SETTING_DISABLED); }
@@ -174,7 +174,7 @@ uint8_t system_execute_line(char *line)
case 'I' : // Print or store build info. [IDLE/ALARM] case 'I' : // Print or store build info. [IDLE/ALARM]
if ( line[++char_counter] == 0 ) { if ( line[++char_counter] == 0 ) {
settings_read_build_info(line); settings_read_build_info(line);
report_build_info(line); report_build_info(line, client);
#ifdef ENABLE_BUILD_INFO_WRITE_COMMAND #ifdef ENABLE_BUILD_INFO_WRITE_COMMAND
} else { // Store startup line [IDLE/ALARM] } else { // Store startup line [IDLE/ALARM]
if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); } if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); }
@@ -207,9 +207,9 @@ uint8_t system_execute_line(char *line)
if ( line[++char_counter] == 0 ) { // Print startup lines if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) { if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL); report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
} else { } else {
report_startup_line(helper_var,line); report_startup_line(helper_var,line, client);
} }
} }
break; break;
@@ -218,6 +218,9 @@ uint8_t system_execute_line(char *line)
helper_var = true; // Set helper_var to flag storing method. helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters. // No break. Continues into default: to read remaining command characters.
} }
case 'W':
//TODO
break;
#ifdef ENABLE_SD_CARD // ==================== SD Card ============================ #ifdef ENABLE_SD_CARD // ==================== SD Card ============================
case 'F': case 'F':
char fileLine[255]; char fileLine[255];
@@ -244,7 +247,7 @@ uint8_t system_execute_line(char *line)
closeFile(); closeFile();
} }
else { else {
report_status_message(gc_execute_line(fileLine)); // execute the first line report_status_message(gc_execute_line(fileLine, CLIENT_SERIAL), CLIENT_SERIAL); // execute the first line
} }
} }
else { else {
@@ -262,7 +265,7 @@ uint8_t system_execute_line(char *line)
line[char_counter-helper_var] = line[char_counter]; line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0); } while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid. // Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code. helper_var = gc_execute_line(line, CLIENT_SERIAL); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); } if (helper_var) { return(helper_var); }
else { else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter helper_var = trunc(parameter); // Set helper_var to int value of parameter

View File

@@ -189,7 +189,7 @@ void system_clear_exec_accessory_overrides();
// Execute the startup script lines stored in EEPROM upon initialization // Execute the startup script lines stored in EEPROM upon initialization
void system_execute_startup(char *line); void system_execute_startup(char *line);
uint8_t system_execute_line(char *line); uint8_t system_execute_line(char *line, uint8_t client);
void system_flag_wco_change(); void system_flag_wco_change();

View File

@@ -50,7 +50,6 @@ Using SD Card
### Roadmap ### Roadmap
- Add Wifi support and a web page interface - Add Wifi support and a web page interface
- Add spindle enable and direction.
### Credits ### Credits
@@ -68,5 +67,9 @@ Start asking questions...I'll put the frequent ones here.
### Donation
This project requires a lot of work and often expensive items for testing. Please consider a donation to it.
[![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TKNJ9Z775VXB2)