mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 21:42:43 +00:00
1002 lines
40 KiB
C++
1002 lines
40 KiB
C++
#include <nlohmann/json.hpp>
|
|
#include "DevFilaSystem.h"
|
|
#include "slic3r/Utils/NetworkAgent.hpp"
|
|
#include "DevNozzleSystem.h" // DevNozzle / DevNozzleSystem for GetNozzleFlowStringByAmsId
|
|
|
|
// TODO: remove this include
|
|
#include "slic3r/GUI/DeviceManager.hpp"
|
|
#include "slic3r/GUI/I18N.hpp"
|
|
#include "slic3r/GUI/GUI_App.hpp"
|
|
|
|
#include "DevUtil.h"
|
|
#include "DevUtilBackend.h"
|
|
|
|
using namespace nlohmann;
|
|
|
|
namespace Slic3r {
|
|
static int _hex_digit_to_int(const char c) { return (c >= '0' && c <= '9') ? c - '0' : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1; }
|
|
|
|
wxColour DevAmsTray::decode_color(const std::string &color)
|
|
{
|
|
std::array<int, 4> ret = {0, 0, 0, 0};
|
|
const char * c = color.data();
|
|
if (color.size() == 8) {
|
|
for (size_t j = 0; j < 4; ++j) {
|
|
int digit1 = _hex_digit_to_int(*c++);
|
|
int digit2 = _hex_digit_to_int(*c++);
|
|
if (digit1 == -1 || digit2 == -1) break;
|
|
ret[j] = static_cast<float>(digit1 * 16 + digit2);
|
|
}
|
|
} else { return wxColour(255, 255, 255, 255); }
|
|
|
|
return wxColour(ret[0], ret[1], ret[2], ret[3]);
|
|
}
|
|
|
|
void DevAmsTray::UpdateColorFromStr(const std::string& color)
|
|
{
|
|
if (color.empty()) return;
|
|
if (this->color != color)
|
|
{
|
|
wx_color = "#" + wxString::FromUTF8(color);
|
|
this->color = color;
|
|
}
|
|
}
|
|
|
|
void DevAmsTray::reset()
|
|
{
|
|
tag_uid = "";
|
|
setting_id = "";
|
|
filament_setting_id = "";
|
|
m_fila_type = "";
|
|
sub_brands = "";
|
|
color = "";
|
|
weight = "";
|
|
diameter = "";
|
|
temp = "";
|
|
time = "";
|
|
bed_temp_type = "";
|
|
bed_temp = "";
|
|
nozzle_temp_max = "";
|
|
nozzle_temp_min = "";
|
|
xcam_info = "";
|
|
uuid = "";
|
|
k = 0.0f;
|
|
n = 0.0f;
|
|
is_bbl = false;
|
|
hold_count = 0;
|
|
remain = 0;
|
|
}
|
|
|
|
|
|
bool DevAmsTray::is_tray_info_ready() const
|
|
{
|
|
if (color.empty()) return false;
|
|
if (m_fila_type.empty()) return false;
|
|
//if (setting_id.empty()) return false;
|
|
return true;
|
|
}
|
|
|
|
bool DevAmsTray::is_unset_third_filament() const
|
|
{
|
|
if (this->is_bbl) return false;
|
|
return (color.empty() || m_fila_type.empty());
|
|
}
|
|
|
|
std::string DevAmsTray::get_display_filament_type() const
|
|
{
|
|
if (m_fila_type == "PLA-S") return "Sup.PLA";
|
|
if (m_fila_type == "PA-S") return "Sup.PA";
|
|
if (m_fila_type == "ABS-S") return "Sup.ABS";
|
|
return m_fila_type;
|
|
}
|
|
|
|
std::string DevAmsTray::get_filament_type()
|
|
{
|
|
if (m_fila_type == "Sup.PLA") { return "PLA-S"; }
|
|
if (m_fila_type == "Sup.PA") { return "PA-S"; }
|
|
if (m_fila_type == "Sup.ABS") { return "ABS-S"; }
|
|
if (m_fila_type == "Support W") { return "PLA-S"; }
|
|
if (m_fila_type == "Support G") { return "PA-S"; }
|
|
// setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
|
if (m_fila_type == "Support") {
|
|
auto* agent = GUI::wxGetApp().getAgent();
|
|
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(setting_id) : setting_id;
|
|
if (printer_filament_id == "GFS00") { m_fila_type = "PLA-S"; } else if (printer_filament_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; }
|
|
}
|
|
|
|
return m_fila_type;
|
|
}
|
|
|
|
std::optional<Slic3r::DevFilamentDryingPreset> DevAmsTray::get_ams_drying_preset() const
|
|
{
|
|
return DevUtilBackend::GetFilamentDryingPreset(setting_id);
|
|
}
|
|
|
|
|
|
DevAms::DevAms(const std::string& ams_id, int extruder_id, AmsType type)
|
|
{
|
|
m_ams_id = ams_id;
|
|
m_ext_id = extruder_id;
|
|
m_ams_type = type;
|
|
}
|
|
|
|
DevAms::DevAms(const std::string& ams_id, int nozzle_id, int type)
|
|
{
|
|
m_ams_id = ams_id;
|
|
m_ext_id = nozzle_id;
|
|
m_ams_type = (AmsType)type;
|
|
assert(EXT_SPOOL < type && m_ams_type <= AMS_LITE_MIXED);
|
|
}
|
|
|
|
DevAms::~DevAms()
|
|
{
|
|
for (auto it = m_trays.begin(); it != m_trays.end(); it++)
|
|
{
|
|
if (it->second)
|
|
{
|
|
delete it->second;
|
|
it->second = nullptr;
|
|
}
|
|
}
|
|
m_trays.clear();
|
|
}
|
|
|
|
static unordered_map<int, wxString> s_ams_display_formats = {
|
|
{DevAms::AMS, "AMS-%d"},
|
|
{DevAms::AMS_LITE, "AMS Lite-%d"},
|
|
{DevAms::N3F, "AMS 2 PRO-%d"},
|
|
{DevAms::N3S, "AMS HT-%d"}
|
|
};
|
|
|
|
wxString DevAms::GetDisplayName() const
|
|
{
|
|
wxString ams_display_format;
|
|
// GetAmsType() maps AMS_LITE_MIXED -> AMS_LITE so N9 shows the AMS-Lite name.
|
|
auto iter = s_ams_display_formats.find(GetAmsType());
|
|
if (iter != s_ams_display_formats.end())
|
|
{
|
|
ams_display_format = iter->second;
|
|
}
|
|
else
|
|
{
|
|
assert(0 && __FUNCTION__);
|
|
ams_display_format = "AMS-%d";
|
|
}
|
|
|
|
int num_id;
|
|
try
|
|
{
|
|
num_id = std::stoi(GetAmsId());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
assert(0 && __FUNCTION__);
|
|
BOOST_LOG_TRIVIAL(error) << "Invalid AMS ID: " << GetAmsId() << ", error: " << e.what();
|
|
num_id = 0;
|
|
}
|
|
|
|
int loc = (num_id > 127) ? (num_id - 127) : (num_id + 1);
|
|
return wxString::Format(ams_display_format, loc);
|
|
}
|
|
|
|
int DevAms::GetSlotCount() const
|
|
{
|
|
// GetAmsType() maps AMS_LITE_MIXED -> AMS_LITE, so N9 reports 4 slots like AMS-Lite.
|
|
auto ams_type = GetAmsType();
|
|
if (ams_type == AMS || ams_type == AMS_LITE || ams_type == N3F)
|
|
{
|
|
return 4;
|
|
}
|
|
else if (ams_type == N3S)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
DevAmsTray* DevAms::GetTray(const std::string& tray_id) const
|
|
{
|
|
auto it = m_trays.find(tray_id);
|
|
if (it != m_trays.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool DevAms::IsSupportRemoteDry(const MachineObject* obj) const
|
|
{
|
|
if (obj && obj->is_support_remote_dry) {
|
|
return SupportDrying();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DevAms::AmsIsDrying()
|
|
{
|
|
if (!GetDryStatus().has_value()) {
|
|
return false;
|
|
}
|
|
|
|
return GetDryStatus().value() == DevAms::DryStatus::Checking
|
|
|| GetDryStatus().value() == DevAms::DryStatus::Drying
|
|
|| GetDryStatus().value() == DevAms::DryStatus::Error
|
|
|| GetDryStatus().value() == DevAms::DryStatus::CannotStopHeatOutofControl;
|
|
}
|
|
|
|
DevFilaSystem::~DevFilaSystem()
|
|
{
|
|
for (auto it = amsList.begin(); it != amsList.end(); it++)
|
|
{
|
|
if (it->second)
|
|
{
|
|
delete it->second;
|
|
it->second = nullptr;
|
|
}
|
|
}
|
|
amsList.clear();
|
|
}
|
|
|
|
DevAms* DevFilaSystem::GetAmsById(const std::string& ams_id) const
|
|
{
|
|
auto it = amsList.find(ams_id);
|
|
if (it != amsList.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
DevAmsTray* DevFilaSystem::GetAmsTray(const std::string& ams_id, const std::string& tray_id) const
|
|
{
|
|
auto it = amsList.find(ams_id);
|
|
if (it == amsList.end()) return nullptr;
|
|
if (!it->second) return nullptr;
|
|
return it->second->GetTray(tray_id);;
|
|
}
|
|
|
|
void DevFilaSystem::CollectAmsColors(std::vector<wxColour>& ams_colors) const
|
|
{
|
|
ams_colors.clear();
|
|
ams_colors.reserve(amsList.size());
|
|
for (auto ams = amsList.begin(); ams != amsList.end(); ams++)
|
|
{
|
|
for (auto tray = ams->second->GetTrays().begin(); tray != ams->second->GetTrays().end(); tray++)
|
|
{
|
|
if (tray->second->is_tray_info_ready())
|
|
{
|
|
auto ams_color = DevAmsTray::decode_color(tray->second->color);
|
|
ams_colors.emplace_back(ams_color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int DevFilaSystem::GetExtruderIdByAmsId(const std::string& ams_id) const
|
|
{
|
|
auto it = amsList.find(ams_id);
|
|
if (it != amsList.end())
|
|
{
|
|
return it->second->GetExtruderId();
|
|
}
|
|
else if (stoi(ams_id) == VIRTUAL_TRAY_MAIN_ID)
|
|
{
|
|
return MAIN_EXTRUDER_ID;
|
|
}
|
|
else if (stoi(ams_id) == VIRTUAL_TRAY_DEPUTY_ID)
|
|
{
|
|
return DEPUTY_EXTRUDER_ID;
|
|
}
|
|
|
|
assert(false && __FUNCTION__);
|
|
return 0; // not found
|
|
}
|
|
|
|
std::string DevFilaSystem::GetNozzleFlowStringByAmsId(const std::string& ams_id) const
|
|
{
|
|
auto extruder_id = GetExtruderIdByAmsId(ams_id);
|
|
auto nozzle = GetOwner()->GetNozzleSystem()->GetExtNozzle(extruder_id);
|
|
return DevNozzle::GetNozzleFlowTypeString(nozzle.GetNozzleFlowType());
|
|
}
|
|
|
|
std::map<int, DevAmsSlotId> DevFilaSystem::GetTrayIndexMap()
|
|
{
|
|
std::map<int, DevAmsSlotId> tray_id_map;
|
|
tray_id_map[VIRTUAL_TRAY_MAIN_ID] = DevAmsSlotId{VIRTUAL_TRAY_MAIN_ID, 0};
|
|
tray_id_map[VIRTUAL_TRAY_DEPUTY_ID] = DevAmsSlotId{VIRTUAL_TRAY_DEPUTY_ID, 0};
|
|
|
|
for (auto& [ams_id, ams_item] : GetAmsList()) {
|
|
for (auto &[slot_id, slot_item] : ams_item->GetTrays()) {
|
|
if (ams_item && slot_item) {
|
|
try {
|
|
int ams_id_int = stoi(ams_id);
|
|
int slot_id_int = stoi(slot_id);
|
|
int tray_index = -1;
|
|
if (ams_item->GetAmsType() == DevAms::N3S) {
|
|
tray_index = ams_id_int;
|
|
} else if(ams_item->GetAmsType() == DevAms::AMS_LITE && ams_item->IsAmsLiteMixed()) {
|
|
tray_index = 24 + slot_id_int;
|
|
} else {
|
|
tray_index = (ams_id_int * 4 + slot_id_int);
|
|
}
|
|
tray_id_map[tray_index] = {ams_id_int, slot_id_int};
|
|
} catch(...) {
|
|
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "invalid ams id: " << ams_id << " or slot id: " << slot_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return tray_id_map;
|
|
}
|
|
|
|
bool DevFilaSystem::IsAmsSettingUp() const
|
|
{
|
|
int setting_up_stat = DevUtil::get_flag_bits(m_ams_cali_stat, 0, 8);
|
|
if (setting_up_stat == 0x01 || setting_up_stat == 0x02 || setting_up_stat == 0x03 || setting_up_stat == 0x04)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DevFilaSystem::IsBBL_Filament(std::string tag_uid)
|
|
{
|
|
if (tag_uid.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < tag_uid.length(); i++)
|
|
{
|
|
if (tag_uid[i] != '0') { return true; }
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaSystem* system, bool key_field_only)
|
|
{
|
|
if (jj.contains("ams"))
|
|
{
|
|
if (jj["ams"].contains("ams"))
|
|
{
|
|
if (jj["ams"].contains("ams_exist_bits"))
|
|
{
|
|
obj->ams_exist_bits = stol(jj["ams"]["ams_exist_bits"].get<std::string>(), nullptr, 16);
|
|
}
|
|
|
|
if (jj["ams"].contains("tray_exist_bits"))
|
|
{
|
|
obj->tray_exist_bits = stol(jj["ams"]["tray_exist_bits"].get<std::string>(), nullptr, 16);
|
|
}
|
|
|
|
if (jj["ams"].contains("cali_stat")) { system->m_ams_cali_stat = jj["ams"]["cali_stat"].get<int>(); }
|
|
|
|
if (!key_field_only)
|
|
{
|
|
// Newer firmware sends the exact filament-change step sequence in ams.cfs, so the
|
|
// client no longer hardcodes the steps per model. Absent on current firmware, which
|
|
// keeps the list empty and the legacy hardcoded/ams_status_sub step path in effect.
|
|
if (jj["ams"].contains("cfs")) {
|
|
system->m_filament_change_steps = DevJsonValParser::GetVal<std::vector<DevFilamentStep>>(jj["ams"], "cfs");
|
|
} else {
|
|
system->m_filament_change_steps.clear();
|
|
}
|
|
|
|
if (jj["ams"].contains("tray_read_done_bits"))
|
|
{
|
|
obj->tray_read_done_bits = stol(jj["ams"]["tray_read_done_bits"].get<std::string>(), nullptr, 16);
|
|
}
|
|
if (jj["ams"].contains("tray_reading_bits"))
|
|
{
|
|
obj->tray_reading_bits = stol(jj["ams"]["tray_reading_bits"].get<std::string>(), nullptr, 16);
|
|
}
|
|
if (jj["ams"].contains("tray_is_bbl_bits"))
|
|
{
|
|
obj->tray_is_bbl_bits = stol(jj["ams"]["tray_is_bbl_bits"].get<std::string>(), nullptr, 16);
|
|
}
|
|
if (jj["ams"].contains("version"))
|
|
{
|
|
if (jj["ams"]["version"].is_number())
|
|
{
|
|
obj->ams_version = jj["ams"]["version"].get<int>();
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (jj["ams"].contains("ams_rfid_status")) { }
|
|
#endif
|
|
|
|
if (time(nullptr) - obj->ams_user_setting_start > HOLD_TIME_3SEC)
|
|
{
|
|
if (jj["ams"].contains("insert_flag"))
|
|
{
|
|
system->m_ams_system_setting.SetDetectOnInsertEnabled(jj["ams"]["insert_flag"].get<bool>());
|
|
}
|
|
if (jj["ams"].contains("power_on_flag"))
|
|
{
|
|
system->m_ams_system_setting.SetDetectOnPowerupEnabled(jj["ams"]["power_on_flag"].get<bool>());
|
|
}
|
|
if (jj["ams"].contains("calibrate_remain_flag"))
|
|
{
|
|
system->m_ams_system_setting.SetDetectRemainEnabled(jj["ams"]["calibrate_remain_flag"].get<bool>());
|
|
}
|
|
}
|
|
|
|
json j_ams = jj["ams"]["ams"];
|
|
std::set<std::string> ams_id_set;
|
|
|
|
for (auto it = system->amsList.begin(); it != system->amsList.end(); it++)
|
|
{
|
|
ams_id_set.insert(it->first);
|
|
}
|
|
|
|
for (auto it = j_ams.begin(); it != j_ams.end(); it++)
|
|
{
|
|
if (!it->contains("id")) continue;
|
|
std::string ams_id = (*it)["id"].get<std::string>();
|
|
|
|
int extuder_id = MAIN_EXTRUDER_ID; // Default nozzle id
|
|
int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s
|
|
|
|
/*ams info*/
|
|
std::set<int> binded_extruder_set;
|
|
std::optional<DevFilaSwitch::SwitchPos> binded_switcher_pos;
|
|
if (it->contains("info")) {
|
|
const std::string& info = (*it)["info"].get<std::string>();
|
|
type_id = DevUtil::get_flag_bits(info, 0, 4);
|
|
extuder_id = DevUtil::get_flag_bits(info, 8, 4);
|
|
if (extuder_id == 0xE && obj->GetFilaSwitch()->IsInstalled()) {
|
|
int bind_switch_in = DevUtil::get_flag_bits(info, 24, 4);
|
|
if (bind_switch_in == 0 || bind_switch_in == 1) {
|
|
binded_extruder_set = { MAIN_EXTRUDER_ID, DEPUTY_EXTRUDER_ID };
|
|
}
|
|
|
|
if (bind_switch_in == 0) {
|
|
binded_switcher_pos = DevFilaSwitch::SwitchPos::POS_IN_B;
|
|
} else if (bind_switch_in == 1) {
|
|
binded_switcher_pos = DevFilaSwitch::SwitchPos::POS_IN_A;
|
|
}
|
|
|
|
// Orca: the switch feeds every AMS to both extruders; pin a deterministic
|
|
// single-extruder id so legacy GetExtruderId() consumers keep a valid value
|
|
// while switch-aware code reads the binding set instead.
|
|
extuder_id = MAIN_EXTRUDER_ID;
|
|
} else if (extuder_id != 0xE) {
|
|
binded_extruder_set = { extuder_id };
|
|
}
|
|
} else {
|
|
if (!obj->is_enable_ams_np && obj->get_printer_ams_type() == "f1") {
|
|
type_id = DevAms::AMS_LITE;
|
|
}
|
|
binded_extruder_set = { MAIN_EXTRUDER_ID };
|
|
}
|
|
|
|
/*AMS without initialization*/
|
|
// Orca: an AMS reporting extruder 0xE without a Filament Track Switch installed has
|
|
// no usable extruder binding; drop it, preserving the existing display for
|
|
// half-initialized printers. With the switch installed the 0xE case is remapped
|
|
// above to both extruders and falls through to normal handling.
|
|
if (extuder_id == 0xE)
|
|
{
|
|
ams_id_set.erase(ams_id);
|
|
system->amsList.erase(ams_id);
|
|
continue;
|
|
}
|
|
|
|
ams_id_set.erase(ams_id);
|
|
DevAms* curr_ams = nullptr;
|
|
auto ams_it = system->amsList.find(ams_id);
|
|
if (ams_it == system->amsList.end())
|
|
{
|
|
DevAms* new_ams = new DevAms(ams_id, extuder_id, type_id);
|
|
system->amsList.insert(std::make_pair(ams_id, new_ams));
|
|
// new ams added event
|
|
curr_ams = new_ams;
|
|
}
|
|
else
|
|
{
|
|
if (extuder_id != ams_it->second->GetExtruderId())
|
|
{
|
|
ams_it->second->m_ext_id = extuder_id;
|
|
}
|
|
|
|
curr_ams = ams_it->second;
|
|
}
|
|
if (!curr_ams) continue;
|
|
|
|
/*set ams type flag*/
|
|
curr_ams->SetAmsType(type_id);
|
|
|
|
// Refresh the switch-aware extruder binding on every push (both create and
|
|
// update paths) so it can't go stale after an AMS is re-homed to another
|
|
// extruder. Without the switch the set holds the single bound extruder and
|
|
// the track position stays empty.
|
|
curr_ams->m_binded_extruder_set = binded_extruder_set;
|
|
curr_ams->m_binded_switcher_pos = binded_switcher_pos;
|
|
|
|
|
|
/*set ams exist flag*/
|
|
try
|
|
{
|
|
if (!ams_id.empty())
|
|
{
|
|
int ams_id_int = atoi(ams_id.c_str());
|
|
|
|
if (type_id < 4)
|
|
{
|
|
curr_ams->m_exist = (obj->ams_exist_bits & (1 << ams_id_int)) != 0 ? true : false;
|
|
}
|
|
else if (type_id == DevAms::AMS_LITE_MIXED)
|
|
{
|
|
// Mixed AMS-Lite (A2L / N9) exist flag lives at bit 12.
|
|
curr_ams->m_exist = DevUtil::get_flag_bits(obj->ams_exist_bits, 12);
|
|
}
|
|
else
|
|
{
|
|
curr_ams->m_exist = DevUtil::get_flag_bits(obj->ams_exist_bits, 4 + (ams_id_int - 128));
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
;
|
|
}
|
|
|
|
|
|
if (it->contains("temp"))
|
|
{
|
|
std::string temp = (*it)["temp"].get<std::string>();
|
|
try
|
|
{
|
|
curr_ams->m_current_temperature = DevUtil::string_to_float(temp);
|
|
}
|
|
catch (...)
|
|
{
|
|
curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE;
|
|
}
|
|
}
|
|
|
|
if (it->contains("humidity"))
|
|
{
|
|
try
|
|
{
|
|
std::string humidity = (*it)["humidity"].get<std::string>();
|
|
curr_ams->m_humidity_level = atoi(humidity.c_str());
|
|
}
|
|
catch (...)
|
|
{
|
|
;
|
|
}
|
|
}
|
|
|
|
if (it->contains("humidity_raw"))
|
|
{
|
|
try
|
|
{
|
|
std::string humidity_raw = (*it)["humidity_raw"].get<std::string>();
|
|
curr_ams->m_humidity_percent = atoi(humidity_raw.c_str());
|
|
}
|
|
catch (...)
|
|
{
|
|
;
|
|
}
|
|
}
|
|
|
|
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
|
|
{
|
|
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
|
|
}
|
|
|
|
// Drying status — only parse if printer supports remote drying
|
|
if (obj->is_support_remote_dry) {
|
|
if (it->contains("info")) {
|
|
const std::string& info = (*it)["info"].get<std::string>();
|
|
curr_ams->m_dry_status = (DevAms::DryStatus)DevUtil::get_flag_bits(info, 4, 4);
|
|
curr_ams->m_dry_fan1_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 18, 2);
|
|
curr_ams->m_dry_fan2_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 20, 2);
|
|
curr_ams->m_dry_sub_status = (DevAms::DrySubStatus)DevUtil::get_flag_bits(info, 22, 2);
|
|
}
|
|
|
|
if (it->contains("dry_setting")) {
|
|
const auto& j_dry_settings = (*it)["dry_setting"];
|
|
DevAms::DrySettings dry_settings;
|
|
DevJsonValParser::ParseVal(j_dry_settings, "dry_filament", dry_settings.dry_filament);
|
|
DevJsonValParser::ParseVal(j_dry_settings, "dry_temperature", dry_settings.dry_temp);
|
|
DevJsonValParser::ParseVal(j_dry_settings, "dry_duration", dry_settings.dry_hour);
|
|
curr_ams->m_dry_settings = dry_settings;
|
|
}
|
|
|
|
if (it->contains("dry_sf_reason")) {
|
|
curr_ams->m_dry_cannot_reasons = DevJsonValParser::GetVal<std::vector<DevAms::CannotDryReason>>((*it), "dry_sf_reason");
|
|
}
|
|
}
|
|
|
|
if (it->contains("tray"))
|
|
{
|
|
std::set<std::string> tray_id_set;
|
|
for (auto it = curr_ams->GetTrays().cbegin(); it != curr_ams->GetTrays().cend(); it++)
|
|
{
|
|
tray_id_set.insert(it->first);
|
|
}
|
|
for (auto tray_it = (*it)["tray"].begin(); tray_it != (*it)["tray"].end(); tray_it++)
|
|
{
|
|
if (!tray_it->contains("id")) continue;
|
|
std::string tray_id = (*tray_it)["id"].get<std::string>();
|
|
tray_id_set.erase(tray_id);
|
|
// compare tray_list
|
|
DevAmsTray* curr_tray = nullptr;
|
|
auto tray_iter = curr_ams->GetTrays().find(tray_id);
|
|
if (tray_iter == curr_ams->GetTrays().end())
|
|
{
|
|
DevAmsTray* new_tray = new DevAmsTray(tray_id);
|
|
curr_ams->m_trays.insert(std::make_pair(tray_id, new_tray));
|
|
curr_tray = new_tray;
|
|
}
|
|
else
|
|
{
|
|
curr_tray = tray_iter->second;
|
|
}
|
|
if (!curr_tray) continue;
|
|
|
|
if (curr_tray->hold_count > 0)
|
|
{
|
|
curr_tray->hold_count--;
|
|
continue;
|
|
}
|
|
|
|
curr_tray->id = (*tray_it)["id"].get<std::string>();
|
|
if (tray_it->contains("tag_uid"))
|
|
curr_tray->tag_uid = (*tray_it)["tag_uid"].get<std::string>();
|
|
else
|
|
curr_tray->tag_uid = "0";
|
|
if (tray_it->contains("tray_info_idx") && tray_it->contains("tray_type"))
|
|
{
|
|
curr_tray->setting_id = (*tray_it)["tray_info_idx"].get<std::string>();
|
|
//std::string type = (*tray_it)["tray_type"].get<std::string>();
|
|
std::string type = MachineObject::setting_id_to_type(curr_tray->setting_id, (*tray_it)["tray_type"].get<std::string>());
|
|
// curr_tray->setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
|
auto* agent = GUI::wxGetApp().getAgent();
|
|
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(curr_tray->setting_id) : curr_tray->setting_id;
|
|
if (printer_filament_id == "GFS00")
|
|
{
|
|
curr_tray->m_fila_type = "PLA-S";
|
|
}
|
|
else if (printer_filament_id == "GFS01")
|
|
{
|
|
curr_tray->m_fila_type = "PA-S";
|
|
}
|
|
else
|
|
{
|
|
curr_tray->m_fila_type = type;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curr_tray->setting_id = "";
|
|
curr_tray->m_fila_type = "";
|
|
}
|
|
if (tray_it->contains("tray_sub_brands"))
|
|
curr_tray->sub_brands = (*tray_it)["tray_sub_brands"].get<std::string>();
|
|
else
|
|
curr_tray->sub_brands = "";
|
|
if (tray_it->contains("tray_weight"))
|
|
curr_tray->weight = (*tray_it)["tray_weight"].get<std::string>();
|
|
else
|
|
curr_tray->weight = "";
|
|
if (tray_it->contains("tray_diameter"))
|
|
curr_tray->diameter = (*tray_it)["tray_diameter"].get<std::string>();
|
|
else
|
|
curr_tray->diameter = "";
|
|
if (tray_it->contains("tray_temp"))
|
|
curr_tray->temp = (*tray_it)["tray_temp"].get<std::string>();
|
|
else
|
|
curr_tray->temp = "";
|
|
if (tray_it->contains("tray_time"))
|
|
curr_tray->time = (*tray_it)["tray_time"].get<std::string>();
|
|
else
|
|
curr_tray->time = "";
|
|
if (tray_it->contains("bed_temp_type"))
|
|
curr_tray->bed_temp_type = (*tray_it)["bed_temp_type"].get<std::string>();
|
|
else
|
|
curr_tray->bed_temp_type = "";
|
|
if (tray_it->contains("bed_temp"))
|
|
curr_tray->bed_temp = (*tray_it)["bed_temp"].get<std::string>();
|
|
else
|
|
curr_tray->bed_temp = "";
|
|
if (tray_it->contains("tray_color"))
|
|
{
|
|
auto color = (*tray_it)["tray_color"].get<std::string>();
|
|
curr_tray->UpdateColorFromStr(color);
|
|
}
|
|
else
|
|
{
|
|
curr_tray->color = "";
|
|
}
|
|
if (tray_it->contains("nozzle_temp_max"))
|
|
{
|
|
curr_tray->nozzle_temp_max = (*tray_it)["nozzle_temp_max"].get<std::string>();
|
|
}
|
|
else
|
|
curr_tray->nozzle_temp_max = "";
|
|
if (tray_it->contains("nozzle_temp_min"))
|
|
curr_tray->nozzle_temp_min = (*tray_it)["nozzle_temp_min"].get<std::string>();
|
|
else
|
|
curr_tray->nozzle_temp_min = "";
|
|
if (tray_it->contains("xcam_info"))
|
|
curr_tray->xcam_info = (*tray_it)["xcam_info"].get<std::string>();
|
|
else
|
|
curr_tray->xcam_info = "";
|
|
if (tray_it->contains("tray_uuid"))
|
|
curr_tray->uuid = (*tray_it)["tray_uuid"].get<std::string>();
|
|
else
|
|
curr_tray->uuid = "0";
|
|
|
|
if (tray_it->contains("ctype"))
|
|
curr_tray->ctype = (*tray_it)["ctype"].get<int>();
|
|
else
|
|
curr_tray->ctype = 0;
|
|
curr_tray->cols.clear();
|
|
if (tray_it->contains("cols"))
|
|
{
|
|
if ((*tray_it)["cols"].is_array())
|
|
{
|
|
for (auto it = (*tray_it)["cols"].begin(); it != (*tray_it)["cols"].end(); it++)
|
|
{
|
|
curr_tray->cols.push_back(it.value().get<std::string>());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tray_it->contains("remain"))
|
|
{
|
|
curr_tray->remain = (*tray_it)["remain"].get<int>();
|
|
}
|
|
else
|
|
{
|
|
curr_tray->remain = -1;
|
|
}
|
|
if (tray_it->contains("tray_slot_placeholder")) {
|
|
curr_tray->is_slot_placeholder = true;
|
|
}
|
|
int ams_id_int = 0;
|
|
int tray_id_int = 0;
|
|
try
|
|
{
|
|
if (!ams_id.empty() && !curr_tray->id.empty())
|
|
{
|
|
ams_id_int = atoi(ams_id.c_str());
|
|
tray_id_int = atoi(curr_tray->id.c_str());
|
|
|
|
if (type_id < 4)
|
|
{
|
|
curr_tray->is_exists = (obj->tray_exist_bits & (1 << (ams_id_int * 4 + tray_id_int))) != 0 ? true : false;
|
|
}
|
|
else if (type_id == DevAms::AMS_LITE_MIXED)
|
|
{
|
|
// Mixed AMS-Lite (A2L / N9) trays occupy tray-exist bits 24..27.
|
|
curr_tray->is_exists = DevUtil::get_flag_bits(obj->tray_exist_bits, AMS_LITE_MIXED_TRAY_INDEX_OFFSET + tray_id_int);
|
|
}
|
|
else
|
|
{
|
|
curr_tray->is_exists = DevUtil::get_flag_bits(obj->tray_exist_bits, 16 + (ams_id_int - 128));
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
if (tray_it->contains("setting_id"))
|
|
{
|
|
curr_tray->filament_setting_id = (*tray_it)["setting_id"].get<std::string>();
|
|
}
|
|
auto curr_time = std::chrono::system_clock::now();
|
|
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - obj->extrusion_cali_set_hold_start);
|
|
if (diff.count() > HOLD_TIMEOUT || diff.count() < 0
|
|
|| ams_id_int != (obj->extrusion_cali_set_tray_id / 4)
|
|
|| tray_id_int != (obj->extrusion_cali_set_tray_id % 4))
|
|
{
|
|
if (tray_it->contains("k"))
|
|
{
|
|
curr_tray->k = (*tray_it)["k"].get<float>();
|
|
}
|
|
if (tray_it->contains("n"))
|
|
{
|
|
curr_tray->n = (*tray_it)["n"].get<float>();
|
|
}
|
|
}
|
|
|
|
std::string temp = tray_it->dump();
|
|
|
|
if (tray_it->contains("cali_idx"))
|
|
{
|
|
curr_tray->cali_idx = (*tray_it)["cali_idx"].get<int>();
|
|
}
|
|
}
|
|
// remove not in trayList
|
|
for (auto tray_it = tray_id_set.begin(); tray_it != tray_id_set.end(); tray_it++)
|
|
{
|
|
std::string tray_id = *tray_it;
|
|
auto tray = curr_ams->GetTrays().find(tray_id);
|
|
if (tray != curr_ams->GetTrays().end())
|
|
{
|
|
curr_ams->m_trays.erase(tray_id);
|
|
BOOST_LOG_TRIVIAL(trace) << "parse_json: remove ams_id=" << ams_id << ", tray_id=" << tray_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// remove not in amsList
|
|
for (auto it = ams_id_set.begin(); it != ams_id_set.end(); it++)
|
|
{
|
|
std::string ams_id = *it;
|
|
auto ams = system->amsList.find(ams_id);
|
|
if (ams != system->amsList.end())
|
|
{
|
|
BOOST_LOG_TRIVIAL(trace) << "parse_json: remove ams_id=" << ams_id;
|
|
system->amsList.erase(ams_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static DevAms::AmsType ams_type_from_string(const std::string& s)
|
|
{
|
|
if (s == "ams_lite" || s == "ams-lite") return DevAms::AMS_LITE;
|
|
if (s == "n3f") return DevAms::N3F;
|
|
if (s == "n3s") return DevAms::N3S;
|
|
return DevAms::AMS; // default
|
|
}
|
|
|
|
void DevFilaSystemParser::ParseAgentFilament(const json& data, MachineObject* obj, DevFilaSystem* system)
|
|
{
|
|
if (!system || !data.is_object())
|
|
return;
|
|
|
|
// --- AMS units ---
|
|
if (data.contains("units") && data["units"].is_array())
|
|
{
|
|
std::set<std::string> seen_units;
|
|
|
|
for (const auto& u : data["units"])
|
|
{
|
|
if (!u.is_object() || !u.contains("id"))
|
|
continue;
|
|
const std::string ams_id = u.value("id", std::string());
|
|
if (ams_id.empty())
|
|
continue;
|
|
seen_units.insert(ams_id);
|
|
|
|
const int ext_id = u.value("extruder", MAIN_EXTRUDER_ID);
|
|
const DevAms::AmsType type = ams_type_from_string(u.value("type", std::string("ams")));
|
|
|
|
DevAms* ams = nullptr;
|
|
auto it = system->amsList.find(ams_id);
|
|
if (it == system->amsList.end())
|
|
{
|
|
ams = new DevAms(ams_id, ext_id, type);
|
|
system->amsList.insert(std::make_pair(ams_id, ams));
|
|
}
|
|
else
|
|
{
|
|
ams = it->second;
|
|
ams->m_ext_id = ext_id;
|
|
ams->SetAmsType(type);
|
|
}
|
|
|
|
ams->m_exist = true;
|
|
ams->m_current_temperature = u.value("temperature", (float) INVALID_AMS_TEMPERATURE);
|
|
ams->m_humidity_percent = u.value("humidity_percent", -1);
|
|
ams->m_left_dry_time = u.value("dry_time_min", 0);
|
|
|
|
// --- slots / trays ---
|
|
std::set<std::string> seen_slots;
|
|
if (u.contains("slots") && u["slots"].is_array())
|
|
{
|
|
for (const auto& s : u["slots"])
|
|
{
|
|
if (!s.is_object())
|
|
continue;
|
|
const std::string tray_id = std::to_string(s.value("index", -1));
|
|
seen_slots.insert(tray_id);
|
|
|
|
DevAmsTray* tray = nullptr;
|
|
auto tit = ams->m_trays.find(tray_id);
|
|
if (tit == ams->m_trays.end())
|
|
{
|
|
tray = new DevAmsTray(tray_id);
|
|
ams->m_trays.insert(std::make_pair(tray_id, tray));
|
|
}
|
|
else
|
|
{
|
|
tray = tit->second;
|
|
}
|
|
|
|
tray->is_exists = s.value("loaded", false);
|
|
tray->m_fila_type = s.value("material", std::string());
|
|
tray->setting_id = s.value("preset_id", std::string());
|
|
tray->UpdateColorFromStr(s.value("color", std::string()));
|
|
tray->nozzle_temp_min = std::to_string(s.value("nozzle_temp_min", 0));
|
|
tray->nozzle_temp_max = std::to_string(s.value("nozzle_temp_max", 0));
|
|
tray->remain = s.value("remain_percent", -1);
|
|
tray->k = s.value("k", 0.0f);
|
|
if (s.contains("diameter_mm") && s["diameter_mm"].is_number())
|
|
tray->diameter = std::to_string(s["diameter_mm"].get<double>());
|
|
if (s.contains("weight_g") && s["weight_g"].is_number())
|
|
tray->weight = std::to_string(s["weight_g"].get<int>());
|
|
|
|
tray->cols.clear();
|
|
if (s.contains("colors") && s["colors"].is_array())
|
|
{
|
|
for (const auto& c : s["colors"])
|
|
if (c.is_string())
|
|
tray->cols.push_back(c.get<std::string>());
|
|
}
|
|
tray->ctype = tray->cols.size() > 1 ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
// prune trays no longer reported
|
|
for (auto tit = ams->m_trays.begin(); tit != ams->m_trays.end();)
|
|
{
|
|
if (seen_slots.count(tit->first) == 0)
|
|
{
|
|
delete tit->second;
|
|
tit = ams->m_trays.erase(tit);
|
|
}
|
|
else
|
|
{
|
|
++tit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// prune units no longer reported
|
|
for (auto it = system->amsList.begin(); it != system->amsList.end();)
|
|
{
|
|
if (seen_units.count(it->first) == 0)
|
|
{
|
|
delete it->second;
|
|
it = system->amsList.erase(it);
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- external / direct spools -> obj->vt_slot ---
|
|
// extruder 0 -> main virtual slot, extruder >0 -> deputy.
|
|
if (obj && data.contains("external") && data["external"].is_array())
|
|
{
|
|
obj->vt_slot.clear();
|
|
for (const auto& e : data["external"])
|
|
{
|
|
if (!e.is_object())
|
|
continue;
|
|
const int ext = e.value("extruder", MAIN_EXTRUDER_ID);
|
|
const int vt_id = (ext == MAIN_EXTRUDER_ID) ? VIRTUAL_TRAY_MAIN_ID : VIRTUAL_TRAY_DEPUTY_ID;
|
|
DevAmsTray tray(std::to_string(vt_id));
|
|
tray.is_exists = e.value("loaded", false);
|
|
tray.m_fila_type = e.value("material", std::string());
|
|
tray.setting_id = e.value("preset_id", std::string());
|
|
tray.UpdateColorFromStr(e.value("color", std::string()));
|
|
tray.nozzle_temp_min = std::to_string(e.value("nozzle_temp_min", 0));
|
|
tray.nozzle_temp_max = std::to_string(e.value("nozzle_temp_max", 0));
|
|
tray.remain = e.value("remain_percent", -1);
|
|
obj->vt_slot.push_back(tray);
|
|
}
|
|
}
|
|
}
|
|
|
|
} |