Reboot on estop clear, save estop state in EEPROM, stop spindle, flush USART and...
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Tue, 23 Aug 2016 06:03:09 +0000 (23:03 -0700)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Tue, 23 Aug 2016 06:03:09 +0000 (23:03 -0700)
27 files changed:
src/command.c
src/command.def
src/command.h
src/config.h
src/estop.c
src/estop.h
src/gcode_parser.c
src/hardware.c
src/homing.c
src/homing.h
src/huanyang.c
src/huanyang.h
src/i2c.c
src/i2c.h
src/machine.c
src/machine.h
src/main.c
src/plan/planner.c
src/pwm_spindle.c
src/pwm_spindle.h
src/spindle.c
src/spindle.h
src/stepper.c
src/usart.c
src/usart.h
src/vars.c
src/vars.def

index 4e6ced9ad2eb987dfc6b7f5fb262b04282f7113d..bc389504d6f84ebf2ba41b9fec1e15a7bbcd6841 100644 (file)
@@ -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"
 #include <stdlib.h>
 
 
+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;
+}
index 7f451b329338fe3285d7c724acbe81e9f04bfb0c..ee7d4b266aebdda904099e8608e0b1a2b23fe83c 100644 (file)
@@ -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")
index e6420a37ebc12156659d1d1828aa318fca4229ed..c5ef5babd04efa3663b53673ba75f3f37f3ae544 100644 (file)
@@ -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();
index 085eaf4714693de4b95c04aab469863bb03bc0bd..c75301c65609d409551ff9a314131611be77e9fa 100644 (file)
@@ -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
index fbc99380b952cced50bfd58d12157e7bb7ad2070..df1896a77f3b5327e8bca68680581a84f1e2b393 100644 (file)
 #include "spindle.h"
 #include "switch.h"
 #include "report.h"
+#include "hardware.h"
+#include "homing.h"
 #include "config.h"
 
 #include "plan/planner.h"
 
+#include <avr/eeprom.h>
+
 
 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");
   }
 }
index 189378a3b282954c6c1c07ae3b2a91b5742c850c..a493deb681f15dcbd171af0777ef05d934ab5e7b 100644 (file)
 #include <stdbool.h>
 
 
+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();
index dca9e55225032b33190fd5e77af45c7e53d7bc70..0ada698afa25a3219d8b71970cedf655875d6263 100644 (file)
@@ -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
index a279fddffb6994f4b5f2702094f0d38bac7b331f..f920a6f1b2392f95d4259beb4ef5868a2ddec0b0 100644 (file)
 #include "hardware.h"
 #include "rtc.h"
 #include "usart.h"
+#include "huanyang.h"
 #include "config.h"
 
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
+#include <avr/eeprom.h>
 #include <avr/wdt.h>
 
 #include <stdbool.h>
@@ -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
index 7c700cf298379d5eaa91396a2eba1e1af02de97f..abe4d28318bba97a4d13de4d15a71e9237946603 100644 (file)
@@ -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
index 16a2c2035782177982136c829a27add146579630..33355eaecceb9167c8c79436f7b8f6dd9dbb5efa 100644 (file)
@@ -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();
index 4167e2f071fd8034469fdcedf3a24f88daf430ee..7ec670825343849f5c29d14483480473459f28c6 100644 (file)
@@ -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;
index d3a6e9ab5e4f53f28304478ac7113d53865b5aa8..6defa889bf2d54428863253f85bf08d7855aff21 100644 (file)
@@ -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();
index 4670054fb80a26de6a5aba31b5b3e1a8e94c1316..2f2df66322e75257c08fb1bc1a39e742af8258d3 100644 (file)
--- a/src/i2c.c
+++ b/src/i2c.c
@@ -27,7 +27,6 @@
 \******************************************************************************/
 
 #include "i2c.h"
-#include "config.h"
 
 #include <avr/interrupt.h>
 
 
 
 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;}
index 53f7d6d80a98105daab4eddc5a85762bd1a7426d..9502ce47fc4e9d0ef528e712288b9ad4fab5d073 100644 (file)
--- a/src/i2c.h
+++ b/src/i2c.h
 
 #pragma once
 
-#include <stdint.h>
+#include "config.h"
 
+#include <stdbool.h>
 
-#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);
index 3710c5d23444ca3f8b53881ee0ee1403a48ceab0..5d9318356b972e1256bb9aa6404b242b8a92d0b1 100644 (file)
@@ -92,7 +92,7 @@
 #include <stdio.h>
 
 
-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();
 }
 
 
index 4eceef433dbbd6b453a5389bbc75e6f89d011c7d..a8b9ebeced4ad0bf0d5d28feafe76e09a378df5b 100644 (file)
 
 /* 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
index f68472d379853ec15e1fe57f7d540ea3bfe4ce85..3d38205756cf222ef66c23b82672aa645fd2a00f 100644 (file)
@@ -71,6 +71,7 @@ int main() {
   machine_init();                 // gcode machine
   vars_init();                    // configuration variables
   estop_init();                   // emergency stop handler
+  command_init();
 
   sei();                          // enable interrupts
 
index 1fcf7cbda72dd6c94b27866e1539896605d137a8..e779a1849c24277e41766e8600e41df9d6e728d6 100644 (file)
@@ -64,6 +64,7 @@
 #include "machine.h"
 #include "stepper.h"
 #include "motor.h"
+#include "estop.h"
 
 #include <string.h>
 #include <stdbool.h>
@@ -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;
 }
 
index 56017e9adec2dbeff855a6a6e94669f8f57af2bc..7960d7a0511fa88729da6a3dd56f75c6de0815f0 100644 (file)
@@ -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;
index 89c6fe149ae875a31f885097964604ae9db7c870..cb3ff68f741d160afb84eb7c68aee6be5b1694e8 100644 (file)
@@ -32,3 +32,4 @@
 
 void pwm_spindle_init();
 void pwm_spindle_set(machSpindleMode_t mode, float speed);
+void pwm_spindle_estop();
index 5e02a41387c597a1b05e2bb0cc8c06a5e7a9bea2..24f8dfcaa76cb73a7691ab7e7d71352f4c562a94 100644 (file)
@@ -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};
index 36f780023cea3efa70d0ae52a985b565afced0fd..2ea2fcd99c6b93a848569636868030b91fe5b5b9 100644 (file)
@@ -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();
index c597bf679e09ba808b07a163dc4db770a8e04e0e..8118fa1d6f0161cc08968d570d73eac44d5f3bf5 100644 (file)
@@ -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();
index 3846178e58e147a308177bd7e18e09d03e550145..f5340f77b0bb4a50ccc61472ab40d1a7cb795dc5 100644 (file)
@@ -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) {
index c32124b7aa2b4f239c410871cfb95f00a227ba6c..ccb3ac1217214308295d8062e7db5c8263629c7d 100644 (file)
@@ -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,
index 06e78781d648244094de35803e51b136654e6ac5..f2a6a1f034c89e591730c72d3e206103641f3432 100644 (file)
@@ -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 = "<bool>";
 #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);
index e22393df690615bc8ae7afdf0ba61d8a2bdd1925..168e479fde54b5dcdd1359f6d05a97222676a1bf 100644 (file)
@@ -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")