Multi-host support

This commit is contained in:
Thomas Moore
2017-11-05 08:49:38 -06:00
committed by Scott Lahteine
parent dabb75034c
commit f7efac57b7
41 changed files with 1192 additions and 747 deletions

View File

@ -58,12 +58,19 @@ uint8_t commands_in_queue = 0, // Count of commands in the queue
char command_queue[BUFSIZE][MAX_CMD_SIZE];
/*
* The port that the command was received on
*/
#if NUM_SERIAL > 1
int16_t command_queue_port[BUFSIZE];
#endif
/**
* Serial command injection
*/
// Number of characters read in the current line of serial input
static int serial_count = 0;
static int serial_count[NUM_SERIAL] = { 0 };
bool send_ok[BUFSIZE];
@ -90,8 +97,15 @@ void clear_command_queue() {
/**
* Once a new command is in the ring buffer, call this to commit it
*/
inline void _commit_command(bool say_ok) {
inline void _commit_command(bool say_ok
#if NUM_SERIAL > 1
, int16_t port = -1
#endif
) {
send_ok[cmd_queue_index_w] = say_ok;
#if NUM_SERIAL > 1
command_queue_port[cmd_queue_index_w] = port;
#endif
if (++cmd_queue_index_w >= BUFSIZE) cmd_queue_index_w = 0;
commands_in_queue++;
}
@ -101,10 +115,18 @@ inline void _commit_command(bool say_ok) {
* Return true if the command was successfully added.
* Return false for a full buffer, or if the 'command' is a comment.
*/
inline bool _enqueuecommand(const char* cmd, bool say_ok/*=false*/) {
inline bool _enqueuecommand(const char* cmd, bool say_ok
#if NUM_SERIAL > 1
, int16_t port = -1
#endif
) {
if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
strcpy(command_queue[cmd_queue_index_w], cmd);
_commit_command(say_ok);
_commit_command(say_ok
#if NUM_SERIAL > 1
, port
#endif
);
return true;
}
@ -178,21 +200,25 @@ void enqueue_and_echo_commands_P(const char * const pgcode) {
* B<int> Block queue space remaining
*/
void ok_to_send() {
#if NUM_SERIAL > 1
const int16_t port = command_queue_port[cmd_queue_index_r];
if (port < 0) return;
#endif
gcode.refresh_cmd_timeout();
if (!send_ok[cmd_queue_index_r]) return;
SERIAL_PROTOCOLPGM(MSG_OK);
SERIAL_PROTOCOLPGM_P(port, MSG_OK);
#if ENABLED(ADVANCED_OK)
char* p = command_queue[cmd_queue_index_r];
if (*p == 'N') {
SERIAL_PROTOCOL(' ');
SERIAL_ECHO(*p++);
SERIAL_PROTOCOL_P(port, ' ');
SERIAL_ECHO_P(port, *p++);
while (NUMERIC_SIGNED(*p))
SERIAL_ECHO(*p++);
SERIAL_ECHO_P(port, *p++);
}
SERIAL_PROTOCOLPGM(" P"); SERIAL_PROTOCOL(int(BLOCK_BUFFER_SIZE - planner.movesplanned() - 1));
SERIAL_PROTOCOLPGM(" B"); SERIAL_PROTOCOL(BUFSIZE - commands_in_queue);
SERIAL_PROTOCOLPGM_P(port, " P"); SERIAL_PROTOCOL_P(port, int(BLOCK_BUFFER_SIZE - planner.movesplanned() - 1));
SERIAL_PROTOCOLPGM_P(port, " B"); SERIAL_PROTOCOL_P(port, BUFSIZE - commands_in_queue);
#endif
SERIAL_EOL();
SERIAL_EOL_P(port);
}
/**
@ -200,20 +226,39 @@ void ok_to_send() {
* indicate that a command needs to be re-sent.
*/
void flush_and_request_resend() {
//char command_queue[cmd_queue_index_r][100]="Resend:";
MYSERIAL.flush();
SERIAL_PROTOCOLPGM(MSG_RESEND);
SERIAL_PROTOCOLLN(gcode_LastN + 1);
ok_to_send();
#if NUM_SERIAL > 1
const int16_t port = command_queue_port[cmd_queue_index_r];
if (port < 0) return;
#endif
SERIAL_FLUSH_P(port);
SERIAL_PROTOCOLPGM_P(port, MSG_RESEND);
SERIAL_PROTOCOLLN_P(port, gcode_LastN + 1);
}
void gcode_line_error(const char* err, bool doFlush = true) {
SERIAL_ERROR_START();
serialprintPGM(err);
SERIAL_ERRORLN(gcode_LastN);
//Serial.println(gcode_N);
if (doFlush) flush_and_request_resend();
serial_count = 0;
void gcode_line_error(const char* err, uint8_t port) {
SERIAL_ERROR_START_P(port);
serialprintPGM_P(port, err);
SERIAL_ERRORLN_P(port, gcode_LastN);
flush_and_request_resend();
serial_count[port] = 0;
}
static bool serial_data_available() {
return (MYSERIAL0.available() ? true :
#if NUM_SERIAL > 1
MYSERIAL1.available() ? true :
#endif
false);
}
static int read_serial(const int index) {
switch (index) {
case 0: return MYSERIAL0.read();
#if NUM_SERIAL > 1
case 1: return MYSERIAL1.read();
#endif
default: return -1;
}
}
/**
@ -222,15 +267,15 @@ void gcode_line_error(const char* err, bool doFlush = true) {
* left on the serial port.
*/
inline void get_serial_commands() {
static char serial_line_buffer[MAX_CMD_SIZE];
static bool serial_comment_mode = false;
static char serial_line_buffer[NUM_SERIAL][MAX_CMD_SIZE];
static bool serial_comment_mode[NUM_SERIAL] = { false };
// If the command buffer is empty for too long,
// send "wait" to indicate Marlin is still waiting.
#if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
static millis_t last_command_time = 0;
const millis_t ms = millis();
if (commands_in_queue == 0 && !MYSERIAL.available() && ELAPSED(ms, last_command_time + NO_TIMEOUTS)) {
if (commands_in_queue == 0 && !serial_data_available() && ELAPSED(ms, last_command_time + NO_TIMEOUTS)) {
SERIAL_ECHOLNPGM(MSG_WAIT);
last_command_time = ms;
}
@ -239,110 +284,117 @@ inline void get_serial_commands() {
/**
* Loop while serial characters are incoming and the queue is not full
*/
int c;
while (commands_in_queue < BUFSIZE && (c = MYSERIAL.read()) >= 0) {
char serial_char = c;
while (commands_in_queue < BUFSIZE && serial_data_available()) {
for (uint8_t i = 0; i < NUM_SERIAL; ++i) {
int c;
if ((c = read_serial(i)) < 0) continue;
/**
* If the character ends the line
*/
if (serial_char == '\n' || serial_char == '\r') {
char serial_char = c;
serial_comment_mode = false; // end of line == end of comment
/**
* If the character ends the line
*/
if (serial_char == '\n' || serial_char == '\r') {
if (!serial_count) continue; // Skip empty lines
serial_comment_mode[i] = false; // end of line == end of comment
serial_line_buffer[serial_count] = 0; // Terminate string
serial_count = 0; // Reset buffer
if (!serial_count[i]) continue; // Skip empty lines
char* command = serial_line_buffer;
serial_line_buffer[i][serial_count[i]] = 0; // Terminate string
serial_count[i] = 0; // Reset buffer
while (*command == ' ') command++; // Skip leading spaces
char *npos = (*command == 'N') ? command : NULL; // Require the N parameter to start the line
char* command = serial_line_buffer[i];
if (npos) {
while (*command == ' ') command++; // Skip leading spaces
char *npos = (*command == 'N') ? command : NULL; // Require the N parameter to start the line
bool M110 = strstr_P(command, PSTR("M110")) != NULL;
if (npos) {
if (M110) {
char* n2pos = strchr(command + 4, 'N');
if (n2pos) npos = n2pos;
}
bool M110 = strstr_P(command, PSTR("M110")) != NULL;
gcode_N = strtol(npos + 1, NULL, 10);
if (M110) {
char* n2pos = strchr(command + 4, 'N');
if (n2pos) npos = n2pos;
}
if (gcode_N != gcode_LastN + 1 && !M110) {
gcode_line_error(PSTR(MSG_ERR_LINE_NO));
return;
}
gcode_N = strtol(npos + 1, NULL, 10);
char *apos = strrchr(command, '*');
if (apos) {
uint8_t checksum = 0, count = uint8_t(apos - command);
while (count) checksum ^= command[--count];
if (strtol(apos + 1, NULL, 10) != checksum) {
gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH));
if (gcode_N != gcode_LastN + 1 && !M110) {
gcode_line_error(PSTR(MSG_ERR_LINE_NO), i);
return;
}
}
else {
gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM));
return;
char *apos = strrchr(command, '*');
if (apos) {
uint8_t checksum = 0, count = uint8_t(apos - command);
while (count) checksum ^= command[--count];
if (strtol(apos + 1, NULL, 10) != checksum) {
gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH), i);
return;
}
}
else {
gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM), i);
return;
}
gcode_LastN = gcode_N;
}
gcode_LastN = gcode_N;
}
// Movement commands alert when stopped
if (IsStopped()) {
char* gpos = strchr(command, 'G');
if (gpos) {
const int codenum = strtol(gpos + 1, NULL, 10);
switch (codenum) {
case 0:
case 1:
case 2:
case 3:
SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
break;
// Movement commands alert when stopped
if (IsStopped()) {
char* gpos = strchr(command, 'G');
if (gpos) {
const int codenum = strtol(gpos + 1, NULL, 10);
switch (codenum) {
case 0:
case 1:
case 2:
case 3:
SERIAL_ERRORLNPGM_P(i, MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
break;
}
}
}
}
#if DISABLED(EMERGENCY_PARSER)
// If command was e-stop process now
if (strcmp(command, "M108") == 0) {
wait_for_heatup = false;
#if ENABLED(ULTIPANEL)
wait_for_user = false;
#if DISABLED(EMERGENCY_PARSER)
// If command was e-stop process now
if (strcmp(command, "M108") == 0) {
wait_for_heatup = false;
#if ENABLED(ULTIPANEL)
wait_for_user = false;
#endif
}
if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
if (strcmp(command, "M410") == 0) { quickstop_stepper(); }
#endif
#if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
last_command_time = ms;
#endif
// Add the command to the queue
_enqueuecommand(serial_line_buffer[i], true
#if NUM_SERIAL > 1
, i
#endif
}
if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
if (strcmp(command, "M410") == 0) { quickstop_stepper(); }
#endif
#if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
last_command_time = ms;
#endif
// Add the command to the queue
_enqueuecommand(serial_line_buffer, true);
}
else if (serial_count >= MAX_CMD_SIZE - 1) {
// Keep fetching, but ignore normal characters beyond the max length
// The command will be injected when EOL is reached
}
else if (serial_char == '\\') { // Handle escapes
// if we have one more character, copy it over
if ((c = MYSERIAL.read()) >= 0 && !serial_comment_mode)
serial_line_buffer[serial_count++] = serial_char;
}
else { // it's not a newline, carriage return or escape char
if (serial_char == ';') serial_comment_mode = true;
if (!serial_comment_mode) serial_line_buffer[serial_count++] = serial_char;
}
);
}
else if (serial_count[i] >= MAX_CMD_SIZE - 1) {
// Keep fetching, but ignore normal characters beyond the max length
// The command will be injected when EOL is reached
}
else if (serial_char == '\\') { // Handle escapes
// if we have one more character, copy it over
if ((c = read_serial(i)) >= 0 && !serial_comment_mode[i])
serial_line_buffer[i][serial_count[i]++] = serial_char;
}
else { // it's not a newline, carriage return or escape char
if (serial_char == ';') serial_comment_mode[i] = true;
if (!serial_comment_mode[i]) serial_line_buffer[i][serial_count[i]++] = serial_char;
}
} // for NUM_SERIAL
} // queue has space, serial has data
}