diff --git a/Grbl_Esp32/Grbl_Esp32.ino b/Grbl_Esp32/Grbl_Esp32.ino
index 9775e4e2..1d4ee718 100644
--- a/Grbl_Esp32/Grbl_Esp32.ino
+++ b/Grbl_Esp32/Grbl_Esp32.ino
@@ -56,6 +56,10 @@ void setup() {
#ifdef USE_PEN_SOLENOID
solenoid_init();
#endif
+
+ #ifdef USE_MACHINE_INIT
+ machine_init(); // user supplied function for special initialization
+ #endif
// Initialize system state.
#ifdef FORCE_INITIALIZATION_ALARM
diff --git a/Grbl_Esp32/atari_1020.cpp b/Grbl_Esp32/atari_1020.cpp
new file mode 100644
index 00000000..f26741e1
--- /dev/null
+++ b/Grbl_Esp32/atari_1020.cpp
@@ -0,0 +1,324 @@
+/*
+ atari_1020.cpp
+ Part of Grbl_ESP32
+
+ copyright (c) 2018 - Bart Dring This file was modified 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 .
+
+ --------------------------------------------------------------
+
+ This contains all the special features required to control an
+ Atari 1010 Pen Plotter
+*/
+#include "grbl.h"
+
+#ifdef ATARI_1020
+
+#define HOMING_PHASE_FULL_APPROACH 0 // move to right end
+#define HOMING_PHASE_CHECK 1 // check reed switch
+#define HOMING_PHASE_RETRACT 2 // retract
+#define HOMING_PHASE_SHORT_APPROACH 3 // retract
+
+static TaskHandle_t solenoidSyncTaskHandle = 0;
+static TaskHandle_t atariHomingTaskHandle = 0;
+uint16_t solenoid_pull_count;
+bool atari_homing = false;
+uint8_t homing_phase = HOMING_PHASE_FULL_APPROACH;
+uint8_t current_tool;
+
+void machine_init()
+{
+ solenoid_pull_count = 0; // initialize
+
+ grbl_send(CLIENT_SERIAL, "[MSG:Atari 1020 Solenoid]\r\n");
+
+ // setup PWM channel
+ ledcSetup(SOLENOID_CHANNEL_NUM, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
+ ledcAttachPin(SOLENOID_PEN_PIN, SOLENOID_CHANNEL_NUM);
+
+ pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
+ pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
+
+ // setup a task that will calculate solenoid position
+ xTaskCreatePinnedToCore( solenoidSyncTask, // task
+ "solenoidSyncTask", // name for task
+ 4096, // size of task stack
+ NULL, // parameters
+ 1, // priority
+ &solenoidSyncTaskHandle,
+ 0 // core
+ );
+ // setup a task that will do the custom homing sequence
+ xTaskCreatePinnedToCore( atari_home_task, // task
+ "atari_home_task", // name for task
+ 4096, // size of task stack
+ NULL, // parameters
+ 1, // priority
+ &atariHomingTaskHandle,
+ 0 // core
+ );
+}
+
+// this task tracks the Z position and sets the solenoid
+void solenoidSyncTask(void *pvParameters)
+{
+ int32_t current_position[N_AXIS]; // copy of current location
+ float m_pos[N_AXIS]; // machine position in mm
+ TickType_t xLastWakeTime;
+ const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
+
+ xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
+ while(true) { // don't ever return from this or the task dies
+
+ memcpy(current_position,sys_position,sizeof(sys_position)); // get current position in step
+ system_convert_array_steps_to_mpos(m_pos,current_position); // convert to millimeters
+ calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
+
+ vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
+ }
+}
+
+// to do...have this return a true or false. This could be used by the normal homing feature to
+// continue with regular homing after setup
+// return true if this completes homing
+
+bool user_defined_homing() {
+ // create and start a task to do the special homing
+ homing_phase = HOMING_PHASE_FULL_APPROACH;
+ atari_homing = true;
+ return true; // this does it...skip the rest of mc_homing_cycle(...)
+}
+
+/*
+ Do a custom homing routine.
+
+ A task is used because it needs to wait until until idle after each move.
+
+ 1) Do a full travel move to the right. OK to stall if the pen started closer
+ 2) Check for pen 1
+ 3) If fail Retract
+ 4) move to right end
+ 5) Check...
+ ....repeat up to 12 times to try to find pen one
+
+ TODO can the retract, move back be 1 phase rather than 2?
+
+*/
+void atari_home_task(void *pvParameters) {
+ uint8_t homing_attempt = 0; // how many times have we tried to home
+ TickType_t xLastWakeTime;
+ const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
+ char gcode_line[20];
+
+ while(true) { // this task will only last as long as it is homing
+
+ if (atari_homing) {
+ // must be in idle or alarm state
+ if (sys.state == STATE_IDLE) {
+ switch(homing_phase) {
+ case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
+ inputBuffer.push("G90G0Z1\r"); // lift the pen
+ sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
+ inputBuffer.push(gcode_line);
+ homing_attempt = 1;
+ homing_phase = HOMING_PHASE_CHECK;
+ break;
+ case HOMING_PHASE_CHECK: // check the limits switch
+ if (digitalRead(REED_SW_PIN) == 0) { // see if reed switch is grounded
+ inputBuffer.push("G4P0.1\n"); // dramtic pause
+
+ sys_position[X_AXIS] = ATARI_HOME_POS * settings.steps_per_mm[X_AXIS];
+ sys_position[Y_AXIS] = 0.0;
+ sys_position[Z_AXIS] = 1.0 * settings.steps_per_mm[Y_AXIS];
+
+ gc_sync_position();
+ plan_sync_position();
+
+ sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
+ inputBuffer.push(gcode_line);
+
+ current_tool = 1; // local copy for reference...until actual M6 change
+ gc_state.tool = current_tool;
+ atari_homing = false; // done with homing sequence
+ }
+ else {
+ homing_phase = HOMING_PHASE_RETRACT;
+ homing_attempt++;
+ }
+ break;
+ case HOMING_PHASE_RETRACT:
+ sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
+ inputBuffer.push(gcode_line);
+ sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
+ inputBuffer.push(gcode_line);
+ homing_phase = HOMING_PHASE_CHECK;
+ break;
+ default:
+ grbl_sendf(CLIENT_SERIAL, "[MSG:Homing phase error %d]\r\n", homing_phase);
+ atari_homing = false;; // kills task
+ break;
+ }
+
+ if (homing_attempt > ATARI_HOMING_ATTEMPTS) { // try all positions plus 1
+ grbl_send(CLIENT_SERIAL, "[MSG: Atari homing failed]\r\n");
+ inputBuffer.push("G90\r");
+ atari_homing = false;;
+ }
+ }
+ }
+ vTaskDelayUntil(&xLastWakeTime, xHomingTaskFrequency);
+ }
+}
+
+
+// calculate and set the PWM value for the servo
+void calc_solenoid(float penZ)
+{
+ bool isPenUp;
+ static bool previousPenState = false;
+ uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
+
+ isPenUp = ( (penZ > 0) || (sys.state == STATE_ALARM) ); // is pen above Z0 or is there an alarm
+
+ // if the state has not change, we only count down to the pull time
+ if (previousPenState == isPenUp) { // if state is unchanged
+ if (solenoid_pull_count > 0) {
+ solenoid_pull_count--;
+ solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
+ }
+ else {
+ solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
+ }
+ }
+ else { // pen direction has changed
+ solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
+ solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
+ }
+
+ previousPenState = isPenUp; // save the prev state
+
+ digitalWrite(SOLENOID_DIRECTION_PIN, isPenUp);
+
+ // skip setting value if it is unchanged
+ if (ledcRead(SOLENOID_CHANNEL_NUM) == solenoid_pen_pulse_len)
+ return;
+
+ // update the PWM value
+ // ledcWrite appears to have issues with interrupts, so make this a critical section
+ portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
+ portENTER_CRITICAL(&myMutex);
+ ledcWrite(SOLENOID_CHANNEL_NUM, solenoid_pen_pulse_len);
+ portEXIT_CRITICAL(&myMutex);
+}
+
+
+/*
+ A tool (pen) change is done by bumping the carriage against the right edge 3 times per
+ position change. Pen 1-4 is valid range.
+*/
+void user_tool_change(uint8_t new_tool) {
+ uint8_t move_count;
+ char gcode_line[20];
+
+ protocol_buffer_synchronize(); // wait for all previous moves to complete
+
+ if ((new_tool < 1) || (new_tool > MAX_PEN_NUMBER)) {
+ grbl_sendf(CLIENT_ALL, "[MSG: Requested Pen#%d is out of 1-4 range]\r\n", new_tool);
+ return;
+ }
+
+ if (new_tool == current_tool)
+ return;
+
+ if (new_tool > current_tool) {
+ move_count = BUMPS_PER_PEN_CHANGE * (new_tool - current_tool);
+ }
+ else {
+ move_count = BUMPS_PER_PEN_CHANGE * ((MAX_PEN_NUMBER - current_tool) + new_tool);
+ }
+ sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
+ inputBuffer.push(gcode_line);
+ for (uint8_t i = 0; i < move_count; i++) {
+ sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
+ inputBuffer.push(gcode_line);
+ inputBuffer.push("G0X0\r");
+ }
+
+ current_tool = new_tool;
+
+ grbl_sendf(CLIENT_ALL, "[MSG: Change to Pen#%d]\r\n", current_tool);
+
+}
+
+// move from current tool to next tool....
+void atari_next_pen() {
+ if (current_tool < MAX_PEN_NUMBER) {
+ gc_state.tool = current_tool + 1;
+ }
+ else {
+ gc_state.tool = 1;
+ }
+ user_tool_change(gc_state.tool);
+}
+
+// Polar coaster has macro buttons, this handles those button pushes.
+void user_defined_macro(uint8_t index)
+{
+ char gcode_line[20];
+
+ switch (index) {
+ #ifdef MACRO_BUTTON_0_PIN
+ case CONTROL_PIN_INDEX_MACRO_0:
+ grbl_send(CLIENT_SERIAL, "[MSG: Pen Switch]\r\n");
+ inputBuffer.push("$H\r");
+ break;
+ #endif
+
+ #ifdef MACRO_BUTTON_1_PIN
+ case CONTROL_PIN_INDEX_MACRO_1:
+ grbl_send(CLIENT_SERIAL, "[MSG: Color Switch]\r\n");
+ atari_next_pen();
+ sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
+ inputBuffer.push(gcode_line);
+ break;
+ #endif
+
+ #ifdef MACRO_BUTTON_2_PIN
+ case CONTROL_PIN_INDEX_MACRO_2:
+ // feed out some paper and reset the Y 0
+ grbl_send(CLIENT_SERIAL, "[MSG: Paper Switch]\r\n");
+ inputBuffer.push("G0Y-25\r");
+ inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
+ sys_position[Y_AXIS] = 0.0; // reset the Y position
+ gc_sync_position();
+ plan_sync_position();
+ break;
+ #endif
+
+ default:
+ grbl_sendf(CLIENT_SERIAL, "[MSG: Unknown Switch %d]\r\n", index);
+ break;
+ }
+}
+
+void user_m30() {
+ char gcode_line[20];
+ sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
+ inputBuffer.push(gcode_line);
+}
+
+#endif
+
diff --git a/Grbl_Esp32/atari_1020.h b/Grbl_Esp32/atari_1020.h
new file mode 100644
index 00000000..b0dcf80b
--- /dev/null
+++ b/Grbl_Esp32/atari_1020.h
@@ -0,0 +1,63 @@
+/*
+ atari_1020.h
+ Part of Grbl_ESP32
+
+ copyright (c) 2018 - Bart Dring This file was modified 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 .
+
+ This contains all the special features required to control an
+ Atari 1010 Pen Plotter
+*/
+
+#define SOLENOID_PWM_FREQ 5000
+#define SOLENOID_PWM_RES_BITS 8
+
+#define SOLENOID_PULSE_LEN_PULL 255
+#define SOLENOID_PULL_DURATION 50 // in task counts...after this delay power will change to hold level see SOLENOID_TASK_FREQ
+#define SOLENOID_PULSE_LEN_HOLD 40 // solenoid hold level ... typically a lower value to prevent overheating
+
+#define SOLENOID_TASK_FREQ 50 // this is milliseconds
+
+#define MAX_PEN_NUMBER 4
+#define BUMPS_PER_PEN_CHANGE 3
+
+
+#define ATARI_HOME_POS -10.0f // this amound to the left of the paper 0
+#define ATARI_PAPER_WIDTH 100.0f //
+#define ATARI_HOMING_ATTEMPTS 13
+
+// tells grbl we have some special functions to call
+#define USE_MACHINE_INIT
+#define USE_CUSTOM_HOMING
+#define USE_TOOL_CHANGE
+#define ATARI_TOOL_CHANGE_Z 5.0
+#define USE_M30 // use the user defined end of program
+
+#ifndef atari_h
+ #define atari_h
+
+ void machine_init();
+ void solenoid_disable();
+ void solenoidSyncTask(void *pvParameters);
+ void calc_solenoid(float penZ);
+ bool user_defined_homing();
+ void atari_home_task(void *pvParameters);
+ void user_tool_change(uint8_t new_tool);
+ void user_defined_macro(uint8_t index);
+ void user_m30();
+ void atari_next_pen();
+
+#endif
\ No newline at end of file
diff --git a/Grbl_Esp32/cpu_map.h b/Grbl_Esp32/cpu_map.h
index 6577b6b3..730d6f6f 100644
--- a/Grbl_Esp32/cpu_map.h
+++ b/Grbl_Esp32/cpu_map.h
@@ -1346,6 +1346,118 @@
#define DEFAULT_B_MAX_TRAVEL 250.0 // mm NOTE: Must be a positive value.
#define DEFAULT_C_MAX_TRAVEL 100.0 // This is percent in servo mode
+#endif
+
+#ifdef CPU_MAP_ATARI_1020
+
+ #include "atari_1020.h"
+
+ #define CPU_MAP_NAME "CPU_MAP_ATARI_1020"
+
+ #define ATARI_1020
+
+ #define USE_UNIPOLAR
+
+ #define X_UNIPOLAR
+ #define X_PIN_PHASE_0 GPIO_NUM_13
+ #define X_PIN_PHASE_1 GPIO_NUM_21
+ #define X_PIN_PHASE_2 GPIO_NUM_16
+ #define X_PIN_PHASE_3 GPIO_NUM_22
+
+ #define Y_UNIPOLAR
+ #define Y_PIN_PHASE_0 GPIO_NUM_25
+ #define Y_PIN_PHASE_1 GPIO_NUM_27
+ #define Y_PIN_PHASE_2 GPIO_NUM_26
+ #define Y_PIN_PHASE_3 GPIO_NUM_32
+
+
+ #define SOLENOID_DIRECTION_PIN GPIO_NUM_4
+ #define SOLENOID_PEN_PIN GPIO_NUM_2
+ #define SOLENOID_CHANNEL_NUM 6
+
+ #ifdef HOMING_CYCLE_0
+ #undef HOMING_CYCLE_0
+ #endif
+ #define HOMING_CYCLE_0 (1<
#include
@@ -89,3 +89,7 @@
#include "grbl_trinamic.h"
#endif
+#ifdef USE_UNIPOLAR
+ #include "grbl_unipolar.h"
+#endif
+
diff --git a/Grbl_Esp32/grbl_unipolar.cpp b/Grbl_Esp32/grbl_unipolar.cpp
new file mode 100644
index 00000000..aaef0761
--- /dev/null
+++ b/Grbl_Esp32/grbl_unipolar.cpp
@@ -0,0 +1,236 @@
+/*
+ unipolar.cpp
+ Part of Grbl_ESP32
+
+ copyright (c) 2019 - Bart Dring. This file was intended 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 .
+
+ Unipolar Class
+
+ This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
+ is typically tied to a voltage, while the other 4 are switched to ground in a
+ sequence
+
+ To take a step simply call the step(step, direction) function.
+
+*/
+#include "grbl.h"
+
+#ifdef USE_UNIPOLAR
+
+ // assign the I/O pins used for each coil of the motors
+ #ifdef X_UNIPOLAR
+ Unipolar X_Unipolar(X_PIN_PHASE_0, X_PIN_PHASE_1, X_PIN_PHASE_2, X_PIN_PHASE_3, true);
+ #endif
+
+ #ifdef Y_UNIPOLAR
+ Unipolar Y_Unipolar(Y_PIN_PHASE_0, Y_PIN_PHASE_1, Y_PIN_PHASE_2, Y_PIN_PHASE_3, true);
+ #endif
+
+ #ifdef Z_UNIPOLAR
+ Unipolar Z_Unipolar(Z_PIN_PHASE_0, Z_PIN_PHASE_1, Z_PIN_PHASE_2, Z_PIN_PHASE_3, true);
+ #endif
+
+ void unipolar_init(){
+ #ifdef X_UNIPOLAR
+ X_Unipolar.init();
+ grbl_send(CLIENT_SERIAL, "[MSG:X Unipolar]\r\n");
+ #endif
+ #ifdef Y_UNIPOLAR
+ Y_Unipolar.init();
+ grbl_send(CLIENT_SERIAL, "[MSG:Y Unipolar]\r\n");
+ #endif
+ #ifdef Z_UNIPOLAR
+ Z_Unipolar.init();
+ grbl_send(CLIENT_SERIAL, "[MSG:Z Unipolar]\r\n");
+ #endif
+ }
+
+ void unipolar_step(uint8_t step_mask, uint8_t dir_mask)
+ {
+ #ifdef X_UNIPOLAR
+ X_Unipolar.step(step_mask & (1<.
+
+ Unipolar Class
+
+ This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
+ is typically tied to a voltage, while the other 4 are switched to ground in a
+ sequence
+
+ To take a step simply call the step(direction) function. It will take
+
+*/
+#ifndef grbl_unipolar_h
+ #define grbl_unipolar_h
+
+ void unipolar_init();
+ void unipolar_step(uint8_t step_mask, uint8_t dir_mask);
+ void unipolar_disable(bool enable);
+
+ class Unipolar{
+ public:
+ Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step); // constructor
+ void set_enabled(bool enabled);
+ void step(bool step, bool dir_forward);
+ void init();
+
+ private:
+ uint8_t _current_phase = 0;
+ bool _enabled = false;
+ bool _half_step = true; // default is half step, full step
+ uint8_t _pin_phase0;
+ uint8_t _pin_phase1;
+ uint8_t _pin_phase2;
+ uint8_t _pin_phase3;
+
+ };
+#endif
\ No newline at end of file
diff --git a/Grbl_Esp32/motion_control.cpp b/Grbl_Esp32/motion_control.cpp
index 692d6c56..440f091a 100644
--- a/Grbl_Esp32/motion_control.cpp
+++ b/Grbl_Esp32/motion_control.cpp
@@ -231,6 +231,12 @@ void mc_dwell(float seconds)
// executing the homing cycle. This prevents incorrect buffered plans after homing.
void mc_homing_cycle(uint8_t cycle_mask)
{
+ #ifdef USE_CUSTOM_HOMING
+ if (user_defined_homing())
+ {
+ return;
+ }
+ #endif
// This give kinematics a chance to do something before normal homing
// if it returns true, the homing is canceled.
diff --git a/Grbl_Esp32/report.cpp b/Grbl_Esp32/report.cpp
index ce67c3c9..34dbe274 100644
--- a/Grbl_Esp32/report.cpp
+++ b/Grbl_Esp32/report.cpp
@@ -53,7 +53,7 @@
// this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc)
void grbl_send(uint8_t client, const char *text)
{
- if (client == CLIENT_NONE) return;
+ if (client == CLIENT_INPUT) return;
#ifdef ENABLE_BLUETOOTH
if (SerialBT.hasClient() && ( client == CLIENT_BT || client == CLIENT_ALL ) )
{
@@ -81,7 +81,7 @@ void grbl_send(uint8_t client, const char *text)
// This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
void grbl_sendf(uint8_t client, const char *format, ...)
{
- if (client == CLIENT_NONE) return;
+ if (client == CLIENT_INPUT) return;
char loc_buf[64];
char * temp = loc_buf;
va_list arg;
diff --git a/Grbl_Esp32/report.h b/Grbl_Esp32/report.h
index 82cd68b0..55f2a422 100644
--- a/Grbl_Esp32/report.h
+++ b/Grbl_Esp32/report.h
@@ -99,13 +99,13 @@
#define MESSAGE_SLEEP_MODE 11
#define MESSAGE_SD_FILE_QUIT 60 // mc_reset was called during an SD job
-#define CLIENT_NONE 0
-#define CLIENT_SERIAL 1
+#define CLIENT_SERIAL 1
#define CLIENT_BT 2
#define CLIENT_WEBUI 3
#define CLIENT_TELNET 4
+#define CLIENT_INPUT 5
#define CLIENT_ALL 0xFF
-#define CLIENT_COUNT 5 // total number of client types regardless if they are used
+#define CLIENT_COUNT 5 // total number of client types regardless if they are used
// functions to send data to the user.
void grbl_send(uint8_t client, const char *text);
diff --git a/Grbl_Esp32/serial.cpp b/Grbl_Esp32/serial.cpp
index b8db738d..5a00714e 100644
--- a/Grbl_Esp32/serial.cpp
+++ b/Grbl_Esp32/serial.cpp
@@ -89,7 +89,7 @@ void serialCheckTask(void *pvParameters)
data = Serial.read();
}
else if (inputBuffer.available()){
- client = CLIENT_NONE;
+ client = CLIENT_INPUT;
data = inputBuffer.read();
}
else
@@ -228,7 +228,7 @@ void serialCheck()
}
else if (inputBuffer.available())
{
- client = CLIENT_NONE;
+ client = CLIENT_INPUT;
data = inputBuffer.read();
}
#if defined (ENABLE_BLUETOOTH) || (defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN))
diff --git a/Grbl_Esp32/stepper.cpp b/Grbl_Esp32/stepper.cpp
index fe68ae1c..08417cd7 100644
--- a/Grbl_Esp32/stepper.cpp
+++ b/Grbl_Esp32/stepper.cpp
@@ -234,7 +234,11 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste
#else
set_stepper_pins_on(st.step_outbits);
step_pulse_off_time = esp_timer_get_time() + (settings.pulse_microseconds); // determine when to turn off pulse
- #endif
+ #endif
+
+ #ifdef USE_UNIPOLAR
+ unipolar_step(st.step_outbits, st.dir_outbits);
+ #endif
busy = true;
// If there is no step segment, attempt to pop one from the stepper buffer
@@ -435,9 +439,9 @@ void stepper_init()
set_stepper_disable(true);
#endif
- //#ifdef USE_TMC2130
- // TMC2130_Init();
- //#endif
+ #ifdef USE_UNIPOLAR
+ unipolar_init();
+ #endif
#ifdef USE_TRINAMIC
Trinamic_Init();
@@ -1505,6 +1509,10 @@ void set_stepper_disable(uint8_t isOn) // isOn = true // to disable
isOn = !isOn; // Apply pin invert.
}
+ #ifdef USE_UNIPOLAR
+ unipolar_disable(isOn);
+ #endif
+
#ifdef STEPPERS_DISABLE_PIN
digitalWrite(STEPPERS_DISABLE_PIN, isOn );
#endif
diff --git a/Grbl_Esp32/system.cpp b/Grbl_Esp32/system.cpp
index 84d1b288..41aa4ea9 100644
--- a/Grbl_Esp32/system.cpp
+++ b/Grbl_Esp32/system.cpp
@@ -22,6 +22,7 @@
#include "config.h"
xQueueHandle control_sw_queue; // used by control switch debouncing
+bool debouncing = false; // debouncing in process
void system_ini() // Renamed from system_init() due to conflict with esp32 files
{
@@ -46,21 +47,25 @@ void system_ini() // Renamed from system_init() due to conflict with esp32 files
#endif
#ifdef MACRO_BUTTON_0_PIN
+ grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 0]\r\n");
pinMode(MACRO_BUTTON_0_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_0_PIN), isr_control_inputs, CHANGE);
#endif
#ifdef MACRO_BUTTON_1_PIN
+ grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 1]\r\n");
pinMode(MACRO_BUTTON_1_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_1_PIN), isr_control_inputs, CHANGE);
#endif
#ifdef MACRO_BUTTON_2_PIN
+ grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 2]\r\n");
pinMode(MACRO_BUTTON_2_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_2_PIN), isr_control_inputs, CHANGE);
#endif
#ifdef MACRO_BUTTON_3_PIN
+ grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 3]\r\n");
pinMode(MACRO_BUTTON_3_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_3_PIN), isr_control_inputs, CHANGE);
#endif
@@ -86,22 +91,24 @@ void system_ini() // Renamed from system_init() due to conflict with esp32 files
// Setup USER_DIGITAL_PINs controlled by M62 and M63
#ifdef USER_DIGITAL_PIN_1
- pinMode(USER_DIGITAL_PIN_1, OUTPUT);
+ pinMode(USER_DIGITAL_PIN_1, OUTPUT);
+ sys_io_control(1<<1, false); // turn off
#endif
#ifdef USER_DIGITAL_PIN_2
pinMode(USER_DIGITAL_PIN_2, OUTPUT);
+ sys_io_control(1<<2, false); // turn off
#endif
#ifdef USER_DIGITAL_PIN_3
pinMode(USER_DIGITAL_PIN_3, OUTPUT);
+ sys_io_control(1<<3, false); // turn off
#endif
#ifdef USER_DIGITAL_PIN_4
pinMode(USER_DIGITAL_PIN_4, OUTPUT);
- #endif
-
- sys_io_control(0xFF, false); // turn them all off
+ sys_io_control(1<<4, false); // turn off
+ #endif
}
#ifdef ENABLE_CONTROL_SW_DEBOUNCE
@@ -111,22 +118,26 @@ void controlCheckTask(void *pvParameters)
while(true) {
int evt;
xQueueReceive(control_sw_queue, &evt, portMAX_DELAY); // block until receive queue
- vTaskDelay( CONTROL_SW_DEBOUNCE_PERIOD / portTICK_PERIOD_MS ); // delay a while
+ vTaskDelay(CONTROL_SW_DEBOUNCE_PERIOD); // delay a while
uint8_t pin = system_control_get_state();
if (pin) {
system_exec_control_pin(pin);
}
+ debouncing = false;
}
}
#endif
void IRAM_ATTR isr_control_inputs()
-{
+{
#ifdef ENABLE_CONTROL_SW_DEBOUNCE
// we will start a task that will recheck the switches after a small delay
int evt;
- xQueueSendFromISR(control_sw_queue, &evt, NULL);
+ if (!debouncing) { // prevent resending until debounce is done
+ debouncing = true;
+ xQueueSendFromISR(control_sw_queue, &evt, NULL);
+ }
#else
uint8_t pin = system_control_get_state();
system_exec_control_pin(pin);
@@ -541,17 +552,17 @@ void system_exec_control_pin(uint8_t pin) {
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
}
#ifdef MACRO_BUTTON_0_PIN
- else if (pin == 96) {
+ else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_0)) {
user_defined_macro(CONTROL_PIN_INDEX_MACRO_0); // function must be implemented by user
}
#endif
#ifdef MACRO_BUTTON_1_PIN
- else if (pin == 80) {
+ else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_1)) {
user_defined_macro(CONTROL_PIN_INDEX_MACRO_1); // function must be implemented by user
}
#endif
#ifdef MACRO_BUTTON_2_PIN
- else if (pin == 48) {
+ else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_2)) {
user_defined_macro(CONTROL_PIN_INDEX_MACRO_2); // function must be implemented by user
}
#endif