From 321b1a90a2eb74b8b87e5f6930ab2a50c8189e94 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 8 Nov 2015 09:12:59 +0100 Subject: [PATCH 1/2] Two fixes for --debug --- lib/Slic3r/Print/Object.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 99e692de2..35198b31b 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -686,7 +686,7 @@ sub detect_surfaces_type { # as bottom surfaces (to allow for bridge detection) if (@top && @bottom) { my $overlapping = intersection_ex([ map $_->p, @top ], [ map $_->p, @bottom ]); - Slic3r::debugf " layer %d contains %d membrane(s)\n", $layerm->id, scalar(@$overlapping) + Slic3r::debugf " layer %d contains %d membrane(s)\n", $layerm->layer->id, scalar(@$overlapping) if $Slic3r::debug; @top = $difference->([map $_->expolygon, @top], $overlapping, S_TYPE_TOP); } @@ -703,7 +703,7 @@ sub detect_surfaces_type { $layerm->slices->append($_) for (@bottom, @top, @internal); Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n", - $layerm->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug; + $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug; } # clip surfaces to the fill boundaries From 21a5d6e137c9d5275f9c85b1b7f72a364d8ec0e1 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 19 Nov 2015 13:17:52 +0100 Subject: [PATCH 2/2] Several fixes to GCodeSender, including compilation on older OS X and DTR reset --- .../GUI/Controller/ManualControlDialog.pm | 3 +- xs/Build.PL | 3 +- xs/src/libslic3r/GCodeSender.cpp | 162 ++++++++++++------ xs/src/libslic3r/GCodeSender.hpp | 3 + 4 files changed, 112 insertions(+), 59 deletions(-) diff --git a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm index d22d86d79..84c61deb1 100644 --- a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm +++ b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm @@ -60,7 +60,7 @@ sub new { my ($pos) = @_; # delete any pending commands to get a smoother movement - $self->purge_queue(1); + $self->sender->purge_queue(1); $self->abs_xy_move($pos); }); $bed_sizer->Add($canvas, 0, wxEXPAND | wxRIGHT, 3); @@ -97,6 +97,7 @@ sub new { my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); $main_sizer->Add($bed_sizer, 1, wxEXPAND | wxALL, 10); $main_sizer->Add($self->CreateButtonSizer(wxCLOSE), 0, wxEXPAND); + EVT_BUTTON($self, wxID_CLOSE, sub { $self->Close }); $self->SetSizer($main_sizer); $self->SetMinSize($self->GetSize); diff --git a/xs/Build.PL b/xs/Build.PL index bdec67ace..8b88ce88a 100644 --- a/xs/Build.PL +++ b/xs/Build.PL @@ -10,7 +10,8 @@ use Module::Build::WithXSpp; # _GLIBCXX_USE_C99 : to get the long long type for g++ # HAS_BOOL : stops Perl/lib/CORE/handy.h from doing "# define bool char" for MSVC # NOGDI : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace -my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS); +# BOOST_ASIO_DISABLE_KQUEUE : prevents a Boost ASIO bug on OS X: https://svn.boost.org/trac/boost/ticket/5339 +my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS -DBOOST_ASIO_DISABLE_KQUEUE); my @INC = qw(); my @LIBS = qw(); diff --git a/xs/src/libslic3r/GCodeSender.cpp b/xs/src/libslic3r/GCodeSender.cpp index 7f6b7af08..27a2d34c5 100644 --- a/xs/src/libslic3r/GCodeSender.cpp +++ b/xs/src/libslic3r/GCodeSender.cpp @@ -36,6 +36,8 @@ GCodeSender::~GCodeSender() bool GCodeSender::connect(std::string devname, unsigned int baud_rate) { + this->disconnect(); + this->set_error_status(false); try { this->serial.open(devname); @@ -57,6 +59,7 @@ GCodeSender::connect(std::string devname, unsigned int baud_rate) // set baud rate again because set_option overwrote it this->set_baud_rate(baud_rate); this->open = true; + this->reset(); // this gives some work to the io_service before it is started // (post() runs the supplied function in its thread) @@ -117,7 +120,6 @@ void GCodeSender::disconnect() { if (!this->open) return; - this->open = false; this->connected = false; this->io.post(boost::bind(&GCodeSender::do_close, this)); @@ -262,73 +264,81 @@ GCodeSender::on_read(const boost::system::error_code& error, { this->set_error_status(false); if (error) { - // error can be true even because the serial port was closed. - // In this case it is not a real error, so ignore. - if (this->open) { - this->do_close(); - this->set_error_status(true); + if (error.value() == 45) { + // OS X bug: http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html + this->do_read(); + } else { + // printf("ERROR: [%d] %s\n", error.value(), error.message().c_str()); + // error can be true even because the serial port was closed. + // In this case it is not a real error, so ignore. + if (this->open) { + this->do_close(); + this->set_error_status(true); + } } return; } - // copy the read buffer into string std::istream is(&this->read_buffer); std::string line; std::getline(is, line); - // note that line might contain \r at its end - - // parse incoming line - if (!this->connected - && (boost::starts_with(line, "start") - || boost::starts_with(line, "Grbl "))) { - this->connected = true; - { - boost::lock_guard l(this->queue_mutex); - this->can_send = true; - } - this->send(); - } else if (boost::starts_with(line, "ok")) { - { - boost::lock_guard l(this->queue_mutex); - this->can_send = true; - } - this->send(); - } else if (boost::istarts_with(line, "resend") // Marlin uses "Resend: " - || boost::istarts_with(line, "rs")) { - // extract the first number from line - boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit()); - size_t toresend = boost::lexical_cast(line.substr(0, line.find_first_not_of("0123456789"))); - if (toresend == this->sent) { + if (!line.empty()) { + // note that line might contain \r at its end + // parse incoming line + if (!this->connected + && (boost::starts_with(line, "start") + || boost::starts_with(line, "Grbl ") + || boost::starts_with(line, "ok") + || boost::contains(line, "T:"))) { + this->connected = true; { boost::lock_guard l(this->queue_mutex); - this->priqueue.push(this->last_sent); - this->sent--; // resend it with the same line number this->can_send = true; } this->send(); + } else if (boost::starts_with(line, "ok")) { + { + boost::lock_guard l(this->queue_mutex); + this->can_send = true; + } + this->send(); + } else if (boost::istarts_with(line, "resend") // Marlin uses "Resend: " + || boost::istarts_with(line, "rs")) { + // extract the first number from line + boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit()); + size_t toresend = boost::lexical_cast(line.substr(0, line.find_first_not_of("0123456789"))); + if (toresend == this->sent) { + { + boost::lock_guard l(this->queue_mutex); + this->priqueue.push(this->last_sent); + this->sent--; // resend it with the same line number + this->can_send = true; + } + this->send(); + } else { + printf("Cannot resend %lu (last was %lu)\n", toresend, this->sent); + } + } else if (boost::starts_with(line, "wait")) { + // ignore } else { - printf("Cannot resend %lu (last was %lu)\n", toresend, this->sent); - } - } else if (boost::starts_with(line, "wait")) { - // ignore - } else { - // push any other line into the log - boost::lock_guard l(this->log_mutex); - this->log.push(line); - } - - // parse temperature info - { - size_t pos = line.find("T:"); - if (pos != std::string::npos && line.size() > pos + 2) { - // we got temperature info + // push any other line into the log boost::lock_guard l(this->log_mutex); - this->T = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2)); - - pos = line.find("B:"); + this->log.push(line); + } + + // parse temperature info + { + size_t pos = line.find("T:"); if (pos != std::string::npos && line.size() > pos + 2) { - // we got bed temperature info - this->B = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2)); + // we got temperature info + boost::lock_guard l(this->log_mutex); + this->T = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2)); + + pos = line.find("B:"); + if (pos != std::string::npos && line.size() > pos + 2) { + // we got bed temperature info + this->B = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2)); + } } } } @@ -370,6 +380,12 @@ GCodeSender::send(const std::string &line, bool priority) void GCodeSender::send() +{ + this->io.post(boost::bind(&GCodeSender::do_send, this)); +} + +void +GCodeSender::do_send() { boost::lock_guard l(this->queue_mutex); @@ -414,15 +430,47 @@ GCodeSender::do_send(const std::string &line) cs = cs ^ *it; // write line to device - asio::streambuf b; - std::ostream os(&b); - os << full_line << "*" << cs << "\n"; - asio::write(this->serial, b); + full_line += "*"; + full_line += boost::lexical_cast(cs); + full_line += "\n"; + asio::async_write(this->serial, asio::buffer(full_line), boost::bind(&GCodeSender::do_send, this)); this->last_sent = line; this->can_send = false; } +void +GCodeSender::set_DTR(bool on) +{ +#if defined(_WIN32) && !defined(__SYMBIAN32__) + asio::serial_port_service::native_handle_type handle = this->serial.native_handle(); + if (on) + EscapeCommFunction(handle, SETDTR); + else + EscapeCommFunction(handle, CLRDTR); +#else + int fd = this->serial.native_handle(); + int status; + ioctl(fd, TIOCMGET, &status); + if (on) + status |= TIOCM_DTR; + else + status &= ~TIOCM_DTR; + ioctl(fd, TIOCMSET, &status); +#endif +} + +void +GCodeSender::reset() +{ + this->set_DTR(false); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + this->set_DTR(true); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + this->set_DTR(false); + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); +} + } #ifdef SLIC3RXS diff --git a/xs/src/libslic3r/GCodeSender.hpp b/xs/src/libslic3r/GCodeSender.hpp index 5390e8e9e..6b5af95fe 100644 --- a/xs/src/libslic3r/GCodeSender.hpp +++ b/xs/src/libslic3r/GCodeSender.hpp @@ -32,6 +32,8 @@ class GCodeSender : private boost::noncopyable { std::vector purge_log(); std::string getT() const; std::string getB() const; + void set_DTR(bool on); + void reset(); private: asio::io_service io; @@ -58,6 +60,7 @@ class GCodeSender : private boost::noncopyable { void set_baud_rate(unsigned int baud_rate); void set_error_status(bool e); + void do_send(); void do_send(const std::string &line); void do_close(); void do_read();