#include "estop.h"
#include "plan/jog.h"
#include "plan/calibrate.h"
+#include "plan/buffer.h"
#include "config.h"
#include <avr/pgmspace.h>
};
-stat_t command_dispatch() {
- // Read input line or return if incomplete, usart_gets() is non-blocking
- char *input = usart_readline();
- if (!input) return STAT_EAGAIN;
-
- return command_eval(input);
-}
+static char *_cmd = 0;
int command_find(const char *match) {
}
-int command_eval(char *cmd) {
- // Skip leading whitespace
- while (*cmd && isspace(*cmd)) cmd++;
+stat_t command_hi() {
+ // Get next command
+ if (!_cmd) {
+ // Read input line or return if incomplete, usart_readline() is non-blocking
+ _cmd = usart_readline();
+ if (!_cmd) return STAT_OK;
+
+ // Skip leading whitespace
+ while (*_cmd && isspace(*_cmd)) _cmd++;
+ }
+
+ if (usart_tx_full()) return STAT_OK;
+
+ stat_t status = STAT_OK;
- switch (*cmd) {
- case 0: report_request_full(); return STAT_OK;
- case '{': return vars_parser(cmd);
- case '$': return command_parser(cmd);
- default:
- if (estop_triggered()) return STAT_MACHINE_ALARMED;
- if (calibrate_busy()) return STAT_OK;
- if (mp_jog_busy()) return STAT_OK;
- return gc_gcode_parser(cmd);
+ switch (*_cmd) {
+ case 0: report_request_full(); break; // Full report
+ case '{': status = vars_parser(_cmd); break;
+ case '$': status = command_parser(_cmd); break;
+ default: return STAT_OK; // Continue processing in command_lo()
}
+
+ _cmd = 0; // Command complete
+ return status;
+}
+
+
+stat_t command_lo() {
+ if (!_cmd || mp_get_planner_buffers_available() < PLANNER_BUFFER_HEADROOM ||
+ usart_tx_full())
+ return STAT_OK; // Wait
+
+ if (estop_triggered()) return STAT_MACHINE_ALARMED;
+ if (calibrate_busy()) return STAT_BUSY;
+ if (mp_jog_busy()) return STAT_BUSY;
+
+ stat_t status = gc_gcode_parser(_cmd);
+ _cmd = 0;
+ return status;
}
// Command functions
void static print_command_help(int i) {
- static const char fmt[] PROGMEM = " $%-8S %S\n";
+ static const char fmt[] PROGMEM = " $%-12S %S\n";
const char *name = pgm_read_word(&commands[i].name);
const char *help = pgm_read_word(&commands[i].help);
} command_t;
-stat_t command_dispatch();
int command_find(const char *name);
int command_exec(int argc, char *argv[]);
-int command_eval(char *cmd);
+stat_t command_hi();
+stat_t command_lo();
#include <stdbool.h>
-/// Return eagain if TX queue is backed up
-static stat_t _sync_to_tx_buffer() {
- return usart_tx_full() ? STAT_EAGAIN : STAT_OK;
-}
-
-
-/// Return eagain if planner is not ready for a new command
-static stat_t _sync_to_planner() {
- return mp_get_planner_buffers_available() < PLANNER_BUFFER_HEADROOM ?
- STAT_EAGAIN : STAT_OK;
-}
-
-
-/// Shut down system if limit switch fired
-static stat_t _limit_switch_handler() {
- if (cm_get_machine_state() == MACHINE_ALARM) return STAT_NOOP;
- if (!switch_get_limit_thrown()) return STAT_NOOP;
-
- return CM_ALARM(STAT_LIMIT_SWITCH_HIT);
-}
-
-
static bool _dispatch(stat_t (*func)()) {
stat_t err = func();
/* Main loop
*
- * The order of the dispatched tasks is very important.
- * Tasks are ordered by increasing dependency (blocking hierarchy).
- * Tasks that are dependent on completion of lower-level tasks must be
- * later in the list than the task(s) they are dependent upon.
- *
- * Tasks must be written as continuations as they will be called repeatedly,
- * and are called even if they are not currently active.
- *
- * The DISPATCH macro calls the function and returns to the caller
- * if not finished (STAT_EAGAIN), preventing later routines from running
- * (they remain blocked). Any other condition - OK or ERR - drops through
- * and runs the next routine in the list.
+ * The task order is very important. Tasks are ordered by increasing dependency
+ * (blocking hierarchy). Tasks that are dependent on completion of lower-level
+ * tasks must be later in the list. Tasks are called repeatedly even if they
+ * are not currently active.
*
- * A routine that had no action (i.e. is OFF or idle) should return STAT_NOOP
+ * The DISPATCH macro calls a function and returns if not finished
+ * (STAT_EAGAIN). This prevents later routines from running. Any other
+ * condition - OK or ERR - drops through and runs the next routine in the list.
*/
static void _run() {
#define DISPATCH(func) if (_dispatch(func)) return;
DISPATCH(hw_reset_handler); // handle hard reset requests
- DISPATCH(_limit_switch_handler); // limit switch thrown
-
DISPATCH(tmc2660_sync); // synchronize driver config
DISPATCH(motor_power_callback); // stepper motor power sequencing
+ DISPATCH(command_hi);
+
DISPATCH(cm_feedhold_sequencing_callback); // feedhold state machine
DISPATCH(mp_plan_hold_callback); // plan a feedhold
DISPATCH(cm_arc_callback); // arc generation runs
DISPATCH(cm_homing_callback); // G28.2 continuation
DISPATCH(cm_probe_callback); // G38.2 continuation
-
- DISPATCH(_sync_to_planner); // ensure a free planning buffer
- DISPATCH(_sync_to_tx_buffer); // sync with TX buffer
DISPATCH(report_callback); // report changes
- DISPATCH(command_dispatch); // read and execute next command
+
+ DISPATCH(command_lo);
}
STAT_MSG(EAGAIN, "Run command again")
STAT_MSG(NOOP, "No op")
STAT_MSG(COMPLETE, "Complete")
+STAT_MSG(BUSY, "Busy")
STAT_MSG(NO_SUCH_DEVICE, "No such device")
STAT_MSG(BUFFER_FULL, "Buffer full")
STAT_MSG(BUFFER_FULL_FATAL, "Buffer full - fatal")
arc.ms.target[arc.plane_axis_1] = arc.center_1 + cos(arc.theta) * arc.radius;
arc.ms.target[arc.linear_axis] += arc.arc_segment_linear_travel;
mp_aline(&arc.ms); // run the line
- copy_vector(arc.position, arc.ms.target); // update arc current pos
+ copy_vector(arc.position, arc.ms.target); // update arc current pos
if (--arc.arc_segment_count > 0) return STAT_EAGAIN;
stat_t report_callback() {
+ if (usart_tx_full()) return STAT_OK; // Wait for buffer space
+
if (report_requested && usart_tx_empty()) {
uint32_t now = rtc_get_time();
if (now - last_report < 100) return STAT_OK;
// Setup pins
// Must set the SS pin either in/high or any/output for master mode to work
- TMC2660_SPI_PORT.OUTSET = 1 << TMC2660_SPI_SS_PIN; // High
+ // Note, this pin is also used by the USART as the CTS line
TMC2660_SPI_PORT.DIRSET = 1 << TMC2660_SPI_SS_PIN; // Output
TMC2660_SPI_PORT.OUTSET = 1 << TMC2660_SPI_SCK_PIN; // High
static void _set_rxc_interrupt(bool enable) {
- if (enable) USARTC0.CTRLA |= USART_RXCINTLVL_HI_gc;
- else USARTC0.CTRLA &= ~USART_RXCINTLVL_HI_gc;
+ if (enable) {
+ USARTC0.CTRLA |= USART_RXCINTLVL_HI_gc;
+ if (4 <= rx_buf_space()) PORTC.OUTCLR = 1 << 4; // CTS Lo (enable)
+
+ } else USARTC0.CTRLA &= ~USART_RXCINTLVL_HI_gc;
}
uint8_t data = USARTC0.DATA;
rx_buf_push(data);
if (usart_flags & USART_ECHO) _echo_char(data);
+ if (rx_buf_space() < 4) PORTC.OUTSET = 1 << 4; // CTS Hi (disable)
}
}
PR.PRPC &= ~PR_USART0_bm; // Disable power reduction
// Setup pins
- PORTC.OUTSET = 1 << 3; // High
- PORTC.DIRSET = 1 << 3; // Output
- PORTC.DIRCLR = 1 << 2; // Input
+ PORTC.OUTSET = 1 << 4; // CTS Hi (disable)
+ PORTC.DIRSET = 1 << 4; // CTS Output
+ PORTC.OUTSET = 1 << 3; // Tx High
+ PORTC.DIRSET = 1 << 3; // Tx Output
+ PORTC.DIRCLR = 1 << 2; // Rx Input
// Set baud rate
usart_set_baud(USART_BAUD_115200);
USART_CHSIZE_8BIT_gc;
// Configure receiver and transmitter
- USARTC0.CTRLA = USART_RXCINTLVL_HI_gc;
USARTC0.CTRLB = USART_RXEN_bm | USART_TXEN_bm | USART_CLK2X_bm;
PMIC.CTRL |= PMIC_HILVLEN_bm; // Interrupt level on
// Connect IO
stdout = &_stdout;
stderr = &_stdout;
+
+ // Enable Rx
+ _set_rxc_interrupt(true);
}
void vars_print_help() {
- static const char fmt[] PROGMEM = " $%-5s %-14S %-12S %S\n";
+ static const char fmt[] PROGMEM = " $%-5s %-20S %-16S %S\n";
// Save and disable watchdog
uint8_t wd_state = hw_disable_watchdog();
VAR(power_level, "pl", float, MOTORS, 1, 0, "Motor drive current")
VAR(idle_level, "il", float, MOTORS, 1, 0, "Motor idle current")
VAR(current_level, "cl", float, MOTORS, 1, 0, "Motor current now")
-VAR(stallguard, "sg", int8_t, MOTORS, 1, 0, "StallGuard threshold")
-VAR(sg_value, "sgv", uint16_t, MOTORS, 0, 0, "StallGuard reading")
+VAR(stallguard, "th", int8_t, MOTORS, 1, 0, "StallGuard threshold")
+VAR(sg_value, "sg", uint16_t, MOTORS, 0, 0, "StallGuard reading")
VAR(status_flags, "mf", uint8_t, MOTORS, 0, 0, "Motor status flags")
-VAR(status_strings,"mfs", flags_t, MOTORS, 0, 0, "Motor status strings")
+VAR(status_strings, "ms", flags_t, MOTORS, 0, 0, "Motor status strings")
// Axis
VAR(position, "p", float, AXES, 0, 0, "Current axis position")
// System
VAR(velocity, "v", float, 0, 0, 0, "Current velocity")
VAR(hw_id, "id", string, 0, 0, 0, "Hardware ID")
-VAR(echo, "echo", bool, 0, 1, 1, "Enable or disable echo")
-VAR(estop, "estop", bool, 0, 1, 1, "Emergency stop")
+VAR(echo, "ec", bool, 0, 1, 1, "Enable or disable echo")
+VAR(estop, "es", bool, 0, 1, 1, "Emergency stop")