diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 7c1644b54..4047f2e0d 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -5910,7 +5910,7 @@ void MachineObject::check_ams_filament_valid() std::string nozzle_diameter_str = stream.str(); assert(nozzle_diameter_str.size() == 3); if (m_nozzle_filament_data.find(nozzle_diameter_str) == m_nozzle_filament_data.end()) { - assert(false); + //assert(false); continue; } auto &data = m_nozzle_filament_data[nozzle_diameter_str]; diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index 38aedd793..52fb0d821 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -298,7 +298,12 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) case PrinterFileSystem::Initializing: icon = m_bmp_loading; msg = _L("Initializing..."); break; case PrinterFileSystem::Connecting: icon = m_bmp_loading; msg = _L("Connecting..."); break; case PrinterFileSystem::Failed: icon = m_bmp_failed; if (extra != 1) msg = _L("Please check the network and try again, You can restart or update the printer if the issue persists."); break; - case PrinterFileSystem::ListSyncing: icon = m_bmp_loading; msg = _L("Loading file list..."); break; + case PrinterFileSystem::ListSyncing: { + icon = m_bmp_loading; + msg = _L("Loading file list..."); + fs->ListAllFiles(); + break; + } case PrinterFileSystem::ListReady: icon = extra == 0 ? m_bmp_empty : m_bmp_failed; msg = extra == 0 ? _L("No files") : _L("Load failed"); break; } int err = fs->GetLastError(); diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp index 84f79601d..7e4eb2caa 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp @@ -39,18 +39,30 @@ wxDEFINE_EVENT(EVT_FILE_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_SELECT_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_THUMBNAIL, wxCommandEvent); wxDEFINE_EVENT(EVT_DOWNLOAD, wxCommandEvent); +wxDEFINE_EVENT(EVT_MEDIA_ABILITY_CHANGED, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPLOADING, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPLOAD_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_FILE_CALLBACK, wxCommandEvent); static wxBitmap default_thumbnail; static std::map error_messages = { - {PrinterFileSystem::ERROR_PIPE, L("Reconnecting the printer, the operation cannot be completed immediately, please try again later.")}, - {PrinterFileSystem::ERROR_RES_BUSY, L("The device cannot handle more conversations. Please retry later.")}, - {PrinterFileSystem::FILE_NO_EXIST, L("File does not exist.")}, - {PrinterFileSystem::FILE_CHECK_ERR, L("File checksum error. Please retry.")}, - {PrinterFileSystem::FILE_TYPE_ERR, L("Not supported on the current printer version.")}, - {PrinterFileSystem::STORAGE_UNAVAILABLE, L("Please check if the SD card is inserted into the printer.\nIf it still cannot be read, you can try formatting the SD card.")} + {PrinterFileSystem::ERROR_PIPE, L("Reconnecting the printer, the operation cannot be completed immediately, please try again later.")}, + {PrinterFileSystem::ERROR_RES_BUSY, L("The device cannot handle more conversations. Please retry later.")}, + {PrinterFileSystem::ERROR_TIME_OUT, L("Timeout, please try again.")}, + {PrinterFileSystem::FILE_NO_EXIST, L("File does not exist.")}, + {PrinterFileSystem::FILE_CHECK_ERR, L("File checksum error. Please retry.")}, + {PrinterFileSystem::FILE_TYPE_ERR, L("Not supported on the current printer version.")}, + {PrinterFileSystem::STORAGE_UNAVAILABLE, L("Please check if the SD card is inserted into the printer.\nIf it still cannot be read, you can try formatting the SD card.")}, + {PrinterFileSystem::API_VERSION_UNSUPPORT, L("The firmware version of the printer is too low. Please update the firmware and try again.")}, + {PrinterFileSystem::FILE_EXIST, L("The file already exists, do you want to replace it?")}, + {PrinterFileSystem::STORAGE_SPACE_NOT_ENOUGH, L("Insufficient storage space, please clear the space and try again.")}, + {PrinterFileSystem::FILE_CREATE_ERR, L("File creation failed, please try again.")}, + {PrinterFileSystem::FILE_WRITE_ERR, L("File write failed, please try again.")}, + {PrinterFileSystem::MD5_COMPARE_ERR, L("MD5 verification failed, please try again.")}, + {PrinterFileSystem::FILE_RENAME_ERR, L("File renaming failed, please try again.")}, + {PrinterFileSystem::SEND_ERR, L("File upload failed, please try again.")} }; struct StaticBambuLib : BambuLib { @@ -124,7 +136,6 @@ void PrinterFileSystem::SetFileType(FileType type, std::string const &storage) return; m_status = Status::ListSyncing; SendChangedEvent(EVT_STATUS_CHANGED, m_status); - ListAllFiles(); } void PrinterFileSystem::SetGroupMode(GroupMode mode) @@ -255,6 +266,14 @@ struct PrinterFileSystem::Download : Progress boost::uuids::detail::md5 boost_md5; }; +struct PrinterFileSystem::Upload : Progress +{ + std::string error; + boost::uint32_t frag_id{0}; + MD5_CTX ctx; + boost::filesystem::ifstream ifs; +}; + void PrinterFileSystem::DownloadFiles(size_t index, std::string const &path) { if (index == (size_t) -1) { @@ -531,6 +550,16 @@ void PrinterFileSystem::Stop(bool quit) m_cond.notify_all(); } +void PrinterFileSystem::SetUploadFile(const std::string &path, const std::string &name, const std::string &select_storage) +{ + if (!m_upload_file) { + m_upload_file = std::make_unique(); + } + m_upload_file->path = path; + m_upload_file->name = name; + m_upload_file->select_storage = select_storage; +} + void PrinterFileSystem::BuildGroups() { m_group_year.clear(); @@ -1037,6 +1066,194 @@ void PrinterFileSystem::DumpLog(void * thiz, int, tchar const *msg) static_cast(thiz)->Bambu_FreeLogMsg(msg); } +boost::uint32_t PrinterFileSystem::RequestMediaAbility(int api_version) +{ + json req; + req["peer"] = "studio"; + req["api_version"] = api_version; + + return SendRequest( + REQUEST_MEDIA_ABILITY, req, [this](const json &resp, MediaAbilityList &list, auto) -> int { + json abliity_list = resp["storage"]; + list = abliity_list.get(); + return 0; + }, + [this](int result, MediaAbilityList list){ + if (result != 0) { + m_last_error = result; + m_media_ability_list.clear(); + SendChangedEvent(EVT_MEDIA_ABILITY_CHANGED, RequestMediaAbilityStatus::S_FAILED, "", m_last_error); + return result; + } + + m_media_ability_list.swap(list); + SendChangedEvent(EVT_MEDIA_ABILITY_CHANGED, RequestMediaAbilityStatus::S_SUCCESS); + return 0; + }); +} + +void PrinterFileSystem::RequestUploadFile() +{ + json req; + req["type"] = "model"; + req["storage"] = m_upload_file->select_storage; + req["path"] = m_upload_file->name; + + m_upload_file->upload = std::make_unique(); + boost::filesystem::path path = boost::filesystem::path(m_upload_file->path); + boost::system::error_code ec; + boost::uint32_t file_size = boost::filesystem::file_size(path, ec); + + req["total"] = file_size; + m_upload_file->size = file_size; + m_upload_file->upload->total = file_size; + + m_upload_seq = SendRequest( + FILE_UPLOAD, req, + [this](int result, const json& resp, auto) -> int{ + if (result != SUCCESS && result != CONTINUE && result != FILE_EXIST) { + std::string error_msg = ""; + if (result == ERROR_CANCEL) { + error_msg = L("User cancels task."); + } else if (result == FILE_READ_WRITE_ERR || result == FILE_OPEN_ERR) { + error_msg = L("Failed to read file, please try again."); + } + wxLogWarning("PrinterFileSystem::UploadFile error: %d\n", result); + SendChangedEvent(EVT_UPLOAD_CHANGED, FF_UPLOADCANCEL, error_msg, result); + } else if (result == SUCCESS) { + SendChangedEvent(EVT_UPLOADING, 100); + SendChangedEvent(EVT_UPLOAD_CHANGED, FF_UPLOADDONE); + } else if (result == CONTINUE || result == FILE_EXIST) { + if (m_upload_file) { + m_upload_file->chunk_size = resp["chunk_size"]; + m_upload_file->upload->size = resp["offset"]; + m_upload_file->flags |= FF_UPLOADING; + } + + { + boost::unique_lock l(m_mutex); + auto cb = [this, upload_file = m_upload_file, seq = m_upload_seq](std::string &msg) -> int { + return UploadFileTask(upload_file, seq, msg); + }; + m_produce_message_cb_map[m_upload_seq] = cb; + } + + return CONTINUE; + } + + // reset m_upload_file + if (m_upload_file) { + m_upload_file.reset(); + } + return result; + }); +} + +int PrinterFileSystem::UploadFileTask(std::shared_ptr upload_file, boost::uint64_t seq, std::string &msg) +{ + if (!upload_file) + return FILE_OPEN_ERR; + + if (!(upload_file->flags & FF_UPLOADING)) + return FILE_OPEN_ERR; + + auto &upload = upload_file->upload; + if (!upload->ifs.is_open()) { + upload->ifs.open(upload_file->path, std::ios::binary); + if (!upload_file->upload->ifs) { + wxLogWarning("PrinterFileSystem::UploadFile open error: %s\n", wxString::FromUTF8(upload_file->path)); + return FILE_OPEN_ERR; + } + MD5_Init(&upload->ctx); + } + + const boost::uint32_t buffer_size = upload_file->chunk_size * 1024; + char *buffer = new char[buffer_size]; + + upload->ifs.seekg(upload->size, std::ios::beg); + upload->ifs.read(buffer, buffer_size); + boost::int32_t read_size = upload->ifs.gcount(); + + if (read_size <= 0) { + wxLogWarning("PrinterFileSystem::Upload read error.\n"); + upload->ifs.close(); + + if (buffer) { + delete[] buffer; + buffer = nullptr; + } + return FILE_READ_WRITE_ERR; + } + + json req; + req["frag_id"] = upload->frag_id; + req["offset"] = upload->size; + req["size"] = read_size; + + MD5_Update(&upload->ctx, buffer, read_size); + upload->size += read_size; + if (upload->size == upload->total) { + unsigned char digest[16]; + MD5_Final(digest, &upload->ctx); + char md5_str[33]; + for (int j = 0; j < 16; j++) { sprintf(&md5_str[j * 2], "%02X", (unsigned int) digest[j]); } + std::string md5_out = std::string(md5_str); + std::transform(md5_out.begin(), md5_out.end(), md5_out.begin(), ::tolower); + + req["file_md5"] = md5_out; + // OutputDebugStringA(md5_out.c_str()); + // OutputDebugStringA("\n"); + } + + if (m_upload_file && m_upload_file->flags & FF_UPLOADING) { + upload->frag_id++; + upload->progress = upload->size * 100 / upload->total; + int progress = upload->progress == 100 ? 99 : upload->progress; + SendChangedEvent(EVT_UPLOADING, progress); + } + + json root; + + root["cmdtype"] = FILE_UPLOAD; + root["sequence"] = seq; + root["req"] = req; + + std::ostringstream oss; + oss << root; + oss << "\n\n"; + oss << std::string(buffer, read_size); + msg = oss.str(); + + if (buffer) { + delete[] buffer; + buffer = nullptr; + } + + if (upload->size == upload->total) { + upload->ifs.close(); + return SUCCESS; + } + + return CONTINUE; +} + +PrinterFileSystem::MediaAbilityList PrinterFileSystem::GetMediaAbilityList() const +{ + return m_media_ability_list; +} + +void PrinterFileSystem::CancelUploadTask(bool send_cancel_req) +{ + if (!m_upload_file) + return; + + if (send_cancel_req) { + CancelRequest(m_upload_seq); + } else { + CancelRequests2({m_upload_seq}); + } +} + boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callback_t2 const &callback) { if (m_session.tunnel == nullptr) { @@ -1044,14 +1261,14 @@ boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callba callback(ERROR_PIPE, json(), nullptr); return 0; } - boost::uint32_t seq = m_sequence + m_callbacks.size(); + boost::uint32_t seq = m_sequence + m_callbacks.size(); json root; root["cmdtype"] = type; root["sequence"] = seq; root["req"] = req; std::ostringstream oss; oss << root; - auto msg = oss.str(); + auto msg = oss.str(); boost::unique_lock l(m_mutex); m_messages.push_back(msg); m_callbacks.push_back(callback); @@ -1092,13 +1309,15 @@ void PrinterFileSystem::CancelRequests2(std::vector const &seqs for (auto &f : seqs) { boost::uint32_t seq = f; seq -= m_sequence; - if (size_t(seq) >= m_callbacks.size()) - continue; + if (size_t(seq) >= m_callbacks.size()) continue; auto &c = m_callbacks[seq]; - if (c == nullptr) - continue; + if (c == nullptr) continue; callbacks.emplace_back(f, c); c = nullptr; + + // erase m_produce_message_cb + if (m_produce_message_cb_map.find(seq) != m_produce_message_cb_map.end()) + m_produce_message_cb_map.erase(seq); } while (!m_callbacks.empty() && m_callbacks.front() == nullptr) { m_callbacks.pop_front(); @@ -1125,6 +1344,45 @@ void PrinterFileSystem::RecvMessageThread() break; } } + if (m_messages.empty() && !m_produce_message_cb_map.empty()) { + auto it = m_produce_message_cb_map.begin(); + while(it != m_produce_message_cb_map.end()) { + std::string msg; + auto prodeuce_message_cb = it->second; + l.unlock(); + int res = prodeuce_message_cb(msg); + l.lock(); + if (res == CONTINUE || res == SUCCESS) { + m_messages.emplace_back(msg); + if (res == SUCCESS) { + it = m_produce_message_cb_map.erase(it); + continue; + } + it++; + } else { + int seq2 = it->first - m_sequence; + // erase it + it = m_produce_message_cb_map.erase(it); + if (size_t(seq2) >= m_callbacks.size()) + continue; + auto c = m_callbacks[seq2]; + if (c == nullptr) + continue;; + m_callbacks[seq2] = nullptr; + if (seq2 == 0) { + // if produce message return error, erase callback and sequence should plus + while (!m_callbacks.empty() && m_callbacks.front() == nullptr) { + m_callbacks.pop_front(); + ++m_sequence; + } + } + + l.unlock(); + c(res, json(), nullptr); + l.lock(); + } + } + } if (!m_messages.empty()) { auto & msg = m_messages.front(); // OutputDebugStringA(msg.c_str()); @@ -1208,7 +1466,7 @@ void PrinterFileSystem::HandleResponse(boost::unique_lock &l, Bamb int result2 = c(result, resp, json_end); l.lock(); if (result2 != CONTINUE) { - int seq2 = seq - m_sequence; + int seq2 = seq - m_sequence; m_callbacks[seq2] = callback_t2(); if (seq2 == 0) { while (!m_callbacks.empty() && m_callbacks.front() == nullptr) { @@ -1221,6 +1479,11 @@ void PrinterFileSystem::HandleResponse(boost::unique_lock &l, Bamb CancelRequest(seq); l.lock(); } + + // error should erase m_produce_message_cb + if (m_produce_message_cb_map.find(seq2) != m_produce_message_cb_map.end()) { + m_produce_message_cb_map.erase(seq2); + } } } } @@ -1307,12 +1570,15 @@ void PrinterFileSystem::Reconnect(boost::unique_lock &l, int resul SendChangedEvent(EVT_STATUS_CHANGED, m_status, "", url.size() < 2 ? 1 : m_last_error); m_cond.timed_wait(l, boost::posix_time::seconds(10)); } - m_status = Status::ListSyncing; - SendChangedEvent(EVT_STATUS_CHANGED, m_status); + #ifdef PRINTER_FILE_SYSTEM_TEST PostCallback([this] { SendChangedEvent(EVT_FILE_CHANGED); }); #else - PostCallback([this] { m_task_flags = 0; ListAllFiles(); }); + PostCallback([this] { + m_task_flags = 0; + m_status = Status::ListSyncing; + SendChangedEvent(EVT_STATUS_CHANGED, m_status); + }); #endif } @@ -1398,4 +1664,4 @@ void StaticBambuLib::reset() extern "C" BambuLib *bambulib_get() { return &StaticBambuLib::get(); -} +} \ No newline at end of file diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.h b/src/slic3r/GUI/Printer/PrinterFileSystem.h index 237378744..0aea95c57 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.h +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.h @@ -22,39 +22,52 @@ wxDECLARE_EVENT(EVT_FILE_CHANGED, wxCommandEvent); wxDECLARE_EVENT(EVT_SELECT_CHANGED, wxCommandEvent); wxDECLARE_EVENT(EVT_THUMBNAIL, wxCommandEvent); wxDECLARE_EVENT(EVT_DOWNLOAD, wxCommandEvent); +wxDECLARE_EVENT(EVT_MEDIA_ABILITY_CHANGED, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPLOADING, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPLOAD_CHANGED, wxCommandEvent); class PrinterFileSystem : public wxEvtHandler, public boost::enable_shared_from_this, BambuLib { static const int CTRL_TYPE = 0x3001; enum { - LIST_INFO = 0x0001, - SUB_FILE = 0x0002, - FILE_DEL = 0x0003, - FILE_DOWNLOAD = 0X0004, - NOTIFY_FIRST = 0x0100, - LIST_CHANGE_NOTIFY = 0x0100, - LIST_RESYNC_NOTIFY = 0x0101, - TASK_CANCEL = 0x1000 + LIST_INFO = 0x0001, + SUB_FILE = 0x0002, + FILE_DEL = 0x0003, + FILE_DOWNLOAD = 0x0004, + FILE_UPLOAD = 0x0005, + REQUEST_MEDIA_ABILITY = 0x0007, + NOTIFY_FIRST = 0x0100, + LIST_CHANGE_NOTIFY = 0x0100, + LIST_RESYNC_NOTIFY = 0x0101, + TASK_CANCEL = 0x1000 }; public: enum { - SUCCESS = 0, - CONTINUE = 1, - ERROR_JSON = 2, - ERROR_PIPE = 3, - ERROR_CANCEL = 4, - ERROR_RES_BUSY = 5, - - FILE_NO_EXIST = 10, - FILE_NAME_INVALID = 11, - FILE_SIZE_ERR = 12, - FILE_OPEN_ERR = 13, - FILE_READ_WRITE_ERR = 14, - FILE_CHECK_ERR = 15, - FILE_TYPE_ERR = 16, - STORAGE_UNAVAILABLE = 17, + SUCCESS = 0, + CONTINUE = 1, + ERROR_JSON = 2, + ERROR_PIPE = 3, + ERROR_CANCEL = 4, + ERROR_RES_BUSY = 5, + ERROR_TIME_OUT = 6, + FILE_NO_EXIST = 10, + FILE_NAME_INVALID = 11, + FILE_SIZE_ERR = 12, + FILE_OPEN_ERR = 13, + FILE_READ_WRITE_ERR = 14, + FILE_CHECK_ERR = 15, + FILE_TYPE_ERR = 16, + STORAGE_UNAVAILABLE = 17, + API_VERSION_UNSUPPORT = 18, + FILE_EXIST = 19, + STORAGE_SPACE_NOT_ENOUGH = 20, + FILE_CREATE_ERR = 21, + FILE_WRITE_ERR = 22, + MD5_COMPARE_ERR = 23, + FILE_RENAME_ERR = 24, + SEND_ERR = 25, }; @@ -90,12 +103,28 @@ public: template using Callback = std::function; enum Flags { - FF_SELECT = 1, - FF_THUMNAIL = 2, // Thumbnail ready - FF_DOWNLOAD = 4, // Request download - FF_DELETED = 8, // Request delete - FF_FETCH_MODEL = 16,// Request model - FF_THUMNAIL_RETRY = 0x100, // Thumbnail need retry + FF_SELECT = 1, + FF_THUMNAIL = 2, // Thumbnail ready + FF_DOWNLOAD = 4, // Request download + FF_DELETED = 8, // Request delete + FF_FETCH_MODEL = 16, // Request model + FF_UPLOADING = 1 << 5, // File uploading + FF_UPLOADDONE = 1 << 6, // File upload done + FF_UPLOADCANCEL = 1 << 7, // File upload cancel + FF_THUMNAIL_RETRY = 0x100, // Thumbnail need retry + }; + + enum UploadStatus + { + Uploading = 1 << 0, + UploadDone = 1 << 1, + UploadCancel = 1 << 2, + }; + + enum RequestMediaAbilityStatus + { + S_SUCCESS, + S_FAILED }; struct Progress @@ -106,6 +135,7 @@ public: }; struct Download; + struct Upload; struct File { @@ -128,9 +158,23 @@ public: friend bool operator<(File const & l, File const & r) { return l.time > r.time; } }; + struct UploadFile + { + std::string name; + std::string path; + std::string select_storage; + int flags{0}; + boost::uint32_t size{0}; + boost::uint32_t chunk_size{0}; // KB + std::unique_ptr upload; + + bool IsUploading() const { return flags & FF_UPLOADING; } + }; + struct Void {}; typedef std::vector FileList; + typedef std::vector MediaAbilityList; void ListAllFiles(); @@ -185,6 +229,16 @@ public: void Stop(bool quit = false); + boost::uint32_t RequestMediaAbility(int api_version); + + void RequestUploadFile(); + + MediaAbilityList GetMediaAbilityList() const; + + void SetUploadFile(const std::string& path, const std::string& name, const std::string& select_storage); + + void CancelUploadTask(bool send_cancel_req = true); + private: void BuildGroups(); @@ -217,13 +271,14 @@ private: typedef std::function callback_t2; - template - boost::uint32_t SendRequest(int type, json const& req, Translator const& translator, Callback const& callback) + typedef std::function callback_t3; + + template boost::uint32_t SendRequest(int type, json const &req, Translator const &translator, Callback const &callback) { auto c = [translator, callback, this](int result, json const &resp, unsigned char const *data) -> int { T t; - if (result == 0 || result == CONTINUE) { + if (result == 0 || result == CONTINUE || result == FILE_EXIST) { try { int n = (translator != nullptr) ? translator(resp, t, data) : 0; result = n == 0 ? result : n; @@ -289,6 +344,8 @@ private: void PostCallback(std::function const & callback); + int UploadFileTask(std::shared_ptr upload_file, boost::uint64_t seq, std::string &msg); + protected: FileType m_file_type = F_INVALID_TYPE; std::string m_file_storage; @@ -298,6 +355,7 @@ protected: std::vector m_group_year; std::vector m_group_month; std::vector m_group_flags; + std::shared_ptr m_upload_file; private: size_t m_select_count = 0; @@ -315,6 +373,7 @@ private: boost::uint32_t m_sequence = 0; boost::uint32_t m_download_seq = 0; boost::uint32_t m_fetch_model_seq = 0; + boost::uint32_t m_upload_seq = 0; std::deque m_messages; std::deque m_callbacks; std::deque m_notifies; @@ -324,6 +383,9 @@ private: boost::thread m_recv_thread; Status m_status; int m_last_error = 0; + + MediaAbilityList m_media_ability_list; + std::map m_produce_message_cb_map; }; #endif // !slic3r_GUI_PrinterFileSystem_h_ diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index e9edba949..fc43ec0b3 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -90,7 +90,9 @@ enum PrintDialogStatus { PrintStatusBlankPlate, PrintStatusUnsupportedPrinter, PrintStatusTimelapseWarning, - PrintStatusMixAmsAndVtSlotWarning + PrintStatusMixAmsAndVtSlotWarning, + PrintStatusPublicInitFailed, + PrintStatusPublicUploadFiled }; class Material diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index e2de60f96..491aa8db2 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -27,12 +27,13 @@ namespace GUI { #define LIST_REFRESH_INTERVAL 200 #define MACHINE_LIST_REFRESH_INTERVAL 2000 +constexpr int timeout_period = 15000; // ms + wxDEFINE_EVENT(EVT_UPDATE_USER_MACHINE_LIST, wxCommandEvent); wxDEFINE_EVENT(EVT_PRINT_JOB_CANCEL, wxCommandEvent); wxDEFINE_EVENT(EVT_SEND_JOB_SUCCESS, wxCommandEvent); wxDEFINE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent); - void SendToPrinterDialog::stripWhiteSpace(std::string& str) { if (str == "") { return; } @@ -262,6 +263,14 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) m_button_refresh->Bind(wxEVT_BUTTON, &SendToPrinterDialog::on_refresh, this); m_sizer_printer->Add(m_button_refresh, 0, wxALL | wxLEFT, FromDIP(5)); + + /*select storage*/ + m_storage_panel = new wxPanel(this); + m_storage_panel->SetBackgroundColour(*wxWHITE); + m_storage_sizer = new wxBoxSizer(wxHORIZONTAL); + m_storage_panel->SetSizer(m_storage_sizer); + m_storage_panel->Layout(); + m_statictext_printer_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); m_statictext_printer_msg->SetFont(::Label::Body_13); m_statictext_printer_msg->SetForegroundColour(*wxBLACK); @@ -517,6 +526,7 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) m_sizer_main->Add(m_line_materia, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(12)); m_sizer_main->Add(m_sizer_printer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); + m_sizer_main->Add(m_storage_panel, 0, wxALIGN_CENTER|wxTOP, FromDIP(8)); m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(11)); m_sizer_main->Add(m_statictext_printer_msg, 0, wxALIGN_CENTER_HORIZONTAL, 0); m_sizer_main->Add(0, 1, 0, wxTOP, FromDIP(22)); @@ -538,6 +548,49 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) wxGetApp().UpdateDlgDarkUI(this); } +std::string SendToPrinterDialog::get_storage_selected() +{ + for (const auto& radio : m_storage_radioBox) { + if (radio->GetValue()) { + return radio->GetLabel().ToStdString(); + } + } + return ""; +} + +void SendToPrinterDialog::update_storage_list(std::vector storages) +{ + m_storage_radioBox.clear(); + m_storage_panel->DestroyChildren(); + + for (int i=0; i < storages.size(); i++) { + RadioBox* radiobox = new RadioBox(m_storage_panel); + Label* storage_text = new Label(m_storage_panel, storages[i]); + radiobox->SetLabel(storages[i]); + radiobox->Bind(wxEVT_LEFT_DOWN, [this, radiobox](auto& e) { + for (const auto& radio : m_storage_radioBox) { + radio->SetValue(false); + } + radiobox->SetValue(true); + }); + + if (m_storage_radioBox.size() > 0) { + m_storage_sizer->Add(0, 0, 0, wxEXPAND|wxLEFT, FromDIP(6)); + auto radio = m_storage_radioBox.front(); + radio->SetValue(true); + } + + m_storage_sizer->Add(radiobox, 0, wxALIGN_CENTER, 0); + m_storage_sizer->Add(0, 0, 0, wxEXPAND|wxLEFT, FromDIP(6)); + m_storage_sizer->Add(storage_text, 0, wxALIGN_CENTER,0); + m_storage_radioBox.push_back(radiobox); + } + + m_storage_panel->Layout(); + m_storage_panel->Fit(); + Layout(); + Fit(); +} void SendToPrinterDialog::update_print_error_info(int code, std::string msg, std::string extra) { m_print_error_code = code; @@ -676,6 +729,15 @@ void SendToPrinterDialog::on_cancel(wxCloseEvent &event) m_send_job->join(); } } + if (m_file_sys) { + m_file_sys->CancelUploadTask(); + + if (m_task_timer && m_task_timer->IsRunning()) { + m_task_timer->Stop(); + m_task_timer.reset(); + } + } + this->EndModal(wxID_CANCEL); } @@ -719,6 +781,9 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) } m_send_job->join(); } + if (m_file_sys) { + m_file_sys->CancelUploadTask(); + } m_is_canceled = true; wxCommandEvent* event = new wxCommandEvent(EVT_PRINT_JOB_CANCEL); wxQueueEvent(this, event); @@ -773,44 +838,71 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) fs::path default_output_file_path = boost::filesystem::path(default_output_file.c_str()); file_name = default_output_file_path.filename().string(); }*/ + if (obj_->is_lan_mode_printer()) { + update_print_status_msg(wxEmptyString, false, false); + if (m_file_sys) { + PrintPrepareData print_data; + m_plater->get_print_job_data(&print_data); + std::string project_name = m_current_project_name.utf8_string() + ".3mf"; + std::string _3mf_path = print_data._3mf_path.string(); + m_file_sys->SetUploadFile(_3mf_path, project_name, get_storage_selected()); + m_file_sys->RequestUploadFile(); + // time out + if (m_task_timer && m_task_timer->IsRunning()) + m_task_timer->Stop(); + m_task_timer.reset(new wxTimer()); + m_task_timer->SetOwner(this); - m_send_job = std::make_shared(m_status_bar, m_plater, m_printer_last_select); - m_send_job->m_dev_ip = obj_->dev_ip; - m_send_job->m_access_code = obj_->get_access_code(); + this->Bind( + wxEVT_TIMER, + [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); + + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + fs->CancelUploadTask(false); + update_print_status_msg(_L("Upload file timeout, please check if the firmware version supports it."), false, true); + }, + m_task_timer->GetId()); + m_task_timer->StartOnce(timeout_period); + } + } else { + m_send_job = std::make_shared(m_status_bar, m_plater, m_printer_last_select); + m_send_job->m_dev_ip = obj_->dev_ip; + m_send_job->m_access_code = obj_->get_access_code(); #if !BBL_RELEASE_TO_PUBLIC - m_send_job->m_local_use_ssl_for_ftp = wxGetApp().app_config->get("enable_ssl_for_ftp") == "true" ? true : false; - m_send_job->m_local_use_ssl_for_mqtt = wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false; + m_send_job->m_local_use_ssl_for_ftp = wxGetApp().app_config->get("enable_ssl_for_ftp") == "true" ? true : false; + m_send_job->m_local_use_ssl_for_mqtt = wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false; #else - m_send_job->m_local_use_ssl_for_ftp = obj_->local_use_ssl_for_ftp; - m_send_job->m_local_use_ssl_for_mqtt = obj_->local_use_ssl_for_mqtt; + m_send_job->m_local_use_ssl_for_ftp = obj_->local_use_ssl_for_ftp; + m_send_job->m_local_use_ssl_for_mqtt = obj_->local_use_ssl_for_mqtt; #endif - m_send_job->connection_type = obj_->connection_type(); - m_send_job->cloud_print_only = true; - m_send_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL; - m_send_job->set_project_name(m_current_project_name.utf8_string()); + m_send_job->connection_type = obj_->connection_type(); + m_send_job->cloud_print_only = true; + m_send_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL; + m_send_job->set_project_name(m_current_project_name.utf8_string()); - enable_prepare_mode = false; + enable_prepare_mode = false; - m_send_job->on_check_ip_address_fail([this](int result) { - wxCommandEvent* evt = new wxCommandEvent(EVT_CLEAR_IPADDRESS); - wxQueueEvent(this, evt); - wxGetApp().show_ip_address_enter_dialog(); - }); + m_send_job->on_check_ip_address_fail([this](int result) { + wxCommandEvent *evt = new wxCommandEvent(EVT_CLEAR_IPADDRESS); + wxQueueEvent(this, evt); + wxGetApp().show_ip_address_enter_dialog(); + }); - if (obj_->is_lan_mode_printer()) { - m_send_job->set_check_mode(); - m_send_job->check_and_continue(); - m_send_job->start(); + if (obj_->is_lan_mode_printer()) { + m_send_job->set_check_mode(); + m_send_job->check_and_continue(); + m_send_job->start(); + } else { + m_send_job->start(); + } } - else { - m_send_job->start(); - } - BOOST_LOG_TRIVIAL(info) << "send_job: send print job"; } @@ -852,9 +944,10 @@ void SendToPrinterDialog::update_user_machine_list() void SendToPrinterDialog::on_refresh(wxCommandEvent &event) { BOOST_LOG_TRIVIAL(info) << "m_printer_last_select: on_refresh"; - show_status(PrintDialogStatus::PrintStatusRefreshingMachineList); - - update_user_machine_list(); + /* show_status(PrintDialogStatus::PrintStatusRefreshingMachineList); + update_user_machine_list();*/ + /*todo refresh*/ + if (m_file_sys) { m_file_sys->Retry(); } } void SendToPrinterDialog::on_print_job_cancel(wxCommandEvent &evt) @@ -1001,8 +1094,11 @@ void SendToPrinterDialog::on_selection_changed(wxCommandEvent &event) obj->command_request_push_all(); if (!dev->get_selected_machine()) { dev->set_selected_machine(m_printer_last_select, true); + if (m_file_sys) m_file_sys.reset(); }else if (dev->get_selected_machine()->dev_id != m_printer_last_select) { + update_storage_list(std::vector()); dev->set_selected_machine(m_printer_last_select, true); + if (m_file_sys) m_file_sys.reset(); } } else { @@ -1086,8 +1182,137 @@ void SendToPrinterDialog::update_show_status() } if (!m_is_in_sending_mode) { - show_status(PrintDialogStatus::PrintStatusReadingFinished); - return; + if (obj_->connection_type() == "lan") { + show_status(PrintDialogStatus::PrintStatusReadingFinished); + return; + } else if (obj_->connection_type() == "cloud") { + Enable(obj_ && obj_->is_connected() && obj_->m_push_count > 0); + std::string dev_id = obj_->dev_ip; + if (m_file_sys) { + if (dev_id == m_device_select) { + if ((m_waiting_enable && IsEnabled()) || (m_waiting_support && obj_->file_remote)) + m_file_sys->Retry(); + return; + } + } + + m_device_select.swap(dev_id); + m_file_sys = boost::make_shared(); + m_file_sys->Attached(); + + m_file_sys->Bind(EVT_STATUS_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + e.Skip(); + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + + wxString msg; + int status = e.GetInt(); + int extra = e.GetExtraLong(); + switch (status) { + case PrinterFileSystem::Initializing: + case PrinterFileSystem::Connecting: show_status(PrintDialogStatus::PrintStatusReading); break; + case PrinterFileSystem::ListSyncing: { + show_status(PrintDialogStatus::PrintStatusReading); + boost::uint32_t seq = fs->RequestMediaAbility(3); + + if (m_task_timer && m_task_timer->IsRunning()) + m_task_timer->Stop(); + + m_task_timer.reset(new wxTimer()); + m_task_timer->SetOwner(this); + + this->Bind(wxEVT_TIMER, [this, wfs_1 = boost::weak_ptr(fs), seq](auto e) { + show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); + boost::shared_ptr fs_1(wfs_1.lock()); + if (!fs_1) return; + fs_1->CancelUploadTask(false); + update_print_status_msg(_L("Media capability acquisition timeout, please check if the firmware version supports it."), false, true); + }, m_task_timer->GetId()); + m_task_timer->StartOnce(timeout_period); + + break; + } + case PrinterFileSystem::Failed: msg = _L("Please check the network and try again, You can restart or update the printer if the issue persists."); break; + } + + if (!msg.empty()) { + show_status(PrintDialogStatus::PrintStatusPublicInitFailed); + update_print_status_msg(msg, false, true); + } + + if (e.GetInt() == PrinterFileSystem::Initializing) { + CallAfter([=] { + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + fetchUrl(boost::weak_ptr(fs)); + }); + } + }); + + m_file_sys->Bind(EVT_MEDIA_ABILITY_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + + if (m_task_timer && m_task_timer->IsRunning()) { + m_task_timer->Stop(); + m_task_timer.reset(); + } + + m_ability_list = fs->GetMediaAbilityList(); + + if (e.GetInt() == PrinterFileSystem::RequestMediaAbilityStatus::S_SUCCESS) { + update_storage_list(m_ability_list); + show_status(PrintDialogStatus::PrintStatusReadingFinished); + } else { + show_status(PrintDialogStatus::PrintStatusPublicInitFailed); + update_print_status_msg(e.GetString(), false, true); + } + }); + + m_file_sys->Bind(EVT_UPLOADING, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + int progress = e.GetInt(); + m_status_bar->set_progress(10 + std::floor(progress * 0.9)); + + if (m_task_timer && m_task_timer->IsRunning()) m_task_timer->Stop(); + + if (progress == 99) { + m_task_timer.reset(new wxTimer()); + m_task_timer->SetOwner(this); + + this->Bind( + wxEVT_TIMER, + [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + fs->CancelUploadTask(false); + update_print_status_msg(_L("Upload file timeout, please check if the firmware version supports it."), false, true); + }, + m_task_timer->GetId()); + m_task_timer->StartOnce(timeout_period); + } + }); + m_file_sys->Bind(EVT_UPLOAD_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) { + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + + if (e.GetInt() == PrinterFileSystem::FF_UPLOADDONE) { + show_status(PrintDialogStatus::PrintStatusReadingFinished); + wxCommandEvent *evt = new wxCommandEvent(m_plater->get_send_finished_event()); + evt->SetString(from_u8(m_current_project_name.utf8_string())); + wxQueueEvent(m_plater, evt); + } else if (PrinterFileSystem::FF_UPLOADCANCEL) { + show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); + wxString err_msg = e.GetString(); + if (err_msg.IsEmpty()) + err_msg = _u8L("Sending failed, please try again!"); + update_print_status_msg(err_msg, false, true); + } + }); + m_file_sys->Start(); + } } } @@ -1149,7 +1374,7 @@ void SendToPrinterDialog::show_status(PrintDialogStatus status, std::vector()); wxGetApp().reset_to_active(); set_default(); update_user_machine_list(); @@ -1393,12 +1626,84 @@ bool SendToPrinterDialog::Show(bool show) Layout(); Fit(); if (show) { CenterOnParent(); } + + if (m_file_sys) { + show ? m_file_sys->Start() : m_file_sys->Stop(); + } + return DPIDialog::Show(show); } +extern wxString hide_passwd(wxString url, std::vector const &passwords); +extern void refresh_agora_url(char const *device, char const *dev_ver, char const *channel, void *context, void (*callback)(void *context, char const *url)); + +void SendToPrinterDialog::fetchUrl(boost::weak_ptr wfs) +{ + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + + if (!IsEnabled()) { + m_waiting_enable = true; + fs->SetUrl("0"); + return; + } + + m_waiting_enable = false; + DeviceManager *dm = GUI::wxGetApp().getDeviceManager(); + MachineObject *obj = dm->get_selected_machine(); + + std::string dev_ver = obj->get_ota_version(); + std::string dev_id = obj->dev_id; + int remote_proto = obj->file_remote; + if (!remote_proto) { + m_waiting_support = true; + fs->SetUrl("0"); + return; + } + + if (obj->is_camera_busy_off()) { + fs->SetUrl("0"); + return; + } + + m_waiting_support = false; + NetworkAgent *agent = wxGetApp().getAgent(); + std::string agent_version = agent ? agent->get_version() : ""; + + if (agent) { + std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; + agent->get_camera_url(obj->dev_id + "|" + dev_ver + "|" + protocols[remote_proto], + [this, wfs, m = dev_id, v = agent->get_version(), dv = dev_ver](std::string url) { + if (boost::algorithm::starts_with(url, "bambu:///")) { + url += "&device=" + m; + url += "&net_ver=" + v; + url += "&dev_ver=" + dv; + url += "&refresh_url=" + boost::lexical_cast(&refresh_agora_url); + url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid"); + url += "&cli_ver=" + std::string(SLIC3R_VERSION); + } + BOOST_LOG_TRIVIAL(info) << "SendToPrinter::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); + std::cout << "SendToPrinter::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); + CallAfter([=] { + boost::shared_ptr fs(wfs.lock()); + if (!fs) return; + if (boost::algorithm::starts_with(url, "bambu:///")) { + fs->SetUrl(url); + } else { + fs->SetUrl("3"); + } + }); + }); + } + + return; +} + SendToPrinterDialog::~SendToPrinterDialog() { delete m_refresh_timer; + if (m_task_timer && m_task_timer->IsRunning()) + m_task_timer->Stop(); } } diff --git a/src/slic3r/GUI/SendToPrinter.hpp b/src/slic3r/GUI/SendToPrinter.hpp index 16a545ed1..7cbf4fe9e 100644 --- a/src/slic3r/GUI/SendToPrinter.hpp +++ b/src/slic3r/GUI/SendToPrinter.hpp @@ -38,6 +38,7 @@ #include "Widgets/ScrolledWindow.hpp" #include #include +#include "Printer/PrinterFileSystem.h" namespace Slic3r { namespace GUI { @@ -62,6 +63,7 @@ private: std::string m_print_error_extra; std::string m_print_info; std::string m_printer_last_select; + std::string m_device_select; wxString m_current_project_name; TextInput* m_rename_input{ nullptr }; @@ -83,6 +85,8 @@ private: wxPanel* m_panel_image{ nullptr }; wxPanel* m_rename_normal_panel{ nullptr }; wxPanel* m_line_materia{ nullptr }; + wxBoxSizer* m_storage_sizer{ nullptr }; + wxPanel* m_storage_panel{ nullptr }; wxSimplebook* m_simplebook{ nullptr }; wxStaticText* m_statictext_finish{ nullptr }; wxStaticText* m_stext_sending{ nullptr }; @@ -112,9 +116,16 @@ private: wxColour m_colour_def_color{ wxColour(255, 255, 255) }; wxColour m_colour_bold_color{ wxColour(38, 46, 48) }; wxTimer* m_refresh_timer{ nullptr }; + std::unique_ptr m_task_timer{ nullptr }; std::shared_ptr m_status_bar; wxScrolledWindow* m_sw_print_failed_info{nullptr}; std::shared_ptr m_token = std::make_shared(0); + std::vector m_storage_radioBox; + + bool m_waiting_support{ false }; + bool m_waiting_enable{ false }; + boost::shared_ptr m_file_sys; + std::vector m_ability_list; public: SendToPrinterDialog(Plater* plater = nullptr); @@ -153,8 +164,13 @@ public: void show_print_failed_info(bool show, int code = 0, wxString description = wxEmptyString, wxString extra = wxEmptyString); void update_print_error_info(int code, std::string msg, std::string extra); void on_change_color_mode() { wxGetApp().UpdateDlgDarkUI(this); } + void update_storage_list(std::vector storages); + std::string get_storage_selected(); + wxString format_text(wxString& m_msg); std::vector sort_string(std::vector strArray); + + void fetchUrl(boost::weak_ptr wfs); }; wxDECLARE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent);