diff --git a/Grbl_Esp32/Custom/CoreXY.cpp b/Grbl_Esp32/Custom/CoreXY.cpp index cefab842..238a46df 100644 --- a/Grbl_Esp32/Custom/CoreXY.cpp +++ b/Grbl_Esp32/Custom/CoreXY.cpp @@ -51,9 +51,15 @@ float three_axis_dist(float* point1, float* point2); void machine_init() { // print a startup message to show the kinematics are enable + +#ifdef MIDTBOT + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "CoreXY (midTbot) Kinematics Init"); +#else grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "CoreXY Kinematics Init"); +#endif } +// Cycle mask is 0 unless the user sends a single axis command like $HZ // This will always return true to prevent the normal Grbl homing cycle bool user_defined_homing(uint8_t cycle_mask) { uint8_t n_cycle; // each home is a multi cycle operation approach, pulloff, approach..... @@ -61,12 +67,6 @@ bool user_defined_homing(uint8_t cycle_mask) { float max_travel; uint8_t axis; - // check for single axis homing - if (cycle_mask != 0) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "CoreXY Single axis homing not allowed. Use $H only"); - return true; - } - // check for multi axis homing per cycle ($Homing/Cycle0=XY type)...not allowed in CoreXY bool setting_error = false; for (int cycle = 0; cycle < 3; cycle++) { @@ -90,9 +90,21 @@ bool user_defined_homing(uint8_t cycle_mask) { pl_data->motion.systemMotion = 1; pl_data->motion.noFeedOverride = 1; - for (int cycle = 0; cycle < 3; cycle++) { - AxisMask mask = homing_cycle[cycle]->get(); + uint8_t cycle_count = (cycle_mask == 0) ? 3 : 1; // if we have a cycle_mask, we are only going to do one axis + + AxisMask mask = 0; + for (int cycle = 0; cycle < cycle_count; cycle++) { + // if we have a cycle_mask, do that. Otherwise get the cycle from the settings + mask = cycle_mask ? cycle_mask : homing_cycle[cycle]->get(); + + // If not X or Y do a normal home + if (!(bitnum_istrue(mask, X_AXIS) || bitnum_istrue(mask, Y_AXIS))) { + limits_go_home(mask); // Homing cycle 0 + continue; // continue to next item in for loop + } + mask = motors_set_homing_mode(mask, true); // non standard homing motors will do their own thing and get removed from the mask + for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) { if (bit(axis) == mask) { // setup for the homing of this axis @@ -190,7 +202,7 @@ bool user_defined_homing(uint8_t cycle_mask) { } while (n_cycle-- > 0); } } - } + } // for // after sussefully setting X & Y axes, we set the current positions @@ -231,7 +243,7 @@ void inverse_kinematics(float* position) { motors[X_AXIS] = geometry_factor * position[X_AXIS] + position[Y_AXIS]; motors[Y_AXIS] = geometry_factor * position[X_AXIS] - position[Y_AXIS]; - motors[Z_AXIS] = position[Z_AXIS]; + motors[Z_AXIS] = position[Z_AXIS]; position[0] = motors[0]; position[1] = motors[1]; diff --git a/Grbl_Esp32/Custom/atari_1020.cpp b/Grbl_Esp32/Custom/atari_1020.cpp index 5661ae6d..27a55021 100644 --- a/Grbl_Esp32/Custom/atari_1020.cpp +++ b/Grbl_Esp32/Custom/atari_1020.cpp @@ -57,7 +57,8 @@ void machine_init() { NULL, // parameters 1, // priority &solenoidSyncTaskHandle, - 0 // core + CONFIG_ARDUINO_RUNNING_CORE // must run the task on same core + // core ); // setup a task that will do the custom homing sequence xTaskCreatePinnedToCore(atari_home_task, // task @@ -66,7 +67,8 @@ void machine_init() { NULL, // parameters 1, // priority &atariHomingTaskHandle, - 0 // core + CONFIG_ARDUINO_RUNNING_CORE // must run the task on same core + // core ); } diff --git a/Grbl_Esp32/src/Config.h b/Grbl_Esp32/src/Config.h index 50b014f8..f22e88aa 100644 --- a/Grbl_Esp32/src/Config.h +++ b/Grbl_Esp32/src/Config.h @@ -47,14 +47,16 @@ Some features should not be changed. See notes below. // that the machine file might choose to undefine. // Note: HOMING_CYCLES are now settings +#define SUPPORT_TASK_CORE 1 // Reference: CONFIG_ARDUINO_RUNNING_CORE = 1 // Inverts pin logic of the control command pins based on a mask. This essentially means you can use // normally-closed switches on the specified pins, rather than the default normally-open switches. -// The mask order is Cycle Start | Feed Hold | Reset | Safety Door +// The mask order is ... +// Macro3 | Macro2 | Macro 1| Macr0 |Cycle Start | Feed Hold | Reset | Safety Door // For example B1101 will invert the function of the Reset pin. -#define INVERT_CONTROL_PIN_MASK B1111 +#define INVERT_CONTROL_PIN_MASK B00001111 -#define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable. +// #define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable. #define CONTROL_SW_DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds #define USE_RMT_STEPS @@ -128,7 +130,7 @@ const int MAX_N_AXIS = 6; // "in the clear" over unsecured channels. It should be treated as a // "friendly suggestion" to prevent unwitting dangerous actions, rather than // as effective security against malice. -//#define ENABLE_AUTHENTICATION +// #define ENABLE_AUTHENTICATION //CONFIGURE_EYECATCH_END (DO NOT MODIFY THIS LINE) #ifdef ENABLE_AUTHENTICATION diff --git a/Grbl_Esp32/src/Defaults.h b/Grbl_Esp32/src/Defaults.h index 6ca3728c..41776f56 100644 --- a/Grbl_Esp32/src/Defaults.h +++ b/Grbl_Esp32/src/Defaults.h @@ -159,6 +159,10 @@ # define DEFAULT_LASER_MODE 0 // false #endif +#ifndef DEFAULT_LASER_FULL_POWER +# define DEFAULT_LASER_FULL_POWER 1000 +#endif + #ifndef DEFAULT_SPINDLE_RPM_MAX // $30 # define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm #endif @@ -457,6 +461,10 @@ // This can eliminate checking to see if the pin is defined because // the overridden pinMode and digitalWrite functions will deal with it. +#ifndef SDCARD_DET_PIN +# define SDCARD_DET_PIN UNDEFINED_PIN +#endif + #ifndef STEPPERS_DISABLE_PIN # define STEPPERS_DISABLE_PIN UNDEFINED_PIN #endif @@ -643,3 +651,19 @@ #ifndef USER_ANALOG_PIN_3_FREQ # define USER_ANALOG_PIN_3_FREQ 5000 #endif + +#ifndef DEFAULT_USER_MACRO0 +# define DEFAULT_USER_MACRO0 "" +#endif + +#ifndef DEFAULT_USER_MACRO1 +# define DEFAULT_USER_MACRO1 "" +#endif + +#ifndef DEFAULT_USER_MACRO2 +# define DEFAULT_USER_MACRO2 "" +#endif + +#ifndef DEFAULT_USER_MACRO3 +# define DEFAULT_USER_MACRO3 "" +#endif \ No newline at end of file diff --git a/Grbl_Esp32/src/Eeprom.cpp b/Grbl_Esp32/src/Eeprom.cpp deleted file mode 100644 index 083570c1..00000000 --- a/Grbl_Esp32/src/Eeprom.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - Eeprom.cpp - Coordinate data stored in EEPROM - Part of Grbl - Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC - - 2018 - Bart Dring This file was modifed for use on the ESP32 - CPU. Do not use this with Grbl for atMega328P - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . -*/ - -#include "Grbl.h" - -void memcpy_to_eeprom_with_checksum(unsigned int destination, const char* source, unsigned int size) { - unsigned char checksum = 0; - for (; size > 0; size--) { - unsigned char data = static_cast(*source++); - // Note: This checksum calculation is broken as described below. - checksum = (checksum << 1) || (checksum >> 7); - checksum += data; - EEPROM.write(destination++, *(source++)); - } - EEPROM.write(destination, checksum); - EEPROM.commit(); -} - -int memcpy_from_eeprom_with_old_checksum(char* destination, unsigned int source, unsigned int size) { - unsigned char data, checksum = 0; - for (; size > 0; size--) { - data = EEPROM.read(source++); - // Note: This checksum calculation is broken - the || should be just | - - // thus making the checksum very weak. - // We leave it as-is so we can read old data after a firmware upgrade. - // The new storage format uses the tagged NVS mechanism, avoiding this bug. - checksum = (checksum << 1) || (checksum >> 7); - checksum += data; - *(destination++) = data; - } - return (checksum == EEPROM.read(source)); -} -int memcpy_from_eeprom_with_checksum(char* destination, unsigned int source, unsigned int size) { - unsigned char data, checksum = 0; - for (; size > 0; size--) { - data = EEPROM.read(source++); - checksum = (checksum << 1) | (checksum >> 7); - checksum += data; - *(destination++) = data; - } - return (checksum == EEPROM.read(source)); -} - -// Read selected coordinate data from EEPROM. Updates pointed coord_data value. -// This is now a compatibility routine that is used to propagate coordinate data -// in the old EEPROM format to the new tagged NVS format. -bool old_settings_read_coord_data(uint8_t coord_select, float* coord_data) { - uint32_t addr = coord_select * (sizeof(float) * N_AXIS + 1) + EEPROM_ADDR_PARAMETERS; - if (!(memcpy_from_eeprom_with_old_checksum((char*)coord_data, addr, sizeof(float) * N_AXIS)) && - !(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float) * MAX_N_AXIS))) { - // Reset with default zero vector - clear_vector_float(coord_data); - // The old code used to rewrite the zeroed data but now that is done - // elsewhere, in a different format. - return false; - } - return true; -} - -// Allow iteration over CoordIndex values -CoordIndex& operator ++ (CoordIndex& i) { - i = static_cast(static_cast(i) + 1); - return i; -} diff --git a/Grbl_Esp32/src/Eeprom.h b/Grbl_Esp32/src/Eeprom.h deleted file mode 100644 index 32d66c65..00000000 --- a/Grbl_Esp32/src/Eeprom.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -/* - Eeprom.h - Header for system level commands and real-time processes - Part of Grbl - Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC - - 2018 - Bart Dring This file was modifed for use on the ESP32 - CPU. Do not use this with Grbl for atMega328P - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . -*/ - -#include "Grbl.h" - -// Define EEPROM memory address location values for saved coordinate data. -const int EEPROM_SIZE = 1024U; -const int EEPROM_ADDR_PARAMETERS = 512U; - -//unsigned char eeprom_get_char(unsigned int addr); -//void eeprom_put_char(unsigned int addr, unsigned char new_value); -void memcpy_to_eeprom_with_checksum(unsigned int destination, const char* source, unsigned int size); -int memcpy_from_eeprom_with_checksum(char* destination, unsigned int source, unsigned int size); -int memcpy_from_eeprom_with_old_checksum(char* destination, unsigned int source, unsigned int size); - -// Reads selected coordinate data from EEPROM -bool old_settings_read_coord_data(uint8_t coord_select, float* coord_data); - -// Various places in the code access saved coordinate system data -// by a small integer index according to the values below. -enum CoordIndex : uint8_t{ - Begin = 0, - G54 = Begin, - G55, - G56, - G57, - G58, - G59, - // To support 9 work coordinate systems it would be necessary to define - // the following 3 and modify GCode.cpp to support G59.1, G59.2, G59.3 - // G59_1, - // G59_2, - // G59_3, - NWCSystems, - G28 = NWCSystems, - G30, - // G92_2, - // G92_3, - End, -}; -// Allow iteration over CoordIndex values -CoordIndex& operator ++ (CoordIndex& i); diff --git a/Grbl_Esp32/src/Error.cpp b/Grbl_Esp32/src/Error.cpp index 149b0665..34dd1cd4 100644 --- a/Grbl_Esp32/src/Error.cpp +++ b/Grbl_Esp32/src/Error.cpp @@ -79,4 +79,5 @@ std::map ErrorNames = { { Error::NvsSetFailed, "Failed to store setting" }, { Error::NvsGetStatsFailed, "Failed to get setting status" }, { Error::AuthenticationFailed, "Authentication failed!" }, + { Error::AnotherInterfaceBusy, "Another interface is busy"}, }; diff --git a/Grbl_Esp32/src/Error.h b/Grbl_Esp32/src/Error.h index 09a54030..80f40a39 100644 --- a/Grbl_Esp32/src/Error.h +++ b/Grbl_Esp32/src/Error.h @@ -83,6 +83,7 @@ enum class Error : uint8_t { NvsGetStatsFailed = 101, AuthenticationFailed = 110, Eol = 111, + AnotherInterfaceBusy = 120, }; extern std::map ErrorNames; diff --git a/Grbl_Esp32/src/GCode.cpp b/Grbl_Esp32/src/GCode.cpp index 5a24d342..b1a7a079 100644 --- a/Grbl_Esp32/src/GCode.cpp +++ b/Grbl_Esp32/src/GCode.cpp @@ -24,6 +24,12 @@ #include "Grbl.h" +// Allow iteration over CoordIndex values +CoordIndex& operator++(CoordIndex& i) { + i = static_cast(static_cast(i) + 1); + return i; +} + // NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an // arbitrary value, and some GUIs may require more. So we increased it based on a max safe // value when converting a float (7.2 digit precision)s to an integer. @@ -473,9 +479,10 @@ Error gc_execute_line(char* line, uint8_t client) { gc_block.modal.spindle = SpindleState::Cw; break; case 4: // Supported if SPINDLE_DIR_PIN is defined or laser mode is on. - if (spindle->is_reversable || laser_mode->get()) { + if (spindle->is_reversable || spindle->inLaserMode()) { gc_block.modal.spindle = SpindleState::Ccw; } else { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "M4 requires laser mode or a reversable spindle"); FAIL(Error::GcodeUnsupportedCommand); } break; @@ -1290,7 +1297,7 @@ Error gc_execute_line(char* line, uint8_t client) { return status; } // If in laser mode, setup laser power based on current and past parser conditions. - if (laser_mode->get()) { + if (spindle->inLaserMode()) { if (!((gc_block.modal.motion == Motion::Linear) || (gc_block.modal.motion == Motion::CwArc) || (gc_block.modal.motion == Motion::CcwArc))) { gc_parser_flags |= GCParserLaserDisable; diff --git a/Grbl_Esp32/src/GCode.h b/Grbl_Esp32/src/GCode.h index 4b070459..1ef3abf6 100644 --- a/Grbl_Esp32/src/GCode.h +++ b/Grbl_Esp32/src/GCode.h @@ -232,6 +232,32 @@ enum GCParserFlags { GCParserLaserIsMotion = bit(7), }; +// Various places in the code access saved coordinate system data +// by a small integer index according to the values below. +enum CoordIndex : uint8_t{ + Begin = 0, + G54 = Begin, + G55, + G56, + G57, + G58, + G59, + // To support 9 work coordinate systems it would be necessary to define + // the following 3 and modify GCode.cpp to support G59.1, G59.2, G59.3 + // G59_1, + // G59_2, + // G59_3, + NWCSystems, + G28 = NWCSystems, + G30, + // G92_2, + // G92_3, + End, +}; + +// Allow iteration over CoordIndex values +CoordIndex& operator ++ (CoordIndex& i); + // NOTE: When this struct is zeroed, the 0 values in the above types set the system defaults. typedef struct { Motion motion; // {G0,G1,G2,G3,G38.2,G80} diff --git a/Grbl_Esp32/src/Grbl.h b/Grbl_Esp32/src/Grbl.h index 647e0c06..93c3f1e6 100644 --- a/Grbl_Esp32/src/Grbl.h +++ b/Grbl_Esp32/src/Grbl.h @@ -23,7 +23,7 @@ // Grbl versioning system const char* const GRBL_VERSION = "1.3a"; -const char* const GRBL_VERSION_BUILD = "20201124"; +const char* const GRBL_VERSION_BUILD = "20201212"; //#include #include @@ -41,7 +41,6 @@ const char* const GRBL_VERSION_BUILD = "20201124"; #include "Defaults.h" #include "Error.h" -#include "Eeprom.h" #include "WebUI/Authentication.h" #include "WebUI/Commands.h" #include "Probe.h" diff --git a/Grbl_Esp32/src/I2SOut.cpp b/Grbl_Esp32/src/I2SOut.cpp index d41fed02..211cffaf 100644 --- a/Grbl_Esp32/src/I2SOut.cpp +++ b/Grbl_Esp32/src/I2SOut.cpp @@ -526,7 +526,9 @@ static void IRAM_ATTR i2sOutTask(void* parameter) { I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status static UBaseType_t uxHighWaterMark = 0; +# ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +# endif } } #endif diff --git a/Grbl_Esp32/src/Limits.cpp b/Grbl_Esp32/src/Limits.cpp index 41198dcf..029e3477 100644 --- a/Grbl_Esp32/src/Limits.cpp +++ b/Grbl_Esp32/src/Limits.cpp @@ -372,7 +372,9 @@ void limitCheckTask(void* pvParameters) { sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event } static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +#endif } } diff --git a/Grbl_Esp32/src/Machines/6_pack_stepstick_XYZ_v1.h b/Grbl_Esp32/src/Machines/6_pack_stepstick_XYZ_v1.h index b86c0c26..5bc9da03 100644 --- a/Grbl_Esp32/src/Machines/6_pack_stepstick_XYZ_v1.h +++ b/Grbl_Esp32/src/Machines/6_pack_stepstick_XYZ_v1.h @@ -106,19 +106,38 @@ Socket #5 #define Z_LIMIT_PIN GPIO_NUM_35 + + // // 4x Input Module in Socket #2 // // https://github.com/bdring/6-Pack_CNC_Controller/wiki/4x-Switch-Input-module -// #define X_LIMIT_PIN GPIO_NUM_2 -// #define Y_LIMIT_PIN GPIO_NUM_25 -// #define Z_LIMIT_PIN GPIO_NUM_39 +#define MACRO_BUTTON_0_PIN GPIO_NUM_2 +#define MACRO_BUTTON_1_PIN GPIO_NUM_25 +#define MACRO_BUTTON_2_PIN GPIO_NUM_39 +#define MACRO_BUTTON_3_PIN GPIO_NUM_36 -// // 4x Input Module in Socket #3 -// // https://github.com/bdring/6-Pack_CNC_Controller/wiki/4x-Switch-Input-module -// #define CONTROL_CYCLE_START_PIN GPIO_NUM_26 -// #define CONTROL_FEED_HOLD_PIN GPIO_NUM_4 -// #define CONTROL_RESET_PIN GPIO_NUM_16 -// #define CONTROL_SAFETY_DOOR_PIN GPIO_NUM_27 -// //#define INVERT_CONTROL_PIN_MASK B0000 +// 5V output CNC module in socket #4 +// https://github.com/bdring/6-Pack_CNC_Controller/wiki/4x-5V-Buffered-Output-Module +#define SPINDLE_TYPE SpindleType::PWM +#define SPINDLE_OUTPUT_PIN GPIO_NUM_14 +#define SPINDLE_ENABLE_PIN GPIO_NUM_13 // optional +#define LASER_OUTPUT_PIN GPIO_NUM_15 // optional +#define LASER_ENABLE_PIN GPIO_NUM_12 + + + + +// // RS485 Modbus In socket #3 +// // https://github.com/bdring/6-Pack_CNC_Controller/wiki/RS485-Modbus-Module +// #define VFD_RS485_TXD_PIN GPIO_NUM_26 +// #define VFD_RS485_RTS_PIN GPIO_NUM_4 +// #define VFD_RS485_RXD_PIN GPIO_NUM_16 + +// Example (4x) 5V Buffer Output on socket #5 +// https://github.com/bdring/6-Pack_CNC_Controller/wiki/4x-5V-Buffered-Output-Module +#define USER_DIGITAL_PIN_0 I2SO(24) // No PWM +#define USER_DIGITAL_PIN_1 I2SO(25) +#define USER_DIGITAL_PIN_2 I2SO(26) // M7 on M9 Off +#define USER_DIGITAL_PIN_3 I2SO(27) // M8 on M9 Off // ================= Setting Defaults ========================== #define DEFAULT_X_STEPS_PER_MM 800 diff --git a/Grbl_Esp32/src/Machines/fystec_e4.h b/Grbl_Esp32/src/Machines/fystec_e4.h new file mode 100644 index 00000000..63b47bab --- /dev/null +++ b/Grbl_Esp32/src/Machines/fystec_e4.h @@ -0,0 +1,81 @@ +#pragma once +// clang-format off + +/* + fystec_e4.h + https://github.com/FYSETC/FYSETC-E4 + + 2020-12-03 B. Dring + + This is a machine definition file to use the FYSTEC E4 3D Printer controller + This is a 4 motor controller. This is setup for XYZA, but XYYZ, could also be used. + There are 5 inputs + The controller has outputs for a Fan, Hotbed and Extruder. There are mapped to + spindle, mist and flood coolant to drive an external relay. + + Grbl_ESP32 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl_ESP32. If not, see . +*/ + +#define MACHINE_NAME "FYSTEC E4 3D Printer Controller" + +#define N_AXIS 4 + +#define TRINAMIC_RUN_MODE TrinamicMode :: StealthChop +#define TRINAMIC_HOMING_MODE TrinamicMode :: StealthChop + +#define TMC_UART UART_NUM_1 +#define TMC_UART_RX GPIO_NUM_21 +#define TMC_UART_TX GPIO_NUM_22 + +#define X_TRINAMIC_DRIVER 2209 +#define X_STEP_PIN GPIO_NUM_27 +#define X_DIRECTION_PIN GPIO_NUM_26 +#define X_RSENSE TMC2209_RSENSE_DEFAULT +#define X_DRIVER_ADDRESS 1 +#define DEFAULT_X_MICROSTEPS 16 + +#define Y_TRINAMIC_DRIVER 2209 +#define Y_STEP_PIN GPIO_NUM_33 +#define Y_DIRECTION_PIN GPIO_NUM_32 +#define Y_RSENSE TMC2209_RSENSE_DEFAULT +#define Y_DRIVER_ADDRESS 3 +#define DEFAULT_Y_MICROSTEPS 16 + +#define Z_TRINAMIC_DRIVER 2209 +#define Z_STEP_PIN GPIO_NUM_14 +#define Z_DIRECTION_PIN GPIO_NUM_12 +#define Z_RSENSE TMC2209_RSENSE_DEFAULT +#define Z_DRIVER_ADDRESS 0 +#define DEFAULT_Z_MICROSTEPS 16 + +#define A_TRINAMIC_DRIVER 2209 +#define A_STEP_PIN GPIO_NUM_16 +#define A_DIRECTION_PIN GPIO_NUM_17 +#define A_RSENSE TMC2209_RSENSE_DEFAULT +#define A_DRIVER_ADDRESS 2 +#define DEFAULT_A_MICROSTEPS 16 + +#define X_LIMIT_PIN GPIO_NUM_34 +#define Y_LIMIT_PIN GPIO_NUM_35 +#define Z_LIMIT_PIN GPIO_NUM_15 +#define A_LIMIT_PIN GPIO_NUM_36 // Labeled TB +#define PROBE_PIN GPIO_NUM_39 // Labeled TE + +// OK to comment out to use pin for other features +#define STEPPERS_DISABLE_PIN GPIO_NUM_25 + +#define SPINDLE_TYPE SpindleType::RELAY +#define SPINDLE_OUTPUT_PIN GPIO_NUM_13 // labeled Fan +#define COOLANT_MIST_PIN GPIO_NUM_2 // Labeled Hotbed +#define COOLANT_FLOOD_PIN GPIO_NUM_4 // Labeled Heater \ No newline at end of file diff --git a/Grbl_Esp32/src/Machines/mpcnc_laser_module_v1p2.h b/Grbl_Esp32/src/Machines/mpcnc_laser_module_v1p2.h index f7b02d29..43f2864c 100644 --- a/Grbl_Esp32/src/Machines/mpcnc_laser_module_v1p2.h +++ b/Grbl_Esp32/src/Machines/mpcnc_laser_module_v1p2.h @@ -53,8 +53,8 @@ // OK to comment out to use pin for other features #define STEPPERS_DISABLE_PIN GPIO_NUM_13 -#define SPINDLE_TYPE SpindleType::PWM -#define SPINDLE_OUTPUT_PIN GPIO_NUM_16 +#define SPINDLE_TYPE SpindleType::LASER +#define LASER_OUTPUT_PIN GPIO_NUM_16 #define COOLANT_MIST_PIN GPIO_NUM_2 diff --git a/Grbl_Esp32/src/MotionControl.cpp b/Grbl_Esp32/src/MotionControl.cpp index 5d725ac9..74b53d26 100644 --- a/Grbl_Esp32/src/MotionControl.cpp +++ b/Grbl_Esp32/src/MotionControl.cpp @@ -246,16 +246,17 @@ static bool mask_is_single_axis(uint8_t axis_mask) { return axis_mask && ((axis_mask & (axis_mask - 1)) == 0); } -// return true if the axis is defined as a squared axis -// Squaring: is used on gantry type axes that have two motors -// Each motor with touch off its own switch to square the axis -static bool mask_has_squared_axis(uint8_t axis_mask) { - return axis_mask & homing_squared_axes->get(); -} - -// return true if axis_mask refers to a single squared axis static bool axis_is_squared(uint8_t axis_mask) { - return mask_is_single_axis(axis_mask) && mask_has_squared_axis(axis_mask); + // Squaring can only be done if it is the only axis in the mask + if (axis_mask & homing_squared_axes->get()) { + if (mask_is_single_axis(axis_mask)) { + return true; + } + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Cannot multi-axis home with squared axes. Homing normally"); + return false; + } + + return false; } #ifdef USE_I2S_STEPS diff --git a/Grbl_Esp32/src/Motors/Motors.cpp b/Grbl_Esp32/src/Motors/Motors.cpp index 8c7d550a..1c06a7d7 100644 --- a/Grbl_Esp32/src/Motors/Motors.cpp +++ b/Grbl_Esp32/src/Motors/Motors.cpp @@ -42,17 +42,29 @@ #include "RcServo.h" #include "Dynamixel2.h" #include "TrinamicDriver.h" +#include "TrinamicUartDriver.h" -Motors::Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged) -void init_motors() { +Motors::Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged) +void init_motors() { grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Init Motors"); auto n_axis = number_axis->get(); if (n_axis >= 1) { #ifdef X_TRINAMIC_DRIVER - myMotor[X_AXIS][0] = new Motors::TrinamicDriver( - X_AXIS, X_STEP_PIN, X_DIRECTION_PIN, X_DISABLE_PIN, X_CS_PIN, X_TRINAMIC_DRIVER, X_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[X_AXIS][0] = + new Motors::TrinamicDriver(X_AXIS, X_STEP_PIN, X_DIRECTION_PIN, X_DISABLE_PIN, X_CS_PIN, X_TRINAMIC_DRIVER, X_RSENSE); + } +# elif (X_TRINAMIC_DRIVER == 2208 || X_TRINAMIC_DRIVER == 2209) + { + myMotor[X_AXIS][0] = new Motors::TrinamicUartDriver( + X_AXIS, X_STEP_PIN, X_DIRECTION_PIN, X_DISABLE_PIN, X_TRINAMIC_DRIVER, X_RSENSE, X_DRIVER_ADDRESS); + } +# else +# error X Axis undefined motor p/n +# endif #elif defined(X_SERVO_PIN) myMotor[X_AXIS][0] = new Motors::RcServo(X_AXIS, X_SERVO_PIN); #elif defined(X_UNIPOLAR) @@ -66,8 +78,19 @@ void init_motors() { #endif #ifdef X2_TRINAMIC_DRIVER - myMotor[X_AXIS][1] = new Motors::TrinamicDriver( - X2_AXIS, X2_STEP_PIN, X2_DIRECTION_PIN, X2_DISABLE_PIN, X2_CS_PIN, X2_TRINAMIC_DRIVER, X2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[X_AXIS][1] = + new Motors::TrinamicDriver(X2_AXIS, X2_STEP_PIN, X2_DIRECTION_PIN, X2_DISABLE_PIN, X2_CS_PIN, X2_TRINAMIC_DRIVER, X2_RSENSE); + } +# elif (X2_TRINAMIC_DRIVER == 2208 || X2_TRINAMIC_DRIVER == 2209) + { + myMotor[X_AXIS][1] = new Motors::TrinamicUartDriver( + X2_AXIS, X2_STEP_PIN, X2_DIRECTION_PIN, X2_DISABLE_PIN, X2_TRINAMIC_DRIVER, X2_RSENSE, X2_DRIVER_ADDRESS); + } +# else +# error X2 Axis undefined motor p/n +# endif #elif defined(X2_UNIPOLAR) myMotor[X_AXIS][1] = new Motors::UnipolarMotor(X2_AXIS, X2_PIN_PHASE_0, X2_PIN_PHASE_1, X2_PIN_PHASE_2, X2_PIN_PHASE_3); #elif defined(X2_STEP_PIN) @@ -83,8 +106,19 @@ void init_motors() { if (n_axis >= 2) { // this WILL be done better with settings #ifdef Y_TRINAMIC_DRIVER - myMotor[Y_AXIS][0] = new Motors::TrinamicDriver( - Y_AXIS, Y_STEP_PIN, Y_DIRECTION_PIN, Y_DISABLE_PIN, Y_CS_PIN, Y_TRINAMIC_DRIVER, Y_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[Y_AXIS][0] = + new Motors::TrinamicDriver(Y_AXIS, Y_STEP_PIN, Y_DIRECTION_PIN, Y_DISABLE_PIN, Y_CS_PIN, Y_TRINAMIC_DRIVER, Y_RSENSE); + } +# elif (Y_TRINAMIC_DRIVER == 2208 || Y_TRINAMIC_DRIVER == 2209) + { + myMotor[Y_AXIS][0] = new Motors::TrinamicUartDriver( + Y_AXIS, Y_STEP_PIN, Y_DIRECTION_PIN, Y_DISABLE_PIN, Y_TRINAMIC_DRIVER, Y_RSENSE, Y_DRIVER_ADDRESS); + } +# else +# error Y Axis undefined motor p/n +# endif #elif defined(Y_SERVO_PIN) myMotor[Y_AXIS][0] = new Motors::RcServo(Y_AXIS, Y_SERVO_PIN); #elif defined(Y_UNIPOLAR) @@ -98,8 +132,19 @@ void init_motors() { #endif #ifdef Y2_TRINAMIC_DRIVER - myMotor[Y_AXIS][1] = new Motors::TrinamicDriver( - Y2_AXIS, Y2_STEP_PIN, Y2_DIRECTION_PIN, Y2_DISABLE_PIN, Y2_CS_PIN, Y2_TRINAMIC_DRIVER, Y2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[Y_AXIS][1] = + new Motors::TrinamicDriver(Y2_AXIS, Y2_STEP_PIN, Y2_DIRECTION_PIN, Y2_DISABLE_PIN, Y2_CS_PIN, Y2_TRINAMIC_DRIVER, Y2_RSENSE); + } +# elif (Y2_TRINAMIC_DRIVER == 2208 || Y2_TRINAMIC_DRIVER == 2209) + { + myMotor[Y_AXIS][1] = new Motors::TrinamicUartDriver( + Y2_AXIS, Y2_STEP_PIN, Y2_DIRECTION_PIN, Y2_DISABLE_PIN, Y2_TRINAMIC_DRIVER, Y2_RSENSE, Y2_DRIVER_ADDRESS); + } +# else +# error Y2 Axis undefined motor p/n +# endif #elif defined(Y2_UNIPOLAR) myMotor[Y_AXIS][1] = new Motors::UnipolarMotor(Y2_AXIS, Y2_PIN_PHASE_0, Y2_PIN_PHASE_1, Y2_PIN_PHASE_2, Y2_PIN_PHASE_3); #elif defined(Y2_STEP_PIN) @@ -115,8 +160,19 @@ void init_motors() { if (n_axis >= 3) { // this WILL be done better with settings #ifdef Z_TRINAMIC_DRIVER - myMotor[Z_AXIS][0] = new Motors::TrinamicDriver( - Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN, Z_DISABLE_PIN, Z_CS_PIN, Z_TRINAMIC_DRIVER, Z_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[Z_AXIS][0] = + new Motors::TrinamicDriver(Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN, Z_DISABLE_PIN, Z_CS_PIN, Z_TRINAMIC_DRIVER, Z_RSENSE); + } +# elif (Z_TRINAMIC_DRIVER == 2208 || Z_TRINAMIC_DRIVER == 2209) + { + myMotor[Z_AXIS][0] = new Motors::TrinamicUartDriver( + Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN, Z_DISABLE_PIN, Z_TRINAMIC_DRIVER, Z_RSENSE, Z_DRIVER_ADDRESS); + } +# else +# error Z Axis undefined motor p/n +# endif #elif defined(Z_SERVO_PIN) myMotor[Z_AXIS][0] = new Motors::RcServo(Z_AXIS, Z_SERVO_PIN); #elif defined(Z_UNIPOLAR) @@ -130,8 +186,19 @@ void init_motors() { #endif #ifdef Z2_TRINAMIC_DRIVER - myMotor[Z_AXIS][1] = new Motors::TrinamicDriver( - Z2_AXIS, Z2_STEP_PIN, Z2_DIRECTION_PIN, Z2_DISABLE_PIN, Z2_CS_PIN, Z2_TRINAMIC_DRIVER, Z2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[Z_AXIS][1] = + new Motors::TrinamicDriver(Z2_AXIS, Z2_STEP_PIN, Z2_DIRECTION_PIN, Z2_DISABLE_PIN, Z2_CS_PIN, Z2_TRINAMIC_DRIVER, Z2_RSENSE); + } +# elif (Z2_TRINAMIC_DRIVER == 2208 || Z2_TRINAMIC_DRIVER == 2209) + { + myMotor[Z_AXIS][1] = new Motors::TrinamicUartDriver( + Z2_AXIS, Z2_STEP_PIN, Z2_DIRECTION_PIN, Z2_DISABLE_PIN, Z2_TRINAMIC_DRIVER, Z2_RSENSE, Z2_DRIVER_ADDRESS); + } +# else +# error Z2 Axis undefined motor p/n +# endif #elif defined(Z2_UNIPOLAR) myMotor[Z_AXIS][1] = new Motors::UnipolarMotor(Z2_AXIS, Z2_PIN_PHASE_0, Z2_PIN_PHASE_1, Z2_PIN_PHASE_2, Z2_PIN_PHASE_3); #elif defined(Z2_STEP_PIN) @@ -147,8 +214,19 @@ void init_motors() { if (n_axis >= 4) { // this WILL be done better with settings #ifdef A_TRINAMIC_DRIVER - myMotor[A_AXIS][0] = new Motors::TrinamicDriver( - A_AXIS, A_STEP_PIN, A_DIRECTION_PIN, A_DISABLE_PIN, A_CS_PIN, A_TRINAMIC_DRIVER, A_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[A_AXIS][1] = + new Motors::TrinamicDriver(A_AXIS, A_STEP_PIN, A_DIRECTION_PIN, A_DISABLE_PIN, A_CS_PIN, A_TRINAMIC_DRIVER, A_RSENSE); + } +# elif (A_TRINAMIC_DRIVER == 2208 || A_TRINAMIC_DRIVER == 2209) + { + myMotor[A_AXIS][0] = new Motors::TrinamicUartDriver( + A_AXIS, A_STEP_PIN, A_DIRECTION_PIN, A_DISABLE_PIN, A_TRINAMIC_DRIVER, A_RSENSE, A_DRIVER_ADDRESS); + } +# else +# error A Axis undefined motor p/n +# endif #elif defined(A_SERVO_PIN) myMotor[A_AXIS][0] = new Motors::RcServo(A_AXIS, A_SERVO_PIN); #elif defined(A_UNIPOLAR) @@ -162,8 +240,19 @@ void init_motors() { #endif #ifdef A2_TRINAMIC_DRIVER - myMotor[A_AXIS][1] = new Motors::TrinamicDriver( - A2_AXIS, A2_STEP_PIN, A2_DIRECTION_PIN, A2_DISABLE_PIN, A2_CS_PIN, A2_TRINAMIC_DRIVER, A2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[A_AXIS][1] = + new Motors::TrinamicDriver(A2_AXIS, A2_STEP_PIN, A2_DIRECTION_PIN, A2_DISABLE_PIN, A2_CS_PIN, A2_TRINAMIC_DRIVER, A2_RSENSE); + } +# elif (A2_TRINAMIC_DRIVER == 2208 || A2_TRINAMIC_DRIVER == 2209) + { + myMotor[A_AXIS][1] = new Motors::TrinamicUartDriver( + A2_AXIS, A2_STEP_PIN, A2_DIRECTION_PIN, A2_DISABLE_PIN, A2_TRINAMIC_DRIVER, A2_RSENSE, A2_DRIVER_ADDRESS); + } +# else +# error A2 Axis undefined motor p/n +# endif #elif defined(A2_UNIPOLAR) myMotor[A_AXIS][1] = new Motors::UnipolarMotor(A2_AXIS, A2_PIN_PHASE_0, A2_PIN_PHASE_1, A2_PIN_PHASE_2, A2_PIN_PHASE_3); #elif defined(A2_STEP_PIN) @@ -179,8 +268,19 @@ void init_motors() { if (n_axis >= 5) { // this WILL be done better with settings #ifdef B_TRINAMIC_DRIVER - myMotor[B_AXIS][0] = new Motors::TrinamicDriver( - B_AXIS, B_STEP_PIN, B_DIRECTION_PIN, B_DISABLE_PIN, B_CS_PIN, B_TRINAMIC_DRIVER, B_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[B_AXIS][1] = + new Motors::TrinamicDriver(B_AXIS, B_STEP_PIN, B_DIRECTION_PIN, B_DISABLE_PIN, B_CS_PIN, B_TRINAMIC_DRIVER, B_RSENSE); + } +# elif (B_TRINAMIC_DRIVER == 2208 || B_TRINAMIC_DRIVER == 2209) + { + myMotor[B_AXIS][0] = new Motors::TrinamicUartDriver( + B_AXIS, B_STEP_PIN, B_DIRECTION_PIN, B_DISABLE_PIN, B_TRINAMIC_DRIVER, B_RSENSE, B_DRIVER_ADDRESS); + } +# else +# error B Axis undefined motor p/n +# endif #elif defined(B_SERVO_PIN) myMotor[B_AXIS][0] = new Motors::RcServo(B_AXIS, B_SERVO_PIN); #elif defined(B_UNIPOLAR) @@ -194,8 +294,19 @@ void init_motors() { #endif #ifdef B2_TRINAMIC_DRIVER - myMotor[B_AXIS][1] = new Motors::TrinamicDriver( - B2_AXIS, B2_STEP_PIN, B2_DIRECTION_PIN, B2_DISABLE_PIN, B2_CS_PIN, B2_TRINAMIC_DRIVER, B2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[B_AXIS][1] = + new Motors::TrinamicDriver(B2_AXIS, B2_STEP_PIN, B2_DIRECTION_PIN, B2_DISABLE_PIN, B2_CS_PIN, B2_TRINAMIC_DRIVER, B2_RSENSE); + } +# elif (B2_TRINAMIC_DRIVER == 2208 || B2_TRINAMIC_DRIVER == 2209) + { + myMotor[B_AXIS][1] = new Motors::TrinamicUartDriver( + B2_AXIS, B2_STEP_PIN, B2_DIRECTION_PIN, B2_DISABLE_PIN, B2_TRINAMIC_DRIVER, B2_RSENSE, B2_DRIVER_ADDRESS); + } +# else +# error B2 Axis undefined motor p/n +# endif #elif defined(B2_UNIPOLAR) myMotor[B_AXIS][1] = new Motors::UnipolarMotor(B2_AXIS, B2_PIN_PHASE_0, B2_PIN_PHASE_1, B2_PIN_PHASE_2, B2_PIN_PHASE_3); #elif defined(B2_STEP_PIN) @@ -211,8 +322,19 @@ void init_motors() { if (n_axis >= 6) { // this WILL be done better with settings #ifdef C_TRINAMIC_DRIVER - myMotor[C_AXIS][0] = new Motors::TrinamicDriver( - C_AXIS, C_STEP_PIN, C_DIRECTION_PIN, C_DISABLE_PIN, C_CS_PIN, C_TRINAMIC_DRIVER, C_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[C_AXIS][1] = + new Motors::TrinamicDriver(C_AXIS, C_STEP_PIN, C_DIRECTION_PIN, C_DISABLE_PIN, C_CS_PIN, C_TRINAMIC_DRIVER, C_RSENSE); + } +# elif (C_TRINAMIC_DRIVER == 2208 || C_TRINAMIC_DRIVER == 2209) + { + myMotor[C_AXIS][0] = new Motors::TrinamicUartDriver( + C_AXIS, C_STEP_PIN, C_DIRECTION_PIN, C_DISABLE_PIN, C_TRINAMIC_DRIVER, C_RSENSE, C_DRIVER_ADDRESS); + } +# else +# error C Axis undefined motor p/n +# endif #elif defined(C_SERVO_PIN) myMotor[C_AXIS][0] = new Motors::RcServo(C_AXIS, C_SERVO_PIN); #elif defined(C_UNIPOLAR) @@ -226,8 +348,19 @@ void init_motors() { #endif #ifdef C2_TRINAMIC_DRIVER - myMotor[C_AXIS][1] = new Motors::TrinamicDriver( - C2_AXIS, C2_STEP_PIN, C2_DIRECTION_PIN, C2_DISABLE_PIN, C2_CS_PIN, C2_TRINAMIC_DRIVER, C2_RSENSE); +# if (X_TRINAMIC_DRIVER == 2130 || X_TRINAMIC_DRIVER == 5160) + { + myMotor[C_AXIS][1] = + new Motors::TrinamicDriver(C2_AXIS, C2_STEP_PIN, C2_DIRECTION_PIN, C2_DISABLE_PIN, C2_CS_PIN, C2_TRINAMIC_DRIVER, C2_RSENSE); + } +# elif (C2_TRINAMIC_DRIVER == 2208 || C2_TRINAMIC_DRIVER == 2209) + { + myMotor[C_AXIS][1] = new Motors::TrinamicUartDriver( + C2_AXIS, C2_STEP_PIN, C2_DIRECTION_PIN, C2_DISABLE_PIN, C2_TRINAMIC_DRIVER, C2_RSENSE, C2_DRIVER_ADDRESS); + } +# else +# error C2 Axis undefined motor p/n +# endif #elif defined(C2_UNIPOLAR) myMotor[C_AXIS][1] = new Motors::UnipolarMotor(C2_AXIS, C2_PIN_PHASE_0, C2_PIN_PHASE_1, C2_PIN_PHASE_2, C2_PIN_PHASE_3); #elif defined(C2_STEP_PIN) @@ -279,23 +412,16 @@ void init_motors() { } } -void motors_set_disable(bool disable) { +void motors_set_disable(bool disable, uint8_t mask) { static bool previous_state = true; - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Motors disable %d", disable); - - /* - if (previous_state == disable) { - return; - } - previous_state = disable; -*/ - // now loop through all the motors to see if they can individually disable auto n_axis = number_axis->get(); for (uint8_t gang_index = 0; gang_index < MAX_GANGED; gang_index++) { for (uint8_t axis = X_AXIS; axis < n_axis; axis++) { - myMotor[axis][gang_index]->set_disable(disable); + if (bitnum_istrue(mask, axis)) { + myMotor[axis][gang_index]->set_disable(disable); + } } } @@ -320,7 +446,7 @@ void motors_read_settings() { // They can use this to setup things like Stall uint8_t motors_set_homing_mode(uint8_t homing_mask, bool isHoming) { uint8_t can_home = 0; - auto n_axis = number_axis->get(); + auto n_axis = number_axis->get(); for (uint8_t axis = X_AXIS; axis < n_axis; axis++) { if (bitnum_istrue(homing_mask, axis)) { if (myMotor[axis][0]->set_homing_mode(isHoming)) { @@ -367,4 +493,4 @@ void motors_unstep() { myMotor[axis][0]->unstep(); myMotor[axis][1]->unstep(); } -} +} \ No newline at end of file diff --git a/Grbl_Esp32/src/Motors/Motors.h b/Grbl_Esp32/src/Motors/Motors.h index a6451eff..14550f68 100644 --- a/Grbl_Esp32/src/Motors/Motors.h +++ b/Grbl_Esp32/src/Motors/Motors.h @@ -39,7 +39,7 @@ void motors_read_settings(); // The return value is a bitmask of axes that can home uint8_t motors_set_homing_mode(uint8_t homing_mask, bool isHoming); -void motors_set_disable(bool disable); +void motors_set_disable(bool disable, uint8_t mask = B11111111); // default is all axes void motors_step(uint8_t step_mask, uint8_t dir_mask); void motors_unstep(); diff --git a/Grbl_Esp32/src/Motors/Servo.cpp b/Grbl_Esp32/src/Motors/Servo.cpp index 65e213a1..3702f06b 100644 --- a/Grbl_Esp32/src/Motors/Servo.cpp +++ b/Grbl_Esp32/src/Motors/Servo.cpp @@ -40,6 +40,7 @@ namespace Motors { } void Servo::startUpdateTask() { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Servo Update Task Started"); if (this == List) { xTaskCreatePinnedToCore(updateTask, // task "servoUpdateTask", // name for task @@ -47,7 +48,7 @@ namespace Motors { NULL, // parameters 1, // priority NULL, // handle - 0 // core + SUPPORT_TASK_CORE // core ); } } @@ -67,7 +68,9 @@ namespace Motors { vTaskDelayUntil(&xLastWakeTime, xUpdate); static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +#endif } } diff --git a/Grbl_Esp32/src/Motors/StandardStepper.cpp b/Grbl_Esp32/src/Motors/StandardStepper.cpp index d2a2e51a..8e782ba4 100644 --- a/Grbl_Esp32/src/Motors/StandardStepper.cpp +++ b/Grbl_Esp32/src/Motors/StandardStepper.cpp @@ -44,10 +44,14 @@ namespace Motors { } void StandardStepper::init() { - init_step_dir_pins(); + read_settings(); config_message(); } + void StandardStepper::read_settings() { + init_step_dir_pins(); + } + void StandardStepper::init_step_dir_pins() { _invert_step_pin = bitnum_istrue(step_invert_mask->get(), _axis_index); _invert_dir_pin = bitnum_istrue(dir_invert_mask->get(), _axis_index); diff --git a/Grbl_Esp32/src/Motors/StandardStepper.h b/Grbl_Esp32/src/Motors/StandardStepper.h index efc72f66..269e5b2f 100644 --- a/Grbl_Esp32/src/Motors/StandardStepper.h +++ b/Grbl_Esp32/src/Motors/StandardStepper.h @@ -15,6 +15,7 @@ namespace Motors { void set_direction(bool) override; void step() override; void unstep() override; + void read_settings() override; void init_step_dir_pins(); diff --git a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp index af0f39e7..26229dd2 100644 --- a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp +++ b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp @@ -67,8 +67,7 @@ namespace Motors { return; } - _has_errors = false; - init_step_dir_pins(); // from StandardStepper + _has_errors = false; digitalWrite(_cs_pin, HIGH); pinMode(_cs_pin, OUTPUT); @@ -115,7 +114,8 @@ namespace Motors { NULL, // parameters 1, // priority NULL, - 0 // core + SUPPORT_TASK_CORE // must run the task on same core + // core ); } } @@ -210,6 +210,8 @@ namespace Motors { } tmcstepper->microsteps(axis_settings[_axis_index]->microsteps->get()); tmcstepper->rms_current(run_i_ma, hold_i_percent); + + init_step_dir_pins(); } bool TrinamicDriver::set_homing_mode(bool isHoming) { @@ -353,10 +355,6 @@ namespace Motors { xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time. while (true) { // don't ever return from this or the task dies - if (motorSettingChanged) { - motors_read_settings(); - motorSettingChanged = false; - } if (stallguard_debug_mask->get() != 0) { if (sys.state == State::Cycle || sys.state == State::Homing || sys.state == State::Jog) { for (TrinamicDriver* p = List; p; p = p->link) { @@ -371,7 +369,9 @@ namespace Motors { vTaskDelayUntil(&xLastWakeTime, xreadSg); static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +#endif } } diff --git a/Grbl_Esp32/src/Motors/TrinamicUartDriver.h b/Grbl_Esp32/src/Motors/TrinamicUartDriver.h new file mode 100644 index 00000000..3fb6e7cd --- /dev/null +++ b/Grbl_Esp32/src/Motors/TrinamicUartDriver.h @@ -0,0 +1,131 @@ +#pragma once + +/* + TrinamicUartDriver.h + + Part of Grbl_ESP32 + 2020 - The Ant Team + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#include "Motor.h" +#include "StandardStepper.h" + +#include // https://github.com/teemuatlut/TMCStepper + +const float TMC2208_RSENSE_DEFAULT = 0.11f; +const float TMC2209_RSENSE_DEFAULT = 0.11f; + +const double TRINAMIC_UART_FCLK = 12700000.0; // Internal clock Approx (Hz) used to calculate TSTEP from homing rate + +// ==== defaults OK to define them in your machine definition ==== + +#ifndef TRINAMIC_UART_RUN_MODE +# define TRINAMIC_UART_RUN_MODE TrinamicUartMode ::StealthChop +#endif + +#ifndef TRINAMIC_UART_HOMING_MODE +# define TRINAMIC_UART_HOMING_MODE TRINAMIC_UART_RUN_MODE +#endif + +#ifndef TRINAMIC_UART_TOFF_DISABLE +# define TRINAMIC_UART_TOFF_DISABLE 0 +#endif + +#ifndef TRINAMIC_UART_TOFF_STEALTHCHOP +# define TRINAMIC_UART_TOFF_STEALTHCHOP 5 +#endif + +#ifndef TRINAMIC_UART_TOFF_COOLSTEP +# define TRINAMIC_UART_TOFF_COOLSTEP 3 +#endif + +#ifndef TMC_UART +# define TMC_UART UART_NUM_2 +#endif + +#ifndef TMC_UART_RX +# define TMC_UART_RX UNDEFINED_PIN +#endif + +#ifndef TMC_UART_TX +# define TMC_UART_TX UNDEFINED_PIN +#endif + +extern HardwareSerial tmc_serial; + +namespace Motors { + + enum class TrinamicUartMode : uint8_t { + None = 0, // not for machine defs! + StealthChop = 1, + CoolStep = 2, + StallGuard = 3, + }; + + class TrinamicUartDriver : public StandardStepper { + public: + TrinamicUartDriver(uint8_t axis_index, + uint8_t step_pin, + uint8_t dir_pin, + uint8_t disable_pin, + uint16_t driver_part_number, + float r_senseS, + uint8_t address); + + void config_message(); + void hw_serial_init(); + void init(); + void set_mode(); + void read_settings(); + void debug_message(); + bool set_homing_mode(bool is_homing) override; + void set_disable(bool disable) override; + + uint8_t addr; + + private: + uint32_t calc_tstep(float speed, float percent); //TODO: see if this is useful/used. + + TMC2208Stepper* tmcstepper; // all other driver types are subclasses of this one + TrinamicUartMode _homing_mode; + uint16_t _driver_part_number; // example: use 2209 for TMC2209 + float _r_sense; + bool _has_errors; + bool _disabled; + + TrinamicUartMode _mode = TrinamicUartMode::None; + bool test(); + void set_mode(bool isHoming); + void trinamic_test_response(); + void trinamic_stepper_enable(bool enable); + + bool report_open_load(TMC2208_n ::DRV_STATUS_t status); + bool report_short_to_ground(TMC2208_n ::DRV_STATUS_t status); + bool report_over_temp(TMC2208_n ::DRV_STATUS_t status); + bool report_short_to_ps(TMC2208_n ::DRV_STATUS_t status); + + uint8_t get_next_index(); + + // Linked list of Trinamic driver instances, used by the + // StallGuard reporting task. TODO: verify if this is really used/useful. + static TrinamicUartDriver* List; + TrinamicUartDriver* link; + static void readSgTask(void*); + + protected: + // void config_message() override; + }; + +} \ No newline at end of file diff --git a/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp b/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp new file mode 100644 index 00000000..e930a848 --- /dev/null +++ b/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp @@ -0,0 +1,370 @@ +/* + TrinamicUartDriverClass.cpp + + This is used for Trinamic UART controlled stepper motor drivers. + + Part of Grbl_ESP32 + 2020 - The Ant Team + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "TrinamicUartDriver.h" + +#include + +HardwareSerial tmc_serial(TMC_UART); + +namespace Motors { + + /* HW Serial Constructor. */ + TrinamicUartDriver::TrinamicUartDriver( + uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin, uint16_t driver_part_number, float r_sense, uint8_t addr) : + StandardStepper(axis_index, step_pin, dir_pin, disable_pin) { + _driver_part_number = driver_part_number; + _has_errors = false; + _r_sense = r_sense; + this->addr = addr; + + uart_set_pin(TMC_UART, TMC_UART_TX, TMC_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + tmc_serial.begin(115200, SERIAL_8N1, TMC_UART_RX, TMC_UART_TX); + tmc_serial.setRxBufferSize(128); + hw_serial_init(); + } + + void TrinamicUartDriver::hw_serial_init() { + if (_driver_part_number == 2208) + // TMC 2208 does not use address, this field is 0 + tmcstepper = new TMC2208Stepper(&tmc_serial, _r_sense); + else if (_driver_part_number == 2209) + tmcstepper = new TMC2209Stepper(&tmc_serial, _r_sense, addr); + else { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unsupported Trinamic motor p/n:%d", _driver_part_number); + return; + } + } + + void TrinamicUartDriver ::init() { + if (_has_errors) { + return; + } + + init_step_dir_pins(); // from StandardStepper + config_message(); + + tmcstepper->begin(); + + _has_errors = !test(); // Try communicating with motor. Prints an error if there is a problem. + + /* If communication with the driver is working, read the + main settings, apply new driver settings and then read + them back. */ + if (!_has_errors) { //TODO: verify if this is the right way to set the Irun/IHold and microsteps. + read_settings(); + set_mode(false); + } + } + + /* + This is the startup message showing the basic definition. + */ + void TrinamicUartDriver::config_message() { //TODO: The RX/TX pin could be added to the msg. + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s motor Trinamic TMC%d Step:%s Dir:%s Disable:%s UART%d Rx:%s Tx:%s Addr:%d R:%0.3f %s", + reportAxisNameMsg(_axis_index, _dual_axis_index), + _driver_part_number, + pinName(_step_pin).c_str(), + pinName(_dir_pin).c_str(), + pinName(_disable_pin).c_str(), + TMC_UART, + pinName(TMC_UART_RX), + pinName(TMC_UART_TX), + this->addr, + _r_sense, + reportAxisLimitsMsg(_axis_index)); + } + + bool TrinamicUartDriver::test() { + if (_has_errors) { + return false; + } + switch (tmcstepper->test_connection()) { + case 1: + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s driver test failed. Check connection", + reportAxisNameMsg(_axis_index, _dual_axis_index)); + return false; + case 2: + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s driver test failed. Check motor power", + reportAxisNameMsg(_axis_index, _dual_axis_index)); + return false; + default: + // driver responded, so check for other errors from the DRV_STATUS register + + TMC2208_n ::DRV_STATUS_t status { 0 }; // a useful struct to access the bits. + status.sr = tmcstepper->DRV_STATUS(); + + bool err = false; + + // look for errors + if (report_short_to_ground(status)) { + err = true; + } + + if (report_over_temp(status)) { + err = true; + } + + if (report_short_to_ps(status)) { + err = true; + } + + if (err) { + return false; + } + + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "%s driver test passed", reportAxisNameMsg(_axis_index, _dual_axis_index)); + return true; + } + } + + /* + Read setting and send them to the driver. Called at init() and whenever related settings change + both are stored as float Amps, but TMCStepper library expects... + uint16_t run (mA) + float hold (as a percentage of run) + */ + void TrinamicUartDriver::read_settings() { + if (_has_errors) { + return; + } + + uint16_t run_i_ma = (uint16_t)(axis_settings[_axis_index]->run_current->get() * 1000.0); + float hold_i_percent; + + if (axis_settings[_axis_index]->run_current->get() == 0) + hold_i_percent = 0; + else { + hold_i_percent = axis_settings[_axis_index]->hold_current->get() / axis_settings[_axis_index]->run_current->get(); + if (hold_i_percent > 1.0) + hold_i_percent = 1.0; + } + tmcstepper->microsteps(axis_settings[_axis_index]->microsteps->get()); + tmcstepper->rms_current(run_i_ma, hold_i_percent); + + // grbl_msg_sendf(CLIENT_SERIAL, + // MsgLevel::Info, + // "Setting current of driver %s, target: %u, read irun: %d, hold percent: %f, usteps: %d", + // reportAxisNameMsg(_axis_index, _dual_axis_index), run_i_ma, tmcstepper->rms_current(), hold_i_percent, axis_settings[_axis_index]->microsteps->get()); + } + + bool TrinamicUartDriver::set_homing_mode(bool isHoming) { + set_mode(isHoming); + return true; + } + + /* + There are ton of settings. I'll start by grouping then into modes for now. + Many people will want quiet and stallgaurd homing. Stallguard only run in + Coolstep mode, so it will need to switch to Coolstep when homing + */ + void TrinamicUartDriver::set_mode(bool isHoming) { + if (_has_errors) { + return; + } + + TrinamicUartMode newMode = isHoming ? TRINAMIC_UART_HOMING_MODE : TRINAMIC_UART_RUN_MODE; + + if (newMode == _mode) { + return; + } + _mode = newMode; + + switch (_mode) { + case TrinamicUartMode ::StealthChop: + //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "StealthChop"); + // tmcstepper->en_pwm_mode(true); //TODO: check if this is present in TMC2208/09 + tmcstepper->en_spreadCycle(false); + tmcstepper->pwm_autoscale(true); + // if (_driver_part_number == 2209) { + // tmcstepper->diag1_stall(false); //TODO: check the equivalent in TMC2209 + // } + break; + case TrinamicUartMode ::CoolStep: + //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Coolstep"); + // tmcstepper->en_pwm_mode(false); //TODO: check if this is present in TMC2208/09 + tmcstepper->en_spreadCycle(true); + tmcstepper->pwm_autoscale(false); + if (_driver_part_number == 2209) { + // tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep //TODO: add this solving compilation issue. + // tmcstepper->THIGH(NORMAL_THIGH); //TODO: this does not exist in TMC2208/09. verify and eventually remove. + } + break; + case TrinamicUartMode ::StallGuard: //TODO: check all configurations for stallguard + //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Stallguard"); + // tmcstepper->en_pwm_mode(false); //TODO: check if this is present in TMC2208/09 + tmcstepper->en_spreadCycle(false); + tmcstepper->pwm_autoscale(false); + // tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); + // tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0)); + // tmcstepper->sfilt(1); + // tmcstepper->diag1_stall(true); // stallguard i/o is on diag1 + // tmcstepper->sgt(axis_settings[_axis_index]->stallguard->get()); + break; + default: + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode); + } + } + + /* + This is the stallguard tuning info. It is call debug, so it could be generic across all classes. + */ + void TrinamicUartDriver::debug_message() { + if (_has_errors) { + return; + } + uint32_t tstep = tmcstepper->TSTEP(); + + if (tstep == 0xFFFFF || tstep < 1) { // if axis is not moving return + return; + } + float feedrate = st_get_realtime_rate(); //* settings.microsteps[axis_index] / 60.0 ; // convert mm/min to Hz + + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d", + reportAxisNameMsg(_axis_index, _dual_axis_index), + 0, // tmcstepper->stallguard(), // TODO: add this again solving the compilation issues + 0, // tmcstepper->sg_result(), + feedrate, + axis_settings[_axis_index]->stallguard->get()); + + TMC2208_n ::DRV_STATUS_t status { 0 }; // a useful struct to access the bits. + status.sr = tmcstepper->DRV_STATUS(); + + // these only report if there is a fault condition + report_open_load(status); + report_short_to_ground(status); + report_over_temp(status); + report_short_to_ps(status); + + // grbl_msg_sendf(CLIENT_SERIAL, + // MsgLevel::Info, + // "%s Status Register %08x GSTAT %02x", + // reportAxisNameMsg(_axis_index, _dual_axis_index), + // status.sr, + // tmcstepper->GSTAT()); + } + + // calculate a tstep from a rate + // tstep = TRINAMIC_UART_FCLK / (time between 1/256 steps) + // This is used to set the stallguard window from the homing speed. + // The percent is the offset on the window + uint32_t TrinamicUartDriver::calc_tstep(float speed, float percent) { + float tstep = + speed / 60.0 * axis_settings[_axis_index]->steps_per_mm->get() * (float)(256 / axis_settings[_axis_index]->microsteps->get()); + tstep = TRINAMIC_UART_FCLK / tstep * percent / 100.0; + + return static_cast(tstep); + } + + // this can use the enable feature over SPI. The dedicated pin must be in the enable mode, + // but that can be hardwired that way. + void TrinamicUartDriver::set_disable(bool disable) { + if (_has_errors) { + return; + } + + if (_disabled == disable) { + return; + } + + _disabled = disable; + + digitalWrite(_disable_pin, _disabled); + +#ifdef USE_TRINAMIC_ENABLE + if (_disabled) { + tmcstepper->toff(TRINAMIC_UART_TOFF_DISABLE); + } else { + if (_mode == TrinamicUartMode::StealthChop) { + tmcstepper->toff(TRINAMIC_UART_TOFF_STEALTHCHOP); + } else { + tmcstepper->toff(TRINAMIC_UART_TOFF_COOLSTEP); + } + } +#endif + // the pin based enable could be added here. + // This would be for individual motors, not the single pin for all motors. + } + + // =========== Reporting functions ======================== + + bool TrinamicUartDriver::report_open_load(TMC2208_n ::DRV_STATUS_t status) { + if (status.ola || status.olb) { + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s Driver open load A:%s B:%s", + reportAxisNameMsg(_axis_index, _dual_axis_index), + status.ola ? "Y" : "N", + status.olb ? "Y" : "N"); + return true; + } + return false; // no error + } + + bool TrinamicUartDriver::report_short_to_ground(TMC2208_n ::DRV_STATUS_t status) { + if (status.s2ga || status.s2gb) { + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s Driver shorted coil A:%s B:%s", + reportAxisNameMsg(_axis_index, _dual_axis_index), + status.s2ga ? "Y" : "N", + status.s2gb ? "Y" : "N"); + return true; + } + return false; // no error + } + + bool TrinamicUartDriver::report_over_temp(TMC2208_n ::DRV_STATUS_t status) { + if (status.ot || status.otpw) { + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s Driver temp Warning:%s Fault:%s", + reportAxisNameMsg(_axis_index, _dual_axis_index), + status.otpw ? "Y" : "N", + status.ot ? "Y" : "N"); + return true; + } + return false; // no error + } + + bool TrinamicUartDriver::report_short_to_ps(TMC2208_n ::DRV_STATUS_t status) { + // check for short to power supply + if ((status.sr & bit(12)) || (status.sr & bit(13))) { + grbl_msg_sendf(CLIENT_SERIAL, + MsgLevel::Info, + "%s Driver short vsa:%s vsb:%s", + reportAxisNameMsg(_axis_index, _dual_axis_index), + (status.sr & bit(12)) ? "Y" : "N", + (status.sr & bit(13)) ? "Y" : "N"); + return true; + } + return false; // no error + } + +} \ No newline at end of file diff --git a/Grbl_Esp32/src/ProcessSettings.cpp b/Grbl_Esp32/src/ProcessSettings.cpp index f8539203..a6831713 100644 --- a/Grbl_Esp32/src/ProcessSettings.cpp +++ b/Grbl_Esp32/src/ProcessSettings.cpp @@ -79,7 +79,6 @@ namespace WebUI { } void settings_init() { - EEPROM.begin(EEPROM_SIZE); make_settings(); WebUI::make_web_settings(); make_grbl_commands(); @@ -389,13 +388,45 @@ Error listErrors(const char* value, WebUI::AuthenticationLevel auth_level, WebUI return Error::Ok; } +Error motor_disable(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { + char* s; + if (value == NULL) { + value = "\0"; + } + + s = strdup(value); + s = trim(s); + + int32_t convertedValue; + char* endptr; + if (*s == '\0') { + convertedValue = 255; // all axes + } else { + convertedValue = strtol(s, &endptr, 10); + if (endptr == s || *endptr != '\0') { + // Try to convert as an axis list + convertedValue = 0; + auto axisNames = String("XYZABC"); + while (*s) { + int index = axisNames.indexOf(toupper(*s++)); + if (index < 0) { + return Error::BadNumberFormat; + } + convertedValue |= bit(index); + } + } + } + motors_set_disable(true, convertedValue); + return Error::Ok; +} + static bool anyState() { return false; } static bool idleOrJog() { return sys.state != State::Idle && sys.state != State::Jog; } -static bool idleOrAlarm() { +bool idleOrAlarm() { return sys.state != State::Idle && sys.state != State::Alarm; } static bool notCycleOrHold() { @@ -427,6 +458,8 @@ void make_grbl_commands() { new GrblCommand("V", "Settings/Stats", Setting::report_nvs_stats, idleOrAlarm); new GrblCommand("#", "GCode/Offsets", report_ngc, idleOrAlarm); new GrblCommand("H", "Home", home_all, idleOrAlarm); + new GrblCommand("MD", "Motor/Disable", motor_disable, idleOrAlarm); + #ifdef HOMING_SINGLE_AXIS_COMMANDS new GrblCommand("HX", "Home/X", home_x, idleOrAlarm); new GrblCommand("HY", "Home/Y", home_y, idleOrAlarm); diff --git a/Grbl_Esp32/src/Protocol.cpp b/Grbl_Esp32/src/Protocol.cpp index 982cecca..bfda25f5 100644 --- a/Grbl_Esp32/src/Protocol.cpp +++ b/Grbl_Esp32/src/Protocol.cpp @@ -96,7 +96,7 @@ bool can_park() { #ifdef ENABLE_PARKING_OVERRIDE_CONTROL sys.override_ctrl == Override::ParkingMotion && #endif - homing_enable->get() && !laser_mode->get(); + homing_enable->get() && !spindle->inLaserMode(); } /* @@ -558,7 +558,7 @@ static void protocol_exec_rt_suspend() { restore_spindle_speed = block->spindle_speed; } #ifdef DISABLE_LASER_DURING_HOLD - if (laser_mode->get()) { + if (spindle->inLaserMode()) { sys_rt_exec_accessory_override.bit.spindleOvrStop = true; } #endif @@ -661,7 +661,7 @@ static void protocol_exec_rt_suspend() { if (gc_state.modal.spindle != SpindleState::Disable) { // Block if safety door re-opened during prior restore actions. if (!sys.suspend.bit.restartRetract) { - if (laser_mode->get()) { + if (spindle->inLaserMode()) { // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts. sys.step_control.updateSpindleRpm = true; } else { @@ -717,7 +717,7 @@ static void protocol_exec_rt_suspend() { } else if (sys.spindle_stop_ovr.bit.restore || sys.spindle_stop_ovr.bit.restoreCycle) { if (gc_state.modal.spindle != SpindleState::Disable) { report_feedback_message(Message::SpindleRestore); - if (laser_mode->get()) { + if (spindle->inLaserMode()) { // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts. sys.step_control.updateSpindleRpm = true; } else { diff --git a/Grbl_Esp32/src/Report.cpp b/Grbl_Esp32/src/Report.cpp index 20cff520..33c53c11 100644 --- a/Grbl_Esp32/src/Report.cpp +++ b/Grbl_Esp32/src/Report.cpp @@ -239,6 +239,7 @@ void report_status_message(Error status_code, uint8_t client) { grbl_sendf(client, "error:%d\r\n", status_code); // most senders seem to tolerate this error and keep on going grbl_sendf(CLIENT_ALL, "error:%d in SD file at line %d\r\n", status_code, sd_get_current_line_number()); // don't close file + SD_ready_next = true; // flag so system_execute_line() will send the next line } else { grbl_notifyf("SD print error", "Error:%d during SD file at line: %d", status_code, sd_get_current_line_number()); grbl_sendf(CLIENT_ALL, "error:%d in SD file at line %d\r\n", status_code, sd_get_current_line_number()); @@ -753,16 +754,16 @@ void report_realtime_status(uint8_t client) { strcat(status, "S"); } if (ctrl_pin_state.bit.macro0) { - strcat(status, "M0"); + strcat(status, "0"); } if (ctrl_pin_state.bit.macro1) { - strcat(status, "M1"); + strcat(status, "1"); } if (ctrl_pin_state.bit.macro2) { - strcat(status, "M2"); + strcat(status, "2"); } if (ctrl_pin_state.bit.macro3) { - strcat(status, "M3"); + strcat(status, "3"); } } } diff --git a/Grbl_Esp32/src/SDCard.cpp b/Grbl_Esp32/src/SDCard.cpp index c2d8d3c1..2a6fab21 100644 --- a/Grbl_Esp32/src/SDCard.cpp +++ b/Grbl_Esp32/src/SDCard.cpp @@ -20,12 +20,12 @@ #include "SDCard.h" -File myFile; -bool SD_ready_next = false; // Grbl has processed a line and is waiting for another -uint8_t SD_client = CLIENT_SERIAL; +File myFile; +bool SD_ready_next = false; // Grbl has processed a line and is waiting for another +uint8_t SD_client = CLIENT_SERIAL; WebUI::AuthenticationLevel SD_auth_level = WebUI::AuthenticationLevel::LEVEL_GUEST; -uint32_t sd_current_line_number; // stores the most recent line number read from the SD -static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. +uint32_t sd_current_line_number; // stores the most recent line number read from the SD +static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. // attempt to mount the SD card /*bool sd_mount() @@ -128,13 +128,14 @@ uint32_t sd_get_current_line_number() { uint8_t sd_state = SDCARD_IDLE; uint8_t get_sd_state(bool refresh) { -#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; + if (SDCARD_DET_PIN != UNDEFINED_PIN) { + if (digitalRead(SDCARD_DET_PIN) != SDCARD_DET_VAL) { + sd_state = SDCARD_NOT_PRESENT; + return sd_state; + //no need to go further if SD detect is not correct + } } -#endif + //if busy doing something return state if (!((sd_state == SDCARD_NOT_PRESENT) || (sd_state == SDCARD_IDLE))) { return sd_state; diff --git a/Grbl_Esp32/src/SDCard.h b/Grbl_Esp32/src/SDCard.h index a64a4e7d..298fbdec 100644 --- a/Grbl_Esp32/src/SDCard.h +++ b/Grbl_Esp32/src/SDCard.h @@ -20,8 +20,8 @@ #include #include -#define SDCARD_DET_PIN -1 -const int SDCARD_DET_VAL = 0; +//#define SDCARD_DET_PIN -1 +const int SDCARD_DET_VAL = 0; // for now, CD is close to ground const int SDCARD_IDLE = 0; const int SDCARD_NOT_PRESENT = 1; @@ -29,8 +29,8 @@ const int SDCARD_BUSY_PRINTING = 2; const int SDCARD_BUSY_UPLOADING = 4; const int SDCARD_BUSY_PARSING = 8; -extern bool SD_ready_next; // Grbl has processed a line and is waiting for another -extern uint8_t SD_client; +extern bool SD_ready_next; // Grbl has processed a line and is waiting for another +extern uint8_t SD_client; extern WebUI::AuthenticationLevel SD_auth_level; //bool sd_mount(); diff --git a/Grbl_Esp32/src/Serial.cpp b/Grbl_Esp32/src/Serial.cpp index caa78bb6..5e5e2549 100644 --- a/Grbl_Esp32/src/Serial.cpp +++ b/Grbl_Esp32/src/Serial.cpp @@ -79,7 +79,9 @@ void heapCheckTask(void* pvParameters) { vTaskDelay(3000 / portTICK_RATE_MS); // Yield to other tasks static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +#endif } } @@ -104,7 +106,8 @@ void serial_init() { NULL, // parameters 1, // priority &serialCheckTaskHandle, - 1 // core + SUPPORT_TASK_CORE // must run the task on same core + // core ); } @@ -156,9 +159,16 @@ void serialCheckTask(void* pvParameters) { if (is_realtime_command(data)) { execute_realtime_command(static_cast(data), client); } else { - vTaskEnterCritical(&myMutex); - client_buffer[client].write(data); - vTaskExitCritical(&myMutex); + if (get_sd_state(false) == SDCARD_IDLE) { + vTaskEnterCritical(&myMutex); + client_buffer[client].write(data); + vTaskExitCritical(&myMutex); + } else { + if (data == '\r' || data == '\n') { + grbl_sendf(client, "error %d\r\n", Error::AnotherInterfaceBusy); + grbl_msg_sendf(client, MsgLevel::Info, "SD card job running"); + } + } } } // if something available WebUI::COMMANDS::handle(); @@ -174,8 +184,10 @@ void serialCheckTask(void* pvParameters) { vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); - } // while(true) +#endif + } } void serial_reset_read_buffer(uint8_t client) { diff --git a/Grbl_Esp32/src/Settings.cpp b/Grbl_Esp32/src/Settings.cpp index 5450b444..678a43c0 100644 --- a/Grbl_Esp32/src/Settings.cpp +++ b/Grbl_Esp32/src/Settings.cpp @@ -8,8 +8,10 @@ Word::Word(type_t type, permissions_t permissions, const char* description, cons Command* Command::List = NULL; -Command::Command(const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName) : - Word(type, permissions, description, grblName, fullName) { +Command::Command( + const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName, bool (*cmdChecker)()) : + Word(type, permissions, description, grblName, fullName), + _cmdChecker(cmdChecker) { link = List; List = this; } @@ -126,6 +128,7 @@ Error IntSetting::setStringValue(char* s) { _storedValue = convertedValue; } } + check(NULL); return Error::Ok; } @@ -223,6 +226,7 @@ Error AxisMaskSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } @@ -323,6 +327,7 @@ Error FloatSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } @@ -412,6 +417,7 @@ Error StringSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } @@ -442,11 +448,15 @@ void StringSetting::addWebui(WebUI::JSONencoder* j) { typedef std::map enum_opt_t; -EnumSetting::EnumSetting( - const char* description, type_t type, permissions_t permissions, const char* grblName, const char* name, int8_t defVal, enum_opt_t* opts) - // No checker function because enumerations have an exact set of value - : - Setting(description, type, permissions, grblName, name, NULL), +EnumSetting::EnumSetting(const char* description, + type_t type, + permissions_t permissions, + const char* grblName, + const char* name, + int8_t defVal, + enum_opt_t* opts, + bool (*checker)(char*) = NULL) : + Setting(description, type, permissions, grblName, name, checker), _defaultValue(defVal), _options(opts) {} void EnumSetting::load() { @@ -471,7 +481,11 @@ void EnumSetting::setDefault() { // This is necessary for WebUI, which uses the number // for setting. Error EnumSetting::setStringValue(char* s) { - s = trim(s); + s = trim(s); + Error err = check(s); + if (err != Error::Ok) { + return err; + } enum_opt_t::iterator it = _options->find(s); if (it == _options->end()) { // If we don't find the value in keys, look for it in the numeric values @@ -497,7 +511,7 @@ Error EnumSetting::setStringValue(char* s) { } _currentValue = it->second; if (_storedValue != _currentValue) { - if (_storedValue == _defaultValue) { + if (_currentValue == _defaultValue) { nvs_erase_key(_handle, _keyName); } else { if (nvs_set_i8(_handle, _keyName, _currentValue)) { @@ -506,6 +520,7 @@ Error EnumSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } @@ -585,6 +600,7 @@ Error FlagSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } const char* FlagSetting::getDefaultString() { @@ -665,6 +681,7 @@ Error IPaddrSetting::setStringValue(char* s) { _storedValue = _currentValue; } } + check(NULL); return Error::Ok; } @@ -689,7 +706,7 @@ void IPaddrSetting::addWebui(WebUI::JSONencoder* j) { AxisSettings::AxisSettings(const char* axisName) : name(axisName) {} Error GrblCommand::action(char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - if (_checker && _checker()) { + if (_cmdChecker && _cmdChecker()) { return Error::IdleError; } return _action((const char*)value, auth_level, out); diff --git a/Grbl_Esp32/src/Settings.h b/Grbl_Esp32/src/Settings.h index 63dce4f5..e206b307 100644 --- a/Grbl_Esp32/src/Settings.h +++ b/Grbl_Esp32/src/Settings.h @@ -75,12 +75,13 @@ public: class Command : public Word { protected: Command* link; // linked list of setting objects + bool (*_cmdChecker)(); public: static Command* List; Command* next() { return link; } ~Command() {} - Command(const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName); + Command(const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName, bool (*cmcChecker)()); // The default implementation of addWebui() does nothing. // Derived classes may override it to do something. @@ -343,10 +344,17 @@ public: const char* grblName, const char* name, int8_t defVal, - enum_opt_t* opts); + enum_opt_t* opts, + bool (*checker)(char*)); - EnumSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, int8_t defVal, enum_opt_t* opts) : - EnumSetting(NULL, type, permissions, grblName, name, defVal, opts) {} + EnumSetting(type_t type, + permissions_t permissions, + const char* grblName, + const char* name, + int8_t defVal, + enum_opt_t* opts, + bool (*checker)(char*) = NULL) : + EnumSetting(NULL, type, permissions, grblName, name, defVal, opts, checker) {} void load(); void setDefault(); @@ -435,6 +443,9 @@ public: AxisSettings(const char* axisName); }; + +extern bool idleOrAlarm(); + class WebCommand : public Command { private: Error (*_action)(char*, WebUI::AuthenticationLevel); @@ -447,7 +458,10 @@ public: const char* grblName, const char* name, Error (*action)(char*, WebUI::AuthenticationLevel)) : - Command(description, type, permissions, grblName, name), + // At some point we might want to be more subtle, but for now we block + // all web commands in Cycle and Hold states, to avoid crashing a + // running job. + Command(description, type, permissions, grblName, name, idleOrAlarm), _action(action) {} Error action(char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* response); }; @@ -455,22 +469,21 @@ public: class GrblCommand : public Command { private: Error (*_action)(const char*, WebUI::AuthenticationLevel, WebUI::ESPResponseStream*); - bool (*_checker)(); public: GrblCommand(const char* grblName, const char* name, Error (*action)(const char*, WebUI::AuthenticationLevel, WebUI::ESPResponseStream*), - bool (*checker)(), + bool (*cmdChecker)(), permissions_t auth) : - Command(NULL, GRBLCMD, auth, grblName, name), - _action(action), _checker(checker) {} + Command(NULL, GRBLCMD, auth, grblName, name, cmdChecker), + _action(action) {} GrblCommand(const char* grblName, const char* name, Error (*action)(const char*, WebUI::AuthenticationLevel, WebUI::ESPResponseStream*), - bool (*checker)(void)) : - GrblCommand(grblName, name, action, checker, WG) {} + bool (*cmdChecker)()) : + GrblCommand(grblName, name, action, cmdChecker, WG) {} Error action(char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* response); }; diff --git a/Grbl_Esp32/src/SettingsDefinitions.cpp b/Grbl_Esp32/src/SettingsDefinitions.cpp index 5e2c2e2c..02115c00 100644 --- a/Grbl_Esp32/src/SettingsDefinitions.cpp +++ b/Grbl_Esp32/src/SettingsDefinitions.cpp @@ -1,7 +1,5 @@ #include "Grbl.h" -bool motorSettingChanged = false; - FlagSetting* verbose_errors; FakeSetting* number_axis; @@ -32,6 +30,7 @@ FlagSetting* homing_enable; // TODO Settings - also need to clear, but not set, soft_limits FlagSetting* laser_mode; // TODO Settings - also need to call my_spindle->init; +IntSetting* laser_full_power; IntSetting* status_mask; FloatSetting* junction_deviation; @@ -81,6 +80,11 @@ AxisSettings* c_axis_settings; AxisSettings* axis_settings[MAX_N_AXIS]; +StringSetting* user_macro0; +StringSetting* user_macro1; +StringSetting* user_macro2; +StringSetting* user_macro3; + typedef struct { const char* name; float steps_per_mm; @@ -166,34 +170,37 @@ static const char* makename(const char* axisName, const char* tail) { } static bool checkStartupLine(char* value) { + if (!value) { // No POST functionality + return true; + } if (sys.state != State::Idle) { return false; } return gc_execute_line(value, CLIENT_SERIAL) == Error::Ok; } -static bool checkStallguard(char* value) { - motorSettingChanged = true; +static bool postMotorSetting(char* value) { + if (!value) { + motors_read_settings(); + } return true; } -static bool checkMicrosteps(char* value) { - motorSettingChanged = true; - return true; -} - -static bool checkRunCurrent(char* value) { - motorSettingChanged = true; - return true; -} - -static bool checkHoldcurrent(char* value) { - motorSettingChanged = true; - return true; -} - -static bool checkStallguardDebugMask(char* val) { - motorSettingChanged = true; +static bool checkSpindleChange(char* val) { + if (!val) { + // if not in disable (M5) ... + if (gc_state.modal.spindle != SpindleState::Disable) { + gc_state.modal.spindle = SpindleState::Disable; + if (spindle->use_delays && spindle_delay_spindown->get() != 0) { // old spindle + vTaskDelay(spindle_delay_spindown->get() * 1000); + } + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Spindle turned off with setting change"); + } + gc_state.spindle_speed = 0; // Set S value to 0 + spindle->deinit(); // old spindle + Spindles::Spindle::select(); // get new spindle + return true; + } return true; } @@ -209,20 +216,10 @@ static const char* makeGrblName(int axisNum, int base) { void make_coordinate(CoordIndex index, const char* name) { float coord_data[MAX_N_AXIS] = { 0.0 }; - auto coord = new Coordinates(name); - coords[index] = coord; + auto coord = new Coordinates(name); + coords[index] = coord; if (!coord->load()) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Propagating %s data to NVS format", coord->getName()); - // If coord->load() returns false it means that no entry - // was present in non-volatile storage. In that case we - // first look for an old-format entry in the EEPROM section. - // If an entry is present some number of float values at - // the beginning of coord_data will be overwritten with - // the EEPROM data, and the rest will remain at 0.0. - // If no old-format entry is present, all will remain 0.0 - // Regardless, we create a new entry with that data. - (void)old_settings_read_coord_data(index, coord_data); - coords[index]->set(coord_data); + coords[index]->setDefault(); } } void make_settings() { @@ -259,30 +256,30 @@ void make_settings() { b_axis_settings = axis_settings[B_AXIS]; c_axis_settings = axis_settings[C_AXIS]; for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { - def = &axis_defaults[axis]; - auto setting = new IntSetting( - EXTENDED, WG, makeGrblName(axis, 170), makename(def->name, "StallGuard"), def->stallguard, -64, 63, checkStallguard); + def = &axis_defaults[axis]; + auto setting = + new IntSetting(EXTENDED, WG, makeGrblName(axis, 170), makename(def->name, "StallGuard"), def->stallguard, -64, 63, postMotorSetting); setting->setAxis(axis); axis_settings[axis]->stallguard = setting; } for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { - def = &axis_defaults[axis]; - auto setting = new IntSetting( - EXTENDED, WG, makeGrblName(axis, 160), makename(def->name, "Microsteps"), def->microsteps, 0, 256, checkMicrosteps); + def = &axis_defaults[axis]; + auto setting = + new IntSetting(EXTENDED, WG, makeGrblName(axis, 160), makename(def->name, "Microsteps"), def->microsteps, 0, 256, postMotorSetting); setting->setAxis(axis); axis_settings[axis]->microsteps = setting; } for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { def = &axis_defaults[axis]; auto setting = new FloatSetting( - EXTENDED, WG, makeGrblName(axis, 150), makename(def->name, "Current/Hold"), def->hold_current, 0.05, 20.0, checkHoldcurrent); // Amps + EXTENDED, WG, makeGrblName(axis, 150), makename(def->name, "Current/Hold"), def->hold_current, 0.05, 20.0, postMotorSetting); // Amps setting->setAxis(axis); axis_settings[axis]->hold_current = setting; } for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { def = &axis_defaults[axis]; auto setting = new FloatSetting( - EXTENDED, WG, makeGrblName(axis, 140), makename(def->name, "Current/Run"), def->run_current, 0.0, 20.0, checkRunCurrent); // Amps + EXTENDED, WG, makeGrblName(axis, 140), makename(def->name, "Current/Run"), def->run_current, 0.0, 20.0, postMotorSetting); // Amps setting->setAxis(axis); axis_settings[axis]->run_current = setting; } @@ -322,31 +319,38 @@ void make_settings() { } // Spindle Settings - spindle_pwm_max_value = new FloatSetting(EXTENDED, WG, "36", "Spindle/PWM/Max", DEFAULT_SPINDLE_MAX_VALUE, 0.0, 100.0); - spindle_pwm_min_value = new FloatSetting(EXTENDED, WG, "35", "Spindle/PWM/Min", DEFAULT_SPINDLE_MIN_VALUE, 0.0, 100.0); - spindle_pwm_off_value = - new FloatSetting(EXTENDED, WG, "34", "Spindle/PWM/Off", DEFAULT_SPINDLE_OFF_VALUE, 0.0, 100.0); // these are percentages + spindle_type = + new EnumSetting(NULL, EXTENDED, WG, NULL, "Spindle/Type", static_cast(SPINDLE_TYPE), &spindleTypes, checkSpindleChange); + + spindle_pwm_max_value = + new FloatSetting(EXTENDED, WG, "36", "Spindle/PWM/Max", DEFAULT_SPINDLE_MAX_VALUE, 0.0, 100.0, checkSpindleChange); + spindle_pwm_min_value = + new FloatSetting(EXTENDED, WG, "35", "Spindle/PWM/Min", DEFAULT_SPINDLE_MIN_VALUE, 0.0, 100.0, checkSpindleChange); + spindle_pwm_off_value = new FloatSetting( + EXTENDED, WG, "34", "Spindle/PWM/Off", DEFAULT_SPINDLE_OFF_VALUE, 0.0, 100.0, checkSpindleChange); // these are percentages // IntSetting spindle_pwm_bit_precision(EXTENDED, WG, "Spindle/PWM/Precision", DEFAULT_SPINDLE_BIT_PRECISION, 1, 16); - spindle_pwm_freq = new FloatSetting(EXTENDED, WG, "33", "Spindle/PWM/Frequency", DEFAULT_SPINDLE_FREQ, 0, 100000); - spindle_output_invert = new FlagSetting(GRBL, WG, NULL, "Spindle/PWM/Invert", DEFAULT_INVERT_SPINDLE_OUTPUT_PIN); + spindle_pwm_freq = new FloatSetting(EXTENDED, WG, "33", "Spindle/PWM/Frequency", DEFAULT_SPINDLE_FREQ, 0, 100000, checkSpindleChange); + spindle_output_invert = new FlagSetting(GRBL, WG, NULL, "Spindle/PWM/Invert", DEFAULT_INVERT_SPINDLE_OUTPUT_PIN, checkSpindleChange); spindle_delay_spinup = new FloatSetting(EXTENDED, WG, NULL, "Spindle/Delay/SpinUp", DEFAULT_SPINDLE_DELAY_SPINUP, 0, 30); spindle_delay_spindown = new FloatSetting(EXTENDED, WG, NULL, "Spindle/Delay/SpinDown", DEFAULT_SPINDLE_DELAY_SPINUP, 0, 30); spindle_enbl_off_with_zero_speed = - new FlagSetting(GRBL, WG, NULL, "Spindle/Enable/OffWithSpeed", DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED); + new FlagSetting(GRBL, WG, NULL, "Spindle/Enable/OffWithSpeed", DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED, checkSpindleChange); - spindle_enable_invert = new FlagSetting(GRBL, WG, NULL, "Spindle/Enable/Invert", DEFAULT_INVERT_SPINDLE_ENABLE_PIN); + spindle_enable_invert = new FlagSetting(GRBL, WG, NULL, "Spindle/Enable/Invert", DEFAULT_INVERT_SPINDLE_ENABLE_PIN, checkSpindleChange); // GRBL Non-numbered settings startup_line_0 = new StringSetting(GRBL, WG, "N0", "GCode/Line0", "", checkStartupLine); startup_line_1 = new StringSetting(GRBL, WG, "N1", "GCode/Line1", "", checkStartupLine); // GRBL Numbered Settings - laser_mode = new FlagSetting(GRBL, WG, "32", "GCode/LaserMode", DEFAULT_LASER_MODE); + laser_mode = new FlagSetting(GRBL, WG, "32", "GCode/LaserMode", DEFAULT_LASER_MODE); + laser_full_power = new IntSetting(EXTENDED, WG, NULL, "Laser/FullPower", DEFAULT_LASER_FULL_POWER, 0, 10000, checkSpindleChange); + // TODO Settings - also need to call my_spindle->init(); - rpm_min = new FloatSetting(GRBL, WG, "31", "GCode/MinS", DEFAULT_SPINDLE_RPM_MIN, 0, 100000); - rpm_max = new FloatSetting(GRBL, WG, "30", "GCode/MaxS", DEFAULT_SPINDLE_RPM_MAX, 0, 100000); + rpm_min = new FloatSetting(GRBL, WG, "31", "GCode/MinS", DEFAULT_SPINDLE_RPM_MIN, 0, 100000, checkSpindleChange); + rpm_max = new FloatSetting(GRBL, WG, "30", "GCode/MaxS", DEFAULT_SPINDLE_RPM_MAX, 0, 100000, checkSpindleChange); homing_pulloff = new FloatSetting(GRBL, WG, "27", "Homing/Pulloff", DEFAULT_HOMING_PULLOFF, 0, 1000); homing_debounce = new FloatSetting(GRBL, WG, "26", "Homing/Debounce", DEFAULT_HOMING_DEBOUNCE_DELAY, 0, 10000); @@ -373,17 +377,22 @@ void make_settings() { probe_invert = new FlagSetting(GRBL, WG, "6", "Probe/Invert", DEFAULT_INVERT_PROBE_PIN); limit_invert = new FlagSetting(GRBL, WG, "5", "Limits/Invert", DEFAULT_INVERT_LIMIT_PINS); step_enable_invert = new FlagSetting(GRBL, WG, "4", "Stepper/EnableInvert", DEFAULT_INVERT_ST_ENABLE); - dir_invert_mask = new AxisMaskSetting(GRBL, WG, "3", "Stepper/DirInvert", DEFAULT_DIRECTION_INVERT_MASK); - step_invert_mask = new AxisMaskSetting(GRBL, WG, "2", "Stepper/StepInvert", DEFAULT_STEPPING_INVERT_MASK); + dir_invert_mask = new AxisMaskSetting(GRBL, WG, "3", "Stepper/DirInvert", DEFAULT_DIRECTION_INVERT_MASK, postMotorSetting); + step_invert_mask = new AxisMaskSetting(GRBL, WG, "2", "Stepper/StepInvert", DEFAULT_STEPPING_INVERT_MASK, postMotorSetting); stepper_idle_lock_time = new IntSetting(GRBL, WG, "1", "Stepper/IdleTime", DEFAULT_STEPPER_IDLE_LOCK_TIME, 0, 255); pulse_microseconds = new IntSetting(GRBL, WG, "0", "Stepper/Pulse", DEFAULT_STEP_PULSE_MICROSECONDS, 3, 1000); - spindle_type = new EnumSetting(NULL, EXTENDED, WG, NULL, "Spindle/Type", static_cast(SPINDLE_TYPE), &spindleTypes); - stallguard_debug_mask = new AxisMaskSetting(EXTENDED, WG, NULL, "Report/StallGuard", 0, checkStallguardDebugMask); - homing_cycle[0] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle0", DEFAULT_HOMING_CYCLE_0); - homing_cycle[1] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle1", DEFAULT_HOMING_CYCLE_1); - homing_cycle[2] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle2", DEFAULT_HOMING_CYCLE_2); - homing_cycle[3] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle3", DEFAULT_HOMING_CYCLE_3); - homing_cycle[4] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle4", DEFAULT_HOMING_CYCLE_4); + stallguard_debug_mask = new AxisMaskSetting(EXTENDED, WG, NULL, "Report/StallGuard", 0, postMotorSetting); + homing_cycle[5] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle5", DEFAULT_HOMING_CYCLE_5); + homing_cycle[4] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle4", DEFAULT_HOMING_CYCLE_4); + homing_cycle[3] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle3", DEFAULT_HOMING_CYCLE_3); + homing_cycle[2] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle2", DEFAULT_HOMING_CYCLE_2); + homing_cycle[1] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle1", DEFAULT_HOMING_CYCLE_1); + homing_cycle[0] = new AxisMaskSetting(EXTENDED, WG, NULL, "Homing/Cycle0", DEFAULT_HOMING_CYCLE_0); + + user_macro3 = new StringSetting(EXTENDED, WG, NULL, "User/Macro3", DEFAULT_USER_MACRO3); + user_macro2 = new StringSetting(EXTENDED, WG, NULL, "User/Macro2", DEFAULT_USER_MACRO2); + user_macro1 = new StringSetting(EXTENDED, WG, NULL, "User/Macro1", DEFAULT_USER_MACRO1); + user_macro0 = new StringSetting(EXTENDED, WG, NULL, "User/Macro0", DEFAULT_USER_MACRO0); } diff --git a/Grbl_Esp32/src/SettingsDefinitions.h b/Grbl_Esp32/src/SettingsDefinitions.h index b01038bf..7315637a 100644 --- a/Grbl_Esp32/src/SettingsDefinitions.h +++ b/Grbl_Esp32/src/SettingsDefinitions.h @@ -1,7 +1,5 @@ #pragma once -extern bool motorSettingChanged; - extern FlagSetting* verbose_errors; extern FakeSetting* number_axis; @@ -35,6 +33,7 @@ extern FlagSetting* soft_limits; extern FlagSetting* hard_limits; extern FlagSetting* homing_enable; extern FlagSetting* laser_mode; +extern IntSetting* laser_full_power; extern IntSetting* status_mask; extern FloatSetting* junction_deviation; @@ -61,3 +60,8 @@ extern IntSetting* spindle_pwm_bit_precision; extern EnumSetting* spindle_type; extern AxisMaskSetting* stallguard_debug_mask; + +extern StringSetting* user_macro0; +extern StringSetting* user_macro1; +extern StringSetting* user_macro2; +extern StringSetting* user_macro3; diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.cpp b/Grbl_Esp32/src/Spindles/10vSpindle.cpp index c2f050da..09162c0c 100644 --- a/Grbl_Esp32/src/Spindles/10vSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/10vSpindle.cpp @@ -44,7 +44,7 @@ namespace Spindles { #endif if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: Spindle output pin not defined"); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: Spindle output pin not defined"); return; // We cannot continue without the output pin } @@ -66,7 +66,7 @@ namespace Spindles { // prints the startup message of the spindle config void _10v::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits", pinName(_output_pin).c_str(), @@ -144,7 +144,6 @@ namespace Spindles { } void _10v::set_enable_pin(bool enable) { - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Spindle::_10v::set_enable_pin"); if (_off_with_zero_speed && sys.spindle_speed == 0) { enable = false; } @@ -164,9 +163,33 @@ namespace Spindles { } void _10v::set_dir_pin(bool Clockwise) { - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Spindle::_10v::set_dir_pin"); digitalWrite(_direction_pin, Clockwise); digitalWrite(_forward_pin, Clockwise); digitalWrite(_reverse_pin, !Clockwise); } + + void _10v::deinit() { +#ifdef SPINDLE_OUTPUT_PIN + gpio_reset_pin(SPINDLE_OUTPUT_PIN); + pinMode(SPINDLE_OUTPUT_PIN, INPUT); +#endif +#ifdef SPINDLE_ENABLE_PIN + gpio_reset_pin(SPINDLE_ENABLE_PIN); + pinMode(SPINDLE_ENABLE_PIN, INPUT); +#endif + +#ifdef SPINDLE_DIR_PIN + gpio_reset_pin(SPINDLE_DIR_PIN); + pinMode(SPINDLE_DIR_PIN, INPUT); +#endif +#ifdef SPINDLE_FORWARD_PIN + gpio_reset_pin(SPINDLE_FORWARD_PIN); + pinMode(SPINDLE_FORWARD_PIN, INPUT); +#endif + +#ifdef SPINDLE_REVERSE_PIN + gpio_reset_pin(SPINDLE_FORWARD_PIN); + pinMode(SPINDLE_FORWARD_PIN, INPUT); +#endif + } } diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.h b/Grbl_Esp32/src/Spindles/10vSpindle.h index a0205320..d45a9cb5 100644 --- a/Grbl_Esp32/src/Spindles/10vSpindle.h +++ b/Grbl_Esp32/src/Spindles/10vSpindle.h @@ -45,6 +45,7 @@ namespace Spindles { SpindleState get_state() override; void stop() override; + void deinit() override; virtual ~_10v() {} diff --git a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp index 55630bcb..fceb8bc5 100644 --- a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp @@ -55,7 +55,7 @@ namespace Spindles { get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: BESC output pin not defined"); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: BESC output pin not defined"); return; // We cannot continue without the output pin } @@ -82,7 +82,7 @@ namespace Spindles { // prints the startup message of the spindle config void BESC::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits", pinName(_output_pin).c_str(), diff --git a/Grbl_Esp32/src/Spindles/DacSpindle.cpp b/Grbl_Esp32/src/Spindles/DacSpindle.cpp index b679c857..26910ced 100644 --- a/Grbl_Esp32/src/Spindles/DacSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/DacSpindle.cpp @@ -40,7 +40,7 @@ namespace Spindles { if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins _gpio_ok = false; - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin); return; } @@ -54,7 +54,7 @@ namespace Spindles { } void Dac::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits", pinName(_output_pin).c_str(), @@ -85,7 +85,7 @@ namespace Spindles { rpm = _min_rpm; sys.spindle_speed = rpm; pwm_value = 0; - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value); } } else { // Compute intermediate PWM value with linear spindle speed model. diff --git a/Grbl_Esp32/src/Spindles/Laser.cpp b/Grbl_Esp32/src/Spindles/Laser.cpp index b9fa0c72..6b7d9e6c 100644 --- a/Grbl_Esp32/src/Spindles/Laser.cpp +++ b/Grbl_Esp32/src/Spindles/Laser.cpp @@ -24,19 +24,78 @@ // ===================================== Laser ============================================== namespace Spindles { - bool Laser::isRateAdjusted() { - return true; // can use M4 (CCW) laser mode. + bool Laser::inLaserMode() { + return laser_mode->get(); // can use M4 (CCW) laser mode. } void Laser::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, - "Laser spindle on Pin:%s, Freq:%dHz, Res:%dbits Laser mode:%s", + "Laser spindle on Pin:%s, Enbl:%s, Freq:%dHz, Res:%dbits Laser mode:%s", pinName(_output_pin).c_str(), + pinName(_enable_pin).c_str(), _pwm_freq, _pwm_precision, laser_mode->getStringValue()); // the current mode use_delays = false; // this will override the value set in Spindle::PWM::init() } + + // Get the GPIO from the machine definition + void Laser::get_pins_and_settings() { + // setup all the pins + +#ifdef LASER_OUTPUT_PIN + _output_pin = LASER_OUTPUT_PIN; +#else + _output_pin = UNDEFINED_PIN; +#endif + + _invert_pwm = spindle_output_invert->get(); + +#ifdef LASER_ENABLE_PIN + _enable_pin = LASER_ENABLE_PIN; +#else + _enable_pin = UNDEFINED_PIN; +#endif + + if (_output_pin == UNDEFINED_PIN) { + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: LASER_OUTPUT_PIN not defined"); + return; // We cannot continue without the output pin + } + + _off_with_zero_speed = spindle_enbl_off_with_zero_speed->get(); + + _direction_pin = UNDEFINED_PIN; + is_reversable = false; + + _pwm_freq = spindle_pwm_freq->get(); + _pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision + _pwm_period = (1 << _pwm_precision); + + // pre-caculate some PWM count values + _pwm_off_value = 0; + _pwm_min_value = 0; + _pwm_max_value = _pwm_period; + + _min_rpm = 0; + _max_rpm = laser_full_power->get(); + + _piecewide_linear = false; + + _pwm_chan_num = 0; // Channel 0 is reserved for spindle use + } + + void Laser::deinit() { + stop(); +#ifdef LASER_OUTPUT_PIN + gpio_reset_pin(LASER_OUTPUT_PIN); + pinMode(LASER_OUTPUT_PIN, INPUT); +#endif + +#ifdef LASER_ENABLE_PIN + gpio_reset_pin(LASER_ENABLE_PIN); + pinMode(LASER_ENABLE_PIN, INPUT); +#endif + } } diff --git a/Grbl_Esp32/src/Spindles/Laser.h b/Grbl_Esp32/src/Spindles/Laser.h index 220770b0..10120a31 100644 --- a/Grbl_Esp32/src/Spindles/Laser.h +++ b/Grbl_Esp32/src/Spindles/Laser.h @@ -34,8 +34,10 @@ namespace Spindles { Laser& operator=(const Laser&) = delete; Laser& operator=(Laser&&) = delete; - bool isRateAdjusted() override; + bool inLaserMode() override; void config_message() override; + void get_pins_and_settings() override; + void deinit() override; virtual ~Laser() {} }; diff --git a/Grbl_Esp32/src/Spindles/NullSpindle.cpp b/Grbl_Esp32/src/Spindles/NullSpindle.cpp index c1266019..ddcdb7a2 100644 --- a/Grbl_Esp32/src/Spindles/NullSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/NullSpindle.cpp @@ -40,5 +40,5 @@ namespace Spindles { } SpindleState Null::get_state() { return _current_state; } void Null::stop() {} - void Null::config_message() { grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "No spindle"); } + void Null::config_message() { grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "No spindle"); } } diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp index 3e71ee7b..23477494 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp @@ -34,23 +34,23 @@ namespace Spindles { get_pins_and_settings(); if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: Spindle output pin not defined"); return; // We cannot continue without the output pin } if (_output_pin >= I2S_OUT_PIN_BASE) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str()); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str()); return; } + _current_state = SpindleState::Disable; + _current_pwm_duty = 0; + use_delays = true; + ledcSetup(_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel ledcAttachPin(_output_pin, _pwm_chan_num); // attach the PWM to the pin - pinMode(_enable_pin, OUTPUT); pinMode(_direction_pin, OUTPUT); - use_delays = true; - config_message(); } @@ -80,6 +80,11 @@ namespace Spindles { _direction_pin = UNDEFINED_PIN; #endif + if (_output_pin == UNDEFINED_PIN) { + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: SPINDLE_OUTPUT_PIN not defined"); + return; // We cannot continue without the output pin + } + is_reversable = (_direction_pin != UNDEFINED_PIN); _pwm_freq = spindle_pwm_freq->get(); @@ -87,7 +92,7 @@ namespace Spindles { _pwm_period = (1 << _pwm_precision); if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get()) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: Spindle min pwm is greater than max. Check $35 and $36"); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: Spindle min pwm is greater than max. Check $35 and $36"); } // pre-caculate some PWM count values @@ -117,8 +122,6 @@ namespace Spindles { return rpm; } - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "set_rpm(%d)", rpm); - // apply override rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent) @@ -134,7 +137,7 @@ namespace Spindles { if (_piecewide_linear) { //pwm_value = piecewise_linear_fit(rpm); TODO pwm_value = 0; - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Warning: Linear fit not implemented yet."); + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Warning: Linear fit not implemented yet."); } else { if (rpm == 0) { @@ -144,7 +147,7 @@ namespace Spindles { } } - set_enable_pin(_current_state != SpindleState::Disable); + set_enable_pin(gc_state.modal.spindle != SpindleState::Disable); set_output(pwm_value); return 0; @@ -159,18 +162,14 @@ namespace Spindles { sys.spindle_speed = 0; stop(); if (use_delays && (_current_state != state)) { - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SpinDown Start "); mc_dwell(spindle_delay_spindown->get()); - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SpinDown Done"); } } else { set_dir_pin(state == SpindleState::Cw); set_rpm(rpm); set_enable_pin(state != SpindleState::Disable); // must be done after setting rpm for enable features to work if (use_delays && (_current_state != state)) { - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SpinUp Start %d", rpm); mc_dwell(spindle_delay_spinup->get()); - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SpinUp Done"); } } @@ -197,7 +196,7 @@ namespace Spindles { // prints the startup message of the spindle config void PWM::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits", pinName(_output_pin).c_str(), @@ -223,12 +222,18 @@ namespace Spindles { duty = (1 << _pwm_precision) - duty; } - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "set_output(%d)", duty); - ledcWrite(_pwm_chan_num, duty); } void PWM::set_enable_pin(bool enable) { + // static bool prev_enable = false; + + // if (prev_enable == enable) { + // return; + // } + + // prev_enable = enable; + if (_enable_pin == UNDEFINED_PIN) { return; } @@ -262,4 +267,21 @@ namespace Spindles { return precision - 1; } + + void PWM::deinit() { + stop(); +#ifdef SPINDLE_OUTPUT_PIN + gpio_reset_pin(SPINDLE_OUTPUT_PIN); + pinMode(SPINDLE_OUTPUT_PIN, INPUT); +#endif +#ifdef SPINDLE_ENABLE_PIN + gpio_reset_pin(SPINDLE_ENABLE_PIN); + pinMode(SPINDLE_ENABLE_PIN, INPUT); +#endif + +#ifdef SPINDLE_DIR_PIN + gpio_reset_pin(SPINDLE_DIR_PIN); + pinMode(SPINDLE_DIR_PIN, INPUT); +#endif + } } diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.h b/Grbl_Esp32/src/Spindles/PWMSpindle.h index cb306a1d..07ffdf25 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.h +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.h @@ -65,8 +65,9 @@ namespace Spindles { virtual void set_dir_pin(bool Clockwise); virtual void set_output(uint32_t duty); virtual void set_enable_pin(bool enable_pin); + virtual void deinit(); - void get_pins_and_settings(); - uint8_t calc_pwm_precision(uint32_t freq); + virtual void get_pins_and_settings(); + uint8_t calc_pwm_precision(uint32_t freq); }; } diff --git a/Grbl_Esp32/src/Spindles/RelaySpindle.cpp b/Grbl_Esp32/src/Spindles/RelaySpindle.cpp index eadeb918..41762d4c 100644 --- a/Grbl_Esp32/src/Spindles/RelaySpindle.cpp +++ b/Grbl_Esp32/src/Spindles/RelaySpindle.cpp @@ -46,7 +46,7 @@ namespace Spindles { // prints the startup message of the spindle config void Relay ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, + grbl_msg_sendf(CLIENT_ALL, MsgLevel::Info, "Relay spindle Output:%s, Enbl:%s, Dir:%s", pinName(_output_pin).c_str(), diff --git a/Grbl_Esp32/src/Spindles/Spindle.cpp b/Grbl_Esp32/src/Spindles/Spindle.cpp index 7db5edf2..f705aea7 100644 --- a/Grbl_Esp32/src/Spindles/Spindle.cpp +++ b/Grbl_Esp32/src/Spindles/Spindle.cpp @@ -89,7 +89,7 @@ namespace Spindles { // ========================= Spindle ================================== - bool Spindle::isRateAdjusted() { + bool Spindle::inLaserMode() { return false; // default for basic spindle is false } @@ -100,6 +100,8 @@ namespace Spindles { protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed. set_state(state, rpm); } + + void Spindle::deinit() { stop(); } } Spindles::Spindle* spindle; diff --git a/Grbl_Esp32/src/Spindles/Spindle.h b/Grbl_Esp32/src/Spindles/Spindle.h index d977fa86..6851544a 100644 --- a/Grbl_Esp32/src/Spindles/Spindle.h +++ b/Grbl_Esp32/src/Spindles/Spindle.h @@ -64,8 +64,9 @@ namespace Spindles { virtual SpindleState get_state() = 0; virtual void stop() = 0; virtual void config_message() = 0; - virtual bool isRateAdjusted(); + virtual bool inLaserMode(); virtual void sync(SpindleState state, uint32_t rpm); + virtual void deinit(); virtual ~Spindle() {} diff --git a/Grbl_Esp32/src/Spindles/VFDSpindle.cpp b/Grbl_Esp32/src/Spindles/VFDSpindle.cpp index 3a1305a6..512e243a 100644 --- a/Grbl_Esp32/src/Spindles/VFDSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/VFDSpindle.cpp @@ -194,12 +194,13 @@ namespace Spindles { if (retry_count == MAX_RETRIES) { if (!unresponsive) { grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Spindle RS485 Unresponsive %d", next_cmd.rx_length); - if (next_cmd.critical) { - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Critical Spindle RS485 Unresponsive"); - sys_rt_exec_alarm = ExecAlarm::SpindleControl; - } unresponsive = true; } + if (next_cmd.critical) { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Critical Spindle RS485 Unresponsive"); + mc_reset(); + sys_rt_exec_alarm = ExecAlarm::SpindleControl; + } } vTaskDelay(VFD_RS485_POLL_RATE); // TODO: What is the best value here? @@ -274,7 +275,7 @@ namespace Spindles { this, // parameters 1, // priority &vfd_cmdTaskHandle, - 0 // core + SUPPORT_TASK_CORE // core ); _task_running = true; } @@ -465,4 +466,4 @@ namespace Spindles { return crc; } -} +} \ No newline at end of file diff --git a/Grbl_Esp32/src/Spindles/VFDSpindle.h b/Grbl_Esp32/src/Spindles/VFDSpindle.h index 1c852292..7e81443d 100644 --- a/Grbl_Esp32/src/Spindles/VFDSpindle.h +++ b/Grbl_Esp32/src/Spindles/VFDSpindle.h @@ -22,6 +22,8 @@ #include +// #define VFD_DEBUG_MODE + namespace Spindles { class VFD : public Spindle { @@ -90,4 +92,4 @@ namespace Spindles { virtual ~VFD() {} }; -} +} \ No newline at end of file diff --git a/Grbl_Esp32/src/Stepper.cpp b/Grbl_Esp32/src/Stepper.cpp index ae4a56b2..d4919614 100644 --- a/Grbl_Esp32/src/Stepper.cpp +++ b/Grbl_Esp32/src/Stepper.cpp @@ -551,7 +551,9 @@ void st_prep_buffer() { prep.current_speed = sqrt(pl_block->entry_speed_sqr); } - if (spindle->isRateAdjusted()) { // laser_mode->get() { + st_prep_block->is_pwm_rate_adjusted = false; // set default value + // prep.inv_rate is only used if is_pwm_rate_adjusted is true + if (spindle->inLaserMode()) { // if (pl_block->spindle == SpindleState::Ccw) { // Pre-compute inverse programmed rate to speed up PWM updating per step segment. prep.inv_rate = 1.0 / pl_block->programmed_rate; diff --git a/Grbl_Esp32/src/System.cpp b/Grbl_Esp32/src/System.cpp index 498915f1..6b21702c 100644 --- a/Grbl_Esp32/src/System.cpp +++ b/Grbl_Esp32/src/System.cpp @@ -63,22 +63,22 @@ void system_ini() { // Renamed from system_init() due to conflict with esp32 fi attachInterrupt(digitalPinToInterrupt(CONTROL_CYCLE_START_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_0_PIN - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 0"); + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 0 %s", pinName(MACRO_BUTTON_0_PIN).c_str()); pinMode(MACRO_BUTTON_0_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_0_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_1_PIN - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 1"); + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 1 %s", pinName(MACRO_BUTTON_1_PIN).c_str()); pinMode(MACRO_BUTTON_1_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_1_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_2_PIN - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 2"); + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 2 %s", pinName(MACRO_BUTTON_2_PIN).c_str()); pinMode(MACRO_BUTTON_2_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_2_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_3_PIN - grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 3"); + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro Pin 3 %s", pinName(MACRO_BUTTON_3_PIN).c_str()); pinMode(MACRO_BUTTON_3_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_3_PIN), isr_control_inputs, CHANGE); #endif @@ -87,7 +87,7 @@ void system_ini() { // Renamed from system_init() due to conflict with esp32 fi control_sw_queue = xQueueCreate(10, sizeof(int)); xTaskCreate(controlCheckTask, "controlCheckTask", - 2048, + 3096, NULL, 5, // priority NULL); @@ -125,7 +125,9 @@ void controlCheckTask(void* pvParameters) { debouncing = false; static UBaseType_t uxHighWaterMark = 0; +# ifdef DEBUG_TASK_STACK reportTaskStackSize(uxHighWaterMark); +# endif } } #endif @@ -332,4 +334,39 @@ uint8_t sys_calc_pwm_precision(uint32_t freq) { return precision - 1; } -void __attribute__((weak)) user_defined_macro(uint8_t index); +void __attribute__((weak)) user_defined_macro(uint8_t index) { + // must be in Idle + if (sys.state != State::Idle) { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro button only permitted in idle"); + return; + } + + String user_macro; + char line[255]; + switch (index) { + case 0: + user_macro = user_macro0->get(); + break; + case 1: + user_macro = user_macro1->get(); + break; + case 2: + user_macro = user_macro2->get(); + break; + case 3: + user_macro = user_macro3->get(); + break; + default: + return; + } + + if (user_macro == "") { + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Macro User/Macro%d empty", index); + return; + } + + user_macro.replace('&', '\n'); + user_macro.toCharArray(line, 255, 0); + strcat(line, "\r"); + WebUI::inputBuffer.push(line); +} diff --git a/Grbl_Esp32/src/WebUI/BTConfig.cpp b/Grbl_Esp32/src/WebUI/BTConfig.cpp index 05a7816e..85a2a7e6 100644 --- a/Grbl_Esp32/src/WebUI/BTConfig.cpp +++ b/Grbl_Esp32/src/WebUI/BTConfig.cpp @@ -86,6 +86,9 @@ namespace WebUI { bool BTConfig::isBTnameValid(const char* hostname) { //limited size + if (!hostname) { + return true; + } char c; // length is checked automatically by string setting //only letter and digit diff --git a/Grbl_Esp32/src/WebUI/Commands.cpp b/Grbl_Esp32/src/WebUI/Commands.cpp index 7cfdf003..d59ee19c 100644 --- a/Grbl_Esp32/src/WebUI/Commands.cpp +++ b/Grbl_Esp32/src/WebUI/Commands.cpp @@ -43,6 +43,9 @@ namespace WebUI { } bool COMMANDS::isLocalPasswordValid(char* password) { + if (!password) { + return true; + } char c; //limited size if ((strlen(password) > MAX_LOCAL_PASSWORD_LENGTH) || (strlen(password) < MIN_LOCAL_PASSWORD_LENGTH)) { diff --git a/Grbl_Esp32/src/WebUI/WebServer.cpp b/Grbl_Esp32/src/WebUI/WebServer.cpp index f9ef698d..d58a8b7c 100644 --- a/Grbl_Esp32/src/WebUI/WebServer.cpp +++ b/Grbl_Esp32/src/WebUI/WebServer.cpp @@ -1221,9 +1221,13 @@ namespace WebUI { bool list_files = true; uint64_t totalspace = 0; uint64_t usedspace = 0; - if (get_sd_state(true) != SDCARD_IDLE) { + int8_t state = get_sd_state(true); + if (state != SDCARD_IDLE) { + String status = "{\"status\":\""; + if(state == SDCARD_NOT_PRESENT)status+="No SD Card\"}"; + else status+="Busy\"}"; _webserver->sendHeader("Cache-Control", "no-cache"); - _webserver->send(200, "application/json", "{\"status\":\"No SD Card\"}"); + _webserver->send(200, "application/json", status); return; } set_sd_state(SDCARD_BUSY_PARSING); diff --git a/Grbl_Esp32/src/WebUI/WebSettings.cpp b/Grbl_Esp32/src/WebUI/WebSettings.cpp index b9a34b8c..cec830b9 100644 --- a/Grbl_Esp32/src/WebUI/WebSettings.cpp +++ b/Grbl_Esp32/src/WebUI/WebSettings.cpp @@ -163,6 +163,9 @@ namespace WebUI { } Error WebCommand::action(char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { + if (_cmdChecker && _cmdChecker()) { + return Error::AnotherInterfaceBusy; + } char empty = '\0'; if (!value) { value = ∅ @@ -716,6 +719,10 @@ namespace WebUI { static Error runSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP220 Error err; + if (sys.state == State::Alarm) { + webPrintln("Alarm"); + return Error::IdleError; + } if (sys.state != State::Idle) { webPrintln("Busy"); return Error::IdleError; @@ -859,7 +866,9 @@ namespace WebUI { default: resp = "Busy"; } -#endif +#else + resp = "SD card not enabled"; +#endif webPrintln(resp); return Error::Ok; } @@ -1066,7 +1075,7 @@ namespace WebUI { #ifdef ENABLE_NOTIFICATIONS notification_ts = new StringSetting( "Notification Settings", WEBSET, WA, NULL, "Notification/TS", DEFAULT_TOKEN, 0, MAX_NOTIFICATION_SETTING_LENGTH, NULL); - notification_t2 = new StringSetting("Notification Token 2", + notification_t2 = new StringSetting("Notification Token 2", WEBSET, WA, NULL, @@ -1075,7 +1084,7 @@ namespace WebUI { MIN_NOTIFICATION_TOKEN_LENGTH, MAX_NOTIFICATION_TOKEN_LENGTH, NULL); - notification_t1 = new StringSetting("Notification Token 1", + notification_t1 = new StringSetting("Notification Token 1", WEBSET, WA, NULL, @@ -1084,8 +1093,8 @@ namespace WebUI { MIN_NOTIFICATION_TOKEN_LENGTH, MAX_NOTIFICATION_TOKEN_LENGTH, NULL); - notification_type = - new EnumSetting("Notification type", WEBSET, WA, NULL, "Notification/Type", DEFAULT_NOTIFICATION_TYPE, ¬ificationOptions); + notification_type = new EnumSetting( + "Notification type", WEBSET, WA, NULL, "Notification/Type", DEFAULT_NOTIFICATION_TYPE, ¬ificationOptions, NULL); #endif #ifdef ENABLE_AUTHENTICATION user_password = new StringSetting("User password", @@ -1121,16 +1130,16 @@ namespace WebUI { #ifdef WIFI_OR_BLUETOOTH // user+ to get, admin to set - wifi_radio_mode = new EnumSetting("Radio mode", WEBSET, WA, "ESP110", "Radio/Mode", DEFAULT_RADIO_MODE, &radioEnabledOptions); + wifi_radio_mode = new EnumSetting("Radio mode", WEBSET, WA, "ESP110", "Radio/Mode", DEFAULT_RADIO_MODE, &radioEnabledOptions, NULL); #endif #ifdef ENABLE_WIFI telnet_port = new IntSetting( "Telnet Port", WEBSET, WA, "ESP131", "Telnet/Port", DEFAULT_TELNETSERVER_PORT, MIN_TELNET_PORT, MAX_TELNET_PORT, NULL); - telnet_enable = new EnumSetting("Telnet Enable", WEBSET, WA, "ESP130", "Telnet/Enable", DEFAULT_TELNET_STATE, &onoffOptions); + telnet_enable = new EnumSetting("Telnet Enable", WEBSET, WA, "ESP130", "Telnet/Enable", DEFAULT_TELNET_STATE, &onoffOptions, NULL); http_port = new IntSetting("HTTP Port", WEBSET, WA, "ESP121", "Http/Port", DEFAULT_WEBSERVER_PORT, MIN_HTTP_PORT, MAX_HTTP_PORT, NULL); - http_enable = new EnumSetting("HTTP Enable", WEBSET, WA, "ESP120", "Http/Enable", DEFAULT_HTTP_STATE, &onoffOptions); + http_enable = new EnumSetting("HTTP Enable", WEBSET, WA, "ESP120", "Http/Enable", DEFAULT_HTTP_STATE, &onoffOptions, NULL); wifi_hostname = new StringSetting("Hostname", WEBSET, WA, @@ -1158,7 +1167,7 @@ namespace WebUI { wifi_sta_netmask = new IPaddrSetting("Station Static Mask", WEBSET, WA, NULL, "Sta/Netmask", DEFAULT_STA_MK, NULL); wifi_sta_gateway = new IPaddrSetting("Station Static Gateway", WEBSET, WA, NULL, "Sta/Gateway", DEFAULT_STA_GW, NULL); wifi_sta_ip = new IPaddrSetting("Station Static IP", WEBSET, WA, NULL, "Sta/IP", DEFAULT_STA_IP, NULL); - wifi_sta_mode = new EnumSetting("Station IP Mode", WEBSET, WA, "ESP102", "Sta/IPMode", DEFAULT_STA_IP_MODE, &staModeOptions); + wifi_sta_mode = new EnumSetting("Station IP Mode", WEBSET, WA, "ESP102", "Sta/IPMode", DEFAULT_STA_IP_MODE, &staModeOptions, NULL); // no get, admin to set wifi_sta_password = new StringSetting("Station Password", WEBSET, diff --git a/Grbl_Esp32/src/WebUI/WifiConfig.cpp b/Grbl_Esp32/src/WebUI/WifiConfig.cpp index d918e7c7..e42c0c05 100644 --- a/Grbl_Esp32/src/WebUI/WifiConfig.cpp +++ b/Grbl_Esp32/src/WebUI/WifiConfig.cpp @@ -115,6 +115,9 @@ namespace WebUI { bool WiFiConfig::isHostnameValid(const char* hostname) { //limited size + if (!hostname) { + return true; + } char c; // length is checked automatically by string setting //only letter and digit @@ -139,6 +142,9 @@ namespace WebUI { //char c; // length is checked automatically by string setting //only printable + if (!ssid) { + return true; + } for (int i = 0; i < strlen(ssid); i++) { if (!isPrintable(ssid[i])) { return false; @@ -152,6 +158,9 @@ namespace WebUI { */ bool WiFiConfig::isPasswordValid(const char* password) { + if (!password) { + return true; + } if (strlen(password) == 0) { return true; //open network } diff --git a/Grbl_Esp32/src/data/index.html.gz b/Grbl_Esp32/src/data/index.html.gz index 1cb7e416..05a4f23a 100644 Binary files a/Grbl_Esp32/src/data/index.html.gz and b/Grbl_Esp32/src/data/index.html.gz differ diff --git a/embedded/package-lock.json b/embedded/package-lock.json index 2520c834..a2205bd0 100644 --- a/embedded/package-lock.json +++ b/embedded/package-lock.json @@ -6273,4 +6273,4 @@ } } } -} +} \ No newline at end of file