From 0e697d5bf0fbbfe2575347e3fbc99e08fdc74443 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Mon, 22 Aug 2016 23:03:09 -0700 Subject: [PATCH] Reboot on estop clear, save estop state in EEPROM, stop spindle, flush USART and wait for EEPROM write before reboot --- src/command.c | 108 ++++++++++++++++++++++---------- src/command.def | 1 + src/command.h | 1 + src/config.h | 11 +++- src/estop.c | 88 ++++++++++++++++++-------- src/estop.h | 12 +++- src/gcode_parser.c | 20 +++--- src/hardware.c | 12 +++- src/homing.c | 7 +++ src/homing.h | 1 + src/huanyang.c | 14 ++++- src/huanyang.h | 2 + src/i2c.c | 76 ++++++++++++++++------- src/i2c.h | 28 ++++++--- src/machine.c | 124 ++++++++++++++++++------------------ src/machine.h | 152 +++++++++++++++++++-------------------------- src/main.c | 1 + src/plan/planner.c | 2 + src/pwm_spindle.c | 10 ++- src/pwm_spindle.h | 1 + src/spindle.c | 8 +++ src/spindle.h | 3 +- src/stepper.c | 10 +++ src/usart.c | 2 +- src/usart.h | 1 - src/vars.c | 10 ++- src/vars.def | 1 + 27 files changed, 447 insertions(+), 259 deletions(-) diff --git a/src/command.c b/src/command.c index 4e6ced9..bc38950 100644 --- a/src/command.c +++ b/src/command.c @@ -35,6 +35,7 @@ #include "estop.h" #include "homing.h" #include "probing.h" +#include "i2c.h" #include "plan/jog.h" #include "plan/calibrate.h" #include "plan/buffer.h" @@ -50,6 +51,40 @@ #include +static char *_cmd = 0; + + +static void _estop() {estop_trigger(ESTOP_USER);} +static void _clear() {estop_clear();} +static void _pause() {mach_request_feedhold();} +static void _run() {mach_request_cycle_start();} +static void _flush(uint16_t id) {mach_request_queue_flush(id);} +static void _step() {} +static void _report() {report_request_full();} +static void _reboot() {hw_request_hard_reset();} + + +static void command_i2c_cb(i2c_cmd_t cmd, uint8_t *data, uint8_t length) { + switch (cmd) { + case I2C_ESTOP: _estop(); break; + case I2C_CLEAR: _clear(); break; + case I2C_PAUSE: _pause(); break; + case I2C_RUN: _run(); break; + case I2C_FLUSH: _flush(*(uint16_t *)data); break; + case I2C_STEP: _step(); break; + case I2C_REPORT: _report(); break; + case I2C_HOME: break; + case I2C_REBOOT: _reboot(); break; + default: break; + } +} + + +void command_init() { + i2c_set_read_callback(command_i2c_cb); +} + + // Command forward declarations // (Don't be afraid, X-Macros rock!) #define CMD(NAME, ...) \ @@ -152,49 +187,48 @@ int command_parser(char *cmd) { static char *_command_next() { + if (_cmd) return _cmd; + // Get next command - char *cmd = usart_readline(); - if (!cmd) return 0; + _cmd = usart_readline(); + if (!_cmd) return 0; // Remove leading whitespace - while (*cmd && isspace(*cmd)) cmd++; + while (*_cmd && isspace(*_cmd)) _cmd++; // Remove trailing whitespace - for (size_t len = strlen(cmd); len && isspace(cmd[len - 1]); len--) - cmd[len - 1] = 0; + for (size_t len = strlen(_cmd); len && isspace(_cmd[len - 1]); len--) + _cmd[len - 1] = 0; - return cmd; + return _cmd; } void command_callback() { - char *cmd = _command_next(); - if (!cmd) return; + if (!_command_next()) return; stat_t status = STAT_OK; - switch (*cmd) { + switch (*_cmd) { case 0: break; // Empty line - case '{': status = vars_parser(cmd); break; - case '$': status = command_parser(cmd); break; - default: - if (!cmd[1]) - switch (*cmd) { - case '!': mach_request_feedhold(); return; - case '~': mach_request_cycle_start(); return; - case '%': mach_request_queue_flush(); return; - } + case '{': status = vars_parser(_cmd); break; + case '$': status = command_parser(_cmd); break; + default: if (estop_triggered()) status = STAT_MACHINE_ALARMED; - else if (!mp_get_planner_buffer_room()) status = STAT_BUFFER_FULL; - else if (mach_arc_active()) status = STAT_BUFFER_FULL; - else if (calibrate_busy()) status = STAT_BUSY; - else if (mp_jog_busy()) status = STAT_BUSY; - else if (mach_is_homing()) status = STAT_BUSY; - else if (mach_is_probing()) status = STAT_BUSY; - else status = gc_gcode_parser(cmd); + + else if (!mp_get_planner_buffer_room() || + mach_arc_active() || + mach_is_homing() || + mach_is_probing() || + calibrate_busy() || + mp_jog_busy()) return; // Wait + + // Parse and execute GCode command + status = gc_gcode_parser(_cmd); } + _cmd = 0; // Command consumed report_request(); if (status) status_error(status); @@ -221,13 +255,6 @@ uint8_t command_help(int argc, char *argv[]) { return STAT_OK; } - puts_P(PSTR("\nSpecial Character Commands:\n" - " ! Feedhold (pause).\n" - " ~ Start cycle (unpause).\n" - " % Flush queue\n" - "\n" - "Character commands must be entered alone on a single line.")); - puts_P(PSTR("\nLine editing:\n" " ENTER Submit current command line.\n" " BS Backspace, delete last character.\n" @@ -249,7 +276,7 @@ uint8_t command_help(int argc, char *argv[]) { uint8_t command_reboot(int argc, char *argv[]) { - hw_request_hard_reset(); + _reboot(); return 0; } @@ -296,3 +323,18 @@ uint8_t command_sync(int argc, char *argv[]) { if (end) printf_P(PSTR("\n{\"sync\": %lu}\n"), x); return 0; } + + +uint8_t command_end_flush(int argc, char *argv[]) { + uint16_t id = 0; + char *end = 0; + + if (argc == 2) { + id = strtoul(argv[1], &end, 0); + if (!end) return STAT_BAD_NUMBER_FORMAT; + } + + mach_end_queue_flush(id); + + return 0; +} diff --git a/src/command.def b/src/command.def index 7f451b3..ee7d4b2 100644 --- a/src/command.def +++ b/src/command.def @@ -38,3 +38,4 @@ CMD(mreset, 0, 1, "Reset motor") CMD(calibrate, 0, 0, "Calibrate motors") CMD(messages, 0, 0, "Dump all possible status messages") CMD(sync, 1, 1, "Synchronize with queue processing") +CMD(end_flush, 0, 1, "End a flush request, with optional ID") diff --git a/src/command.h b/src/command.h index e6420a3..c5ef5ba 100644 --- a/src/command.h +++ b/src/command.h @@ -44,6 +44,7 @@ typedef struct { } command_t; +void command_init(); int command_find(const char *name); int command_exec(int argc, char *argv[]); void command_callback(); diff --git a/src/config.h b/src/config.h index 085eaf4..c75301c 100644 --- a/src/config.h +++ b/src/config.h @@ -265,8 +265,8 @@ typedef enum { // Gcode defaults #define GCODE_DEFAULT_UNITS MILLIMETERS // MILLIMETERS or INCHES -#define GCODE_DEFAULT_PLANE PLANE_XY // See machine.h -#define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 +#define GCODE_DEFAULT_PLANE PLANE_XY // See machine.h +#define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 #define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS #define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_MODE @@ -393,3 +393,10 @@ typedef enum { /// Buffers to reserve in planner before processing new input line #define PLANNER_BUFFER_HEADROOM 4 + + +// I2C +#define I2C_DEV TWIC +#define I2C_ISR TWIC_TWIS_vect +#define I2C_ADDR 0x2b +#define I2C_MAX_DATA 8 diff --git a/src/estop.c b/src/estop.c index fbc9938..df1896a 100644 --- a/src/estop.c +++ b/src/estop.c @@ -31,10 +31,14 @@ #include "spindle.h" #include "switch.h" #include "report.h" +#include "hardware.h" +#include "homing.h" #include "config.h" #include "plan/planner.h" +#include + typedef struct { bool triggered; @@ -43,19 +47,38 @@ typedef struct { static estop_t estop = {0}; +static uint16_t estop_reason_eeprom EEMEM; + + +static void _set_reason(estop_reason_t reason) { + eeprom_update_word(&estop_reason_eeprom, reason); +} + + +static estop_reason_t _get_reason() { + return eeprom_read_word(&estop_reason_eeprom); +} + static void _switch_callback(switch_id_t id, bool active) { - if (active) estop_trigger(); + if (active) estop_trigger(ESTOP_SWITCH); else estop_clear(); - - report_request(); } void estop_init() { + if (switch_is_active(SW_ESTOP)) _set_reason(ESTOP_SWITCH); + if (ESTOP_MAX <= _get_reason()) _set_reason(ESTOP_NONE); + estop.triggered = _get_reason() != ESTOP_NONE; + switch_set_callback(SW_ESTOP, _switch_callback); - OUTCLR_PIN(FAULT_PIN); // Low + // Check switch state + + + // Fault signal + if (estop.triggered) OUTSET_PIN(FAULT_PIN); // High + else OUTCLR_PIN(FAULT_PIN); // Low DIRSET_PIN(FAULT_PIN); // Output } @@ -65,37 +88,44 @@ bool estop_triggered() { } -void estop_trigger() { +void estop_trigger(estop_reason_t reason) { estop.triggered = true; // Hard stop the motors and the spindle st_shutdown(); - mach_spindle_control(SPINDLE_OFF); - - // Stop and flush motion - mach_request_feedhold(); - mach_request_queue_flush(); + mach_spindle_estop(); // Set alarm state mach_set_machine_state(MACHINE_ALARM); - // Assert fault signal - OUTSET_PIN(FAULT_PIN); // High -} + // Set axes not homed + mach_set_not_homed(); + // Save reason + _set_reason(reason); -void estop_clear() { - estop.triggered = false; + report_request(); +} - // Clear motor errors - for (int motor = 0; motor < MOTORS; motor++) - motor_reset(motor); - // Clear alarm state - mach_set_machine_state(MACHINE_READY); +void estop_clear() { + // Check if estop switch is set + if (switch_is_active(SW_ESTOP)) { + if (_get_reason() != ESTOP_SWITCH) _set_reason(ESTOP_SWITCH); + return; // Can't clear while estop switch is still active + } // Clear fault signal OUTCLR_PIN(FAULT_PIN); // Low + + estop.triggered = false; + + // Clear reason + _set_reason(ESTOP_NONE); + + // Reboot + // Note, hardware.c waits until any spindle stop command has been delivered + hw_request_hard_reset(); } @@ -105,11 +135,19 @@ bool get_estop() { void set_estop(bool value) { - bool triggered = estop_triggered(); - estop.triggered = value; + if (value == estop_triggered()) return; + if (value) estop_trigger(ESTOP_USER); + else estop_clear(); +} + - if (triggered != estop_triggered()) { - if (value) estop_trigger(); - else estop_clear(); +PGM_P get_estop_reason() { + switch (_get_reason()) { + case ESTOP_NONE: return PSTR("NONE"); + case ESTOP_USER: return PSTR("USER"); + case ESTOP_SWITCH: return PSTR("SWITCH"); + case ESTOP_LIMIT: return PSTR("LIMIT"); + case ESTOP_ALARM: return PSTR("ALARM"); + default: return PSTR("INVALID"); } } diff --git a/src/estop.h b/src/estop.h index 189378a..a493deb 100644 --- a/src/estop.h +++ b/src/estop.h @@ -30,7 +30,17 @@ #include +typedef enum { + ESTOP_NONE, + ESTOP_USER, + ESTOP_SWITCH, + ESTOP_LIMIT, + ESTOP_ALARM, + ESTOP_MAX, +} estop_reason_t; + + void estop_init(); bool estop_triggered(); -void estop_trigger(); +void estop_trigger(estop_reason_t reason); void estop_clear(); diff --git a/src/gcode_parser.c b/src/gcode_parser.c index dca9e55..0ada698 100644 --- a/src/gcode_parser.c +++ b/src/gcode_parser.c @@ -332,10 +332,13 @@ static stat_t _execute_gcode_block() { mach_set_absolute_override(false); // do the program stops and ends : M0, M1, M2, M30, M60 - if (mach.gf.program_flow) { - if (mach.gn.program_flow == PROGRAM_STOP) mach_program_stop(); - else mach_program_end(); - } + if (mach.gf.program_flow) + switch (mach.gn.program_flow) { + case PROGRAM_STOP: mach_program_stop(); break; + case PROGRAM_OPTIONAL_STOP: mach_optional_program_stop(); break; + case PROGRAM_PALLET_CHANGE_STOP: mach_pallet_change_stop(); break; + case PROGRAM_END: mach_program_end(); break; + } return status; } @@ -473,8 +476,12 @@ static stat_t _parse_gcode_block(char *buf) { case 'M': switch ((uint8_t)value) { - case 0: case 1: case 60: + case 0: SET_MODAL(MODAL_GROUP_M4, program_flow, PROGRAM_STOP); + case 1: + SET_MODAL(MODAL_GROUP_M4, program_flow, PROGRAM_OPTIONAL_STOP); + case 60: + SET_MODAL(MODAL_GROUP_M4, program_flow, PROGRAM_PALLET_CHANGE_STOP); case 2: case 30: SET_MODAL(MODAL_GROUP_M4, program_flow, PROGRAM_END); case 3: SET_MODAL(MODAL_GROUP_M7, spindle_mode, SPINDLE_CW); @@ -535,9 +542,6 @@ stat_t gc_gcode_parser(char *block) { char *msg = &none; // gcode message or 0 string uint8_t block_delete_flag; - // don't process Gcode blocks if in alarmed state - if (mach.machine_state == MACHINE_ALARM) return STAT_MACHINE_ALARMED; - _normalize_gcode_block(str, &com, &msg, &block_delete_flag); // Block delete omits the line if a / char is present in the first space diff --git a/src/hardware.c b/src/hardware.c index a279fdd..f920a6f 100644 --- a/src/hardware.c +++ b/src/hardware.c @@ -29,10 +29,12 @@ #include "hardware.h" #include "rtc.h" #include "usart.h" +#include "huanyang.h" #include "config.h" #include #include +#include #include #include @@ -58,8 +60,8 @@ static void _init_clock() { #if defined(__CLOCK_EXTERNAL_8MHZ) // external 8 Mhx Xtal w/ 4x PLL = 32 Mhz // 2-9 MHz crystal; 0.4-16 MHz XTAL w/ 16K CLK startup OSC.XOSCCTRL = OSC_FRQRANGE_2TO9_gc | OSC_XOSCSEL_XTAL_16KCLK_gc; - OSC.CTRL = OSC_XOSCEN_bm; // enable external crystal oscillator - while (!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for oscillator ready + OSC.CTRL = OSC_XOSCEN_bm; // enable external crystal oscillator + while (!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for oscillator ready OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 4; // PLL source, 4x (32 MHz sys clock) OSC.CTRL = OSC_PLLEN_bm | OSC_XOSCEN_bm; // Enable PLL & External Oscillator @@ -156,7 +158,11 @@ void hw_hard_reset() { /// Controller's rest handler void hw_reset_handler() { - if (hw.hard_reset) hw_hard_reset(); + if (hw.hard_reset) { + while (huanyang_stopping() || !usart_tx_empty() || !eeprom_is_ready()) + continue; + hw_hard_reset(); + } if (hw.bootloader) { // TODO enable bootloader interrupt vectors and jump to BOOT_SECTION_START diff --git a/src/homing.c b/src/homing.c index 7c700cf..abe4d28 100644 --- a/src/homing.c +++ b/src/homing.c @@ -347,6 +347,13 @@ bool mach_is_homing() { } +void mach_set_not_homed() { + // TODO save homed to EEPROM + for (int axis = 0; axis < AXES; axis++) + mach.homed[axis] = false; +} + + /// G28.2 homing cycle using limit switches void mach_homing_cycle_start() { // save relevant non-axis parameters from Gcode model diff --git a/src/homing.h b/src/homing.h index 16a2c20..33355ea 100644 --- a/src/homing.h +++ b/src/homing.h @@ -31,6 +31,7 @@ bool mach_is_homing(); +void mach_set_not_homed(); void mach_homing_cycle_start(); void mach_homing_cycle_start_no_set(); void mach_homing_callback(); diff --git a/src/huanyang.c b/src/huanyang.c index 4167e2f..7ec6708 100644 --- a/src/huanyang.c +++ b/src/huanyang.c @@ -113,6 +113,7 @@ typedef struct { bool connected; bool changed; + bool estop; machSpindleMode_t mode; float speed; @@ -450,7 +451,7 @@ void huanyang_init() { void huanyang_set(machSpindleMode_t mode, float speed) { - if (ha.mode != mode || ha.speed != speed) { + if ((ha.mode != mode || ha.speed != speed) && !ha.estop) { if (ha.debug) STATUS_DEBUG("huanyang: mode=%d, speed=%0.2f", mode, speed); ha.mode = mode; @@ -521,6 +522,17 @@ void huanyang_rtc_callback() { } +void huanyang_estop() { + huanyang_set(SPINDLE_OFF, 0); + huanyang_reset(); + ha.estop = true; +} + + +bool huanyang_stopping() { + return ha.estop && (ha.changed || ha.next_command_cb == _update); +} + uint8_t get_huanyang_id(int index) { return ha.id; diff --git a/src/huanyang.h b/src/huanyang.h index d3a6e9a..6defa88 100644 --- a/src/huanyang.h +++ b/src/huanyang.h @@ -34,3 +34,5 @@ void huanyang_init(); void huanyang_set(machSpindleMode_t mode, float speed); void huanyang_reset(); void huanyang_rtc_callback(); +void huanyang_estop(); +bool huanyang_stopping(); diff --git a/src/i2c.c b/src/i2c.c index 4670054..2f2df66 100644 --- a/src/i2c.c +++ b/src/i2c.c @@ -27,7 +27,6 @@ \******************************************************************************/ #include "i2c.h" -#include "config.h" #include @@ -35,47 +34,73 @@ typedef struct { - spi_cb_t cb; + i2c_read_cb_t read_cb; + i2c_write_cb_t write_cb; uint8_t data[I2C_MAX_DATA]; uint8_t length; -} spi_t; + bool done; + bool write; +} i2c_t; -static spi_t spi = {0}; +static i2c_t i2c = {0}; + + +static void _i2c_reset_command() { + i2c.length = 0; + i2c.done = true; + i2c.write = false; +} + + +static void _i2c_end_command() { + if (i2c.length && !i2c.write && i2c.read_cb) + i2c.read_cb(*i2c.data, i2c.data + 1, i2c.length - 1); + + _i2c_reset_command(); +} + + +static void _i2c_command_byte(uint8_t byte) { + i2c.data[i2c.length++] = byte; +} ISR(I2C_ISR) { - static bool first = false; uint8_t status = I2C_DEV.SLAVE.STATUS; // Error or collision - if (status & (TWI_SLAVE_BUSERR_bm | TWI_SLAVE_COLL_bm)) return; // Ignore + if (status & (TWI_SLAVE_BUSERR_bm | TWI_SLAVE_COLL_bm)) { + _i2c_reset_command(); + return; // Ignore - // Address match - else if ((status & TWI_SLAVE_APIF_bm) && (status & TWI_SLAVE_AP_bm)) { + } else if ((status & TWI_SLAVE_APIF_bm) && (status & TWI_SLAVE_AP_bm)) { + // START + address match I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; // ACK address byte - first = true; - spi.length = 0; + _i2c_end_command(); // Handle repeated START - } else if (status & TWI_SLAVE_APIF_bm) { // STOP interrupt + } else if (status & TWI_SLAVE_APIF_bm) { + // STOP I2C_DEV.SLAVE.STATUS = TWI_SLAVE_APIF_bm; // Clear interrupt flag - if (spi.cb) spi.cb(spi.data, spi.length); + _i2c_end_command(); - } else if (status & TWI_SLAVE_DIF_bm) { // Data interrupt - if (status & TWI_SLAVE_DIR_bm) { // Write + } else if (status & TWI_SLAVE_DIF_bm) { + i2c.write = status & TWI_SLAVE_DIR_bm; + + // DATA + if (i2c.write) { // Write // Check if master ACKed last byte sent - if (status & TWI_SLAVE_RXACK_bm && !first) + if (i2c.length && (status & TWI_SLAVE_RXACK_bm || i2c.done)) I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; // End transaction else { - I2C_DEV.SLAVE.DATA = 0; // Send some data + // Send some data + i2c.done = false; + I2C_DEV.SLAVE.DATA = i2c.write_cb(i2c.length++, &i2c.done); I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; // Continue transaction } - first = false; - } else { // Read - uint8_t data = I2C_DEV.SLAVE.DATA; - if (spi.length < I2C_MAX_DATA) spi.data[spi.length++] = data; + _i2c_command_byte(I2C_DEV.SLAVE.DATA); // ACK and continue transaction I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; @@ -84,11 +109,20 @@ ISR(I2C_ISR) { } +static uint8_t _i2c_default_write_cb(uint8_t offset, bool *done) { + *done = true; + return 0; +} + + void i2c_init() { + i2c_set_write_callback(_i2c_default_write_cb); + I2C_DEV.SLAVE.CTRLA = TWI_SLAVE_INTLVL_HI_gc | TWI_SLAVE_DIEN_bm | TWI_SLAVE_ENABLE_bm | TWI_SLAVE_APIEN_bm | TWI_SLAVE_PIEN_bm; I2C_DEV.SLAVE.ADDR = I2C_ADDR << 1; } -void i2c_set_callback(spi_cb_t cb) {spi.cb = cb;} +void i2c_set_read_callback(i2c_read_cb_t cb) {i2c.read_cb = cb;} +void i2c_set_write_callback(i2c_write_cb_t cb) {i2c.write_cb = cb;} diff --git a/src/i2c.h b/src/i2c.h index 53f7d6d..9502ce4 100644 --- a/src/i2c.h +++ b/src/i2c.h @@ -28,16 +28,30 @@ #pragma once -#include +#include "config.h" +#include -#define I2C_DEV TWIC -#define I2C_ISR TWIC_TWIS_vect -#define I2C_ADDR 0x2b -#define I2C_MAX_DATA 8 +typedef enum { + I2C_NULL, + I2C_ESTOP, + I2C_CLEAR, + I2C_PAUSE, + I2C_OPTIONAL_PAUSE, + I2C_RUN, + I2C_FLUSH, + I2C_STEP, + I2C_REPORT, + I2C_HOME, + I2C_REBOOT, +} i2c_cmd_t; + + +typedef void (*i2c_read_cb_t)(i2c_cmd_t cmd, uint8_t *data, uint8_t length); +typedef uint8_t (*i2c_write_cb_t)(uint8_t offset, bool *done); -typedef void (*spi_cb_t)(uint8_t *data, uint8_t length); void i2c_init(); -void i2c_set_callback(spi_cb_t cb); +void i2c_set_read_callback(i2c_read_cb_t cb); +void i2c_set_write_callback(i2c_write_cb_t cb); diff --git a/src/machine.c b/src/machine.c index 3710c5d..5d93183 100644 --- a/src/machine.c +++ b/src/machine.c @@ -92,7 +92,7 @@ #include -machSingleton_t mach = { +machine_t mach = { // Offsets .offset = { {}, // ABSOLUTE_COORDS @@ -181,7 +181,6 @@ machSingleton_t mach = { } }, - .combined_state = COMBINED_READY, .machine_state = MACHINE_READY, // State @@ -201,25 +200,6 @@ static void _exec_absolute_origin(float *value, float *flag); static void _exec_program_finalize(float *value, float *flag); // Machine State functions - -/// Combines raw states into something a user might want to see -machCombinedState_t mach_get_combined_state() { - if (mach.cycle_state == CYCLE_OFF) mach.combined_state = mach.machine_state; - else if (mach.cycle_state == CYCLE_PROBE) - mach.combined_state = COMBINED_PROBE; - else if (mach.cycle_state == CYCLE_HOMING) - mach.combined_state = COMBINED_HOMING; - else { - if (mach.motion_state == MOTION_RUN) mach.combined_state = COMBINED_RUN; - if (mach.motion_state == MOTION_HOLD) mach.combined_state = COMBINED_HOLD; - } - - if (mach.machine_state == MACHINE_SHUTDOWN) - mach.combined_state = COMBINED_SHUTDOWN; - - return mach.combined_state; -} - uint32_t mach_get_line() {return mach.gm.line;} machMachineState_t mach_get_machine_state() {return mach.machine_state;} machCycleState_t mach_get_cycle_state() {return mach.cycle_state;} @@ -664,12 +644,12 @@ void machine_init() { /// Alarm state; send an exception report and stop processing input stat_t mach_alarm(const char *location, stat_t code) { status_message_P(location, STAT_LEVEL_ERROR, code, "ALARM"); - estop_trigger(); + estop_trigger(ESTOP_ALARM); return code; } -/// Clear soft alarm +/// Clear alarm stat_t mach_clear() { if (mach.cycle_state == CYCLE_OFF) mach.machine_state = MACHINE_PROGRAM_STOP; @@ -700,8 +680,7 @@ void mach_set_distance_mode(machDistanceMode_t mode) { /* G10 L2 Pn, delayed persistence * - * This function applies the offset to the GM model. You can also - * use $g54x - $g59c config functions to change offsets. + * This function applies the offset to the GM model. * * It also does not reset the work_offsets which may be * accomplished by calling mach_set_work_offsets() immediately @@ -709,8 +688,7 @@ void mach_set_distance_mode(machDistanceMode_t mode) { */ void mach_set_coord_offsets(machCoordSystem_t coord_system, float offset[], float flag[]) { - if (coord_system < G54 || coord_system > COORD_SYSTEM_MAX) - return; // you can't set G53 + if (coord_system < G54 || MAX_COORDS <= coord_system) return; for (int axis = 0; axis < AXES; axis++) if (fp_TRUE(flag[axis])) @@ -1122,61 +1100,71 @@ void mach_message(const char *message) { * functions set flags for these. The sequencing callback interprets the flags * according to the following rules: * - * A feedhold request received during motion should be honored - * A feedhold request received during a feedhold should be ignored and reset - * A feedhold request received during a motion stop should be ignored and - * reset + * Feedhold request received during motion is honored + * Feedhold request received during a feedhold is ignored and reset + * Feedhold request received during a motion stop is ignored and reset * - * A queue flush request received during motion should be ignored but not - * reset - * A queue flush request received during a feedhold should be deferred until + * Queue flush request received during motion is ignored but not reset + * Queue flush request received during a feedhold is deferred until * the feedhold enters a HOLD state (i.e. until deceleration is complete) - * A queue flush request received during a motion stop should be honored + * Queue flush request received during a motion stop is honored * - * A cycle start request received during motion should be ignored and reset - * A cycle start request received during a feedhold should be deferred until + * Cycle start request received during motion is ignored and reset + * Cycle start request received during a feedhold is deferred until * the feedhold enters a HOLD state (i.e. until deceleration is complete) - * If a queue flush request is also present the queue flush should be done - * first - * A cycle start request received during a motion stop should be honored and - * should start to run anything in the planner queue + * If a queue flush request is also present the queue flush is done first + * Cycle start request received during a motion stop is honored and starts + * to run anything in the planner queue */ /// Initiate a feedhold right now void mach_request_feedhold() {mach.feedhold_requested = true;} -void mach_request_queue_flush() {mach.queue_flush_requested = true;} + + +void mach_request_queue_flush(uint16_t id) { + if (!id) mach.queue_flush_id = 0; + mach.queue_flush_request = id; +} + + +void mach_end_queue_flush(uint16_t id) { + if (mach.queue_flush_request) mach.queue_flush_id = id; +} + + +bool mach_queue_flushing() { + return mach.queue_flush_request && + (int16_t)(mach.queue_flush_id - mach.queue_flush_request) < 0; +} + + void mach_request_cycle_start() {mach.cycle_start_requested = true;} /// Process feedholds, cycle starts & queue flushes void mach_feedhold_callback() { - if (mach.feedhold_requested) { + if (mach.feedhold_requested || mach_queue_flushing()) { if (mach.motion_state == MOTION_RUN && mach.hold_state == FEEDHOLD_OFF) { mach_set_motion_state(MOTION_HOLD); - mach.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution + mach.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution } mach.feedhold_requested = false; } - if (mach.queue_flush_requested) { - if ((mach.motion_state == MOTION_STOP || - (mach.motion_state == MOTION_HOLD && - mach.hold_state == FEEDHOLD_HOLD)) && - !mach_get_runtime_busy()) { - mach.queue_flush_requested = false; - mach_queue_flush(); - } - } + if (mach_queue_flushing() && + (mach.motion_state == MOTION_STOP || + (mach.motion_state == MOTION_HOLD && + mach.hold_state == FEEDHOLD_HOLD)) && + !mach_get_runtime_busy()) mach_queue_flush(); bool processing = mach.hold_state == FEEDHOLD_SYNC || mach.hold_state == FEEDHOLD_PLAN || mach.hold_state == FEEDHOLD_DECEL; - if (mach.cycle_start_requested && !mach.queue_flush_requested && - !processing) { + if (mach.cycle_start_requested && !mach_queue_flushing() && !processing) { mach.cycle_start_requested = false; mach.hold_state = FEEDHOLD_END_HOLD; mach_cycle_start(); @@ -1206,8 +1194,9 @@ stat_t mach_queue_flush() { /* Program and cycle state functions * - * mach_program_end() implements M2 and M30 - * The END behaviors are defined by NIST 3.6.1 are: + * mach_program_end() implements M2 and M30. End behaviors are defined by + * NIST 3.6.1 are: + * * 1. Axis offsets are set to zero (like G92.2) and origin offsets are set * to the default (like G54) * 2. Selected plane is set to PLANE_XY (like G17) @@ -1220,11 +1209,11 @@ stat_t mach_queue_flush() { * 9. Coolant is turned off (like M9) * * mach_program_end() implments things slightly differently: + * * 1. Axis offsets are set to G92.1 CANCEL offsets * (instead of using G92.2 SUSPEND Offsets) - * Set default coordinate system (uses $gco, not G54) - * 2. Selected plane is set to default plane ($gpl) - * (instead of setting it to G54) + * Set default coordinate system + * 2. Selected plane is set to default plane * 3. Distance mode is set to MODE_ABSOLUTE (like G90) * 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94) * 5. Not implemented @@ -1232,10 +1221,10 @@ stat_t mach_queue_flush() { * 7. The spindle is stopped (like M5) * 8. Motion mode is canceled like G80 (not set to G1) * 9. Coolant is turned off (like M9) - * + Default INCHES or MM units mode is restored ($gun) + * + Default INCHES or MM units mode is restored */ static void _exec_program_finalize(float *value, float *flag) { - mach.machine_state = (uint8_t)value[0]; + mach.machine_state = (machMachineState_t)value[0]; mach_set_motion_state(MOTION_STOP); if (mach.cycle_state == CYCLE_MACHINING) mach.cycle_state = CYCLE_OFF; // don't end cycle if homing, probing, etc @@ -1286,8 +1275,15 @@ void mach_program_stop() { /// M1 void mach_optional_program_stop() { - float value[AXES] = {MACHINE_PROGRAM_STOP}; - mp_queue_command(_exec_program_finalize, value, value); + // TODO Check for user stop signal + mach_program_stop(); +} + + +/// M60 +void mach_pallet_change_stop() { + // TODO Emit pallet change signal + mach_program_stop(); } diff --git a/src/machine.h b/src/machine.h index 4eceef4..a8b9ebe 100644 --- a/src/machine.h +++ b/src/machine.h @@ -44,56 +44,35 @@ /* Machine state model * - * The following main variables track machine state and state - * transitions. - * - mach.machine_state - overall state of machine and program execution - * - mach.cycle_state - what cycle the machine is executing (or none) - * - mach.motion_state - state of movement + * The following main variables track machine state and state transitions. * - * Allowed states and combined states: + * machine_state - overall state of machine and program execution + * cycle_state - what cycle the machine is executing (or none) + * motion_state - state of movement * - * MACHINE STATE CYCLE STATE MOTION_STATE COMBINED_STATE (FYI) - * ------------- ------------ ------------- -------------------- - * MACHINE_UNINIT na na (U) - * MACHINE_READY CYCLE_OFF MOTION_STOP (ROS) RESET-OFF-STOP - * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP (SOS) STOP-OFF-STOP - * MACHINE_PROG_END CYCLE_OFF MOTION_STOP (EOS) END-OFF-STOP + * Allowed states: * - * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP (CSS) CYCLE-START-STOP - * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN (CSR) CYCLE-START-RUN - * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD (CSH) CYCLE-START-HOLD - * MACHINE_CYCLE CYCLE_STARTED MOTION_END_HOLD (CSE) CYCLE-START-END_HOLD + * MACHINE STATE CYCLE STATE MOTION_STATE + * ------------- ------------ ------------- + * MACHINE_READY CYCLE_OFF MOTION_STOP + * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP + * MACHINE_PROG_END CYCLE_OFF MOTION_STOP * - * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP (CHS) CYCLE-HOMING-STOP - * MACHINE_CYCLE CYCLE_HOMING MOTION_RUN (CHR) CYCLE-HOMING-RUN - * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD (CHH) CYCLE-HOMING-HOLD - * MACHINE_CYCLE CYCLE_HOMING MOTION_END_HOLD (CHE) CYCLE-HOMING-END_HOLD + * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP + * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN + * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD + * + * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP + * MACHINE_CYCLE CYCLE_HOMING MOTION_RUN + * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD */ -/// check alignment with messages in config.c / msg_stat strings typedef enum { - COMBINED_INITIALIZING, // machine is initializing - COMBINED_READY, // machine is ready for use. Also null move STOP state - COMBINED_ALARM, // machine in soft alarm state - COMBINED_PROGRAM_STOP, // program stop or no more blocks - COMBINED_PROGRAM_END, // program end - COMBINED_RUN, // motion is running - COMBINED_HOLD, // motion is holding - COMBINED_PROBE, // probe cycle active - COMBINED_CYCLE, // machine is running (cycling) - COMBINED_HOMING, // homing is treated as a cycle - COMBINED_SHUTDOWN, // machine in hard alarm state (shutdown) -} machCombinedState_t; - - -typedef enum { - MACHINE_INITIALIZING, // machine is initializing MACHINE_READY, // machine is ready for use - MACHINE_ALARM, // machine in soft alarm state + MACHINE_ALARM, // machine in alarm state MACHINE_PROGRAM_STOP, // program stop or no more blocks MACHINE_PROGRAM_END, // program end MACHINE_CYCLE, // machine is running (cycling) - MACHINE_SHUTDOWN, // machine in hard alarm state (shutdown) } machMachineState_t; @@ -108,7 +87,7 @@ typedef enum { typedef enum { MOTION_STOP, // motion has stopped MOTION_RUN, // machine is in motion - MOTION_HOLD // feedhold in progress + MOTION_HOLD, // feedhold in progress } machMotionState_t; @@ -118,14 +97,14 @@ typedef enum { // feedhold_state machine FEEDHOLD_PLAN, // replan blocks for feedhold FEEDHOLD_DECEL, // decelerate to hold point FEEDHOLD_HOLD, // holding - FEEDHOLD_END_HOLD // end hold (transient state to OFF) + FEEDHOLD_END_HOLD, // end hold (transient state to OFF) } machFeedholdState_t; typedef enum { // applies to mach.homing_state - HOMING_NOT_HOMED, // machine is not homed (0=false) - HOMING_HOMED, // machine is homed (1=true) - HOMING_WAITING // machine waiting to be homed + HOMING_NOT_HOMED, // machine is not homed + HOMING_HOMED, // machine is homed + HOMING_WAITING, // machine waiting to be homed } machHomingState_t; @@ -136,9 +115,9 @@ typedef enum { // applies to mach.probe_state } machProbeState_t; -/* The difference between NextAction and MotionMode is that NextAction is - * used by the current block, and may carry non-modal commands, whereas - * MotionMode persists across blocks (as G modal group 1) +/* The difference between machNextAction_t and machMotionMode_ is that + * machNextAction_t is used by the current block, and may carry non-modal + * commands, whereas machMotionMode_t persists across blocks as G modal group 1 */ /// these are in order to optimized CASE statement @@ -157,7 +136,7 @@ typedef enum { NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS, // G92.2 NEXT_ACTION_RESUME_ORIGIN_OFFSETS, // G92.3 NEXT_ACTION_DWELL, // G4 - NEXT_ACTION_STRAIGHT_PROBE // G38.2 + NEXT_ACTION_STRAIGHT_PROBE, // G38.2 } machNextAction_t; @@ -201,55 +180,49 @@ typedef enum { // Used for detecting gcode errors. See NIST section 3.4 #define MODAL_GROUP_COUNT (MODAL_GROUP_M9 + 1) -// Note 1: Our G0 omits G4,G30,G53,G92.1,G92.2,G92.3 as these have no axis +// Note 1: Our G0 omits G4, G30, G53, G92.1, G92.2, G92.3 as these have no axis // components to error check typedef enum { // plane - translates to: - // axis_0 axis_1 axis_2 - PLANE_XY, // G17 X Y Z - PLANE_XZ, // G18 X Z Y - PLANE_YZ // G19 Y Z X + // axis_0 axis_1 axis_2 + PLANE_XY, // G17 X Y Z + PLANE_XZ, // G18 X Z Y + PLANE_YZ, // G19 Y Z X } machPlane_t; typedef enum { INCHES, // G20 MILLIMETERS, // G21 - DEGREES // ABC axes (this value used for displays only) + DEGREES, // ABC axes (this value used for displays only) } machUnitsMode_t; typedef enum { ABSOLUTE_COORDS, // machine coordinate system - G54, // G54 coordinate system - G55, // G55 coordinate system - G56, // G56 coordinate system - G57, // G57 coordinate system - G58, // G58 coordinate system - G59 // G59 coordinate system + G54, G55, G56, G57, G58, G59, + MAX_COORDS, } machCoordSystem_t; -#define COORD_SYSTEM_MAX G59 // set this manually to the last one - /// G Modal Group 13 typedef enum { /// G61 - hits corners but does not stop if it does not need to. PATH_EXACT_PATH, PATH_EXACT_STOP, // G61.1 - stops at all corners - PATH_CONTINUOUS // G64 and typically the default mode + PATH_CONTINUOUS, // G64 and typically the default mode } machPathControlMode_t; typedef enum { ABSOLUTE_MODE, // G90 - INCREMENTAL_MODE // G91 + INCREMENTAL_MODE, // G91 } machDistanceMode_t; typedef enum { INVERSE_TIME_MODE, // G93 UNITS_PER_MINUTE_MODE, // G94 - UNITS_PER_REVOLUTION_MODE // G95 (unimplemented) + UNITS_PER_REVOLUTION_MODE, // G95 (unimplemented) } machFeedRateMode_t; @@ -257,13 +230,15 @@ typedef enum { ORIGIN_OFFSET_SET, // G92 - set origin offsets ORIGIN_OFFSET_CANCEL, // G92.1 - zero out origin offsets ORIGIN_OFFSET_SUSPEND, // G92.2 - do not apply offsets, but preserve values - ORIGIN_OFFSET_RESUME // G92.3 - resume application of the suspended offsets + ORIGIN_OFFSET_RESUME, // G92.3 - resume application of the suspended offsets } machOriginOffset_t; typedef enum { PROGRAM_STOP, - PROGRAM_END + PROGRAM_OPTIONAL_STOP, + PROGRAM_PALLET_CHANGE_STOP, + PROGRAM_END, } machProgramFlow_t; @@ -271,7 +246,7 @@ typedef enum { typedef enum { SPINDLE_OFF, SPINDLE_CW, - SPINDLE_CCW + SPINDLE_CCW, } machSpindleMode_t; @@ -280,14 +255,14 @@ typedef enum { COOLANT_OFF, // all coolant off COOLANT_ON, // request coolant on or indicate both coolants are on COOLANT_MIST, // indicates mist coolant on - COOLANT_FLOOD // indicates flood coolant on + COOLANT_FLOOD, // indicates flood coolant on } machCoolantState_t; /// used for spindle and arc dir typedef enum { DIRECTION_CW, - DIRECTION_CCW + DIRECTION_CCW, } machDirection_t; @@ -297,7 +272,7 @@ typedef enum { AXIS_STANDARD, // axis in coordinated motion w/standard behaviors AXIS_INHIBITED, // axis is computed but not activated AXIS_RADIUS, // rotary axis calibrated to circumference - AXIS_MODE_MAX + AXIS_MODE_MAX, } machAxisMode_t; // ordering must be preserved. @@ -350,7 +325,7 @@ typedef struct { bool spindle_override_enable; // true = override enabled machMotionMode_t motion_mode; // Group 1 modal motion - machPlane_t select_plane; // G17, G18, G19 + machPlane_t select_plane; // G17, G18, G19 machUnitsMode_t units_mode; // G20, G21 machCoordSystem_t coord_system; // G54-G59 - select coordinate system 1-9 bool absolute_override; // G53 true = move in machine coordinates @@ -399,47 +374,46 @@ typedef struct { typedef struct { // struct to manage mach globals and cycles - // coordinate systems and offsets absolute (G53) + G54,G55,G56,G57,G58,G59 + // coordinate systems & offsets absolute (G53) + G54, G55, G56, G57, G58, G59 float offset[COORDS + 1][AXES]; - float origin_offset[AXES]; // G92 offsets - bool origin_offset_enable; // G92 offsets enabled/disabled + float origin_offset[AXES]; // G92 offsets + bool origin_offset_enable; // G92 offsets enabled/disabled - float position[AXES]; // model position (not used in gn or gf) - float g28_position[AXES]; // stored machine position for G28 - float g30_position[AXES]; // stored machine position for G30 + float position[AXES]; // model position (not used in gn or gf) + float g28_position[AXES]; // stored machine position for G28 + float g30_position[AXES]; // stored machine position for G30 // settings for axes X,Y,Z,A B,C AxisConfig_t a[AXES]; - machCombinedState_t combined_state; // combination of states for display machMachineState_t machine_state; machCycleState_t cycle_state; machMotionState_t motion_state; - machFeedholdState_t hold_state; // hold: feedhold sub-state machine - machHomingState_t homing_state; // home: homing cycle sub-state machine + machFeedholdState_t hold_state; // hold: feedhold sub-state machine + machHomingState_t homing_state; // home: homing cycle sub-state machine bool homed[AXES]; // individual axis homing flags machProbeState_t probe_state; float probe_results[AXES]; // probing results - bool feedhold_requested; // feedhold character received - bool queue_flush_requested; // queue flush character received - bool cycle_start_requested; // cycle start character received + bool feedhold_requested; + uint16_t queue_flush_request; // queue flush request id + uint16_t queue_flush_id; // latest queue flush request id + bool cycle_start_requested; // Model states MoveState_t ms; GCodeState_t gm; // core gcode model state GCodeState_t gn; // gcode input values GCodeState_t gf; // gcode input flags -} machSingleton_t; +} machine_t; -extern machSingleton_t mach; // machine controller singleton +extern machine_t mach; // machine controller singleton // Model state getters and setters uint32_t mach_get_line(); -machCombinedState_t mach_get_combined_state(); machMachineState_t mach_get_machine_state(); machCycleState_t mach_get_cycle_state(); machMotionState_t mach_get_motion_state(); @@ -551,7 +525,8 @@ void mach_message(const char *message); // Program Functions (4.3.10) void mach_request_feedhold(); -void mach_request_queue_flush(); +void mach_request_queue_flush(uint16_t id); +void mach_end_queue_flush(uint16_t id); void mach_request_cycle_start(); void mach_feedhold_callback(); @@ -562,6 +537,7 @@ void mach_cycle_end(); void mach_feedhold(); void mach_program_stop(); void mach_optional_program_stop(); +void mach_pallet_change_stop(); void mach_program_end(); // Cycles diff --git a/src/main.c b/src/main.c index f68472d..3d38205 100644 --- a/src/main.c +++ b/src/main.c @@ -71,6 +71,7 @@ int main() { machine_init(); // gcode machine vars_init(); // configuration variables estop_init(); // emergency stop handler + command_init(); sei(); // enable interrupts diff --git a/src/plan/planner.c b/src/plan/planner.c index 1fcf7cb..e779a18 100644 --- a/src/plan/planner.c +++ b/src/plan/planner.c @@ -64,6 +64,7 @@ #include "machine.h" #include "stepper.h" #include "motor.h" +#include "estop.h" #include #include @@ -171,6 +172,7 @@ float mp_get_runtime_work_position(uint8_t axis) { /// Use this function to sync to the queue. If you wait until it returns /// FALSE you know the queue is empty and the motors have stopped. uint8_t mp_get_runtime_busy() { + if (estop_triggered()) return false; return st_runtime_isbusy() || mr.move_state == MOVE_RUN; } diff --git a/src/pwm_spindle.c b/src/pwm_spindle.c index 56017e9..7960d7a 100644 --- a/src/pwm_spindle.c +++ b/src/pwm_spindle.c @@ -39,6 +39,7 @@ typedef struct { float max_duty; bool reverse; bool enable_invert; + bool estop; } spindle_t; @@ -50,11 +51,12 @@ static spindle_t spindle = { .max_duty = SPINDLE_MAX_DUTY, .reverse = SPINDLE_POLARITY, .enable_invert = false, + .estop = false, }; static void _spindle_set_pwm(machSpindleMode_t mode, float speed) { - if (mode == SPINDLE_OFF || speed < spindle.min_rpm) { + if (mode == SPINDLE_OFF || speed < spindle.min_rpm || spindle.estop) { TIMER_PWM.CTRLA = 0; return; } @@ -127,6 +129,12 @@ void pwm_spindle_set(machSpindleMode_t mode, float speed) { } +void pwm_spindle_estop() { + spindle.estop = true; + _spindle_set_pwm(SPINDLE_OFF, 0); +} + + // TODO implement these float get_max_spin(int index) { return 0; diff --git a/src/pwm_spindle.h b/src/pwm_spindle.h index 89c6fe1..cb3ff68 100644 --- a/src/pwm_spindle.h +++ b/src/pwm_spindle.h @@ -32,3 +32,4 @@ void pwm_spindle_init(); void pwm_spindle_set(machSpindleMode_t mode, float speed); +void pwm_spindle_estop(); diff --git a/src/spindle.c b/src/spindle.c index 5e02a41..24f8dfc 100644 --- a/src/spindle.c +++ b/src/spindle.c @@ -80,6 +80,14 @@ void mach_spindle_control(machSpindleMode_t mode) { } +void mach_spindle_estop() { + switch (spindle_type) { + case SPINDLE_TYPE_PWM: pwm_spindle_estop(); break; + case SPINDLE_TYPE_HUANYANG: huanyang_estop(); break; + } +} + + /// Queue the S parameter to the planner buffer void mach_set_spindle_speed(float speed) { float value[AXES] = {speed}; diff --git a/src/spindle.h b/src/spindle.h index 36f7800..2ea2fcd 100644 --- a/src/spindle.h +++ b/src/spindle.h @@ -33,4 +33,5 @@ void mach_spindle_init(); void mach_set_spindle_speed(float speed); // S parameter -void mach_spindle_control(machSpindleMode_t spindle_mode); // M3, M4, M5 +void mach_spindle_control(machSpindleMode_t spindle_mode); // M3, M4, M5 +void mach_spindle_estop(); diff --git a/src/stepper.c b/src/stepper.c index c597bf6..8118fa1 100644 --- a/src/stepper.c +++ b/src/stepper.c @@ -35,6 +35,7 @@ #include "plan/command.h" #include "motor.h" #include "hardware.h" +#include "estop.h" #include "util.h" #include "cpp_magic.h" @@ -72,6 +73,9 @@ void stepper_init() { void st_shutdown() { for (int motor = 0; motor < MOTORS; motor++) motor_enable(motor, false); + + st.dwell = 0; + st.move_type = MOVE_TYPE_NULL; } @@ -83,6 +87,7 @@ uint8_t st_runtime_isbusy() {return st.busy;} /// ADC channel 0 triggered by load ISR as a "software" interrupt. ISR(ADCB_CH0_vect) { mp_exec_move(); + ADCB_CH0_INTCTRL = 0; st.requesting = false; } @@ -111,6 +116,11 @@ ISR(STEP_TIMER_ISR) { for (int motor = 0; motor < MOTORS; motor++) motor_end_move(motor); + if (estop_triggered()) { + st.move_type = MOVE_TYPE_NULL; + return; + } + // If the next move is not ready try to load it if (!st.move_ready) { _request_exec_move(); diff --git a/src/usart.c b/src/usart.c index 3846178..f5340f7 100644 --- a/src/usart.c +++ b/src/usart.c @@ -44,7 +44,7 @@ #define RING_BUF_SIZE USART_RX_RING_BUF_SIZE #include "ringbuf.def" -static int usart_flags = USART_CRLF | USART_ECHO; +static int usart_flags = USART_CRLF; static void _set_dre_interrupt(bool enable) { diff --git a/src/usart.h b/src/usart.h index c32124b..ccb3ac1 100644 --- a/src/usart.h +++ b/src/usart.h @@ -33,7 +33,6 @@ #define USART_TX_RING_BUF_SIZE 256 #define USART_RX_RING_BUF_SIZE 256 -#define USART_ECHO_RING_BUF_SIZE 32 enum { USART_BAUD_9600, diff --git a/src/vars.c b/src/vars.c index 06e7878..f2a6a1f 100644 --- a/src/vars.c +++ b/src/vars.c @@ -46,6 +46,7 @@ typedef uint8_t flags_t; typedef const char *string; +typedef PGM_P pstring; // Format strings @@ -56,15 +57,20 @@ static const char indexed_code_fmt[] PROGMEM = "\"%c%s\":"; // Type names static const char bool_name [] PROGMEM = ""; #define TYPE_NAME(TYPE) static const char TYPE##_name [] PROGMEM = "<" #TYPE ">" -MAP(TYPE_NAME, SEMI, flags_t, string, float, int8_t, uint8_t, uint16_t, +MAP(TYPE_NAME, SEMI, flags_t, string, pstring, float, int8_t, uint8_t, uint16_t, int32_t); // String -static void var_print_string(const char *s) { +static void var_print_string(string s) { printf_P(PSTR("\"%s\""), s); } +// Program string +static void var_print_pstring(pstring s) { + printf_P(PSTR("\"%S\""), s); +} + // Flags extern void print_status_flags(uint8_t x); diff --git a/src/vars.def b/src/vars.def index e22393d..168e479 100644 --- a/src/vars.def +++ b/src/vars.def @@ -96,5 +96,6 @@ VAR(velocity, "v", float, 0, 0, 0, "Current velocity") VAR(hw_id, "id", string, 0, 0, 0, "Hardware ID") VAR(echo, "ec", bool, 0, 1, 0, "Enable or disable echo") VAR(estop, "es", bool, 0, 1, 0, "Emergency stop") +VAR(estop_reason, "er", pstring, 0, 0, 0, "Emergency stop reason") VAR(line, "ln", int32_t, 0, 0, 0, "Last GCode line executed") VAR(queue, "q", uint16_t, 0, 0, 0, "Space in planner queue") -- 2.27.0