mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-08 17:57:44 +00:00
feat: Filament Track Switch (H2-series O2L-FTS) support
The Filament Track Switch (H2-series accessory, product code O2L-FTS) feeds every AMS to both extruders through a two-track switch. Port full support across the device layer, project config, and GUI. Device / config: - Model the switch-aware AMS binding (the set of extruders an AMS can feed and which input track A/B feeds it), switch readiness, the O2L-FTS firmware module, and the fun2 capability bit for checking a slice against installed hardware. - Register has_filament_switcher and enable_filament_dynamic_map as project config that persists with the project and restores from a saved 3mf, and force both back to false on every project/printer/CLI load path. Live device sync is the only thing that sets them true. GUI: - Sidebar sync activates the switch from live device state, attributes each AMS to the extruder its input track feeds, shows a floating status icon (ready / not-calibrated), and surfaces a one-time tip / not-calibrated warning. - Send dialog gains a non-blocking slice-vs-hardware mismatch warning and a blocking error when a slice needs dynamic nozzle mapping but the switch is missing or not set up. - AMS load/unload guards, AMS-view routing glyph + un-calibrated banner + hidden external-spool road, and mapping-popup external-spool lockout. - Filament pickers collapse the per-extruder split into a single deduplicated "AMS filaments" group with a smart-assign toggle when the switch is ready. - Firmware-upgrade panel lists the O2L-FTS accessory and its version. - Device-provided filament-change steps (ams.cfs) drive the change-step display when firmware sends them, including the three switch steps. - "Load current filament" asks which extruder to feed via a FeedDirectionDialog when the switch is calibrated. Inert without the accessory: every path is gated on the switch being installed (MQTT aux bit 29, default off) or ready, both project flags default false, and the per-extruder AMS attribution is byte-identical, so AMS state, the send/load UI, and sliced g-code are unchanged for every printer that does not report a Filament Track Switch.
This commit is contained in:
@@ -9,9 +9,11 @@
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevManager.h"
|
||||
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
|
||||
#include "slic3r/GUI/DeviceCore/DevFilaSwitch.h"
|
||||
|
||||
#include <wx/simplebook.h>
|
||||
#include <wx/dcgraph.h>
|
||||
#include <wx/artprov.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
@@ -39,7 +41,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
// normal mode
|
||||
//Freeze();
|
||||
wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer_body = new wxBoxSizer(wxVERTICAL);
|
||||
m_amswin = new wxWindow(this, wxID_ANY);
|
||||
m_amswin->SetBackgroundColour(*wxWHITE);
|
||||
m_amswin->SetSize(wxSize(FromDIP(578), -1));
|
||||
@@ -151,6 +153,12 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
||||
m_extruder = new AMSextruder(m_amswin, wxID_ANY, m_total_ext_count, wxDefaultPosition, AMS_EXTRUDER_SIZE);
|
||||
m_sizer_option_mid->Add( m_extruder, 0, wxALIGN_CENTER, 0 );
|
||||
|
||||
// Orca: filament-switch routing glyph; hidden by default so it stays inert (zero layout impact)
|
||||
// on any printer without a Filament Track Switch. Shown from UpdateAms only when installed.
|
||||
m_switcher = new SwitcherImage(m_amswin, wxID_ANY, "fila_switch", wxSize(FromDIP(29), FromDIP(16)), wxDefaultPosition);
|
||||
m_switcher->Hide();
|
||||
m_sizer_option_mid->Add(m_switcher, 0, wxALIGN_CENTER | wxLEFT, FromDIP(6));
|
||||
|
||||
|
||||
/*option right*/
|
||||
m_button_extruder_feed = new Button(m_panel_option_right, _L("Load"));
|
||||
@@ -975,6 +983,32 @@ void AMSControl::UpdateAms(const std::string &series_name,
|
||||
{
|
||||
m_amswin->Layout();
|
||||
}
|
||||
|
||||
/*update switch status*/
|
||||
// Orca: inert on any printer without a Filament Track Switch — install is false, so the banner is
|
||||
// never materialized, the glyph stays hidden, and every ShowRoad(true) below is a no-op.
|
||||
const auto [install, ready] = isFilaSwitchReady();
|
||||
show_switcher_status(install && (!ready));
|
||||
bool isShow = install && m_total_ext_count >= 2;
|
||||
if (m_switcher->IsShown() != isShow)
|
||||
{
|
||||
m_switcher->Show(isShow);
|
||||
m_sizer_body->Layout();
|
||||
m_sizer_body->Fit(this);
|
||||
this->Layout();
|
||||
this->Refresh(true);
|
||||
this->Update();
|
||||
}
|
||||
|
||||
/*update ext road visibility when fila switch installed*/
|
||||
bool road_visibility_changed = false;
|
||||
for (auto& [ams_id, ams_item] : m_ams_item_list) {
|
||||
if (!ams_item) continue;
|
||||
// Orca: drop the external-spool road (AMSModel::EXT_AMS) while the switch routes all filament.
|
||||
const bool should_show_road = !(install && ams_item->get_ams_model() == AMSModel::EXT_AMS);
|
||||
if (ams_item->ShowRoad(should_show_road)) { road_visibility_changed = true; }
|
||||
}
|
||||
if (road_visibility_changed) { m_amswin->Layout(); }
|
||||
}
|
||||
|
||||
void AMSControl::AddAmsPreview(AMSinfo info, AMSModel type)
|
||||
@@ -1596,6 +1630,54 @@ void AMSControl::on_ams_setting_click(wxMouseEvent &event)
|
||||
post_event(SimpleEvent(EVT_AMS_SETTINGS));
|
||||
}
|
||||
|
||||
std::tuple<bool, bool> AMSControl::isFilaSwitchReady()
|
||||
{
|
||||
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!dev) return {false, false};
|
||||
MachineObject* obj = dev->get_selected_machine();
|
||||
if (!obj) return {false, false};
|
||||
// Orca: GetFilaSwitch() is a raw non-null accessor (BBS returns a shared_ptr).
|
||||
DevFilaSwitch* fila_switch = obj->GetFilaSwitch();
|
||||
if (fila_switch)
|
||||
{
|
||||
return {fila_switch->IsInstalled(), fila_switch->IsReady()};
|
||||
}
|
||||
return {false, false};
|
||||
}
|
||||
|
||||
void AMSControl::show_switcher_status(bool show)
|
||||
{
|
||||
// Orca: never materialize the banner on printers that never request it, so the AMS control is
|
||||
// byte-identical without a Filament Track Switch (UpdateAms calls this with show=false every refresh).
|
||||
if (!show && tipPanel == nullptr) { return; }
|
||||
|
||||
if (tipPanel == nullptr)
|
||||
{
|
||||
m_sizer_body->Add(0, 0, 1, wxEXPAND | wxTOP, FromDIP(5));
|
||||
tipPanel = new wxPanel(m_amswin);
|
||||
tipPanel->SetBackgroundColour(wxColour(255, 153, 0));
|
||||
tipSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
tipPanel->SetSizer(tipSizer);
|
||||
icon = new wxStaticBitmap(tipPanel, wxID_ANY,
|
||||
wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MESSAGE_BOX, wxSize(FromDIP(16), FromDIP(16))));
|
||||
tipSizer->Add(icon, 0, wxALL, FromDIP(8));
|
||||
tipText = new wxStaticText(tipPanel, wxID_ANY, _L("AMS has not been initialized. Please initialize it before use."));
|
||||
tipText->SetForegroundColour(wxColour(255, 255, 255));
|
||||
tipText->SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
|
||||
tipText->Wrap(-1);
|
||||
tipText->SetMinSize(wxSize(-1, -1));
|
||||
tipSizer->Add(tipText, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, FromDIP(8));
|
||||
m_sizer_body->Add(tipPanel, 1, wxEXPAND, 0);
|
||||
}
|
||||
if (tipPanel->IsShown() == show)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tipPanel->Show(show);
|
||||
m_amswin->Layout();
|
||||
m_amswin->Fit();
|
||||
}
|
||||
|
||||
void AMSControl::parse_object(MachineObject* obj) {
|
||||
if (!obj || obj->GetFilaSystem()->GetAmsList().size() == 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user