ENH: CLI: refine logic

1. return error when there is object partly inside the plate;
2. add the status callback for progress indicating
3. add the version in help
4. fix the return state of validation from 1 to -51

Change-Id: I716057bd5b28a4beb2871614b94708a0860af1a2
This commit is contained in:
lane.wei 2022-11-05 10:21:04 +08:00 committed by Lane.Wei
parent 8278be8d26
commit 55f55e3ad9
2 changed files with 209 additions and 6 deletions

View file

@ -22,6 +22,13 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
#if defined(__linux__) || defined(__LINUX__)
#include <condition_variable>
#include <mutex>
#include <boost/thread.hpp>
#endif
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/nowide/args.hpp> #include <boost/nowide/args.hpp>
@ -98,6 +105,8 @@ using namespace Slic3r;
#define CLI_NO_SUITABLE_OBJECTS -50 #define CLI_NO_SUITABLE_OBJECTS -50
#define CLI_VALIDATE_ERROR -51 #define CLI_VALIDATE_ERROR -51
#define CLI_OBJECTS_PARTLY_INSIDE -52
#define CLI_SLICING_ERROR -100 #define CLI_SLICING_ERROR -100
@ -122,6 +131,155 @@ std::map<int, std::string> cli_errors = {
{CLI_SLICING_ERROR, "Slice error"} {CLI_SLICING_ERROR, "Slice error"}
}; };
#if defined(__linux__) || defined(__LINUX__)
#define PIPE_BUFFER_SIZE 64
typedef struct _cli_callback_mgr {
int m_plate_count {0};
int m_plate_index;
int m_progress { 0 };
std::string m_message;
int m_warning_step;
bool m_exit {false};
bool m_data_ready {false};
bool m_started {false};
boost::thread m_thread;
// Mutex and condition variable to synchronize m_thread with the UI thread.
std::mutex m_mutex;
std::condition_variable m_condition;
int m_pipe_fd{-1};
bool is_started()
{
bool result;
std::unique_lock<std::mutex> lck(m_mutex);
result = m_started;
lck.unlock();
return result;
}
void set_plate_info(int index, int count)
{
std::unique_lock<std::mutex> lck(m_mutex);
m_plate_count = count;
m_plate_index = index;
lck.unlock();
return;
}
void notify()
{
if (m_pipe_fd < 0)
return;
std::string notify_message;
notify_message = "Plate "+ std::to_string(m_plate_index) + "/" +std::to_string(m_plate_count)+ ": Percent " + std::to_string(m_progress) + ": "+m_message;
char pipe_message[PIPE_BUFFER_SIZE] = {0};
strncpy(pipe_message, notify_message.c_str(), PIPE_BUFFER_SIZE);
int ret = write(m_pipe_fd, pipe_message,PIPE_BUFFER_SIZE);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": write returns "<<ret;
return;
}
void thread_proc()
{
std::unique_lock<std::mutex> lck(m_mutex);
m_started = true;
m_data_ready = false;
lck.unlock();
m_condition.notify_one();
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc started.";
while(1) {
lck.lock();
m_condition.wait(lck, [this](){ return m_data_ready || m_exit; });
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": wakup.";
if (m_exit) {
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc will exit.";
break;
}
notify();
m_data_ready = false;
lck.unlock();
m_condition.notify_one();
}
lck.unlock();
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc exit.";
}
void update(int percent, std::string message, int warning_step)
{
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": percent="<<percent<< ", warning_step = "<< m_warning_step<<", message="<<message;
std::unique_lock<std::mutex> lck(m_mutex);
if (!m_started) {
lck.unlock();
return;
}
if (m_progress >= percent) {
//already update before
lck.unlock();
return;
}
m_message = message;
m_progress = percent;
m_warning_step = warning_step;
m_data_ready = true;
lck.unlock();
m_condition.notify_one();
return;
}
bool start(std::string pipe_name)
{
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start enter.";
m_pipe_fd = open(pipe_name.c_str(),O_WRONLY|O_NONBLOCK);
if (m_pipe_fd < 0) {
BOOST_LOG_TRIVIAL(error) << "could not create pipe for "<<pipe_name;
return false;
}
std::unique_lock<std::mutex> lck(m_mutex);
m_thread = create_thread([this]{
this->thread_proc();
});
lck.unlock();
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start successfully.";
return true;
}
void stop()
{
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop enter.";
std::unique_lock<std::mutex> lck(m_mutex);
if (m_pipe_fd > 0) {
close(m_pipe_fd);
m_pipe_fd = -1;
}
if (!m_started) {
lck.unlock();
return;
}
m_exit = true;
lck.unlock();
m_condition.notify_one();
// Wait until the worker thread exits.
m_thread.join();
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop successfully.";
}
}cli_callback_mgr_t;
cli_callback_mgr_t g_cli_callback_mgr;
void cli_status_callback(const PrintBase::SlicingStatus& slicing_status)
{
g_cli_callback_mgr.update(slicing_status.percent, slicing_status.text, slicing_status.warning_step);
return;
}
#endif
static PrinterTechnology get_printer_technology(const DynamicConfig &config) static PrinterTechnology get_printer_technology(const DynamicConfig &config)
{ {
@ -130,10 +288,18 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config)
} }
//BBS: add flush and exit //BBS: add flush and exit
#if defined(__linux__) || defined(__LINUX__)
#define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, return "<<ret<<", exit..." << std::endl;\
g_cli_callback_mgr.stop();\
boost::nowide::cout.flush();\
boost::nowide::cerr.flush();\
return(ret);}
#else
#define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, exit" << std::endl;\ #define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, exit" << std::endl;\
boost::nowide::cout.flush();\ boost::nowide::cout.flush();\
boost::nowide::cerr.flush();\ boost::nowide::cerr.flush();\
return(ret);} return(ret);}
#endif
static void glfw_callback(int error_code, const char* description) static void glfw_callback(int error_code, const char* description)
{ {
@ -604,7 +770,7 @@ int CLI::run(int argc, char **argv)
m_print_config.apply(fff_print_config, true); m_print_config.apply(fff_print_config, true);
} else { } else {
boost::nowide::cerr << "invalid printer_technology " << std::endl; boost::nowide::cerr << "invalid printer_technology " << std::endl;
flush_and_exit(1); flush_and_exit(CLI_INVALID_PRINTER_TECH);
/*assert(printer_technology == ptSLA); /*assert(printer_technology == ptSLA);
sla_print_config.filename_format.value = "[input_filename_base].sl1"; sla_print_config.filename_format.value = "[input_filename_base].sl1";
@ -1050,6 +1216,11 @@ int CLI::run(int argc, char **argv)
this->print_help(true, ptFFF); this->print_help(true, ptFFF);
} else if (opt_key == "help_sla") { } else if (opt_key == "help_sla") {
this->print_help(true, ptSLA); this->print_help(true, ptSLA);
} else if (opt_key == "pipe") {
#if defined(__linux__) || defined(__LINUX__)
std::string pipe_name = m_config.option<ConfigOptionString>("pipe")->value;
g_cli_callback_mgr.start(pipe_name);
#endif
} else if (opt_key == "export_settings") { } else if (opt_key == "export_settings") {
//FIXME check for mixing the FFF / SLA parameters. //FIXME check for mixing the FFF / SLA parameters.
// or better save fff_print_config vs. sla_print_config // or better save fff_print_config vs. sla_print_config
@ -1147,6 +1318,20 @@ int CLI::run(int argc, char **argv)
BuildVolume build_volume(part_plate->get_shape(), print_height); BuildVolume build_volume(part_plate->get_shape(), print_height);
model.update_print_volume_state(build_volume); model.update_print_volume_state(build_volume);
unsigned int count = model.update_print_volume_state(build_volume); unsigned int count = model.update_print_volume_state(build_volume);
if (count == 0) {
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl;
flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
}
else {
for (ModelObject* model_object : model.objects)
for (ModelInstance *i : model_object->instances)
if (i->print_volume_state == ModelInstancePVS_Partly_Outside)
{
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Found Object " << model_object->name <<" partly inside, can not be sliced." << std::endl;
flush_and_exit(CLI_OBJECTS_PARTLY_INSIDE);
}
}
// BBS: TODO // BBS: TODO
//BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1) //BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1)
// % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) % count << std::endl; // % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) % count << std::endl;
@ -1178,19 +1363,27 @@ int CLI::run(int argc, char **argv)
boost::nowide::cerr << err.string << std::endl; boost::nowide::cerr << err.string << std::endl;
//BBS: continue for other plates //BBS: continue for other plates
//continue; //continue;
flush_and_exit(1); flush_and_exit(CLI_VALIDATE_ERROR);
} }
else if (!warning.string.empty()) else if (!warning.string.empty())
BOOST_LOG_TRIVIAL(info) << "got warnings: "<< warning.string << std::endl; BOOST_LOG_TRIVIAL(info) << "got warnings: "<< warning.string << std::endl;
if (print->empty()) { if (print->empty()) {
BOOST_LOG_TRIVIAL(error) << "Nothing to be sliced, Either the print is empty or no object is fully inside the print volume." << std::endl; BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply." << std::endl;
flush_and_exit(CLI_NO_SUITABLE_OBJECTS); flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
} }
else else
try { try {
std::string outfile_final; std::string outfile_final;
BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<<index << std::endl; BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<<index+1 << std::endl;
#if defined(__linux__) || defined(__LINUX__)
BOOST_LOG_TRIVIAL(info) << "cli callback mgr started: "<<g_cli_callback_mgr.m_started << std::endl;
if (g_cli_callback_mgr.is_started()) {
BOOST_LOG_TRIVIAL(info) << "set print's callback to cli_status_callback.";
print->set_status_callback(cli_status_callback);
g_cli_callback_mgr.set_plate_info(index+1, (plate_to_slice== 0)?partplate_list.get_plate_count():1);
}
#endif
print->process(); print->process();
if (printer_technology == ptFFF) { if (printer_technology == ptFFF) {
// The outfile is processed by a PlaceholderParser. // The outfile is processed by a PlaceholderParser.
@ -1225,7 +1418,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << "Slicing result exported to " << outfile << std::endl; BOOST_LOG_TRIVIAL(info) << "Slicing result exported to " << outfile << std::endl;
part_plate->update_slice_result_valid_state(true); part_plate->update_slice_result_valid_state(true);
} catch (const std::exception &ex) { } catch (const std::exception &ex) {
BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "<<index << std::endl; BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "<<index+1 << std::endl;
boost::nowide::cerr << ex.what() << std::endl; boost::nowide::cerr << ex.what() << std::endl;
//continue; //continue;
flush_and_exit(CLI_SLICING_ERROR); flush_and_exit(CLI_SLICING_ERROR);
@ -1512,6 +1705,10 @@ int CLI::run(int argc, char **argv)
glfwTerminate(); glfwTerminate();
} }
#if defined(__linux__) || defined(__LINUX__)
g_cli_callback_mgr.stop();
#endif
//BBS: flush logs //BBS: flush logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl;
boost::nowide::cout.flush(); boost::nowide::cout.flush();
@ -1630,7 +1827,7 @@ bool CLI::setup(int argc, char **argv)
void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const
{ {
boost::nowide::cout boost::nowide::cout
<< SLIC3R_BUILD_ID << ":" << SLIC3R_APP_KEY <<"-"<< SLIC3R_VERSION << ":"
<< std::endl << std::endl
<< "Usage: bambu-studio [ OPTIONS ] [ file.3mf/file.stl ... ]" << std::endl << "Usage: bambu-studio [ OPTIONS ] [ file.3mf/file.stl ... ]" << std::endl
<< std::endl << std::endl

View file

@ -4342,6 +4342,12 @@ CLIActionsConfigDef::CLIActionsConfigDef()
def->tooltip = L("Export settings to a file."); def->tooltip = L("Export settings to a file.");
def->cli_params = "settings.json"; def->cli_params = "settings.json";
def->set_default_value(new ConfigOptionString("output.json")); def->set_default_value(new ConfigOptionString("output.json"));
def = this->add("pipe", coString);
def->label = L("Send progress to pipe");
def->tooltip = L("Send progress to pipe.");
def->cli_params = "pipename";
def->set_default_value(new ConfigOptionString("cli_pipe"));
} }
//BBS: remove unused command currently //BBS: remove unused command currently