static void command_i2c_cb(i2c_cmd_t cmd, uint8_t *data, uint8_t length) {
switch (cmd) {
- case I2C_NULL: break;
- case I2C_ESTOP: estop_trigger(ESTOP_USER); break;
- case I2C_CLEAR: estop_clear(); break;
- case I2C_PAUSE: mp_request_hold(); break;
- case I2C_OPTIONAL_PAUSE: break; // TODO
- case I2C_RUN: mp_request_start(); break;
- case I2C_STEP: break; // TODO
- case I2C_FLUSH: mp_request_flush(); break;
- case I2C_REPORT: report_request_full(); break;
- case I2C_HOME: break; // TODO
- case I2C_REBOOT: _reboot(); break;
+ case I2C_NULL: break;
+ case I2C_ESTOP: estop_trigger(ESTOP_USER); break;
+ case I2C_CLEAR: estop_clear(); break;
+ case I2C_PAUSE: mp_request_hold(); break;
+ case I2C_OPTIONAL_PAUSE: mp_request_optional_pause(); break;
+ case I2C_RUN: mp_request_start(); break;
+ case I2C_STEP: break; // TODO
+ case I2C_FLUSH: mp_request_flush(); break;
+ case I2C_REPORT: report_request_full(); break;
+ case I2C_HOME: break; // TODO
+ case I2C_REBOOT: _reboot(); break;
case I2C_ZERO:
if (length == 0) mach_zero_all();
else if (length == 1) mach_zero_axis(_parse_axis(*data));
}
-uint8_t get_huanyang_id(int index) {
- return ha.id;
-}
-
-void set_huanyang_id(int index, uint8_t value) {
- ha.id = value;
-}
-
-
-bool get_huanyang_debug(int index) {
- return ha.debug;
-}
-
-void set_huanyang_debug(int index, uint8_t value) {
- ha.debug = value;
-}
-
-
-bool get_huanyang_connected(int index) {
- return ha.connected;
-}
-
-
-float get_huanyang_freq(int index) {
- return ha.actual_freq;
-}
-
-
-float get_huanyang_current(int index) {
- return ha.actual_current;
-}
-
-
-uint16_t get_huanyang_rpm(int index) {
- return ha.actual_rpm;
-}
-
-
-uint16_t get_huanyang_dcv(int index) {
- return ha.dc_voltage;
-}
-
-
-uint16_t get_huanyang_acv(int index) {
- return ha.ac_voltage;
-}
-
-
-uint16_t get_huanyang_temp(int index) {
- return ha.temperature;
-}
-
-
-float get_huanyang_max_freq(int index) {
- return ha.max_freq;
-}
-
-
-float get_huanyang_min_freq(int index) {
- return ha.min_freq;
-}
-
-
-uint16_t get_huanyang_rated_rpm(int index) {
- return ha.rated_rpm;
-}
-
-
-float get_huanyang_status(int index) {
- return ha.status;
-}
+uint8_t get_huanyang_id(int index) {return ha.id;}
+void set_huanyang_id(int index, uint8_t value) {ha.id = value;}
+bool get_huanyang_debug(int index) {return ha.debug;}
+void set_huanyang_debug(int index, uint8_t value) {ha.debug = value;}
+bool get_huanyang_connected(int index) {return ha.connected;}
+float get_huanyang_freq(int index) {return ha.actual_freq;}
+float get_huanyang_current(int index) {return ha.actual_current;}
+uint16_t get_huanyang_rpm(int index) {return ha.actual_rpm;}
+uint16_t get_huanyang_dcv(int index) {return ha.dc_voltage;}
+uint16_t get_huanyang_acv(int index) {return ha.ac_voltage;}
+uint16_t get_huanyang_temp(int index) {return ha.temperature;}
+float get_huanyang_max_freq(int index) {return ha.max_freq;}
+float get_huanyang_min_freq(int index) {return ha.min_freq;}
+uint16_t get_huanyang_rated_rpm(int index) {return ha.rated_rpm;}
+float get_huanyang_status(int index) {return ha.status;}
static stat_t _exec_change_tool(mp_buffer_t *bf) {
mp_runtime_set_tool(bf->value);
+ mp_set_hold_reason(HOLD_REASON_TOOL_CHANGE);
+ mp_state_holding();
return STAT_NOOP; // No move queued
}
-/// M6 This might become a complete tool change cycle
+/// M6
void mach_change_tool(bool x) {
mp_buffer_t *bf = mp_queue_get_tail();
bf->value = mach.gm.tool;
- mp_queue_push_nonstop(_exec_change_tool, mach_get_line());
+ mp_queue_push(_exec_change_tool, mach_get_line());
}
static stat_t _exec_program_stop(mp_buffer_t *bf) {
// Machine should be stopped at this point. Go into hold so that a start is
// needed before executing further instructions.
+ mp_set_hold_reason(HOLD_REASON_PROGRAM_PAUSE);
mp_state_holding();
return STAT_NOOP; // No move queued
}
}
+static stat_t _exec_optional_program_stop(mp_buffer_t *bf) {
+ mp_state_optional_pause(); // Pause here if it was requested by the user
+ return STAT_NOOP; // No move queued
+}
+
+
/// M1
void mach_optional_program_stop() {
- // TODO Check for user stop signal
- mach_program_stop();
+ mp_queue_push(_exec_optional_program_stop, mach_get_line());
+}
+
+
+static stat_t _exec_pallet_change_stop(mp_buffer_t *bf) {
+ // Emit pallet change signal
+ mp_set_hold_reason(HOLD_REASON_PALLET_CHANGE);
+ mp_state_holding();
+ return STAT_NOOP; // No move queued
}
/// M60
void mach_pallet_change_stop() {
- // TODO Emit pallet change signal
- mach_program_stop();
+ mp_queue_push(_exec_pallet_change_stop, mach_get_line());
}
/// Dequeues buffer and executes move callback
stat_t mp_exec_move() {
- if (mp_get_state() == STATE_ESTOPPED || mp_get_state() == STATE_HOLDING)
- return STAT_NOOP;
-
mp_buffer_t *bf = mp_queue_get_head();
- if (!bf) return STAT_NOOP; // Nothing running
+ if (mp_get_state() == STATE_ESTOPPED || mp_get_state() == STATE_HOLDING ||
+ !bf) {
+ mp_runtime_set_velocity(0);
+ mp_runtime_set_busy(false);
+ return STAT_NOOP; // Nothing running
+ }
if (bf->run_state == MOVE_NEW) {
// On restart wait a bit to give planner queue a chance to fill
if (status == STAT_EAGAIN || status == STAT_OK) mp_runtime_set_busy(true);
if (status != STAT_EAGAIN) {
- bool idle = false;
-
// Enter HOLDING state
if (mp_get_state() == STATE_STOPPING &&
fp_ZERO(mp_runtime_get_velocity())) {
mp_state_holding();
- idle = true;
}
// Handle buffer run state
mp_queue_pop(); // Release buffer
// Enter READY state
- if (mp_queue_is_empty()) {
- mp_state_idle();
- idle = true;
- }
+ if (mp_queue_is_empty()) mp_state_idle();
mp_set_cycle(CYCLE_MACHINING); // Default cycle
}
-
- // Queue idle
- if (idle) {
- mp_runtime_set_velocity(0);
- mp_runtime_set_busy(false);
- }
}
switch (status) {
typedef struct {
mp_state_t state;
mp_cycle_t cycle;
+ mp_hold_reason_t hold_reason;
bool hold_requested;
bool flush_requested;
bool start_requested;
bool resume_requested;
+ bool optional_pause_requested;
} planner_state_t;
};
-mp_state_t mp_get_state() {return ps.state;}
-mp_cycle_t mp_get_cycle() {return ps.cycle;}
-
-
PGM_P mp_get_state_pgmstr(mp_state_t state) {
switch (state) {
case STATE_READY: return PSTR("READY");
case STATE_HOLDING: return PSTR("HOLDING");
}
- return PSTR("invalid");
+ return PSTR("INVALID");
}
case CYCLE_JOGGING: return PSTR("JOGGING");
}
- return PSTR("invalid");
+ return PSTR("INVALID");
+}
+
+
+PGM_P mp_get_hold_reason_pgmstr(mp_hold_reason_t reason) {
+ switch (reason) {
+ case HOLD_REASON_USER_PAUSE: return PSTR("USER");
+ case HOLD_REASON_PROGRAM_PAUSE: return PSTR("PROGRAM");
+ case HOLD_REASON_PROGRAM_END: return PSTR("END");
+ case HOLD_REASON_PALLET_CHANGE: return PSTR("PALLET");
+ case HOLD_REASON_TOOL_CHANGE: return PSTR("TOOL");
+ }
+
+ return PSTR("INVALID");
}
+mp_state_t mp_get_state() {return ps.state;}
+mp_cycle_t mp_get_cycle() {return ps.cycle;}
+
+
static void _set_state(mp_state_t state) {
if (ps.state == state) return; // No change
if (ps.state == STATE_ESTOPPED) return; // Can't leave EStop state
}
+mp_hold_reason_t mp_get_hold_reason() {return ps.hold_reason;}
+
+
+void mp_set_hold_reason(mp_hold_reason_t reason) {
+ if (ps.hold_reason == reason) return; // No change
+ ps.hold_reason = reason;
+ report_request();
+}
+
+
bool mp_is_flushing() {return ps.flush_requested && !ps.resume_requested;}
bool mp_is_resuming() {return ps.resume_requested;}
}
+void mp_state_optional_pause() {
+ if (ps.optional_pause_requested) {
+ mp_set_hold_reason(HOLD_REASON_USER_PAUSE);
+ mp_state_holding();
+ }
+}
+
+
void mp_state_holding() {_set_state(STATE_HOLDING);}
void mp_request_start() {ps.start_requested = true;}
void mp_request_flush() {ps.flush_requested = true;}
void mp_request_resume() {if (ps.flush_requested) ps.resume_requested = true;}
+void mp_request_optional_pause() {ps.optional_pause_requested = true;}
/*** Feedholds, queue flushes and starts are all related. Request functions
void mp_state_callback() {
if (ps.hold_requested || ps.flush_requested) {
ps.hold_requested = false;
+ mp_set_hold_reason(HOLD_REASON_USER_PAUSE);
if (mp_get_state() == STATE_RUNNING) _set_state(STATE_STOPPING);
}
if (ps.start_requested && !ps.flush_requested &&
mp_get_state() != STATE_STOPPING) {
ps.start_requested = false;
+ ps.optional_pause_requested = false;
if (mp_get_state() == STATE_HOLDING) {
// Check if any moves are buffered
} mp_cycle_t;
-mp_state_t mp_get_state();
-mp_cycle_t mp_get_cycle();
+typedef enum {
+ HOLD_REASON_USER_PAUSE,
+ HOLD_REASON_PROGRAM_PAUSE,
+ HOLD_REASON_PROGRAM_END,
+ HOLD_REASON_PALLET_CHANGE,
+ HOLD_REASON_TOOL_CHANGE,
+} mp_hold_reason_t;
-void mp_set_cycle(mp_cycle_t cycle);
PGM_P mp_get_state_pgmstr(mp_state_t state);
PGM_P mp_get_cycle_pgmstr(mp_cycle_t cycle);
+PGM_P mp_get_hold_reason_pgmstr(mp_hold_reason_t reason);
+
+mp_state_t mp_get_state();
+
+mp_cycle_t mp_get_cycle();
+void mp_set_cycle(mp_cycle_t cycle);
+
+mp_hold_reason_t mp_get_hold_reason();
+void mp_set_hold_reason(mp_hold_reason_t reason);
bool mp_is_flushing();
bool mp_is_resuming();
bool mp_is_quiescent();
+void mp_state_optional_pause();
void mp_state_holding();
void mp_state_running();
void mp_state_idle();
void mp_request_start();
void mp_request_flush();
void mp_request_resume();
+void mp_request_optional_pause();
void mp_state_callback();
}
-// TODO implement these
-float get_max_spin(int index) {
- return 0;
-}
-
-
-void set_max_spin(int axis, float value) {
-}
-
-
-float get_spin_min_pulse(int index) {
- return 0;
-}
-
-
-void set_spin_min_pulse(int axis, float value) {
-}
-
-
-float get_spin_max_pulse(int index) {
- return 0;
-}
-
-
-void set_spin_max_pulse(int axis, float value) {
-}
-
-
-uint8_t get_spin_polarity(int index) {
- return 0;
-}
-
-
-void set_spin_polarity(int axis, uint8_t value) {
-}
-
-
-float get_spin_up(int index) {
- return 0;
-}
-
-
-void set_spin_up(int axis, float value) {
-}
-
-
-float get_spin_down(int index) {
- return 0;
-}
-
-
-void set_spin_down(int axis, float value) {
-}
+// TODO these need more effort and should work with the huanyang spindle too
+float get_max_spin(int index) {return spindle.max_rpm;}
+void set_max_spin(int axis, float value) {spindle.max_rpm = value;}
+float get_min_spin(int index) {return spindle.min_rpm;}
+void set_min_spin(int axis, float value) {spindle.min_rpm = value;}
+float get_spin_min_pulse(int index) {return spindle.min_duty;}
+void set_spin_min_pulse(int axis, float value) {spindle.min_duty = value;}
+float get_spin_max_pulse(int index) {return spindle.max_duty;}
+void set_spin_max_pulse(int axis, float value) {spindle.max_duty = value;}
+uint8_t get_spin_polarity(int index) {return spindle.reverse;}
+void set_spin_polarity(int axis, uint8_t value) {spindle.reverse = value;}
+float get_spin_up(int index) {return 0;}
+void set_spin_up(int axis, float value) {}
+float get_spin_down(int index) {return 0;}
+void set_spin_down(int axis, float value) {}
void set_echo(bool value) {return usart_set(USART_ECHO, value);}
PGM_P get_state() {return mp_get_state_pgmstr(mp_get_state());}
PGM_P get_cycle() {return mp_get_cycle_pgmstr(mp_get_cycle());}
+
+
+PGM_P get_hold_reason() {
+ return mp_get_hold_reason_pgmstr(mp_get_hold_reason());
+}
VAR(zero_backoff, "zb", float, AXES, 1, 1, "Homing zero backof")
// Spindle
-VAR(max_spin, "ss", float, 0, 1, 1, "Maximum spindle speed")
+VAR(max_spin, "sx", float, 0, 1, 1, "Maximum spindle speed")
+VAR(min_spin, "sm", float, 0, 1, 1, "Minimum spindle speed")
VAR(spindle_type, "st", uint8_t, 0, 1, 1, "PWM=0 or HUANYANG=1")
VAR(spin_min_pulse, "np", float, 0, 1, 1, "Minimum pulse width")
VAR(spin_max_pulse, "mp", float, 0, 1, 1, "Maximum pulse width")
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(state, "x", pstring, 0, 0, 0, "Machine state")
-VAR(cycle, "c", pstring, 0, 0, 0, "Machine cycle")
+VAR(state, "x", pstring, 0, 0, 0, "Machine state")
+VAR(cycle, "c", pstring, 0, 0, 0, "Machine cycle")
+VAR(hold_reason, "pr", pstring, 0, 0, 0, "Machine pause reason")