Initial work for a controller GUI

This commit is contained in:
Alessandro Ranellucci 2014-12-31 19:10:46 +01:00
parent 29d64107de
commit c06ce3b58c
7 changed files with 276 additions and 6 deletions

View File

@ -9,6 +9,8 @@ use Slic3r::GUI::AboutDialog;
use Slic3r::GUI::BedShapeDialog;
use Slic3r::GUI::BonjourBrowser;
use Slic3r::GUI::ConfigWizard;
use Slic3r::GUI::Controller::Frame;
use Slic3r::GUI::Controller::PrinterPanel;
use Slic3r::GUI::MainFrame;
use Slic3r::GUI::Notifier;
use Slic3r::GUI::Plater;
@ -292,4 +294,12 @@ sub CallAfter {
push @cb, $cb;
}
sub show_printer_controller {
my ($self) = @_;
$self->{controller_frame} = Slic3r::GUI::Controller::Frame->new;
$self->{controller_frame}->Show;
return $self->{controller_frame};
}
1;

View File

@ -0,0 +1,33 @@
package Slic3r::GUI::Controller::Frame;
use strict;
use warnings;
use utf8;
use Wx qw(:frame :id :misc :sizer);
use Wx::Event qw(EVT_CLOSE);
use base 'Wx::Frame';
sub new {
my ($class) = @_;
my $self = $class->SUPER::new(undef, -1, "Controller", wxDefaultPosition, [500,350], wxDEFAULT_FRAME_STYLE);
$self->{sizer} = my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add(Slic3r::GUI::Controller::PrinterPanel->new($self), 1, wxEXPAND);
$self->SetSizer($sizer);
$self->SetMinSize($self->GetSize);
$sizer->SetSizeHints($self);
$self->Layout;
EVT_CLOSE($self, sub {
my (undef, $event) = @_;
# ...
$event->Skip;
});
return $self;
}
1;

View File

@ -0,0 +1,142 @@
package Slic3r::GUI::Controller::PrinterPanel;
use strict;
use warnings;
use utf8;
use Wx qw(:panel :id :misc :sizer :button :bitmap);
use Wx::Event qw(EVT_BUTTON);
use base qw(Wx::Panel Class::Accessor);
__PACKAGE__->mk_accessors(qw(sender));
sub new {
my ($class, $parent) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize);
$self->{sizer} = my $sizer = Wx::StaticBoxSizer->new(Wx::StaticBox->new($self, -1, "Printer"), wxVERTICAL);
# connection info
{
my $conn_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$sizer->Add($conn_sizer, 0, wxEXPAND);
{
my $text = Wx::StaticText->new($self, -1, "Port:", wxDefaultPosition, wxDefaultSize);
$conn_sizer->Add($text, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
}
{
$self->{serial_port_combobox} = Wx::ComboBox->new($self, -1, "", wxDefaultPosition, wxDefaultSize, []);
$self->scan_serial_ports;
$conn_sizer->Add($self->{serial_port_combobox}, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 1);
}
{
$self->{btn_rescan_serial} = my $btn = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new("$Slic3r::var/arrow_rotate_clockwise.png", wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, &Wx::wxBORDER_NONE);
$conn_sizer->Add($btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
EVT_BUTTON($self, $btn, sub { $self->scan_serial_ports });
}
{
my $text = Wx::StaticText->new($self, -1, "Speed:", wxDefaultPosition, wxDefaultSize);
$conn_sizer->Add($text, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
}
{
$self->{serial_speed_combobox} = Wx::ComboBox->new($self, -1, "250000", wxDefaultPosition, wxDefaultSize,
["115200", "250000"]);
$conn_sizer->Add($self->{serial_speed_combobox}, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
}
}
# buttons
{
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$sizer->Add($buttons_sizer, 0, wxEXPAND);
{
$self->{btn_connect} = my $btn = Wx::Button->new($self, -1, "Connect", wxDefaultPosition, wxDefaultSize);
$buttons_sizer->Add($btn, 0, wxRIGHT, 5);
EVT_BUTTON($self, $btn, \&connect);
}
{
$self->{btn_disconnect} = my $btn = Wx::Button->new($self, -1, "Disconnect", wxDefaultPosition, wxDefaultSize);
$buttons_sizer->Add($btn, 0, wxRIGHT, 5);
EVT_BUTTON($self, $btn, \&disconnect);
}
}
# status
$self->{status_text} = Wx::StaticText->new($self, -1, "Not connected", wxDefaultPosition, wxDefaultSize);
$sizer->Add($self->{status_text}, 0, wxEXPAND);
$self->SetSizer($sizer);
$self->SetMinSize($self->GetSize);
$sizer->SetSizeHints($self);
$self->_update_connection_controls;
return $self;
}
sub _update_connection_controls {
my ($self) = @_;
if ($self->sender && $self->sender->is_connected) {
$self->{btn_connect}->Hide;
$self->{btn_disconnect}->Show;
$self->{serial_port_combobox}->Disable;
$self->{serial_speed_combobox}->Disable;
$self->{btn_rescan_serial}->Disable;
} else {
$self->{btn_connect}->Show;
$self->{btn_disconnect}->Hide;
$self->{serial_port_combobox}->Enable;
$self->{serial_speed_combobox}->Enable;
$self->{btn_rescan_serial}->Enable;
}
}
sub set_status {
my ($self, $status) = @_;
$self->{status_text}->SetLabel($status);
$self->{status_text}->Refresh;
}
sub connect {
my ($self) = @_;
return if $self->sender && $self->sender->is_connected;
$self->set_status("Connecting...");
$self->sender(Slic3r::GCode::Sender->new);
my $res = $self->sender->connect(
$self->{serial_port_combobox}->GetValue,
$self->{serial_speed_combobox}->GetValue,
);
if (!$res) {
$self->set_status("Connection failed");
}
1 until $self->sender->is_connected;
$self->set_status("Connected");
$self->_update_connection_controls;
}
sub disconnect {
my ($self) = @_;
return if !$self->sender || !$self->sender->is_connected;
$self->sender->disconnect;
$self->set_status("Not connected");
$self->_update_connection_controls;
}
sub scan_serial_ports {
my ($self) = @_;
$self->{serial_port_combobox}->Clear;
# TODO: Windows ports
# UNIX and OS X
$self->{serial_port_combobox}->Append($_)
for glob '/dev/{ttyUSB,ttyACM,tty.,cu.,rfcomm}*';
}
1;

View File

@ -228,6 +228,10 @@ sub _init_menubar {
$self->_append_menu_item($windowMenu, "Select Print&er Settings Tab\tCtrl+4", 'Show the printer settings', sub {
$self->select_tab($tab_count-1);
});
$windowMenu->AppendSeparator();
$self->_append_menu_item($windowMenu, "Printer Controller", 'Show the printer controller', sub {
wxTheApp->show_printer_controller;
});
}
# Help menu

View File

@ -7,22 +7,53 @@
#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>
#if __APPLE__
#include <sys/ioctl.h>
#include <termios.h>
#include <IOKit/serial/ioss.h>
#endif
#ifdef __linux
#include <sys/ioctl.h>
#include <termios.h>
#include <linux/serial.h>
#endif
namespace Slic3r {
namespace asio = boost::asio;
GCodeSender::GCodeSender(std::string devname, unsigned int baud_rate)
GCodeSender::GCodeSender()
: io(), serial(io), can_send(false), sent(0), error(false), connected(false)
{}
GCodeSender::~GCodeSender()
{
this->disconnect();
}
bool
GCodeSender::connect(std::string devname, unsigned int baud_rate)
{
try {
this->serial.open(devname);
this->serial.set_option(asio::serial_port_base::baud_rate(baud_rate));
} catch (boost::system::system_error &e) {
this->error = true;
return false;
}
this->serial.set_option(asio::serial_port_base::parity(asio::serial_port_base::parity::odd));
this->serial.set_option(asio::serial_port_base::character_size(asio::serial_port_base::character_size(8)));
this->serial.set_option(asio::serial_port_base::flow_control(asio::serial_port_base::flow_control::none));
this->serial.set_option(asio::serial_port_base::stop_bits(asio::serial_port_base::stop_bits::one));
this->set_baud_rate(baud_rate);
this->serial.close();
this->serial.open(devname);
this->serial.set_option(asio::serial_port_base::parity(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 gives some work to the io_service before it is started
@ -32,6 +63,52 @@ GCodeSender::GCodeSender(std::string devname, unsigned int baud_rate)
// start reading in the background thread
boost::thread t(boost::bind(&asio::io_service::run, &this->io));
this->background_thread.swap(t);
return true;
}
void
GCodeSender::set_baud_rate(unsigned int baud_rate)
{
try {
// This does not support speeds > 115200
this->serial.set_option(asio::serial_port_base::baud_rate(baud_rate));
} catch (boost::system::system_error &e) {
boost::asio::serial_port::native_handle_type handle = this->serial.native_handle();
#if __APPLE__
termios ios;
::tcgetattr(handle, &ios);
::cfsetspeed(&ios, baud_rate);
speed_t newSpeed = baud_rate;
ioctl(handle, IOSSIOSPEED, &newSpeed);
::tcsetattr(handle, TCSANOW, &ios);
#endif
#ifdef __linux
termios ios;
::tcgetattr(handle, &ios);
::cfsetispeed(&ios, B38400);
::cfsetospeed(&ios, B38400);
::tcflush(handle, TCIFLUSH);
::tcsetattr(handle, TCSANOW, &ios);
struct serial_struct ss;
ioctl(handle, TIOCGSERIAL, &ss);
ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
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 * 98 / 100 || closestSpeed > baud_rate * 102 / 100) {
throw std::exception("Failed to set baud rate");
}
ioctl(handle, TIOCSSERIAL, &ss);
#else
//throw invalid_argument ("OS does not currently support custom bauds");
#endif
}
}
void

View File

@ -16,7 +16,9 @@ namespace asio = boost::asio;
class GCodeSender : private boost::noncopyable {
public:
GCodeSender(std::string devname, unsigned int baud_rate);
GCodeSender();
~GCodeSender();
bool connect(std::string devname, unsigned int baud_rate);
void send(const std::vector<std::string> &lines);
void send(const std::string &s);
void disconnect();
@ -39,6 +41,7 @@ class GCodeSender : private boost::noncopyable {
bool can_send;
size_t sent;
void set_baud_rate(unsigned int baud_rate);
void set_error_status(bool e);
void do_close();
void do_read();

View File

@ -8,12 +8,13 @@
%}
%name{Slic3r::GCode::Sender} class GCodeSender {
GCodeSender(std::string port, unsigned int baud_rate);
GCodeSender();
~GCodeSender();
bool connect(std::string port, unsigned int baud_rate);
void disconnect();
bool is_connected() const;
int queue_size() const;
void disconnect();
void send(std::string s);
};