Synchronized the GCodeSender with the upstream Slic3r, thanks @alexrj.

Fixes https://github.com/prusa3d/Slic3r/issues/654
This commit is contained in:
bubnikv 2018-02-12 20:44:06 +01:00
parent 6f92424bab
commit 81a80ebd61

View File

@ -7,16 +7,36 @@
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#if defined(__APPLE__) || defined(__linux) || defined(__OpenBSD__) #if defined(__APPLE__) || defined(__OpenBSD__)
#include <termios.h> #include <termios.h>
#endif #endif
#if __APPLE__ #ifdef __APPLE__
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <IOKit/serial/ioss.h> #include <IOKit/serial/ioss.h>
#endif #endif
#ifdef __linux #ifdef __linux__
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/serial.h> #include <fcntl.h>
#include "/usr/include/asm-generic/ioctls.h"
/* The following definitions are kindly borrowed from:
/usr/include/asm-generic/termbits.h
Unfortunately we cannot just include that one because
it would redefine the "struct termios" already defined
the <termios.h> already included by Boost.ASIO. */
#define K_NCCS 19
struct termios2 {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[K_NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
#define BOTHER CBAUDEX
#endif #endif
//#define DEBUG_SERIAL //#define DEBUG_SERIAL
@ -47,26 +67,26 @@ GCodeSender::connect(std::string devname, unsigned int baud_rate)
this->set_error_status(false); this->set_error_status(false);
try { try {
this->serial.open(devname); this->serial.open(devname);
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd));
this->serial.set_option(boost::asio::serial_port_base::character_size(boost::asio::serial_port_base::character_size(8)));
this->serial.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));
this->serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
this->set_baud_rate(baud_rate);
this->serial.close();
this->serial.open(devname);
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
// set baud rate again because set_option overwrote it
this->set_baud_rate(baud_rate);
this->open = true;
this->reset();
} catch (boost::system::system_error &) { } catch (boost::system::system_error &) {
this->set_error_status(true); this->set_error_status(true);
return false; return false;
} }
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd));
this->serial.set_option(boost::asio::serial_port_base::character_size(boost::asio::serial_port_base::character_size(8)));
this->serial.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));
this->serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
this->set_baud_rate(baud_rate);
this->serial.close();
this->serial.open(devname);
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
// set baud rate again because set_option overwrote it
this->set_baud_rate(baud_rate);
this->open = true;
this->reset();
// a reset firmware expect line numbers to start again from 1 // a reset firmware expect line numbers to start again from 1
this->sent = 0; this->sent = 0;
this->last_sent.clear(); this->last_sent.clear();
@ -84,6 +104,11 @@ GCodeSender::connect(std::string devname, unsigned int baud_rate)
boost::thread t(boost::bind(&boost::asio::io_service::run, &this->io)); boost::thread t(boost::bind(&boost::asio::io_service::run, &this->io));
this->background_thread.swap(t); this->background_thread.swap(t);
// always send a M105 to check for connection because firmware might be silent on connect
//FIXME Vojtech: This is being sent too early, leading to line number synchronization issues,
// from which the GCodeSender never recovers.
// this->send("M105", true);
return true; return true;
} }
@ -104,27 +129,17 @@ GCodeSender::set_baud_rate(unsigned int baud_rate)
ioctl(handle, IOSSIOSPEED, &newSpeed); ioctl(handle, IOSSIOSPEED, &newSpeed);
::tcsetattr(handle, TCSANOW, &ios); ::tcsetattr(handle, TCSANOW, &ios);
#elif __linux #elif __linux
termios ios; termios2 ios;
::tcgetattr(handle, &ios); if (ioctl(handle, TCGETS2, &ios))
::cfsetispeed(&ios, B38400); printf("Error in TCGETS2: %s\n", strerror(errno));
::cfsetospeed(&ios, B38400); ios.c_ispeed = ios.c_ospeed = baud_rate;
::tcflush(handle, TCIFLUSH); ios.c_cflag &= ~CBAUD;
::tcsetattr(handle, TCSANOW, &ios); ios.c_cflag |= BOTHER | CLOCAL | CREAD;
ios.c_cc[VMIN] = 1; // Minimum of characters to read, prevents eof errors when 0 bytes are read
struct serial_struct ss; ios.c_cc[VTIME] = 1;
ioctl(handle, TIOCGSERIAL, &ss); if (ioctl(handle, TCSETS2, &ios))
ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST; printf("Error in TCSETS2: %s\n", strerror(errno));
ss.custom_divisor = (ss.baud_base + (baud_rate / 2)) / baud_rate;
//cout << "bbase " << ss.baud_base << " div " << ss.custom_divisor;
long closestSpeed = ss.baud_base / ss.custom_divisor;
//cout << " Closest speed " << closestSpeed << endl;
ss.reserved_char[0] = 0;
if (closestSpeed < baud_rate * 98 / 100 || closestSpeed > baud_rate * 102 / 100) {
printf("Failed to set baud rate\n");
}
ioctl(handle, TIOCSSERIAL, &ss);
printf("< set_baud_rate: %u\n", baud_rate);
#elif __OpenBSD__ #elif __OpenBSD__
struct termios ios; struct termios ios;
::tcgetattr(handle, &ios); ::tcgetattr(handle, &ios);
@ -154,6 +169,7 @@ GCodeSender::disconnect()
*/ */
#ifdef DEBUG_SERIAL #ifdef DEBUG_SERIAL
fs << "DISCONNECTED" << std::endl << std::flush;
fs.close(); fs.close();
#endif #endif
} }
@ -292,17 +308,20 @@ GCodeSender::on_read(const boost::system::error_code& error,
{ {
this->set_error_status(false); this->set_error_status(false);
if (error) { if (error) {
#ifdef __APPLE__
if (error.value() == 45) { if (error.value() == 45) {
// OS X bug: http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html // OS X bug: http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html
this->do_read(); this->do_read();
} else { return;
// printf("ERROR: [%d] %s\n", error.value(), error.message().c_str()); }
// error can be true even because the serial port was closed. #endif
// In this case it is not a real error, so ignore.
if (this->open) { // printf("ERROR: [%d] %s\n", error.value(), error.message().c_str());
this->do_close(); // error can be true even because the serial port was closed.
this->set_error_status(true); // In this case it is not a real error, so ignore.
} if (this->open) {
this->do_close();
this->set_error_status(true);
} }
return; return;
} }
@ -339,7 +358,8 @@ GCodeSender::on_read(const boost::system::error_code& error,
// extract the first number from line // extract the first number from line
boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit()); boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit());
size_t toresend = boost::lexical_cast<size_t>(line.substr(0, line.find_first_not_of("0123456789"))); size_t toresend = boost::lexical_cast<size_t>(line.substr(0, line.find_first_not_of("0123456789")));
if (toresend >= this->sent - this->last_sent.size()) { ++ toresend; // N is 0-based
if (toresend >= this->sent - this->last_sent.size() && toresend < this->last_sent.size()) {
{ {
boost::lock_guard<boost::mutex> l(this->queue_mutex); boost::lock_guard<boost::mutex> l(this->queue_mutex);
@ -457,8 +477,8 @@ GCodeSender::do_send()
if (line.empty()) return; if (line.empty()) return;
// compute full line // compute full line
this->sent++;
std::string full_line = "N" + boost::lexical_cast<std::string>(this->sent) + " " + line; std::string full_line = "N" + boost::lexical_cast<std::string>(this->sent) + " " + line;
++ this->sent;
// calculate checksum // calculate checksum
int cs = 0; int cs = 0;