Several fixes to GCodeSender, including compilation on older OS X and DTR reset

This commit is contained in:
Alessandro Ranellucci 2015-11-19 13:17:52 +01:00
parent e50bbc0245
commit 21a5d6e137
4 changed files with 112 additions and 59 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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<boost::mutex> l(this->queue_mutex);
this->can_send = true;
}
this->send();
} else if (boost::starts_with(line, "ok")) {
{
boost::lock_guard<boost::mutex> 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<size_t>(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<boost::mutex> 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<boost::mutex> 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<size_t>(line.substr(0, line.find_first_not_of("0123456789")));
if (toresend == this->sent) {
{
boost::lock_guard<boost::mutex> 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<boost::mutex> 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<boost::mutex> 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<boost::mutex> 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<boost::mutex> 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<std::string>(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

View File

@ -32,6 +32,8 @@ class GCodeSender : private boost::noncopyable {
std::vector<std::string> 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();