ENH: clean codes about device

JIRA: [STUDIO-13609]
Change-Id: I591de7033360b9570600006cfbce2148a8d031d5
(cherry picked from commit e9c774be8f4c89b8dafa14ef56913612fb68bd0c)
This commit is contained in:
xin.zhang
2025-08-01 17:34:35 +08:00
committed by Noisyfox
parent e17c8bfb80
commit 4a787f6ff8
115 changed files with 7238 additions and 5492 deletions

View File

@@ -0,0 +1,52 @@
# GUI/DeviceCore
# usage -- none GUI structure about device
# date -- 2025.07.14
# status -- Building
list(APPEND SLIC3R_GUI_SOURCES
GUI/DeviceCore/DevBed.cpp
GUI/DeviceCore/DevBed.h
GUI/DeviceCore/DevConfig.h
GUI/DeviceCore/DevConfig.cpp
GUI/DeviceCore/DevConfigUtil.h
GUI/DeviceCore/DevConfigUtil.cpp
GUI/DeviceCore/DevCtrl.h
GUI/DeviceCore/DevCtrl.cpp
GUI/DeviceCore/DevDefs.h
GUI/DeviceCore/DevExtruderSystem.h
GUI/DeviceCore/DevExtruderSystem.cpp
GUI/DeviceCore/DevExtruderSystemCtrl.cpp
GUI/DeviceCore/DevFan.cpp
GUI/DeviceCore/DevFan.h
GUI/DeviceCore/DevFilaAmsSetting.h
GUI/DeviceCore/DevFilaAmsSetting.cpp
GUI/DeviceCore/DevFilaBlackList.h
GUI/DeviceCore/DevFilaBlackList.cpp
GUI/DeviceCore/DevFilaSystem.h
GUI/DeviceCore/DevFilaSystem.cpp
GUI/DeviceCore/DevFirmware.h
GUI/DeviceCore/DevFirmware.cpp
GUI/DeviceCore/DevPrintOptions.h
GUI/DeviceCore/DevPrintOptions.cpp
GUI/DeviceCore/DevPrintTaskInfo.h
GUI/DeviceCore/DevPrintTaskInfo.cpp
GUI/DeviceCore/DevHMS.h
GUI/DeviceCore/DevHMS.cpp
GUI/DeviceCore/DevStorage.h
GUI/DeviceCore/DevStorage.cpp
GUI/DeviceCore/DevInfo.h
GUI/DeviceCore/DevInfo.cpp
GUI/DeviceCore/DevLamp.h
GUI/DeviceCore/DevLamp.cpp
GUI/DeviceCore/DevLampCtrl.cpp
GUI/DeviceCore/DevManager.h
GUI/DeviceCore/DevManager.cpp
GUI/DeviceCore/DevMapping.h
GUI/DeviceCore/DevMapping.cpp
GUI/DeviceCore/DevNozzleSystem.h
GUI/DeviceCore/DevNozzleSystem.cpp
GUI/DeviceCore/DevUtil.h
GUI/DeviceCore/DevUtil.cpp
)
set(SLIC3R_GUI_SOURCES ${SLIC3R_GUI_SOURCES} PARENT_SCOPE)

View File

@@ -0,0 +1,25 @@
#include "DevBed.h"
#include "slic3r/GUI/DeviceManager.hpp"
namespace Slic3r {
void DevBed::ParseV1_0(const json &print_json, DevBed *system)
{
if (print_json.contains("bed_temper")) {
if (print_json["bed_temper"].is_number()) { system->bed_temp = print_json["bed_temper"].get<float>(); }
}
if (print_json.contains("bed_target_temper")) {
if (print_json["bed_target_temper"].is_number()) { system->bed_temp_target = print_json["bed_target_temper"].get<float>(); }
}
}
void DevBed::ParseV2_0(const json &print_json, DevBed *system)
{
if (print_json.contains("bed_temp") && print_json["bed_temp"].is_number()) {
int bed_temp_bits = print_json["bed_temp"].get<int>();
system->bed_temp = system->m_owner->get_flag_bits(bed_temp_bits, 0, 16);
system->bed_temp_target = system->m_owner->get_flag_bits(bed_temp_bits, 16, 16);
}
}
} // namespace Slic3r

View File

@@ -0,0 +1,30 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
namespace Slic3r {
class MachineObject;
class DevBed
{
public:
DevBed(MachineObject *obj) : m_owner(obj), bed_temp(0.0f), bed_temp_target(0.0f) {}
float GetBedTemp() { return bed_temp; };
float GetBedTempTarget() { return bed_temp_target; };
public:
static void ParseV1_0(const json &print_json, DevBed *system);
static void ParseV2_0(const json &print_json, DevBed *system);
private:
float bed_temp;
float bed_temp_target;
MachineObject* m_owner = nullptr;
};
} // namespace Slic3r

View File

@@ -0,0 +1,54 @@
#include <nlohmann/json.hpp>
#include "DevConfig.h"
#include "DevUtil.h"
using namespace nlohmann;
namespace Slic3r
{
void DevConfig::ParseConfig(const json& print_json)
{
ParseChamberConfig(print_json);
ParsePrintOptionsConfig(print_json);
ParseCalibrationConfig(print_json);
}
void DevConfig::ParseChamberConfig(const json& print_json)
{
DevJsonValParser::ParseVal(print_json, "support_chamber_temp_edit", m_support_chamber_edit);
if (m_support_chamber_edit)
{
if (print_json.contains("support_chamber_temp_edit_range"))
{
const auto &support_champer_range = print_json["support_chamber_temp_edit_range"];
if (support_champer_range.is_array() && support_champer_range.size() > 1) {
m_chamber_temp_edit_min = support_champer_range[0];
m_chamber_temp_edit_max = support_champer_range[1];
}
}
DevJsonValParser::ParseVal(print_json, "support_chamber_temp_switch_heating", m_chamber_temp_switch_heat);
}
}
void DevConfig::ParsePrintOptionsConfig(const json& print_json)
{
DevJsonValParser::ParseVal(print_json, "support_first_layer_inspect", m_support_first_layer_inspect);
DevJsonValParser::ParseVal(print_json, "support_save_remote_print_file_to_storage", m_support_save_remote_print_file_to_storage);
DevJsonValParser::ParseVal(print_json, "support_ai_monitoring", m_support_ai_monitor);
DevJsonValParser::ParseVal(print_json, "support_print_without_sd", m_support_print_without_sd);
DevJsonValParser::ParseVal(print_json, "support_print_all", m_support_print_all);
}
void DevConfig::ParseCalibrationConfig(const json& print_json)
{
DevJsonValParser::ParseVal(print_json, "support_lidar_calibration", m_support_calibration_lidar);
DevJsonValParser::ParseVal(print_json, "support_nozzle_offset_calibration", m_support_calibration_nozzle_offset);
DevJsonValParser::ParseVal(print_json, "support_high_tempbed_calibration", m_support_calibration_high_temp_bed);
DevJsonValParser::ParseVal(print_json, "support_pa_calibration_auto", m_support_calibration_pa_flow_auto);
}
}

View File

@@ -0,0 +1,77 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
namespace Slic3r
{
//Previous definitions
class MachineObject;
class DevConfig
{
public:
DevConfig(MachineObject* obj) : m_obj(obj) {};
~DevConfig() = default;
public:
// chamber
bool SupportChamberEdit() const { return m_support_chamber_edit; }
int GetChamberTempEditMin() const { return m_chamber_temp_edit_min; }
int GetChamberTempEditMax() const { return m_chamber_temp_edit_max; }
int GetChamberTempSwitchHeat() const { return m_chamber_temp_switch_heat; }
// print options
bool SupportFirstLayerInspect() const { return m_support_first_layer_inspect; }
bool SupportSaveRemotePrintFileToStorage() const { return m_support_save_remote_print_file_to_storage; }
bool SupportAIMonitor() const { return m_support_ai_monitor; }
bool SupportPrintWithoutSD() const { return m_support_print_without_sd; }
bool SupportPrintAllPlates() const { return m_support_print_all; }
// calibration options
bool SupportCalibrationLidar() const { return m_support_calibration_lidar; }
bool SupportCalibrationNozzleOffset() const { return m_support_calibration_nozzle_offset; }
bool SupportCalibrationHighTempBed() const { return m_support_calibration_high_temp_bed; }
bool SupportCalibrationPA_FlowAuto() const { return m_support_calibration_pa_flow_auto; }
public:
/*Setters*/
void ParseConfig(const json& print_json);
void ParseChamberConfig(const json& print_json); // chamber
void ParsePrintOptionsConfig(const json& print_json); // print options
void ParseCalibrationConfig(const json& print_json); //cali
private:
MachineObject* m_obj;
/*configure vals*/
// chamber
bool m_support_chamber_edit = false;
int m_chamber_temp_edit_min = 0;
int m_chamber_temp_edit_max = 60;
int m_chamber_temp_switch_heat = LONG_MAX; /* the min temp to start heating, default to LONG_MAX */
// print options
bool m_support_first_layer_inspect = false;
bool m_support_save_remote_print_file_to_storage = false;
bool m_support_ai_monitor = false;
bool m_support_print_without_sd = false;
bool m_support_print_all = false;
// calibration options
bool m_support_calibration_lidar = false;
bool m_support_calibration_nozzle_offset = false;
bool m_support_calibration_high_temp_bed = false; // High-temperature Heatbed Calibration
bool m_support_calibration_pa_flow_auto = false;// PA flow calibration. used in SendPrint
};
};

View File

@@ -0,0 +1,167 @@
#include "DevConfigUtil.h"
#include <wx/dir.h>
using namespace nlohmann;
namespace Slic3r
{
std::string DevPrinterConfigUtil::m_resource_file_path = "";
std::map<std::string, std::string> DevPrinterConfigUtil::get_all_model_id_with_name()
{
{
std::map<std::string, std::string> models;
wxDir dir(m_resource_file_path + "/printers/");
if (!dir.IsOpened())
{
return models;
}
wxString filename;
std::vector<wxString> m_files;
bool hasFile = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES);
while (hasFile)
{
m_files.push_back(filename);
hasFile = dir.GetNext(&filename);
}
for (wxString file : m_files)
{
if (!file.Lower().ends_with(".json")) continue;
std::string config_file = m_resource_file_path + "/printers/" + file.ToStdString();
boost::nowide::ifstream json_file(config_file.c_str());
try
{
json jj;
if (json_file.is_open())
{
json_file >> jj;
if (jj.contains("00.00.00.00"))
{
json const& printer = jj["00.00.00.00"];
std::string model_id;
std::string display_name;
if (printer.contains("model_id")) { model_id = printer["model_id"].get<std::string>(); }
if (printer.contains("display_name")) { display_name = printer["display_name"].get<std::string>(); }
models[display_name] = model_id;
}
}
}
catch (...) {}
}
return models;
}
}
PrinterArch DevPrinterConfigUtil::get_printer_arch(std::string type_str)
{
const std::string& arch_str = get_value_from_config<std::string>(type_str, "printer_arch");
if (arch_str == "i3")
{
return PrinterArch::ARCH_I3;
}
else if (arch_str == "core_xy")
{
return PrinterArch::ARCH_CORE_XY;
}
return PrinterArch::ARCH_CORE_XY;
}
std::string DevPrinterConfigUtil::get_printer_ext_img(const std::string& type_str, int pos)
{
const auto& vec = get_value_from_config<std::vector<std::string>>(type_str, "printer_ext_image");
return (vec.size() > pos) ? vec[pos] : std::string();
};
std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, const std::string& key)
{
std::vector<std::string> filaments;
std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json";
boost::nowide::ifstream json_file(config_file.c_str());
try
{
json jj;
if (json_file.is_open())
{
json_file >> jj;
if (jj.contains("00.00.00.00"))
{
json const& printer = jj["00.00.00.00"];
if (printer.contains("fan") && printer["fan"].contains(key))
{
return printer["fan"][key].get<std::string>();
}
}
}
}
catch (...) {}
return std::string();
}
std::map<std::string, std::vector<std::string>> DevPrinterConfigUtil::get_all_subseries(std::string type_str)
{
std::map<std::string, std::vector<std::string>> subseries;
std::vector<wxString> m_files;
wxDir dir(m_resource_file_path + "/printers/");
if (!dir.IsOpened()) { return subseries; }
wxString filename;
bool hasFile = dir.GetFirst(&filename, "*.json", wxDIR_FILES);
while (hasFile)
{
m_files.push_back(filename);
hasFile = dir.GetNext(&filename);
}
for (wxString file : m_files)
{
std::string config_file = m_resource_file_path + "/printers/" + file.ToStdString();
boost::nowide::ifstream json_file(config_file.c_str());
try
{
json jj;
if (json_file.is_open())
{
json_file >> jj;
if (jj.contains("00.00.00.00"))
{
json const& printer = jj["00.00.00.00"];
if (printer.contains("subseries"))
{
std::vector<std::string> subs;
std::string model_id = printer["model_id"].get<std::string>();
if (model_id == type_str || type_str.empty())
{
for (auto res : printer["subseries"])
{
subs.emplace_back(res.get<std::string>());
}
}
subseries.insert(make_pair(model_id, subs));
}
}
}
}
catch (...) {}
}
return subseries;
}
};

View File

@@ -0,0 +1,174 @@
/**
* @file DevConfigUtil.h
* @brief Parses configuration files and provides access to printer options.
*
* This class loads a configuration file and allows querying options by key.
* The configuration file format is expected to be key-value pairs (e.g., INI or simple text).
*/
#pragma once
#include <string>
#include <map>
#include <vector>
#include <boost/nowide/fstream.hpp>
#include <nlohmann/json.hpp>
#include <wx/string.h>
#include "slic3r/GUI/DeviceCore/DevDefs.h"
namespace Slic3r
{
class dePrinterConfigFactory
{
public:
dePrinterConfigFactory() = default;
~dePrinterConfigFactory() = default;
};
class DevPrinterConfigUtil
{
public:
DevPrinterConfigUtil() = default;
~DevPrinterConfigUtil() = default;
public:
static void InitFilePath(const std::string& res_file_path) { m_resource_file_path = res_file_path; };
/*printer*/
// info
static std::map<std::string, std::string> get_all_model_id_with_name();
static std::string get_printer_type(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_type"); }
static std::string get_printer_display_name(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "display_name"); }
static std::string get_printer_series_str(std::string type_str) { return get_value_from_config<std::string>(type_str, "printer_series"); }
static PrinterArch get_printer_arch(std::string type_str);
// images
static std::string get_printer_thumbnail_img(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_thumbnail_image"); }
static std::string get_printer_connect_help_img(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_connect_help_image"); }
static std::string get_printer_auto_pa_cali_image(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "auto_pa_cali_thumbnail_image"); }
/*media*/
static std::string get_ftp_folder(std::string type_str) { return get_value_from_config<std::string>(type_str, "ftp_folder"); }
static std::vector<std::string> get_resolution_supported(std::string type_str) { return get_value_from_config<std::vector<std::string>>(type_str, "camera_resolution"); }
static std::vector<std::string> get_compatible_machine(std::string type_str) { return get_value_from_config<std::vector<std::string>>(type_str, "compatible_machine"); }
static std::map<std::string, std::vector<std::string>> get_all_subseries(std::string type_str = "");
/*ams*/
static std::string get_printer_use_ams_type(std::string type_str) { return get_value_from_config<std::string>(type_str, "use_ams_type"); }
static std::string get_printer_ams_img(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_use_ams_image"); }
static std::string get_printer_ext_img(const std::string& type_str, int pos);//printer_ext_image
/*fan*/
static std::string get_fan_text(const std::string& type_str, const std::string& key);
/*extruder*/
static bool get_printer_can_set_nozzle(std::string type_str) { return get_value_from_config<bool>(type_str, "enable_set_nozzle_info"); }// can set nozzle from studio
/*calibration*/
static std::vector<std::string> get_unsupport_auto_cali_filaments(std::string type_str) { return get_value_from_config<std::vector<std::string>>(type_str, "auto_cali_not_support_filaments"); }
/*detection*/
static bool support_wrapping_detection(const std::string& type_str) { return get_value_from_config<bool>(type_str, "support_wrapping_deteciton"); }
public:
template<typename T>
static T get_value_from_config(const std::string& type_str, const std::string& item)
{
std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json";
boost::nowide::ifstream json_file(config_file.c_str());
try
{
nlohmann::json jj;
if (json_file.is_open())
{
json_file >> jj;
if (jj.contains("00.00.00.00"))
{
nlohmann::json const& printer = jj["00.00.00.00"];
if (printer.contains(item))
{
return printer[item].get<T>();
}
}
}
}
catch (...) { assert(0 && "get_value_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors
return T();
};
static nlohmann::json get_json_from_config(const std::string& type_str, const std::string& key1, const std::string& key2 = std::string())
{
std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json";
boost::nowide::ifstream json_file(config_file.c_str());
try
{
nlohmann::json jj;
if (json_file.is_open())
{
json_file >> jj;
if (jj.contains("00.00.00.00"))
{
nlohmann::json const& printer = jj["00.00.00.00"];
if (printer.contains(key1))
{
nlohmann::json const& key1_item = printer[key1];
if (key2.empty())
{
return key1_item;
}
if (key1_item.contains(key2))
{
return key1_item[key2];
}
}
}
}
}
catch (...) { assert(0 && "get_json_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors
return nlohmann::json();
}
private:
static std::string m_resource_file_path; // Path to the configuration file
};
/*special transform*/
static std::string _parse_printer_type(const std::string& type_str)
{
if (type_str.compare("3DPrinter-X1") == 0)
{
return "BL-P002";
}
else if (type_str.compare("3DPrinter-X1-Carbon") == 0)
{
return "BL-P001";
}
else if (type_str.compare("BL-P001") == 0)
{
return type_str;
}
else if (type_str.compare("BL-P002") == 0)
{
return type_str;
}
else
{
std::string result = DevPrinterConfigUtil::get_printer_type(type_str);
if (!result.empty())
{
return result;
}
}
assert(0 && __FUNCTION__);
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Unsupported printer type: " << type_str;
return type_str;
}
};// namespace Slic3r

View File

@@ -0,0 +1,26 @@
#include <nlohmann/json.hpp>
#include "DevCtrl.h"
// TODO: remove this include
#include "DevUtil.h"
#include "slic3r/GUI/DeviceManager.hpp"
using namespace nlohmann;
namespace Slic3r
{
int DevCtrl::command_select_extruder(int id)
{
json j;
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["command"] = "select_extruder";
j["print"]["extruder_index"] = id;
int rtn = m_obj->publish_json(j, 1);
if (rtn == 0)
{
m_obj->targ_nozzle_id_from_pc = id;
}
return rtn;
}
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
namespace Slic3r
{
//Previous definitions
class MachineObject;
class DevCtrl
{
MachineObject* m_obj;
public:
DevCtrl(MachineObject* obj) : m_obj(obj) {};
~DevCtrl() = default;
public:
/*extruder system*/
int command_select_extruder(int id);
};
};

View File

@@ -0,0 +1,99 @@
/**
* @file DevDefs.h
* @brief Common definitions, macros, and constants for printer modules.
* Enhance building and including.
*
* This file provides shared macros, constants, and enumerations for all printer-related
* modules, including printer types, status, binding states, connection types, and error codes.
* It is intended to be included wherever printer-specific definitions are required.
*/
#pragma once
#include <string>
enum PrinterArch
{
ARCH_CORE_XY,
ARCH_I3,
};
enum PrinterSeries
{
SERIES_X1 = 0,
SERIES_P1P,
SERIES_UNKNOWN,
};
namespace Slic3r
{
/*AMS*/
enum AmsStatusMain
{
AMS_STATUS_MAIN_IDLE = 0x00,
AMS_STATUS_MAIN_FILAMENT_CHANGE = 0x01,
AMS_STATUS_MAIN_RFID_IDENTIFYING = 0x02,
AMS_STATUS_MAIN_ASSIST = 0x03,
AMS_STATUS_MAIN_CALIBRATION = 0x04,
AMS_STATUS_MAIN_SELF_CHECK = 0x10,
AMS_STATUS_MAIN_DEBUG = 0x20,
AMS_STATUS_MAIN_UNKNOWN = 0xFF,
};
// Slots and Tray
#define VIRTUAL_TRAY_MAIN_ID 255
#define VIRTUAL_TRAY_DEPUTY_ID 254
#define VIRTUAL_AMS_MAIN_ID_STR "255"
#define VIRTUAL_AMS_DEPUTY_ID_STR "254"
#define INVALID_AMS_TEMPERATURE std::numeric_limits<float>::min()
/* Extruder*/
#define MAIN_EXTRUDER_ID 0
#define DEPUTY_EXTRUDER_ID 1
#define UNIQUE_EXTRUDER_ID MAIN_EXTRUDER_ID
#define INVALID_EXTRUDER_ID -1
/* Nozzle*/
enum NozzleFlowType
{
NONE_FLOWTYPE,
S_FLOW,
H_FLOW
};
/*Print speed*/
enum DevPrintingSpeedLevel
{
SPEED_LEVEL_INVALID = 0,
SPEED_LEVEL_SILENCE = 1,
SPEED_LEVEL_NORMAL = 2,
SPEED_LEVEL_RAPID = 3,
SPEED_LEVEL_RAMPAGE = 4,
SPEED_LEVEL_COUNT
};
/*Upgrade*/
enum class DevFirmwareUpgradingState : int
{
DC = -1,
UpgradingUnavaliable = 0,
UpgradingAvaliable = 1,
UpgradingInProgress = 2,
UpgradingFinished = 3
};
class devPrinterUtil
{
public:
devPrinterUtil() = delete;
~devPrinterUtil() = delete;
public:
static bool IsVirtualSlot(int ams_id) { return (ams_id == VIRTUAL_TRAY_MAIN_ID || ams_id == VIRTUAL_TRAY_DEPUTY_ID);}
static bool IsVirtualSlot(const std::string& ams_id) { return (ams_id == VIRTUAL_AMS_MAIN_ID_STR || ams_id == VIRTUAL_AMS_DEPUTY_ID_STR); }
};
};// namespace Slic3r

View File

@@ -0,0 +1,287 @@
#include <nlohmann/json.hpp>
#include "DevExtruderSystem.h"
#include "DevNozzleSystem.h"
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "DevUtil.h"
using namespace nlohmann;
namespace Slic3r
{
wxString DevExtder::GetDisplayLoc() const
{
if (system->GetTotalExtderCount() == 2)
{
if (m_ext_id == MAIN_EXTRUDER_ID)
{
return _L("right");
}
else
{
return _L("left");
}
}
return wxEmptyString;
}
wxString DevExtder::GetDisplayName() const
{
if (system->GetTotalExtderCount() == 2)
{
if (m_ext_id == MAIN_EXTRUDER_ID)
{
return _L("right extruder");
}
else
{
return _L("left extruder");
}
}
return _L("extruder");
}
NozzleType DevExtder::GetNozzleType() const
{
return system->Owner()->GetNozzleSystem()->GetNozzle(m_current_nozzle_id).m_nozzle_type;
}
NozzleFlowType DevExtder::GetNozzleFlowType() const
{
return system->Owner()->GetNozzleSystem()->GetNozzle(m_current_nozzle_id).m_nozzle_flow;
}
float DevExtder::GetNozzleDiameter() const
{
return system->Owner()->GetNozzleSystem()->GetNozzle(m_current_nozzle_id).m_diameter;
}
DevExtderSystem::DevExtderSystem(MachineObject* obj)
: m_owner(obj)
{
// default to have one extruder
m_total_extder_count = 1;
DevExtder ext(this, MAIN_EXTRUDER_ID);
m_extders.emplace_back(ext);
}
bool DevExtderSystem::CanQuitSwitching() const
{
if (!IsSwitchingFailed())
{
return false;
}
return !m_owner->is_in_printing() && !m_owner->is_in_printing_pause();
}
std::optional<DevExtder> DevExtderSystem::GetCurrentExtder() const
{
return GetExtderById(m_current_extder_id);
}
std::optional<DevExtder> DevExtderSystem::GetLoadingExtder() const
{
if (m_current_loading_extder_id != INVALID_EXTRUDER_ID)
{
return GetExtderById(m_current_loading_extder_id);
}
return std::nullopt;
}
std::optional<DevExtder> DevExtderSystem::GetExtderById(int extder_id) const
{
if (extder_id >= m_extders.size())
{
assert(false && "Invalid extruder ID");
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "No extruder found for " << extder_id;
return std::nullopt;
}
return m_extders[extder_id];
}
std::string DevExtderSystem::GetCurrentAmsId() const
{
auto cur_extder = GetCurrentExtder();
return cur_extder ? cur_extder->GetSlotNow().ams_id : DevAmsSlotInfo().ams_id;
}
std::string DevExtderSystem::GetCurrentSlotId() const
{
auto cur_extder = GetCurrentExtder();
return cur_extder ? GetCurrentExtder()->GetSlotNow().slot_id : DevAmsSlotInfo().slot_id;
}
std::string DevExtderSystem::GetTargetAmsId() const
{
auto cur_extder = GetCurrentExtder();
return cur_extder ? GetCurrentExtder()->GetSlotTarget().ams_id : DevAmsSlotInfo().ams_id;
}
std::string DevExtderSystem::GetTargetSlotId() const
{
auto cur_extder = GetCurrentExtder();
return cur_extder ? GetCurrentExtder()->GetSlotTarget().slot_id : DevAmsSlotInfo().slot_id;
}
bool DevExtderSystem::HasFilamentBackup() const
{
for (const auto& ext : m_extders)
{
if (ext.HasFilamBackup())
{
return true;
}
}
return false;
}
void ExtderSystemParser::ParseV1_0(const nlohmann::json& print_json, DevExtderSystem* system)
{
if (system->GetTotalExtderCount() != 1)
{
return;
}
if (print_json.contains("nozzle_temper") && print_json["nozzle_temper"].is_number())
{
system->m_extders[MAIN_EXTRUDER_ID].m_cur_temp = print_json["nozzle_temper"].get<float>();
}
if (print_json.contains("nozzle_target_temper") && print_json["nozzle_target_temper"].is_number())
{
system->m_extders[MAIN_EXTRUDER_ID].m_target_temp = print_json["nozzle_target_temper"].get<float>();
}
if (print_json.contains("ams") && print_json["ams"].contains("tray_tar"))
{
const std::string& tray_tar = print_json["ams"]["tray_tar"].get<std::string>();
if (!tray_tar.empty())
{
int tray_tar_int = atoi(tray_tar.c_str());
if (tray_tar_int == VIRTUAL_TRAY_MAIN_ID || tray_tar_int == VIRTUAL_TRAY_DEPUTY_ID)
{
system->m_extders[MAIN_EXTRUDER_ID].m_star.ams_id = std::to_string(VIRTUAL_TRAY_MAIN_ID);
system->m_extders[MAIN_EXTRUDER_ID].m_star.slot_id = "0";
}
else
{
if (tray_tar_int >= 0x80 && tray_tar_int <= 0x87)
{
system->m_extders[MAIN_EXTRUDER_ID].m_star.ams_id = std::to_string(tray_tar_int);
}
else
{
system->m_extders[MAIN_EXTRUDER_ID].m_star.ams_id = std::to_string(tray_tar_int >> 2);
}
system->m_extders[MAIN_EXTRUDER_ID].m_star.slot_id = std::to_string(tray_tar_int & 0x3);
}
}
}
if (print_json.contains("ams") && print_json["ams"].contains("tray_now"))
{
const std::string& tray_now = print_json["ams"]["tray_now"].get<std::string>();
if (!tray_now.empty())
{
int tray_now_int = atoi(tray_now.c_str());
if (tray_now_int == VIRTUAL_TRAY_MAIN_ID || tray_now_int == VIRTUAL_TRAY_DEPUTY_ID)
{
system->m_extders[MAIN_EXTRUDER_ID].m_snow.ams_id = std::to_string(VIRTUAL_TRAY_MAIN_ID);
system->m_extders[MAIN_EXTRUDER_ID].m_snow.slot_id = "0";
}
else
{
if (tray_now_int >= 0x80 && tray_now_int <= 0x87)
{
system->m_extders[MAIN_EXTRUDER_ID].m_snow.ams_id = std::to_string(tray_now_int);
}
else
{
system->m_extders[MAIN_EXTRUDER_ID].m_snow.ams_id = std::to_string(tray_now_int >> 2);
}
system->m_extders[MAIN_EXTRUDER_ID].m_snow.slot_id = std::to_string(tray_now_int & 0x3);
}
}
}
system->m_current_busy_for_loading = false;
system->m_current_loading_extder_id = INVALID_EXTRUDER_ID;
if (!system->m_extders[MAIN_EXTRUDER_ID].m_star.ams_id.empty())
{
system->m_current_busy_for_loading = (system->m_extders[MAIN_EXTRUDER_ID].m_snow == system->m_extders[MAIN_EXTRUDER_ID].m_star);
if (system->m_current_busy_for_loading)
{
system->m_current_loading_extder_id = MAIN_EXTRUDER_ID;
}
}
}
void ExtderSystemParser::ParseV2_0(const nlohmann::json& extruder_json, DevExtderSystem* system)
{
system->m_total_extder_count = DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 0, 4);
if (system->m_current_extder_id != DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 4, 4))
{
system->Owner()->targ_nozzle_id_from_pc = INVALID_EXTRUDER_ID;
system->m_current_extder_id = DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 4, 4);
}
else if (system->m_switch_extder_state == ES_SWITCHING_FAILED)
{
system->Owner()->targ_nozzle_id_from_pc = INVALID_EXTRUDER_ID;
}
system->m_target_extder_id = DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 8, 4);
system->m_switch_extder_state = (DevExtderSwitchState)DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 12, 3);
system->m_current_loading_extder_id = DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 15, 4);
system->m_current_busy_for_loading = DevUtil::get_flag_bits(extruder_json["state"].get<int>(), 19);
system->m_extders.clear();
for (auto it = extruder_json["info"].begin(); it != extruder_json["info"].cend(); it++)
{
DevExtder extder_obj(system);
const auto& njon = it.value();
extder_obj.SetExtId(njon["id"].get<int>());
extder_obj.m_filam_bak.clear();
const json& filam_bak_items = njon["filam_bak"];
for (const auto& filam_bak_item : filam_bak_items)
{
const auto& filam_bak_val = filam_bak_item.get<int>();
extder_obj.m_filam_bak.emplace_back(filam_bak_val);
}
extder_obj.m_ext_has_filament = (DevUtil::get_flag_bits(njon["info"].get<int>(), 1) != 0);
extder_obj.m_buffer_has_filament = (DevUtil::get_flag_bits(njon["info"].get<int>(), 2) != 0);
extder_obj.m_has_nozzle = (DevUtil::get_flag_bits(njon["info"].get<int>(), 3) != 0);
extder_obj.m_cur_temp = DevUtil::get_flag_bits(njon["temp"].get<int>(), 0, 16);
extder_obj.m_target_temp = DevUtil::get_flag_bits(njon["temp"].get<int>(), 16, 16);
extder_obj.m_spre.slot_id = std::to_string(DevUtil::get_flag_bits(njon["spre"].get<int>(), 0, 8));
extder_obj.m_spre.ams_id = std::to_string(DevUtil::get_flag_bits(njon["spre"].get<int>(), 8, 8));
extder_obj.m_snow.slot_id = std::to_string(DevUtil::get_flag_bits(njon["snow"].get<int>(), 0, 8));
extder_obj.m_snow.ams_id = std::to_string(DevUtil::get_flag_bits(njon["snow"].get<int>(), 8, 8));
extder_obj.m_star.slot_id = std::to_string(DevUtil::get_flag_bits(njon["star"].get<int>(), 0, 8));
extder_obj.m_star.ams_id = std::to_string(DevUtil::get_flag_bits(njon["star"].get<int>(), 8, 8));
extder_obj.m_ams_stat = DevUtil::get_flag_bits(njon["stat"].get<int>(), 0, 16);
extder_obj.m_rfid_stat = DevUtil::get_flag_bits(njon["stat"].get<int>(), 16, 16);
//current nozzle info
extder_obj.m_current_nozzle_id = njon["hnow"].get<int>();
system->m_extders.push_back(extder_obj);
}
}
}

View File

@@ -0,0 +1,189 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
#include "DevDefs.h"
namespace Slic3r
{
//Previous definitions
class MachineObject;
class DevExtderSystem;
struct DevAmsSlotInfo
{
std::string ams_id;
std::string slot_id;
public:
bool operator==(const DevAmsSlotInfo& other) const { return ams_id == other.ams_id && slot_id == other.slot_id;}
};
enum DevExtderSwitchState
{
ES_IDLE = 0,
ES_BUSY,
ES_SWITCHING,
ES_SWITCHING_FAILED
};
class DevExtder
{
friend class MachineObject;
friend class ExtderSystemParser;
public:
DevExtder(DevExtderSystem* owner/*should not be nullptr*/, int id = -1) : system(owner), m_ext_id(id){};
public:
// Ext
int GetExtId() const { return m_ext_id; }
// display
wxString GetDisplayLoc() const;
wxString GetDisplayName() const;
// installed nozzle info
bool HasNozzleInstalled() const = delete;//{ return m_has_nozzle; }
int GetNozzleId() const { return m_current_nozzle_id; }
int GetTargetNozzleId() const = delete;//{ return m_target_nozzle_id; }
NozzleType GetNozzleType() const;
NozzleFlowType GetNozzleFlowType() const;
float GetNozzleDiameter() const;
// temperature
int GetCurrentTemp() const { return m_cur_temp; }
int GetTargetTemp() const { return m_target_temp; }
// filament
bool HasFilamentInExt() const { return m_ext_has_filament; }
bool HasFilamentInBuffer() const = delete; //{ return m_buffer_has_filament; }
bool HasFilamBackup() const { return !m_filam_bak.empty(); }
std::vector<int> GetFilamBackup() const { return m_filam_bak; }
// ams binding on current extruder
const DevAmsSlotInfo& GetSlotPre() const { return m_spre; }
const DevAmsSlotInfo& GetSlotNow() const { return m_snow; }
const DevAmsSlotInfo& GetSlotTarget() const { return m_star; }
private:
void SetExtId(int val) { m_ext_id = val; }
private:
DevExtderSystem* system = nullptr;
// extruder id
int m_ext_id; // 0-right 1-left
// current nozzle
bool m_has_nozzle = false;
int m_current_nozzle_id = 0; // nozzle id now. for some machine, the extruder may have serveral nozzles
int m_target_nozzle_id = 0; // target nozzle id
// temperature
int m_cur_temp = 0;
int m_target_temp = 0;
// filament
bool m_ext_has_filament = false;
bool m_buffer_has_filament = false;
std::vector<int> m_filam_bak;// the refill filam
// binded ams
DevAmsSlotInfo m_spre; // tray_pre
DevAmsSlotInfo m_snow; // tray_now
DevAmsSlotInfo m_star; // tray_tar
int m_ams_stat = 0;
int m_rfid_stat = 0;
};
// ExtderSystem is the extruder management system for the device.
// It consists of multiple extruders (Extder) and nozzles.
// Each extruder can be associated with different nozzles, and the number of extruders
// does not necessarily equal the number of nozzles.
// Note: The IDs of extruders and nozzles may not match or correspond one-to-one.
class DevExtderSystem
{
friend class MachineObject;
friend class ExtderSystemParser;
public:
DevExtderSystem(MachineObject* obj);
~DevExtderSystem() = default;
public:
MachineObject* Owner() const { return m_owner; }
// access extder info
int GetTotalExtderCount() const { assert(m_extders.size() == m_total_extder_count); return m_total_extder_count; }
int GetTotalExtderSize() const { return static_cast<int>(m_extders.size()); }
int GetCurrentExtderId() const { return m_current_extder_id; }
int GetTargetExtderId() const = delete;//{ return m_target_extder_id; }
// switching
DevExtderSwitchState GetSwitchState() const { return m_switch_extder_state; }
bool IsSwitching() const { return m_switch_extder_state == DevExtderSwitchState::ES_SWITCHING;};
bool IsSwitchingFailed() const { return m_switch_extder_state == DevExtderSwitchState::ES_SWITCHING_FAILED; };
bool CanQuitSwitching() const;
bool CanRetrySwitching() const { return IsSwitchingFailed(); };
int CtrlRetrySwitching();
int CtrlQuitSwitching();
std::optional<DevExtder> GetCurrentExtder() const;
std::optional<DevExtder> GetLoadingExtder() const;
std::optional<DevExtder> GetExtderById(int extder_id) const;
const std::vector<DevExtder>& GetExtruders() const { return m_extders;};
// get nozzle info which is installed on the extruder
NozzleType GetNozzleType(int extder_id) const { return GetExtderById(extder_id) ? GetExtderById(extder_id)->GetNozzleType() : NozzleType::ntUndefine; }
NozzleFlowType GetNozzleFlowType(int extder_id) const { return GetExtderById(extder_id) ? GetExtderById(extder_id)->GetNozzleFlowType() : NozzleFlowType::NONE_FLOWTYPE;; }
float GetNozzleDiameter(int extder_id) const { return GetExtderById(extder_id) ? GetExtderById(extder_id)->GetNozzleDiameter() : 0.0; }
int GetNozzleTempCurrent(int extder_id) const { return GetExtderById(extder_id) ? GetExtderById(extder_id)->GetCurrentTemp() : 0; }
int GetNozzleTempTarget(int extder_id) const { return GetExtderById(extder_id) ? GetExtderById(extder_id)->GetTargetTemp() : 0; }
// get slot info which is connected to the extruder
std::string GetCurrentAmsId() const;
std::string GetCurrentSlotId() const;
std::string GetTargetAmsId() const;
std::string GetTargetSlotId() const;
// filament
bool IsBusyLoading() const { return m_current_busy_for_loading; }
int GetLoadingExtderId() const { return m_current_loading_extder_id; }
bool HasFilamentBackup() const;
bool HasFilamentInExt(int exter_id) { return GetExtderById(exter_id) ? GetExtderById(exter_id)->HasFilamentInExt() : false; }
protected:
void AddExtder(const DevExtder& ext) { m_extders[ext.GetExtId()] = ext; };
private:
MachineObject* m_owner = nullptr;
// extruders
int m_total_extder_count = 1;
std::vector<DevExtder> m_extders;
// current extruder and swtching info
int m_current_extder_id = MAIN_EXTRUDER_ID;
// switching
DevExtderSwitchState m_switch_extder_state = DevExtderSwitchState::ES_IDLE;
int m_target_extder_id = MAIN_EXTRUDER_ID;
// loading extruder
bool m_current_busy_for_loading{ false };
int m_current_loading_extder_id = INVALID_EXTRUDER_ID;
};
class ExtderSystemParser
{
public:
static void ParseV1_0(const nlohmann::json& extruder_json, DevExtderSystem* system);
static void ParseV2_0(const nlohmann::json& extruder_json, DevExtderSystem* system);
};
};

View File

@@ -0,0 +1,22 @@
#include <nlohmann/json.hpp>
#include "DevExtruderSystem.h"
#include "slic3r/GUI/DeviceManager.hpp"
using namespace nlohmann;
namespace Slic3r
{
int DevExtderSystem::CtrlRetrySwitching()
{
if (m_owner) { return m_owner->command_ams_control("resume"); }
return -1;
}
int DevExtderSystem::CtrlQuitSwitching()
{
if (m_owner) { return m_owner->command_ams_control("abort"); }
return -1;
}
}

View File

@@ -0,0 +1,219 @@
#include <nlohmann/json.hpp>
#include "DevFan.h"
#include <wx/app.h>
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"
using namespace nlohmann;
void Slic3r::DevFan::converse_to_duct(bool is_suppt_part_fun, bool is_suppt_aux_fun, bool is_suppt_cham_fun)
{
m_air_duct_data.modes.clear();
m_air_duct_data.parts.clear();
m_air_duct_data.curren_mode = -1; // def mode
if (is_suppt_part_fun) {
AirParts part_fan;
part_fan.type = int(AirDuctType::AIR_FAN_TYPE);
part_fan.id = int(AIR_FUN::FAN_COOLING_0_AIRDOOR);
part_fan.func = int(AIR_FUN::FAN_COOLING_0_AIRDOOR);
part_fan.state = 0;
part_fan.range_start = 0;
part_fan.range_end = 100;
m_air_duct_data.parts.push_back(part_fan);
}
if (is_suppt_aux_fun) {
AirParts aux_fan;
aux_fan.type = int(AirDuctType::AIR_FAN_TYPE);
aux_fan.id = int(AIR_FUN::FAN_REMOTE_COOLING_0_IDX);
aux_fan.func = int(AIR_FUN::FAN_REMOTE_COOLING_0_IDX);
aux_fan.state = 0;
aux_fan.range_start = 0;
aux_fan.range_end = 100;
m_air_duct_data.parts.push_back(aux_fan);
}
if (is_suppt_aux_fun) {
AirParts chamber_fan;
chamber_fan.type = int(AirDuctType::AIR_FAN_TYPE);
chamber_fan.id = int(AIR_FUN::FAN_CHAMBER_0_IDX);
chamber_fan.func = int(AIR_FUN::FAN_CHAMBER_0_IDX);
chamber_fan.state = 0;
chamber_fan.range_start = 0;
chamber_fan.range_end = 100;
m_air_duct_data.parts.push_back(chamber_fan);
}
}
static std::string _get_string_from_fantype(int type)
{
switch (type) {
case 1: return "cooling_fan";
case 2: return "big_cooling_fan";
case 3: return "chamber_fan";
default: return "";
}
return "";
}
// Old protocol
int Slic3r::DevFan::command_control_fan(int fan_type, int val)
{
std::string gcode = (boost::format("M106 P%1% S%2% \n") % (int) fan_type % (val)).str();
return m_owner->publish_gcode(gcode);
}
// New protocol
int Slic3r::DevFan::command_control_fan_new(int fan_id, int val)
{
BOOST_LOG_TRIVIAL(info) << "New protocol of fan setting(set speed), fan_id = " << fan_id;
json j;
j["print"]["command"] = "set_fan";
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["fan_index"] = fan_id;
j["print"]["speed"] = val;
BOOST_LOG_TRIVIAL(info) << "MachineObject::command_control_fan_val, set the speed of fan, fan_id = " << fan_id;
return m_owner->publish_json(j);
}
int Slic3r::DevFan::command_handle_response(const json &response)
{
if (!response.contains("sequence_id")) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ", error reponse.";
return -1;
}
std::string reply = response["sequence_id"].get<std::string>();
auto it = m_callback_list.find(reply);
if (it != m_callback_list.end()) {
if (it->second) it->second(response);
m_callback_list.erase(it);
}
return 0;
}
int Slic3r::DevFan::command_control_air_duct(int mode_id, int submode, const CommandCallBack& cb)
{
BOOST_LOG_TRIVIAL(info) << "MachineObject::command_control_air_duct, set air duct, d = " << mode_id;
m_callback_list[std::to_string(m_owner->m_sequence_id)] = cb;
json j;
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["command"] = "set_airduct";
j["print"]["modeId"] = mode_id;
j["print"]["submode"] = submode;
return m_owner->publish_json(j);
}
void Slic3r::DevFan::ParseV1_0(const json &print_json)
{
if (print_json.contains("fan_gear")) {
fan_gear = print_json["fan_gear"].get<std::uint32_t>();
big_fan2_speed = (int) ((fan_gear & 0x00FF0000) >> 16);
big_fan1_speed = (int) ((fan_gear & 0x0000FF00) >> 8);
cooling_fan_speed = (int) ((fan_gear & 0x000000FF) >> 0);
} else {
if (print_json.contains("cooling_fan_speed")) {
cooling_fan_speed = stoi(print_json["cooling_fan_speed"].get<std::string>());
cooling_fan_speed = round(floor(cooling_fan_speed / float(1.5)) * float(25.5));
} else {
cooling_fan_speed = 0;
}
if (print_json.contains("big_fan1_speed")) {
big_fan1_speed = stoi(print_json["big_fan1_speed"].get<std::string>());
big_fan1_speed = round(floor(big_fan1_speed / float(1.5)) * float(25.5));
} else {
big_fan1_speed = 0;
}
if (print_json.contains("big_fan2_speed")) {
big_fan2_speed = stoi(print_json["big_fan2_speed"].get<std::string>());
big_fan2_speed = round(floor(big_fan2_speed / float(1.5)) * float(25.5));
} else {
big_fan2_speed = 0;
}
}
if (print_json.contains("heatbreak_fan_speed")) { heatbreak_fan_speed = stoi(print_json["heatbreak_fan_speed"].get<std::string>()); }
}
void Slic3r::DevFan::ParseV2_0(const json &print_json) {
if (print_json.contains("support_aux_fan")) {
if (print_json["support_aux_fan"].is_boolean())
is_support_aux_fan = print_json["support_aux_fan"].get<bool>();
}
if (print_json.contains("support_chamber_fan")) {
if (print_json["support_chamber_fan"].is_boolean())
is_support_chamber_fan = print_json["support_chamber_fan"].get<bool>();
}
}
void Slic3r::DevFan::ParseV3_0(const json &device)
{
if (device.contains("airduct")) {
m_air_duct_data.curren_mode = -1;
m_air_duct_data.modes.clear();
m_air_duct_data.parts.clear();
m_air_duct_data.curren_mode = device["airduct"]["modeCur"].get<int>();
const json &airduct = device["airduct"];
if (airduct.contains("modeCur")) { m_air_duct_data.curren_mode = airduct["modeCur"].get<int>(); }
if (airduct.contains("subMode")) { m_air_duct_data.m_sub_mode = airduct["subMode"].get<int>(); }
if (airduct.contains("modeList") && airduct["modeList"].is_array()) {
auto list = airduct["modeList"].get<std::vector<json>>();
for (int i = 0; i < list.size(); ++i) {
// only show 2 mode for o
if (m_owner->is_series_o() && i >= 2) { break; }
json mode_json = list[i];
AirMode mode;
if (mode_json.contains("modeId")) mode.id = mode_json["modeId"].get<int>();
if (mode_json.contains("ctrl")) {
for (auto it_mode_ctrl = mode_json["ctrl"].begin(); it_mode_ctrl != mode_json["ctrl"].end(); it_mode_ctrl++) {
mode.ctrl.push_back((*it_mode_ctrl).get<int>() >> 4);
}
}
if (mode_json.contains("off")) {
for (auto it_mode_off = mode_json["off"].begin(); it_mode_off != mode_json["off"].end(); *it_mode_off++) {
mode.off.push_back((*it_mode_off).get<int>() >> 4);
}
}
if (AIR_DUCT(mode.id) == AIR_DUCT::AIR_DUCT_EXHAUST) { continue; } /*STUDIO-12796*/
m_air_duct_data.modes[mode.id] = mode;
}
}
if (airduct.contains("parts") && airduct["parts"].is_array()) {
for (auto it_part = airduct["parts"].begin(); it_part != airduct["parts"].end(); it_part++) {
int state = (*it_part)["state"].get<int>();
int range = (*it_part)["range"].get<int>();
AirParts part;
part.type = m_owner->get_flag_bits((*it_part)["id"].get<int>(), 0, 4);
part.id = m_owner->get_flag_bits((*it_part)["id"].get<int>(), 4, 9);
part.func = (*it_part)["func"].get<int>();
part.state = m_owner->get_flag_bits(state, 0, 8);
part.range_start = m_owner->get_flag_bits(range, 0, 16);
part.range_end = m_owner->get_flag_bits(range, 16, 16);
m_air_duct_data.parts.push_back(part);
}
}
}
}

View File

@@ -0,0 +1,150 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
namespace Slic3r {
class MachineObject;
enum AirDuctType { AIR_FAN_TYPE, AIR_DOOR_TYPE };
typedef std::function<void(const json &)> CommandCallBack;
enum AIR_FUN {
FAN_HEAT_BREAK_0_IDX = 0,
FAN_COOLING_0_AIRDOOR = 1,
FAN_REMOTE_COOLING_0_IDX = 2,
FAN_CHAMBER_0_IDX = 3,
FAN_HEAT_BREAK_1_IDX = 4,
FAN_MC_BOARD_0_IDX = 5,
FAN_INNNER_LOOP_FAN_0_IDX = 6,
FAN_TOTAL_COUNT = 7
};
enum AIR_DOOR { AIR_DOOR_FUNC_CHAMBER = 0, AIR_DOOR_FUNC_INNERLOOP, AIR_DOOR_FUNC_TOP };
enum AIR_DUCT {
AIR_DUCT_NONE = -1,
AIR_DUCT_COOLING_FILT = 0,
AIR_DUCT_HEATING_INTERNAL_FILT,
AIR_DUCT_EXHAUST,
AIR_DUCT_FULL_COOLING,
AIR_DUCT_INIT = 0xFF // Initial mode, only used within mc
};
struct AirParts
{
int type{0};
int id{0};
int func{0};
int state{0}; // 100%
int range_start{0}; // 100%
int range_end{0}; // 100%
public:
bool operator ==(const AirParts& other) const
{
return (type == other.type) && (id == other.id) && (func == other.func) && (state == other.state) && (range_start == other.range_start) && (range_end == other.range_end);
};
};
struct AirMode
{
int id{-1};
std::vector<int> ctrl;
// If the fan is off, it cannot be controlled and is displayed as off
std::vector<int> off;
// If the fan is not off or ctrl, it will be displayed as auto
public:
bool operator ==(const AirMode& other) const
{
return (id == other.id) && (ctrl == other.ctrl) && (off == other.off);
};
};
struct AirDuctData
{
int curren_mode{0};
std::unordered_map<int, AirMode> modes;
std::vector<AirParts> parts;
int m_sub_mode = -1;// the submode of airduct, for cooling: 0-filter, 1-cooling
bool m_support_cooling_filter = false;// support switch filter on cooling mode or not
public:
bool operator ==(const AirDuctData& other) const
{
return (curren_mode == other.curren_mode) && (modes == other.modes) && (parts == other.parts) &&
(m_sub_mode == other.m_sub_mode) && (m_support_cooling_filter == other.m_support_cooling_filter);
};
bool operator !=(const AirDuctData& other) const
{
return !(operator==(other));
};
bool IsSupportCoolingFilter() const { return m_support_cooling_filter; }
bool IsCoolingFilerOn() const { return m_sub_mode == 0; }
};
class DevFan
{
public:
DevFan(MachineObject *obj) : m_owner(obj){};
public:
enum FanType {//if have devPrinter , delete?
COOLING_FAN = 1,
BIG_COOLING_FAN = 2,
CHAMBER_FAN = 3,
EXHAUST_FAN,
FILTER_FAN,
};
bool is_at_heating_mode() const { return m_air_duct_data.curren_mode == AIR_DUCT_HEATING_INTERNAL_FILT; };
void SetSupportCoolingFilter(bool enable) { m_air_duct_data.m_support_cooling_filter = enable; }
AirDuctData GetAirDuctData() { return m_air_duct_data; };
void converse_to_duct(bool is_suppt_part_fun, bool is_suppt_aux_fun, bool is_suppt_cham_fun); // Convert the data to duct type to make the newand old protocols consistent
int command_handle_response(const json &response);
int command_control_fan(int fan_type, int val); // Old protocol
int command_control_fan_new(int fan_id, int val); // New protocol
int command_control_air_duct(int mode_id, int submode, const CommandCallBack& cb);
void ParseV1_0(const json &print_json);
void ParseV2_0(const json &print_json);
void ParseV3_0(const json &print_json);
public:
bool GetSupportAuxFanData() { return is_support_aux_fan; };
bool GetSupportChamberFan() { return is_support_aux_fan; };
int GetHeatBreakFanSpeed() { return heatbreak_fan_speed; }
int GetCoolingFanSpeed() { return cooling_fan_speed; }
int GetBigFan1Speed() { return big_fan1_speed; }
int GetBigFan2Speed() { return big_fan2_speed; }
uint32_t GetFanGear() { return fan_gear; }
private:
AirDuctData m_air_duct_data;
bool is_support_aux_fan{false};
bool is_support_chamber_fan{false};
int heatbreak_fan_speed = 0;
int cooling_fan_speed = 0;
int big_fan1_speed = 0;
int big_fan2_speed = 0;
uint32_t fan_gear = 0;
std::map<std::string, CommandCallBack> m_callback_list;
MachineObject *m_owner = nullptr;
};
} // namespace Slic3r

View File

@@ -0,0 +1,13 @@
#include "DevFilaAmsSetting.h"
namespace Slic3r {
void DevAmsSystemSetting::Reset()
{
SetDetectOnInsertEnabled(false);
SetDetectOnPowerupEnabled(false);
SetDetectRemainEnabled(false);
SetAutoRefillEnabled(false);
}
}

View File

@@ -0,0 +1,35 @@
#pragma once
namespace Slic3r
{
class DevFilaSystem;
class DevAmsSystemSetting
{
public:
DevAmsSystemSetting(DevFilaSystem* owner) : m_owner(owner) {};
public:
// getters
bool IsDetectOnInsertEnabled() const { return m_enable_detect_on_insert; };
bool IsDetectOnPowerupEnabled() const { return m_enable_detect_on_powerup; }
bool IsDetectRemainEnabled() const { return m_enable_detect_remain; }
bool IsAutoRefillEnabled() const { return m_enable_auto_refill; }
// setters
void Reset();
void SetDetectOnInsertEnabled(bool enable) { m_enable_detect_on_insert = enable; }
void SetDetectOnPowerupEnabled(bool enable) { m_enable_detect_on_powerup = enable; }
void SetDetectRemainEnabled(bool enable) { m_enable_detect_remain = enable; }
void SetAutoRefillEnabled(bool enable) { m_enable_auto_refill = enable; }
private:
DevFilaSystem* m_owner = nullptr;
bool m_enable_detect_on_insert = false;
bool m_enable_detect_on_powerup = false;
bool m_enable_detect_remain = false;
bool m_enable_auto_refill = false;
};
}// namespace Slic3r

View File

@@ -0,0 +1,259 @@
#include <nlohmann/json.hpp>
#include "DevFilaBlackList.h"
#include "DevFilaSystem.h"
#include "DevManager.h"
#include "libslic3r/Utils.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
using namespace nlohmann;
namespace Slic3r {
json DevFilaBlacklist::filaments_blacklist = json::object();
bool DevFilaBlacklist::load_filaments_blacklist_config()
{
if (!filaments_blacklist.empty())
{
return false;
}
filaments_blacklist = json::object();
std::string config_file = Slic3r::resources_dir() + "/printers/filaments_blacklist.json";
boost::nowide::ifstream json_file(config_file.c_str());
try {
if (json_file.is_open()) {
json_file >> filaments_blacklist;
return true;
}
else {
BOOST_LOG_TRIVIAL(error) << "load filaments blacklist config failed";
}
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "load filaments blacklist config failed";
return false;
}
return true;
}
static std::string _get_filament_name_from_ams(int ams_id, int slot_id)
{
std::string name;
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) { return name; }
MachineObject* obj = dev->get_selected_machine();
if (obj == nullptr) { return name; }
if (ams_id < 0 || slot_id < 0)
{
return name;
}
const auto tray = obj->GetFilaSystem()->GetAmsTray(std::to_string(ams_id), std::to_string(slot_id));
if (!tray) { return name; }
std::string filament_id = tray->setting_id;
PresetBundle* preset_bundle = GUI::wxGetApp().preset_bundle;
auto option = preset_bundle->get_filament_by_filament_id(filament_id);
name = option ? option->filament_name : "";
return name;
}
// moved from tao.wang and zhimin.zeng
void check_filaments(std::string model_id,
std::string tag_vendor,
std::string tag_type,
int ams_id,
int slot_id,
std::string tag_name,
bool& in_blacklist,
std::string& ac,
wxString& info,
wxString& wiki_url)
{
if (tag_name.empty())
{
tag_name = _get_filament_name_from_ams(ams_id, slot_id);
}
in_blacklist = false;
std::transform(tag_vendor.begin(), tag_vendor.end(), tag_vendor.begin(), ::tolower);
std::transform(tag_type.begin(), tag_type.end(), tag_type.begin(), ::tolower);
std::transform(tag_name.begin(), tag_name.end(), tag_name.begin(), ::tolower);
DevFilaBlacklist::load_filaments_blacklist_config();
if (DevFilaBlacklist::filaments_blacklist.contains("blacklist"))
{
for (auto filament_item : DevFilaBlacklist::filaments_blacklist["blacklist"])
{
std::string vendor = filament_item.contains("vendor") ? filament_item["vendor"].get<std::string>() : "";
std::string type = filament_item.contains("type") ? filament_item["type"].get<std::string>() : "";
std::string type_suffix = filament_item.contains("type_suffix") ? filament_item["type_suffix"].get<std::string>() : "";
std::string name = filament_item.contains("name") ? filament_item["name"].get<std::string>() : "";
std::string slot = filament_item.contains("slot") ? filament_item["slot"].get<std::string>() : "";
std::vector<std::string> model_ids = filament_item.contains("model_id") ? filament_item["model_id"].get<std::vector<std::string>>() : std::vector<std::string>();
std::string action = filament_item.contains("action") ? filament_item["action"].get<std::string>() : "";
std::string description = filament_item.contains("description") ? filament_item["description"].get<std::string>() : "";
// check model id
if (!model_ids.empty() && std::find(model_ids.begin(), model_ids.end(), model_id) == model_ids.end()) { continue; }
// check vendor
std::transform(vendor.begin(), vendor.end(), vendor.begin(), ::tolower);
if (!vendor.empty())
{
if ((vendor == "bambu lab" && (tag_vendor == vendor)) ||
(vendor == "third party" && (tag_vendor != "bambu lab")))
{
// Do nothing
}
else
{
continue;
}
}
// check type
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
if (!type.empty() && (type != tag_type)) { continue; }
// check type suffix
std::transform(type_suffix.begin(), type_suffix.end(), type_suffix.begin(), ::tolower);
if (!type_suffix.empty())
{
if (tag_type.length() < type_suffix.length()) { continue; }
if ((tag_type.substr(tag_type.length() - type_suffix.length()) != type_suffix)) { continue; }
}
// check name
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
if (!name.empty() && (name != tag_name)) { continue; }
// check loc
if (!slot.empty())
{
bool is_virtual_slot = devPrinterUtil::IsVirtualSlot(ams_id);
bool check_virtual_slot = (slot == "ext");
bool check_ams_slot = (slot == "ams");
if (is_virtual_slot && !check_virtual_slot)
{
continue;
}
else if (!is_virtual_slot && !check_ams_slot)
{
continue;
}
}
if (GUI::wxGetApp().app_config->get("skip_ams_blacklist_check") == "true") {
action = "warning";
}
in_blacklist = true;
ac = action;
info = _L(description);
wiki_url = filament_item.contains("wiki") ? filament_item["wiki"].get<std::string>() : "";
return;
// Using in description
L("TPU is not supported by AMS.");
L("Damp PVA will become flexible and get stuck inside AMS, please take care to dry it before use.");
L("Damp PVA is flexible and may get stuck in extruder. Dry it before use.");
L("The rough surface of PLA Glow can accelerate wear on the AMS system, particularly on the internal components of the AMS Lite.");
L("CF/GF filaments are hard and brittle, it's easy to break or get stuck in AMS, please use with caution.");
L("PPS-CF is brittle and could break in bended PTFE tube above Toolhead.");
L("PPA-CF is brittle and could break in bended PTFE tube above Toolhead.");
}
}
}
void DevFilaBlacklist::check_filaments_in_blacklist(std::string model_id,
std::string tag_vendor,
std::string tag_type,
const std::string& filament_id,
int ams_id,
int slot_id,
std::string tag_name,
bool& in_blacklist,
std::string& ac,
wxString& info)
{
wxString wiki_url;
check_filaments_in_blacklist_url(model_id, tag_vendor, tag_type, filament_id, ams_id, slot_id, tag_name, in_blacklist, ac, info, wiki_url);
}
bool check_filaments_printable(const std::string &tag_vendor, const std::string &tag_type, const std::string& filament_id, int ams_id, bool &in_blacklist, std::string &ac, wxString &info)
{
DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) {
return true;
}
MachineObject *obj = dev->get_selected_machine();
if (obj == nullptr || !obj->is_multi_extruders()) {
return true;
}
Preset *printer_preset = GUI::get_printer_preset(obj);
if (!printer_preset)
return true;
ConfigOptionInts *physical_extruder_map_op = dynamic_cast<ConfigOptionInts *>(printer_preset->config.option("physical_extruder_map"));
if (!physical_extruder_map_op)
return true;
std::vector<int> physical_extruder_maps = physical_extruder_map_op->values;
int obj_extruder_id = obj->get_extruder_id_by_ams_id(std::to_string(ams_id));
int extruder_idx = obj_extruder_id;
for (int index = 0; index < physical_extruder_maps.size(); ++index) {
if (physical_extruder_maps[index] == obj_extruder_id) {
extruder_idx = index;
break;
}
}
PresetBundle *preset_bundle = GUI::wxGetApp().preset_bundle;
std::optional<FilamentBaseInfo> filament_info = preset_bundle->get_filament_by_filament_id(filament_id, printer_preset->name);
if (filament_info.has_value() && !(filament_info->filament_printable >> extruder_idx & 1)) {
wxString extruder_name = extruder_idx == 0 ? _L("left") : _L("right");
ac = "prohibition";
info = wxString::Format(_L("%s is not supported by %s extruder."), tag_type, extruder_name);
in_blacklist = true;
return false;
}
return true;
}
void DevFilaBlacklist::check_filaments_in_blacklist_url(std::string model_id, std::string tag_vendor, std::string tag_type, const std::string& filament_id, int ams_id, int slot_id, std::string tag_name, bool& in_blacklist, std::string& ac, wxString& info, wxString& wiki_url)
{
if (ams_id < 0 || slot_id < 0)
{
return;
}
if (!check_filaments_printable(tag_vendor, tag_type, filament_id, ams_id, in_blacklist, ac, info))
{
return;
}
check_filaments(model_id, tag_vendor, tag_type, ams_id, slot_id, tag_name, in_blacklist, ac, info, wiki_url);
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "slic3r/Utils/json_diff.hpp"
namespace Slic3r
{
class DevFilaBlacklist
{
public:
static bool load_filaments_blacklist_config();
static void check_filaments_in_blacklist(std::string model_id, std::string tag_vendor, std::string tag_type, const std::string& filament_id, int ams_id, int slot_id, std::string tag_name, bool& in_blacklist, std::string& ac, wxString& info);
static void check_filaments_in_blacklist_url(std::string model_id, std::string tag_vendor, std::string tag_type, const std::string& filament_id, int ams_id, int slot_id, std::string tag_name, bool& in_blacklist, std::string& ac, wxString& info, wxString& wiki_url);
public:
static json filaments_blacklist;
};// class DevFilaBlacklist
}// namespace Slic3r

View File

@@ -0,0 +1,719 @@
#include <nlohmann/json.hpp>
#include "DevFilaSystem.h"
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "DevUtil.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;
}
}
wxColour DevAmsTray::get_color() { return decode_color(color); }
void DevAmsTray::reset()
{
tag_uid = "";
setting_id = "";
filament_setting_id = "";
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()
{
if (color.empty()) return false;
if (type.empty()) return false;
//if (setting_id.empty()) return false;
return true;
}
bool DevAmsTray::is_unset_third_filament()
{
if (this->is_bbl) return false;
return (color.empty() || type.empty());
}
std::string DevAmsTray::get_display_filament_type()
{
if (type == "PLA-S") return "Sup.PLA";
if (type == "PA-S") return "Sup.PA";
if (type == "ABS-S") return "Sup.ABS";
return type;
}
std::string DevAmsTray::get_filament_type()
{
if (type == "Sup.PLA") { return "PLA-S"; }
if (type == "Sup.PA") { return "PA-S"; }
if (type == "Sup.ABS") { return "ABS-S"; }
if (type == "Support W") { return "PLA-S"; }
if (type == "Support G") { return "PA-S"; }
if (type == "Support") { if (setting_id == "GFS00") { type = "PLA-S"; } else if (setting_id == "GFS01") { type = "PA-S"; } else { return "PLA-S"; } }
return type;
}
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(DUMMY < type && m_ams_type <= N3S);
}
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;
auto iter = s_ams_display_formats.find(m_ams_type);
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
{
if (m_ams_type == AMS || m_ams_type == AMS_LITE || m_ams_type == N3F)
{
return 4;
}
else if (m_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;
}
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
}
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)
{
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*/
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);
}
/*AMS without initialization*/
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);
/*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
{
curr_ams->m_exist = DevUtil::get_flag_bits(obj->ams_exist_bits, 4 + (ams_id_int - 128));
}
}
}
catch (...)
{
;
}
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
{
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
}
if (it->contains("humidity"))
{
std::string humidity = (*it)["humidity"].get<std::string>();
try
{
curr_ams->m_humidity_level = atoi(humidity.c_str());
}
catch (...)
{
;
}
}
if (it->contains("humidity_raw"))
{
std::string humidity_raw = (*it)["humidity_raw"].get<std::string>();
try
{
curr_ams->m_humidity_percent = atoi(humidity_raw.c_str());
}
catch (...)
{
;
}
if (curr_ams->GetHumidityPercent() != -1)
{
if (curr_ams->GetHumidityPercent() < 20)
{
curr_ams->m_humidity_level = 5;
}
else if (curr_ams->GetHumidityPercent() < 40)
{
curr_ams->m_humidity_level = 4;
}
else if (curr_ams->GetHumidityPercent() < 60)
{
curr_ams->m_humidity_level = 3;
}
else if (curr_ams->GetHumidityPercent() < 80)
{
curr_ams->m_humidity_level = 2;
}
else
{
curr_ams->m_humidity_level = 1;
}
}
}
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("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>());
if (curr_tray->setting_id == "GFS00")
{
curr_tray->type = "PLA-S";
}
else if (curr_tray->setting_id == "GFS01")
{
curr_tray->type = "PA-S";
}
else
{
curr_tray->type = type;
}
}
else
{
curr_tray->setting_id = "";
curr_tray->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;
}
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
{
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);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,190 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include "DevDefs.h"
#include "DevFilaAmsSetting.h"
#include <map>
#include <wx/string.h>
#include <wx/colour.h>
#define HOLD_COUNT_MAX 3
namespace Slic3r
{
class MachineObject;
class DevAmsTray
{
public:
DevAmsTray(std::string tray_id)
{
is_bbl = false;
id = tray_id;
}
static wxColour decode_color(const std::string& color);
bool operator==(DevAmsTray const& o) const
{
return id == o.id && type == o.type && filament_setting_id == o.filament_setting_id && color == o.color;
}
bool operator!=(DevAmsTray const& o) const { return !operator==(o); }
std::string id;
std::string tag_uid; // tag_uid
std::string setting_id; // tray_info_idx
std::string filament_setting_id; // setting_id
std::string type;
std::string sub_brands;
std::string color;
std::vector<std::string> cols;
std::string weight;
std::string diameter;
std::string temp;
std::string time;
std::string bed_temp_type;
std::string bed_temp;
std::string nozzle_temp_max;
std::string nozzle_temp_min;
std::string xcam_info;
std::string uuid;
int ctype = 0;
float k = 0.0f; // k range: 0 ~ 0.5
float n = 0.0f; // k range: 0.6 ~ 2.0
int cali_idx = -1; // - 1 means default
wxColour wx_color;
bool is_bbl;
bool is_exists = false;
int hold_count = 0;
int remain = 0; // filament remain: 0 ~ 100
void set_hold_count() { hold_count = HOLD_COUNT_MAX; }
void UpdateColorFromStr(const std::string& color);
wxColour get_color();
void reset();
bool is_tray_info_ready();
bool is_unset_third_filament();
std::string get_display_filament_type();
std::string get_filament_type();
};
class DevAms
{
friend class DevFilaSystemParser;
public:
enum AmsType : int
{
DUMMY = 0,
AMS = 1, // AMS
AMS_LITE = 2, // AMS-Lite
N3F = 3, // N3F
N3S = 4, // N3S
};
public:
DevAms(const std::string& ams_id, int extruder_id, AmsType type);
DevAms(const std::string& ams_id, int nozzle_id, int type);
~DevAms();
public:
std::string GetAmsId() const { return m_ams_id; }
wxString GetDisplayName() const; // display
void SetAmsType(int type) { m_ams_type = (AmsType)type; }
void SetAmsType(AmsType type) { m_ams_type = type; }
AmsType GetAmsType() const { return m_ams_type; }
// exist or not
bool IsExist() const { return m_exist; }
// slots
int GetSlotCount() const;
DevAmsTray* GetTray(const std::string& tray_id) const;
const std::map<std::string, DevAmsTray*>& GetTrays() const { return m_trays; }
// installed on the extruder
int GetExtruderId() const { return m_ext_id; }
// temperature and humidity
float GetCurrentTemperature() const { return m_current_temperature; }
bool SupportHumidity() const { return (m_ams_type == AMS) || (m_ams_type == N3F) || (m_ams_type == N3S);}
int GetHumidityLevel() const { return m_humidity_level; }
int GetHumidityPercent() const { return m_humidity_percent; }
bool SupportDrying() const { return m_ams_type > AMS_LITE; }
int GetLeftDryTime() const { return m_left_dry_time; }
private:
AmsType m_ams_type = AmsType::AMS;
std::string m_ams_id;
int m_ext_id;//extruder id
bool m_exist = false;
// slots and trays
std::map<std::string, DevAmsTray*> m_trays;//id -> DevAmsTray*
// temperature and humidity
float m_current_temperature = INVALID_AMS_TEMPERATURE; // the temperature
int m_humidity_level = 5;
int m_humidity_percent = -1; // the percentage, -1 means invalid. eg. 100 means 100%
int m_left_dry_time = 0;
};
class DevFilaSystem
{
friend class DevFilaSystemParser;
public:
DevFilaSystem(MachineObject* owner) { m_owner = owner;};
~DevFilaSystem();
public:
bool HasAms() const { return !amsList.empty(); }
bool IsAmsSettingUp() const;
/* ams */
DevAms* GetAmsById(const std::string& ams_id) const;
std::map<std::string, DevAms*>& GetAmsList() { return amsList; }
int GetAmsCount() const { return amsList.size(); }
/* tray*/
DevAmsTray* GetAmsTray(const std::string& ams_id, const std::string& tray_id) const;
void CollectAmsColors(std::vector<wxColour>& ams_colors) const;
// extruder
int GetExtruderIdByAmsId(const std::string& ams_id) const;
/* AMS settings*/
DevAmsSystemSetting& GetAmsSystemSetting() { return m_ams_system_setting; }
bool IsDetectOnInsertEnabled() const { return m_ams_system_setting.IsDetectOnInsertEnabled(); };
bool IsDetectOnPowerupEnabled() const { return m_ams_system_setting.IsDetectOnPowerupEnabled(); }
bool IsDetectRemainEnabled() const { return m_ams_system_setting.IsDetectRemainEnabled(); }
bool IsAutoRefillEnabled() const { return m_ams_system_setting.IsAutoRefillEnabled(); }
public:
static bool IsBBL_Filament(std::string tag_uid);
private:
MachineObject* m_owner;
/* ams properties */
int m_ams_cali_stat = 0;
std::map<std::string, DevAms*> amsList; // key: ams[id], start with 0
DevAmsSystemSetting m_ams_system_setting{ this };
};// class DevFilaSystem
class DevFilaSystemParser
{
public:
static void ParseV1_0(const json& print_json, MachineObject* obj, DevFilaSystem* system, bool key_field_only);
};
}// namespace Slic3r

View File

@@ -0,0 +1,2 @@
#include "DevFirmware.h"
#include "slic3r/GUI/DeviceManager.hpp"

View File

@@ -0,0 +1,57 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
namespace Slic3r {
//Previous definitions
class MachineObject;
enum PrinterFirmwareType
{
FIRMWARE_TYPE_ENGINEER = 0,
FIRMWARE_TYPE_PRODUCTION,
FIRMEARE_TYPE_UKNOWN,
};
class FirmwareInfo
{
public:
std::string module_type; // ota or ams
std::string version;
std::string url;
std::string name;
std::string description;
};
class DevFirmwareVersionInfo
{
public:
std::string name;
wxString product_name;
std::string sn;
std::string hw_ver;
std::string sw_ver;
std::string sw_new_ver;
int firmware_flag = 0;
public:
bool isValid() const { return !sn.empty(); }
bool isAirPump() const { return product_name.Contains("Air Pump"); }
bool isLaszer() const { return product_name.Contains("Laser"); }
bool isCuttingModule() const { return product_name.Contains("Cutting Module"); }
};
class DevFirmware
{
public:
DevFirmware(MachineObject* obj) : m_owner(obj) {}
private:
MachineObject* m_owner = nullptr;
};
} // namespace Slic3r

View File

@@ -0,0 +1,67 @@
//#include "D:/dev/bamboo_slicer/build_release/src/slic3r/CMakeFiles/libslic3r_gui.dir/Release/cmake_pch.hxx"
#include "DevHMS.h"
namespace Slic3r
{
bool DevHMSItem::parse_hms_info(unsigned attr, unsigned code)
{
bool result = true;
unsigned int model_id_int = (attr >> 24) & 0xFF;
this->m_module_id = (ModuleID)model_id_int;
this->m_module_num = (attr >> 16) & 0xFF;
this->m_part_id = (attr >> 8) & 0xFF;
this->m_reserved = (attr >> 0) & 0xFF;
unsigned msg_level_int = code >> 16;
if (msg_level_int < (unsigned)HMS_MSG_LEVEL_MAX)
{
this->m_msg_level = (HMSMessageLevel)msg_level_int;
}
else
{
this->m_msg_level = HMS_UNKNOWN;
}
this->m_msg_code = code & 0xFFFF;
return result;
}
std::string DevHMSItem::get_long_error_code() const
{
char buf[64];
::sprintf(buf, "%02X%02X%02X00000%1X%04X",
this->m_module_id,
this->m_module_num,
this->m_part_id,
(int)this->m_msg_level,
this->m_msg_code);
return std::string(buf);
}
void DevHMS::ParseHMSItems(const json& hms_json)
{
m_hms_list.clear();
try
{
if (hms_json.is_array())
{
for (auto it = hms_json.begin(); it != hms_json.end(); it++)
{
DevHMSItem item;
if ((*it).contains("attr") && (*it).contains("code"))
{
unsigned attr = (*it)["attr"].get<unsigned>();
unsigned code = (*it)["code"].get<unsigned>();
item.parse_hms_info(attr, code);
}
m_hms_list.push_back(item);
}
}
}
catch (const std::exception&)
{
assert(false && "Parse HMS items failed");
}
}
}

View File

@@ -0,0 +1,84 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
#include <map>
namespace Slic3r
{
// Previous definitions
class MachineObject;
class DevHMSItem;
class DevHMS
{
public:
DevHMS(MachineObject* obj) : m_object(obj) {}
public:
void ParseHMSItems(const json& hms_json);
const std::vector<DevHMSItem>& GetHMSItems() const { return m_hms_list; };
private:
MachineObject* m_object = nullptr;
// all hms for this machine
std::vector<DevHMSItem> m_hms_list;
};
enum HMSMessageLevel
{
HMS_UNKNOWN = 0,
HMS_FATAL = 1,
HMS_SERIOUS = 2,
HMS_COMMON = 3,
HMS_INFO = 4,
HMS_MSG_LEVEL_MAX,
};
enum ModuleID
{
MODULE_UKNOWN = 0x00,
MODULE_01 = 0x01,
MODULE_02 = 0x02,
MODULE_MC = 0x03,
MODULE_04 = 0x04,
MODULE_MAINBOARD = 0x05,
MODULE_06 = 0x06,
MODULE_AMS = 0x07,
MODULE_TH = 0x08,
MODULE_09 = 0x09,
MODULE_10 = 0x0A,
MODULE_11 = 0x0B,
MODULE_XCAM = 0x0C,
MODULE_13 = 0x0D,
MODULE_14 = 0x0E,
MODULE_15 = 0x0F,
MODULE_MAX = 0x10
};
class DevHMSItem
{
public:
std::string get_long_error_code() const;
HMSMessageLevel get_level() const { return m_msg_level; }
void set_read() { m_already_read = true; };
bool has_read() const { return m_already_read; };
protected:
friend void DevHMS::ParseHMSItems(const json& hms_json);
bool parse_hms_info(unsigned attr, unsigned code);
private:
ModuleID m_module_id;
unsigned m_module_num;
unsigned m_part_id;
unsigned m_reserved;
HMSMessageLevel m_msg_level = HMS_UNKNOWN;
int m_msg_code = 0;
bool m_already_read = false;
};
};// End of namespace Slic3r

View File

@@ -0,0 +1,7 @@
#include "DevInfo.h"
#include "slic3r/GUI/DeviceManager.hpp"
namespace Slic3r
{
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
namespace Slic3r {
class MachineObject;
/* some static info of machine*/ /*TODO*/
class DevInfo
{
public:
DevInfo(MachineObject* obj) : m_owner(obj) {};
public:
//std::string GetDevName() const { return m_dev_name; }
//std::string GetDevId() const { return m_dev_id; }
//std::string GetDevIP() const { return m_dev_ip; }
//std::string GetPrinterTypeStr() const { return m_printer_type_str; }
//std::string GetPrinterSignal() const { return m_printer_signal; }
//std::string GetConnectType() const { return m_connect_type; }
//std::string GetBindState() const { return m_bind_state; }
private:
//std::string m_dev_name;
//std::string m_dev_id;
//std::string m_dev_ip;
//std::string m_printer_type_str;
//std::string m_printer_signal;
//std::string m_connect_type;
//std::string m_bind_state;
MachineObject* m_owner = nullptr;
};
} // namespace Slic3r

View File

@@ -0,0 +1,18 @@
#include "DevLamp.h"
static Slic3r::DevLamp::LIGHT_EFFECT _light_effect_parse(std::string effect_str)
{
if (effect_str.compare("on") == 0)
return Slic3r::DevLamp::LIGHT_EFFECT_ON;
else if (effect_str.compare("off") == 0)
return Slic3r::DevLamp::LIGHT_EFFECT_OFF;
else if (effect_str.compare("flashing") == 0)
return Slic3r::DevLamp::LIGHT_EFFECT_FLASHING;
return Slic3r::DevLamp::LIGHT_EFFECT_UNKOWN;
}
void Slic3r::DevLamp::SetChamberLight(const std::string& status)
{
m_chamber_light = _light_effect_parse(status);
}

View File

@@ -0,0 +1,42 @@
#pragma once
namespace Slic3r
{
class MachineObject;
class DevLamp
{
public:
DevLamp(MachineObject* obj) : m_owner(obj) {};
public:
enum LIGHT_EFFECT
{
LIGHT_EFFECT_ON,
LIGHT_EFFECT_OFF,
LIGHT_EFFECT_FLASHING,
LIGHT_EFFECT_UNKOWN,
};
public:
void SetChamberLight(const std::string& status);
void SetChamberLight(LIGHT_EFFECT effect) { m_chamber_light = effect; }
bool IsChamberLightOn() const { return m_chamber_light == LIGHT_EFFECT_ON || m_chamber_light == LIGHT_EFFECT_FLASHING; }
void SetLampCloseRecheck(bool enable) { m_lamp_close_recheck = enable;};
bool HasLampCloseRecheck() const { return m_lamp_close_recheck; }
public:
void CtrlSetChamberLight(LIGHT_EFFECT effect);
private:
int command_set_chamber_light(LIGHT_EFFECT effect, int on_time = 500, int off_time = 500, int loops = 1, int interval = 1000);
int command_set_chamber_light2(LIGHT_EFFECT effect, int on_time = 500, int off_time = 500, int loops = 1, int interval = 1000);
private:
MachineObject* m_owner = nullptr;
bool m_lamp_close_recheck = false;
LIGHT_EFFECT m_chamber_light = LIGHT_EFFECT_UNKOWN;
};
}

View File

@@ -0,0 +1,64 @@
#include <nlohmann/json.hpp>
#include "DevLamp.h"
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
using namespace nlohmann;
namespace Slic3r
{
static std::string _light_effect_str(DevLamp::LIGHT_EFFECT effect)
{
switch (effect)
{
case Slic3r::DevLamp::LIGHT_EFFECT_ON:
return "on";
case Slic3r::DevLamp::LIGHT_EFFECT_OFF:
return "off";
case Slic3r::DevLamp::LIGHT_EFFECT_FLASHING:
return "flashing";
default:
return "unknown";
}
return "unknown";
}
void DevLamp::CtrlSetChamberLight(LIGHT_EFFECT effect)
{
// copied from others, TODO CHECK
command_set_chamber_light(effect);
command_set_chamber_light2(effect);
}
int DevLamp::command_set_chamber_light(LIGHT_EFFECT effect, int on_time, int off_time, int loops, int interval)
{
json j;
j["system"]["command"] = "ledctrl";
j["system"]["led_node"] = "chamber_light";
j["system"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["system"]["led_mode"] = _light_effect_str(effect);
j["system"]["led_on_time"] = on_time;
j["system"]["led_off_time"] = off_time;
j["system"]["loop_times"] = loops;
j["system"]["interval_time"] = interval;
return m_owner->publish_json(j);
}
int DevLamp::command_set_chamber_light2(LIGHT_EFFECT effect, int on_time, int off_time, int loops, int interval)
{
json j;
j["system"]["command"] = "ledctrl";
j["system"]["led_node"] = "chamber_light2";
j["system"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["system"]["led_mode"] = _light_effect_str(effect);
j["system"]["led_on_time"] = on_time;
j["system"]["led_off_time"] = off_time;
j["system"]["loop_times"] = loops;
j["system"]["interval_time"] = interval;
return m_owner->publish_json(j);
}
}

View File

@@ -0,0 +1,876 @@
#include <nlohmann/json.hpp>
#include "DevManager.h"
#include "DevUtil.h"
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r/Time.hpp"
using namespace nlohmann;
namespace Slic3r
{
DeviceManager::DeviceManager(NetworkAgent* agent)
{
m_agent = agent;
m_refresher = new DeviceManagerRefresher(this);
DevPrinterConfigUtil::InitFilePath(resources_dir());
// Load saved local machines
if (agent) {
AppConfig* config = GUI::wxGetApp().app_config;
const auto local_machines = config->get_local_machines();
for (auto& it : local_machines) {
const auto& m = it.second;
MachineObject* obj = new MachineObject(this, m_agent, m.dev_name, m.dev_id, m.dev_ip);
obj->printer_type = m.printer_type;
obj->dev_connection_type = "lan";
obj->bind_state = "free";
obj->bind_sec_link = "secure";
obj->m_is_online = true;
obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->set_access_code(config->get("access_code", m.dev_id), false);
obj->set_user_access_code(config->get("user_access_code", m.dev_id), false);
if (obj->has_access_right()) {
localMachineList.insert(std::make_pair(m.dev_id, obj));
} else {
config->erase_local_machine(m.dev_id);
delete obj;
}
}
}
}
void DeviceManager::update_local_machine(const MachineObject& m)
{
AppConfig* config = GUI::wxGetApp().app_config;
if (config) {
if (m.is_lan_mode_printer()) {
if (m.has_access_right()) {
BBLocalMachine local_machine;
local_machine.dev_id = m.get_dev_id();
local_machine.dev_name = m.get_dev_name();
local_machine.dev_ip = m.get_dev_ip();
local_machine.printer_type = m.printer_type;
config->update_local_machine(local_machine);
}
} else {
config->erase_local_machine(m.get_dev_id());
}
}
}
DeviceManager::~DeviceManager()
{
delete m_refresher;
for (auto it = localMachineList.begin(); it != localMachineList.end(); it++)
{
if (it->second)
{
delete it->second;
it->second = nullptr;
}
}
localMachineList.clear();
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
if (it->second)
{
delete it->second;
it->second = nullptr;
}
}
userMachineList.clear();
}
void DeviceManager::EnableMultiMachine(bool enable)
{
m_agent->enable_multi_machine(enable);
m_enable_mutil_machine = enable;
}
void DeviceManager::start_refresher() { m_refresher->Start(); }
void DeviceManager::stop_refresher() { m_refresher->Stop(); }
void DeviceManager::keep_alive()
{
MachineObject* obj = this->get_selected_machine();
if (obj)
{
if (obj->keep_alive_count == 0)
{
obj->last_keep_alive = std::chrono::system_clock::now();
}
obj->keep_alive_count++;
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
auto internal = std::chrono::duration_cast<std::chrono::milliseconds>(start - obj->last_keep_alive);
if (internal.count() > TIMEOUT_FOR_KEEPALIVE && (internal.count() < 1000 * 60 * 60 * 300))
{
BOOST_LOG_TRIVIAL(info) << "keep alive = " << internal.count() << ", count = " << obj->keep_alive_count;
obj->command_request_push_all();
obj->last_keep_alive = start;
}
else if (obj->m_push_count == 0)
{
BOOST_LOG_TRIVIAL(info) << "keep alive = " << internal.count() << ", push_count = 0, count = " << obj->keep_alive_count;
obj->command_request_push_all();
obj->last_keep_alive = start;
}
}
}
void DeviceManager::check_pushing()
{
keep_alive();
MachineObject* obj = this->get_selected_machine();
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
auto internal = std::chrono::duration_cast<std::chrono::milliseconds>(start - obj->last_update_time);
if (obj && !obj->is_support_mqtt_alive)
{
if (internal.count() > TIMEOUT_FOR_STRAT && internal.count() < 1000 * 60 * 60 * 300)
{
BOOST_LOG_TRIVIAL(info) << "command_pushing: diff = " << internal.count();
obj->command_pushing("start");
}
}
}
void DeviceManager::on_machine_alive(std::string json_str)
{
try {
json j = json::parse(json_str);
std::string dev_name = j["dev_name"].get<std::string>();
std::string dev_id = j["dev_id"].get<std::string>();
std::string dev_ip = j["dev_ip"].get<std::string>();
std::string printer_type_str= j["dev_type"].get<std::string>();
std::string printer_signal = j["dev_signal"].get<std::string>();
std::string connect_type = j["connect_type"].get<std::string>();
std::string bind_state = j["bind_state"].get<std::string>();
if (connect_type == "farm") {
connect_type ="lan";
bind_state = "free";
}
std::string sec_link = "";
std::string ssdp_version = "";
if (j.contains("sec_link")) {
sec_link = j["sec_link"].get<std::string>();
}
if (j.contains("ssdp_version")) {
ssdp_version = j["ssdp_version"].get<std::string>();
}
std::string connection_name = "";
if (j.contains("connection_name")) {
connection_name = j["connection_name"].get<std::string>();
}
MachineObject* obj;
/* update userMachineList info */
auto it = userMachineList.find(dev_id);
if (it != userMachineList.end()) {
if (it->second->get_dev_ip() != dev_ip ||
it->second->bind_state != bind_state ||
it->second->bind_sec_link != sec_link ||
it->second->dev_connection_type != connect_type ||
it->second->bind_ssdp_version != ssdp_version)
{
if (it->second->bind_state != bind_state) {
OnMachineBindStateChanged(it->second, bind_state);
}
it->second->set_dev_ip(dev_ip);
it->second->bind_state = bind_state;
it->second->bind_sec_link = sec_link;
it->second->dev_connection_type = connect_type;
it->second->bind_ssdp_version = ssdp_version;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " UpdateUserMachineInfo"
<< ", dev_id= " << dev_id
<< ", ip = " <<dev_ip
<< ", printer_name= " << dev_name
<< ", con_type= " << connect_type << ", signal= " << printer_signal
<< ", bind_state= " << bind_state;
}
}
/* update localMachineList */
it = localMachineList.find(dev_id);
if (it != localMachineList.end()) {
// update properties
/* ip changed */
obj = it->second;
if (obj->get_dev_ip().compare(dev_ip) != 0) {
if ( connection_name.empty() ) {
BOOST_LOG_TRIVIAL(info) << "MachineObject IP changed from " << obj->get_dev_ip()
<< " to " << dev_ip;
obj->set_dev_ip(dev_ip);
}
else {
if ( obj->dev_connection_name.empty() || obj->dev_connection_name.compare(connection_name) == 0) {
BOOST_LOG_TRIVIAL(info) << "MachineObject IP changed from " << obj->get_dev_ip()
<< " to " << dev_ip << " connection_name is " << connection_name;
if(obj->dev_connection_name.empty()){obj->dev_connection_name = connection_name;}
obj->set_dev_ip(dev_ip);
}
}
/* ip changed reconnect mqtt */
}
if (obj->wifi_signal != printer_signal ||
obj->dev_connection_type != connect_type ||
obj->bind_state != bind_state ||
obj->bind_sec_link != sec_link ||
obj->bind_ssdp_version != ssdp_version ||
obj->printer_type != _parse_printer_type(printer_type_str))
{
if (obj->dev_connection_type != connect_type ||
obj->bind_state != bind_state ||
obj->bind_sec_link != sec_link ||
obj->bind_ssdp_version != ssdp_version ||
obj->printer_type != _parse_printer_type(printer_type_str))
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " UpdateLocalMachineInfo"
<< ", dev_id= " << dev_id
<< ", ip = " << dev_ip
<< ", printer_name= " << dev_name
<< ", con_type= " << connect_type << ", signal= " << printer_signal
<< ", bind_state= " << bind_state;
}
else
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " UpdateLocalMachineInfo_WIFI"
<< ", dev_id= " << dev_id
<< ", ip = " << dev_ip
<< ", printer_name= " << dev_name
<< ", con_type= " << connect_type << ", signal= " << printer_signal
<< ", bind_state= " << bind_state;
}
obj->wifi_signal = printer_signal;
obj->dev_connection_type = connect_type;
obj->bind_state = bind_state;
obj->bind_sec_link = sec_link;
obj->bind_ssdp_version = ssdp_version;
obj->printer_type = _parse_printer_type(printer_type_str);
}
// U0 firmware
if (obj->dev_connection_type.empty() && obj->bind_state.empty())
obj->bind_state = "free";
obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->m_is_online = true;
/* if (!obj->dev_ip.empty()) {
Slic3r::GUI::wxGetApp().app_config->set_str("ip_address", obj->dev_id, obj->dev_ip);
Slic3r::GUI::wxGetApp().app_config->save();
}*/
}
else {
/* insert a new machine */
obj = new MachineObject(this, m_agent, dev_name, dev_id, dev_ip);
obj->printer_type = _parse_printer_type(printer_type_str);
obj->wifi_signal = printer_signal;
obj->dev_connection_type = connect_type;
obj->bind_state = bind_state;
obj->bind_sec_link = sec_link;
obj->dev_connection_name = connection_name;
obj->bind_ssdp_version = ssdp_version;
obj->m_is_online = true;
//load access code
AppConfig* config = Slic3r::GUI::wxGetApp().app_config;
if (config) {
obj->set_access_code(Slic3r::GUI::wxGetApp().app_config->get("access_code", dev_id), false);
obj->set_user_access_code(Slic3r::GUI::wxGetApp().app_config->get("user_access_code", dev_id), false);
}
localMachineList.insert(std::make_pair(dev_id, obj));
/* if (!obj->dev_ip.empty()) {
Slic3r::GUI::wxGetApp().app_config->set_str("ip_address", obj->dev_id, obj->dev_ip);
Slic3r::GUI::wxGetApp().app_config->save();
}*/
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " New Machine, dev_id= " << dev_id
<< ", ip = " << dev_ip <<", printer_name = " << dev_name
<< ", con_type= " << connect_type <<", signal= " << printer_signal << ", bind_state= " << bind_state;
}
update_local_machine(*obj);
}
catch (...) {
;
}
}
MachineObject* DeviceManager::insert_local_device(const BBLocalMachine& machine, std::string connection_type, std::string bind_state, std::string version, std::string access_code)
{
MachineObject* obj;
auto it = localMachineList.find(machine.dev_id);
if (it != localMachineList.end()) {
obj = it->second;
} else {
obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip);
localMachineList.insert(std::make_pair(machine.dev_id, obj));
}
obj->printer_type = _parse_printer_type(machine.printer_type);
obj->dev_connection_type = connection_type == "farm" ? "lan":connection_type;
obj->bind_state = connection_type == "farm" ? "free":bind_state;
obj->bind_sec_link = "secure";
obj->bind_ssdp_version = version;
obj->m_is_online = true;
obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->set_access_code(access_code, false);
obj->set_user_access_code(access_code, false);
update_local_machine(*obj);
return obj;
}
int DeviceManager::query_bind_status(std::string& msg)
{
if (!m_agent)
{
msg = "";
return -1;
}
BOOST_LOG_TRIVIAL(trace) << "DeviceManager::query_bind_status";
std::map<std::string, MachineObject*>::iterator it;
std::vector<std::string> query_list;
for (it = localMachineList.begin(); it != localMachineList.end(); it++)
{
query_list.push_back(it->first);
}
unsigned int http_code;
std::string http_body;
int result = m_agent->query_bind_status(query_list, &http_code, &http_body);
if (result < 0)
{
msg = (boost::format("code=%1%,body=%2") % http_code % http_body).str();
}
else
{
msg = "";
try
{
json j = json::parse(http_body);
if (j.contains("bind_list"))
{
for (auto& item : j["bind_list"])
{
auto it = localMachineList.find(item["dev_id"].get<std::string>());
if (it != localMachineList.end())
{
if (!item["user_id"].is_null())
it->second->bind_user_id = item["user_id"].get<std::string>();
if (!item["user_name"].is_null())
it->second->bind_user_name = item["user_name"].get<std::string>();
else
it->second->bind_user_name = "Free";
}
}
}
}
catch (...)
{
;
}
}
return result;
}
MachineObject* DeviceManager::get_user_machine(std::string dev_id)
{
if (!m_agent || !m_agent->is_user_login())
{
return nullptr;
}
std::map<std::string, MachineObject*>::iterator it = userMachineList.find(dev_id);
if (it == userMachineList.end()) return nullptr;
return it->second;
}
MachineObject* DeviceManager::get_my_machine(std::string dev_id)
{
auto list = get_my_machine_list();
auto it = list.find(dev_id);
if (it != list.end())
{
return it->second;
}
return nullptr;
}
void DeviceManager::clean_user_info()
{
BOOST_LOG_TRIVIAL(trace) << "DeviceManager::clean_user_info";
// reset selected_machine
selected_machine = "";
local_selected_machine = "";
// clean user list
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
if (it->second)
{
it->second->set_access_code("");
delete it->second;
it->second = nullptr;
}
}
userMachineList.clear();
}
bool DeviceManager::set_selected_machine(std::string dev_id)
{
BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id;
auto my_machine_list = get_my_machine_list();
auto it = my_machine_list.find(dev_id);
// disconnect last
auto last_selected = my_machine_list.find(selected_machine);
if (last_selected != my_machine_list.end())
{
if (last_selected->second->connection_type() == "lan")
{
m_agent->disconnect_printer();
}
}
// connect curr
if (it != my_machine_list.end())
{
if (selected_machine == dev_id)
{
if (it->second->connection_type() != "lan")
{
// only reset update time
it->second->reset_update_time();
// check subscribe state
Slic3r::GUI::wxGetApp().on_start_subscribe_again(dev_id);
return true;
}
else
{
// lan mode printer reconnect printer
if (m_agent)
{
m_agent->disconnect_printer();
it->second->reset();
#if !BBL_RELEASE_TO_PUBLIC
it->second->connect(Slic3r::GUI::wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false);
#else
it->second->connect(it->second->local_use_ssl_for_mqtt);
#endif
it->second->set_lan_mode_connection_state(true);
}
}
}
else
{
if (m_agent)
{
if (it->second->connection_type() != "lan" || it->second->connection_type().empty())
{
if (m_agent->get_user_selected_machine() == dev_id)
{
it->second->reset_update_time();
}
else
{
BOOST_LOG_TRIVIAL(info) << "static: set_selected_machine: same dev_id = " << dev_id;
m_agent->set_user_selected_machine(dev_id);
it->second->reset();
}
}
else
{
BOOST_LOG_TRIVIAL(info) << "static: set_selected_machine: same dev_id = empty";
it->second->reset();
#if !BBL_RELEASE_TO_PUBLIC
it->second->connect(Slic3r::GUI::wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false);
#else
it->second->connect(it->second->local_use_ssl_for_mqtt);
#endif
m_agent->set_user_selected_machine(dev_id);
it->second->set_lan_mode_connection_state(true);
}
}
}
for (auto& data : it->second->m_nozzle_filament_data)
{
data.second.checked_filament.clear();
}
}
selected_machine = dev_id;
return true;
}
MachineObject* DeviceManager::get_selected_machine()
{
if (selected_machine.empty()) return nullptr;
MachineObject* obj = get_user_machine(selected_machine);
if (obj)
return obj;
// return local machine has access code
auto it = localMachineList.find(selected_machine);
if (it != localMachineList.end())
{
if (it->second->has_access_right())
return it->second;
}
return nullptr;
}
void DeviceManager::add_user_subscribe()
{
/* user machine */
std::vector<std::string> dev_list;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
dev_list.push_back(it->first);
BOOST_LOG_TRIVIAL(trace) << "add_user_subscribe: " << it->first;
}
m_agent->add_subscribe(dev_list);
}
void DeviceManager::del_user_subscribe()
{
/* user machine */
std::vector<std::string> dev_list;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
dev_list.push_back(it->first);
BOOST_LOG_TRIVIAL(trace) << "del_user_subscribe: " << it->first;
}
m_agent->del_subscribe(dev_list);
}
void DeviceManager::subscribe_device_list(std::vector<std::string> dev_list)
{
std::vector<std::string> unsub_list;
subscribe_list_cache.clear();
for (auto& it : subscribe_list_cache)
{
if (it != selected_machine)
{
unsub_list.push_back(it);
BOOST_LOG_TRIVIAL(trace) << "subscribe_device_list: unsub dev id = " << it;
}
}
BOOST_LOG_TRIVIAL(trace) << "subscribe_device_list: unsub_list size = " << unsub_list.size();
if (!selected_machine.empty())
{
subscribe_list_cache.push_back(selected_machine);
}
for (auto& it : dev_list)
{
subscribe_list_cache.push_back(it);
BOOST_LOG_TRIVIAL(trace) << "subscribe_device_list: sub dev id = " << it;
}
BOOST_LOG_TRIVIAL(trace) << "subscribe_device_list: sub_list size = " << subscribe_list_cache.size();
if (!unsub_list.empty())
m_agent->del_subscribe(unsub_list);
if (!dev_list.empty())
m_agent->add_subscribe(subscribe_list_cache);
}
std::map<std::string, MachineObject*> DeviceManager::get_my_machine_list()
{
std::map<std::string, MachineObject*> result;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
if (it->second && !it->second->is_lan_mode_printer())
{
result.insert(std::make_pair(it->first, it->second));
}
}
for (auto it = localMachineList.begin(); it != localMachineList.end(); it++)
{
if (it->second && it->second->has_access_right() && it->second->is_avaliable() && it->second->is_lan_mode_printer())
{
// remove redundant in userMachineList
if (result.find(it->first) == result.end())
{
result.emplace(std::make_pair(it->first, it->second));
}
}
}
return result;
}
std::map<std::string, MachineObject*> DeviceManager::get_my_cloud_machine_list()
{
std::map<std::string, MachineObject*> result;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
if (it->second && !it->second->is_lan_mode_printer()) { result.emplace(*it); }
}
return result;
}
std::string DeviceManager::get_first_online_user_machine() const
{
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{
if (it->second && it->second->is_online())
{
return it->second->get_dev_id();
}
}
return "";
}
void DeviceManager::modify_device_name(std::string dev_id, std::string dev_name)
{
BOOST_LOG_TRIVIAL(trace) << "modify_device_name";
if (m_agent)
{
int result = m_agent->modify_printer_name(dev_id, dev_name);
if (result == 0)
{
update_user_machine_list_info();
}
}
}
void DeviceManager::parse_user_print_info(std::string body)
{
if (device_subseries.size() <= 0) {
device_subseries = DevPrinterConfigUtil::get_all_subseries();
if (device_subseries.size() <= 0) {
device_subseries.insert(std::pair<std::string, std::vector<std::string>>("", std::vector<std::string>()));
}
}
BOOST_LOG_TRIVIAL(trace) << "DeviceManager::parse_user_print_info";
std::lock_guard<std::mutex> lock(listMutex);
std::set<std::string> new_list;
try
{
json j = json::parse(body);
#if !BBL_RELEASE_TO_PUBLIC
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": " << j;
#endif
if (j.contains("devices") && !j["devices"].is_null())
{
for (auto& elem : j["devices"])
{
MachineObject* obj = nullptr;
std::string dev_id;
if (!elem["dev_id"].is_null())
{
dev_id = elem["dev_id"].get<std::string>();
new_list.insert(dev_id);
}
std::map<std::string, MachineObject*>::iterator iter = userMachineList.find(dev_id);
if (iter != userMachineList.end())
{
/* update field */
obj = iter->second;
obj->set_dev_id(dev_id);
}
else
{
obj = new MachineObject(this, m_agent, "", "", "");
if (m_agent)
{
obj->set_bind_status(m_agent->get_user_name());
}
if (obj->get_dev_ip().empty())
{
obj->get_dev_ip() = Slic3r::GUI::wxGetApp().app_config->get("ip_address", dev_id);
}
userMachineList.insert(std::make_pair(dev_id, obj));
}
if (!obj) continue;
if (!elem["dev_id"].is_null())
obj->set_dev_id(elem["dev_id"].get<std::string>());
if (!elem["dev_name"].is_null())
obj->set_dev_name(elem["dev_name"].get<std::string>());
if (!elem["dev_online"].is_null())
obj->m_is_online = elem["dev_online"].get<bool>();
if (elem.contains("dev_model_name") && !elem["dev_model_name"].is_null()) {
auto printer_type = elem["dev_model_name"].get<std::string>();
for (const std::pair<std::string, std::vector<std::string>> &pair : device_subseries) {
auto it = std::find(pair.second.begin(), pair.second.end(), printer_type);
if (it != pair.second.end())
{
obj->printer_type = Slic3r::_parse_printer_type(pair.first);
break;
}
else
{
obj->printer_type = Slic3r::_parse_printer_type(printer_type);
}
}
}
if (!elem["task_status"].is_null())
obj->iot_print_status = elem["task_status"].get<std::string>();
if (elem.contains("dev_product_name") && !elem["dev_product_name"].is_null())
obj->dev_product_name = elem["dev_product_name"].get<std::string>();
if (elem.contains("dev_access_code") && !elem["dev_access_code"].is_null())
{
std::string acc_code = elem["dev_access_code"].get<std::string>();
acc_code.erase(std::remove(acc_code.begin(), acc_code.end(), '\n'), acc_code.end());
obj->set_access_code(acc_code);
}
}
//remove MachineObject from userMachineList
std::map<std::string, MachineObject*>::iterator iterat;
for (iterat = userMachineList.begin(); iterat != userMachineList.end(); )
{
if (new_list.find(iterat->first) == new_list.end())
{
iterat = userMachineList.erase(iterat);
}
else
{
iterat++;
}
}
}
}
catch (std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " exception=" << e.what();
}
}
void DeviceManager::update_user_machine_list_info()
{
if (!m_agent) return;
BOOST_LOG_TRIVIAL(debug) << "update_user_machine_list_info";
unsigned int http_code;
std::string body;
int result = m_agent->get_user_print_info(&http_code, &body);
if (result == 0)
{
parse_user_print_info(body);
}
}
void DeviceManager::load_last_machine()
{
// Get all available machines, include cloud machines and lan machines that have access right
auto all_machines = get_my_machine_list();
if (all_machines.empty())
return;
// Then connect to the machine we last selected if available
const std::string last_monitor_machine = m_agent ? m_agent->get_user_selected_machine() : "";
const auto last_machine = all_machines.find(last_monitor_machine);
if (last_machine != all_machines.end()) {
this->set_selected_machine(last_machine->second->get_dev_id());
} else {
// If not, then select the first available one
this->set_selected_machine(all_machines.begin()->second->get_dev_id());
}
}
void DeviceManager::OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state)
{
if (!obj) { return; }
if (obj->get_dev_id() == selected_machine)
{
if (new_state == "free") { OnSelectedMachineLost(); }
}
}
void DeviceManager::OnSelectedMachineLost()
{
GUI::wxGetApp().sidebar().update_sync_status(nullptr);
GUI::wxGetApp().sidebar().load_ams_list(string(), nullptr);
}
void DeviceManager::reload_printer_settings()
{
for (auto obj : this->userMachineList) { obj.second->reload_printer_settings(); };
}
DeviceManagerRefresher::DeviceManagerRefresher(DeviceManager* manger) : wxObject()
{
m_manager = manger;
m_timer = new wxTimer();
m_timer->Bind(wxEVT_TIMER, &DeviceManagerRefresher::on_timer, this);
}
DeviceManagerRefresher::~DeviceManagerRefresher()
{
m_timer->Stop();
delete m_timer;
}
void DeviceManagerRefresher::on_timer(wxTimerEvent& event)
{
if (!m_manager) { return; }
NetworkAgent* agent = m_manager->get_agent();
if (!agent) { return; }
// reset to active
Slic3r::GUI::wxGetApp().reset_to_active();
MachineObject* obj = m_manager->get_selected_machine();
if (!obj) { return; }
// check valid machine
if (obj && m_manager->get_my_machine(obj->get_dev_id()) == nullptr)
{
m_manager->set_selected_machine("");
agent->set_user_selected_machine("");
return;
}
// do some refresh
if (Slic3r::GUI::wxGetApp().is_user_login())
{
m_manager->check_pushing();
try
{
agent->refresh_connection();
}
catch (...)
{
;
}
}
// certificate
agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer());
}
}

View File

@@ -0,0 +1,125 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
namespace Slic3r
{
//Previous definitions
struct BBLocalMachine;
class MachineObject;
class NetworkAgent;
class DeviceManagerRefresher;
class DeviceManager
{
friend class GUI_App;
friend class DeviceManagerRefresher;
private:
NetworkAgent* m_agent{ nullptr };
DeviceManagerRefresher* m_refresher{ nullptr };
bool m_enable_mutil_machine = false;
std::mutex listMutex;
std::string selected_machine; /* dev_id */
std::string local_selected_machine; /* dev_id */
std::map<std::string, MachineObject*> localMachineList; /* dev_id -> MachineObject*, localMachine SSDP */
std::map<std::string, MachineObject*> userMachineList; /* dev_id -> MachineObject* cloudMachine of User */
public:
DeviceManager(NetworkAgent* agent = nullptr);
~DeviceManager();
public:
NetworkAgent* get_agent() const { return m_agent; }
void set_agent(NetworkAgent* agent) { m_agent = agent; }
void start_refresher();
void stop_refresher();
MachineObject* get_selected_machine();
bool set_selected_machine(std::string dev_id);
// local machine
void set_local_selected_machine(std::string dev_id) { local_selected_machine = dev_id; };
MachineObject* get_local_selected_machine() const { return get_local_machine(local_selected_machine); }
// local machine list
void erase_local_machine(std::string dev_id) { localMachineList.erase(dev_id); }
std::map<std::string, MachineObject*> get_local_machinelist() const { return localMachineList; }
MachineObject* get_local_machine(std::string dev_id) const
{
auto it = localMachineList.find(dev_id);
return (it != localMachineList.end()) ? it->second : nullptr;
}
// user machine
std::map<std::string, MachineObject*> get_user_machinelist() const { return userMachineList; }
std::string get_first_online_user_machine() const;
void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); }
void clean_user_info();
void load_last_machine();
void update_user_machine_list_info();
void parse_user_print_info(std::string body);
void reload_printer_settings();
MachineObject* get_user_machine(std::string dev_id);
// subscribe
void add_user_subscribe();
void del_user_subscribe();
void subscribe_device_list(std::vector<std::string> dev_list);
/* my machine*/
MachineObject* get_my_machine(std::string dev_id);
std::map<std::string, MachineObject*> get_my_machine_list();
std::map<std::string, MachineObject*> get_my_cloud_machine_list();
void modify_device_name(std::string dev_id, std::string dev_name);
/* create machine or update machine properties */
void on_machine_alive(std::string json_str);
int query_bind_status(std::string& msg);
// mutil-device
void EnableMultiMachine(bool enable = true);
bool IsMultiMachineEnabled() const { return m_enable_mutil_machine; }
std::vector<std::string> subscribe_list_cache;//multiple machine subscribe list cache
std::map<std::string, std::vector<std::string>> device_subseries;
private:
void keep_alive();
void check_pushing();
void OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state);
void OnSelectedMachineLost();
/*TODO*/
public:
// to remove
MachineObject* insert_local_device(const BBLocalMachine& machine, std::string connection_type, std::string bind_state, std::string version, std::string access_code);
static void update_local_machine(const MachineObject& m);
};
class DeviceManagerRefresher : public wxObject
{
wxTimer* m_timer{ nullptr };
int m_timer_interval_msec = 1000;
DeviceManager* m_manager{ nullptr };
public:
DeviceManagerRefresher(DeviceManager* manger);
~DeviceManagerRefresher();
public:
void Start() { m_timer->Start(m_timer_interval_msec); }
void Stop() { m_timer->Stop(); }
protected:
virtual void on_timer(wxTimerEvent& event);
};
};

View File

@@ -0,0 +1,364 @@
#include <nlohmann/json.hpp>
#include "DevMapping.h"
#include "DevFilaSystem.h"
#include "DevUtil.h"
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GuiColor.hpp"
using namespace nlohmann;
namespace Slic3r
{
bool DevMappingUtil::is_valid_mapping_result(const MachineObject* obj, std::vector<FilamentInfo>& result, bool check_empty_slot)
{
if (result.empty()) return false;
for (int i = 0; i < result.size(); i++)
{
// invalid mapping result
if (result[i].tray_id < 0)
{
if (result[i].ams_id.empty() && result[i].slot_id.empty())
{
return false;
}
}
else
{
auto ams_item = obj->GetFilaSystem()->GetAmsById(result[i].ams_id);
if (ams_item == nullptr)
{
if ((result[i].ams_id != std::to_string(VIRTUAL_TRAY_MAIN_ID)) &&
(result[i].ams_id != std::to_string(VIRTUAL_TRAY_DEPUTY_ID)))
{
result[i].tray_id = -1;
return false;
}
}
else
{
if (check_empty_slot)
{
auto tray_item = ams_item->GetTrays().find(result[i].slot_id);
if (tray_item == ams_item->GetTrays().end())
{
result[i].tray_id = -1;
return false;
}
else
{
if (!tray_item->second->is_exists)
{
result[i].tray_id = -1;
return false;
}
}
}
}
}
}
return true;
}
// calc distance map
struct DisValue {
int tray_id;
float distance;
bool is_same_color = true;
bool is_type_match = true;
};
static void _parse_tray_info(int ams_id, int slot_id, DevAmsTray tray, FilamentInfo& result)
{
result.color = tray.color;
result.type = tray.get_filament_type();
result.filament_id = tray.setting_id;
result.ctype = tray.ctype;
result.colors = tray.cols;
/*for new ams mapping*/
result.ams_id = std::to_string(ams_id);
result.slot_id = std::to_string(slot_id);
if (ams_id == VIRTUAL_TRAY_MAIN_ID || ams_id == VIRTUAL_TRAY_DEPUTY_ID)
{
result.tray_id = atoi(tray.id.c_str());
result.id = atoi(tray.id.c_str());
}
else
{
result.id = ams_id * 4 + slot_id;
}
}
int DevMappingUtil::ams_filament_mapping(const MachineObject* obj, const std::vector<FilamentInfo>& filaments, std::vector<FilamentInfo>& result, std::vector<bool> map_opt, std::vector<int> exclude_id, bool nozzle_has_ams_then_ignore_ext)
{
if (filaments.empty())
return -1;
/////////////////////////
// Step 1: collect filaments in machine
std::map<int, FilamentInfo> tray_filaments; // tray_index : tray_color
bool left_nozzle_has_ams = false, right_nozzle_has_ams = false;
const auto& ams_list = obj->GetFilaSystem()->GetAmsList();
for (auto ams = ams_list.begin(); ams != ams_list.end(); ams++)
{
std::string ams_id = ams->second->GetAmsId();
auto ams_type = ams->second->GetAmsType();
for (auto tray = ams->second->GetTrays().begin(); tray != ams->second->GetTrays().end(); tray++)
{
int ams_id = atoi(ams->first.c_str());
int tray_id = atoi(tray->first.c_str());
int tray_index = 0;
if (ams_type == DevAms::AMS || ams_type == DevAms::AMS_LITE || ams_type == DevAms::N3F)
{
tray_index = ams_id * 4 + tray_id;
}
else if (ams_type == DevAms::N3S)
{
tray_index = ams_id + tray_id;
}
else
{
assert(0);
}
// skip exclude id
for (int i = 0; i < exclude_id.size(); i++)
{
if (tray_index == exclude_id[i])
continue;
}
// push
FilamentInfo info;
if (tray->second->is_tray_info_ready())
{
_parse_tray_info(ams_id, tray_id, *(tray->second), info);
}
//first: left,nozzle=1,map=1 second: right,nozzle=0,map=2
bool right_ams_valid = ams->second->GetExtruderId() == 0 && map_opt[MappingOption::USE_RIGHT_AMS];
bool left_ams_valid = ams->second->GetExtruderId() == 1 && map_opt[MappingOption::USE_LEFT_AMS];
if (right_ams_valid || left_ams_valid)
{
tray_filaments.emplace(std::make_pair(tray_index, info));
if (right_ams_valid)
{
right_nozzle_has_ams = true;
}
if (left_ams_valid)
{
left_nozzle_has_ams = true;
}
}
}
}
if (map_opt[MappingOption::USE_RIGHT_EXT] || map_opt[MappingOption::USE_LEFT_EXT])
{
for (auto tray : obj->vt_slot)
{
bool right_ext_valid = (tray.id == std::to_string(VIRTUAL_TRAY_MAIN_ID) && map_opt[MappingOption::USE_RIGHT_EXT]);
bool left_ext_valid = (tray.id == std::to_string(VIRTUAL_TRAY_DEPUTY_ID) && map_opt[MappingOption::USE_LEFT_EXT]);
if (right_ext_valid || left_ext_valid)
{
if (nozzle_has_ams_then_ignore_ext)
{
if (right_ext_valid && right_nozzle_has_ams)
{
continue;
}
if (left_ext_valid && left_nozzle_has_ams)
{
continue;
}
}
FilamentInfo info;
_parse_tray_info(atoi(tray.id.c_str()), 0, tray, info);
tray_filaments.emplace(std::make_pair(info.tray_id, info));
}
}
}
/////////////////////////
// Step 2: collect the distances of filaments_in_slicing to filaments_in_machine
char buffer[256];
std::vector<std::vector<DisValue>> distance_map;
// print title
::sprintf(buffer, "F(id)");
std::string line = std::string(buffer);
for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++)
{
::sprintf(buffer, " AMS%02d", tray->second.id + 1);
line += std::string(buffer);
}
BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line;// Print the collected filaments
for (int i = 0; i < filaments.size(); i++)
{
std::vector<DisValue> rol;
::sprintf(buffer, "F(%02d)", filaments[i].id + 1);
line = std::string(buffer);
for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++)
{
DisValue val;
val.tray_id = tray->second.id;
wxColour c = wxColour(filaments[i].color);
wxColour tray_c = DevAmsTray::decode_color(tray->second.color);
val.distance = GUI::calc_color_distance(c, tray_c);
if (filaments[i].type != tray->second.type)
{
val.distance = 999999;
val.is_type_match = false;
}
else
{
if (c.Alpha() != tray_c.Alpha())
val.distance = 999999;
val.is_type_match = true;
}
::sprintf(buffer, " %6.0f", val.distance);
line += std::string(buffer);
rol.push_back(val);
}
BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line;
distance_map.push_back(rol);
}
/////////////////////////
// Step 3: do mapping algorithm
// setup the mapping result
for (int i = 0; i < filaments.size(); i++)
{
FilamentInfo info;
info.id = filaments[i].id;
info.tray_id = -1;
info.type = filaments[i].type;
info.filament_id = filaments[i].filament_id;
result.push_back(info);
}
// traverse the mapping
std::set<int> picked_src;
std::set<int> picked_tar;
for (int k = 0; k < distance_map.size(); k++)
{
float min_val = INT_MAX;
int picked_src_idx = -1;
int picked_tar_idx = -1;
for (int i = 0; i < distance_map.size(); i++)
{
if (picked_src.find(i) != picked_src.end())
continue;
// try to mapping to different tray
for (int j = 0; j < distance_map[i].size(); j++)
{
if (picked_tar.find(j) != picked_tar.end())
{
if (distance_map[i][j].is_same_color
&& distance_map[i][j].is_type_match
&& distance_map[i][j].distance < (float)0.0001)
{
min_val = distance_map[i][j].distance;
picked_src_idx = i;
picked_tar_idx = j;
tray_filaments[picked_tar_idx].distance = min_val;
}
continue;
}
if (distance_map[i][j].is_same_color
&& distance_map[i][j].is_type_match)
{
if (min_val > distance_map[i][j].distance)
{
min_val = distance_map[i][j].distance;
picked_src_idx = i;
picked_tar_idx = j;
tray_filaments[picked_tar_idx].distance = min_val;
}
else if (min_val == distance_map[i][j].distance && filaments[picked_src_idx].filament_id != tray_filaments[picked_tar_idx].filament_id && filaments[i].filament_id == tray_filaments[j].filament_id)
{
picked_src_idx = i;
picked_tar_idx = j;
}
}
}
// take a retry to mapping to used tray
if (picked_src_idx < 0 || picked_tar_idx < 0)
{
for (int j = 0; j < distance_map[i].size(); j++)
{
if (distance_map[i][j].is_same_color && distance_map[i][j].is_type_match)
{
if (min_val > distance_map[i][j].distance)
{
min_val = distance_map[i][j].distance;
picked_src_idx = i;
picked_tar_idx = j;
tray_filaments[picked_tar_idx].distance = min_val;
}
else if (min_val == distance_map[i][j].distance && filaments[picked_src_idx].filament_id != tray_filaments[picked_tar_idx].filament_id && filaments[i].filament_id == tray_filaments[j].filament_id)
{
picked_src_idx = i;
picked_tar_idx = j;
}
}
}
}
}
if (picked_src_idx >= 0 && picked_tar_idx >= 0)
{
auto tray = tray_filaments.find(distance_map[k][picked_tar_idx].tray_id);
if (tray != tray_filaments.end())
{
result[picked_src_idx].tray_id = tray->first;
result[picked_src_idx].color = tray->second.color;
result[picked_src_idx].type = tray->second.type;
result[picked_src_idx].distance = tray->second.distance;
result[picked_src_idx].filament_id = tray->second.filament_id;
result[picked_src_idx].ctype = tray->second.ctype;
result[picked_src_idx].colors = tray->second.colors;
/*for new ams mapping*/
result[picked_src_idx].ams_id = tray->second.ams_id;
result[picked_src_idx].slot_id = tray->second.slot_id;
}
::sprintf(buffer, "ams_mapping, picked F(%02d) AMS(%02d), distance=%6.0f", picked_src_idx + 1, picked_tar_idx + 1,
distance_map[picked_src_idx][picked_tar_idx].distance);
BOOST_LOG_TRIVIAL(info) << std::string(buffer);
picked_src.insert(picked_src_idx);
picked_tar.insert(picked_tar_idx);
}
}
//check ams mapping result
if (DevMappingUtil::is_valid_mapping_result(obj, result, true))
{
return 0;
}
/* for (auto it = result.begin(); it != result.end(); it++) {//This code has never been effective before 2025.03.18
if (it->distance >= 6000) {
it->tray_id = -1;
}
}*/
return 0;
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "libslic3r/ProjectTask.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
namespace Slic3r
{
//Previous definitions
class MachineObject;
enum MappingOption
{
USE_LEFT_AMS = 0,
USE_RIGHT_AMS,
USE_LEFT_EXT,
USE_RIGHT_EXT
};
class DevMappingUtil
{
public:
DevMappingUtil() = delete;
~DevMappingUtil() = delete;
public:
static bool is_valid_mapping_result(const MachineObject* obj, std::vector<FilamentInfo>& result, bool check_empty_slot = false);
static int ams_filament_mapping(const MachineObject* obj, const std::vector<FilamentInfo>& filaments, std::vector<FilamentInfo>& result, std::vector<bool> map_opt, std::vector<int> exclude_id = std::vector<int>(), bool nozzle_has_ams_then_ignore_ext = false);
};
};

View File

@@ -0,0 +1,129 @@
#include "DevExtruderSystem.h"
#include "DevNozzleSystem.h"
#include "DevUtil.h"
#include "slic3r/GUI/DeviceManager.hpp"
namespace Slic3r
{
DevNozzle DevNozzleSystem::GetNozzle(int id) const
{
if (m_nozzles.find(id) != m_nozzles.end())
{
return m_nozzles.at(id);
}
return DevNozzle();
}
void DevNozzleSystem::Reset()
{
m_nozzles.clear();
m_extder_exist = 0;
m_state = 0; // idle state
}
static unordered_map<string, NozzleFlowType> _str2_nozzle_flow_type = {
{"S", NozzleFlowType::S_FLOW},
{"H", NozzleFlowType::H_FLOW},
{"A", NozzleFlowType::S_FLOW},
{"X", NozzleFlowType::S_FLOW}
};
static unordered_map<string, NozzleType> _str2_nozzle_type = {
{"00", NozzleType::ntStainlessSteel},
{"01", NozzleType::ntHardenedSteel},
{"05", NozzleType::ntTungstenCarbide}
};
static void s_parse_nozzle_type(const std::string& nozzle_type_str, DevNozzle& nozzle)
{
if (NozzleTypeStrToEumn.count(nozzle_type_str) != 0)
{
nozzle.m_nozzle_type = NozzleTypeStrToEumn[nozzle_type_str];
}
else if (nozzle_type_str.length() >= 4)
{
const std::string& flow_type_str = nozzle_type_str.substr(1, 1);
if (_str2_nozzle_flow_type.count(flow_type_str) != 0)
{
nozzle.m_nozzle_flow = _str2_nozzle_flow_type[flow_type_str];
}
const std::string& type_str = nozzle_type_str.substr(2, 2);
if (_str2_nozzle_type.count(type_str) != 0)
{
nozzle.m_nozzle_type = _str2_nozzle_type[type_str];
}
}
}
void DevNozzleSystemParser::ParseV1_0(const nlohmann::json& nozzletype_json,
const nlohmann::json& diameter_json,
DevNozzleSystem* system)
{
//Since both the old and new protocols push data.
// assert(system->m_nozzles.size() < 2);
DevNozzle nozzle;
nozzle.m_nozzle_id = 0;
nozzle.m_nozzle_flow = NozzleFlowType::S_FLOW; // default flow type
{
float nozzle_diameter = 0.0f;
if (diameter_json.is_number_float())
{
nozzle_diameter = diameter_json.get<float>();
}
else if (diameter_json.is_string())
{
nozzle_diameter = DevUtil::string_to_float(diameter_json.get<std::string>());
}
if (nozzle_diameter == 0.0f)
{
nozzle.m_diameter = 0.0f;
}
else
{
nozzle.m_diameter = round(nozzle_diameter * 10) / 10;
}
}
{
if (nozzletype_json.is_string())
{
s_parse_nozzle_type(nozzletype_json.get<std::string>(), nozzle);
}
}
system->m_nozzles.emplace(0, nozzle);
}
void DevNozzleSystemParser::ParseV2_0(const json& nozzle_json, DevNozzleSystem* system)
{
system->Reset();
if (nozzle_json.contains("exist"))
{
system->m_extder_exist = DevUtil::get_flag_bits(nozzle_json["exist"].get<int>(), 0, 16);
}
if (nozzle_json.contains("state"))
{
system->m_state = DevUtil::get_flag_bits(nozzle_json["state"].get<int>(), 0, 4);
}
for (auto it = nozzle_json["info"].begin(); it != nozzle_json["info"].end(); it++)
{
DevNozzle nozzle_obj;
const auto& njon = it.value();
nozzle_obj.m_nozzle_id = njon["id"].get<int>();
nozzle_obj.m_diameter = njon["diameter"].get<float>();
s_parse_nozzle_type(njon["type"].get<std::string>(), nozzle_obj);
system->m_nozzles[nozzle_obj.m_nozzle_id] = nozzle_obj;
}
}
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "libslic3r/CommonDefs.hpp"
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
#include <map>
namespace Slic3r
{
// Previous definitions
class MachineObject;
struct DevNozzle
{
int m_nozzle_id = -1;
NozzleFlowType m_nozzle_flow = NozzleFlowType::S_FLOW;// 0-common 1-high flow
NozzleType m_nozzle_type = NozzleType::ntUndefine;// 0-stainless_steel 1-hardened_steel 5-tungsten_carbide
float m_diameter = 0.4f;// 0.2mm 0.4mm 0.6mm 0.8mm
};
class DevNozzleSystem
{
friend class DevNozzleSystemParser;
public:
DevNozzleSystem(MachineObject* owner) : m_owner(owner) {}
public:
bool ContainsNozzle(int id) const { return m_nozzles.find(id) != m_nozzles.end(); }
DevNozzle GetNozzle(int id) const;
const std::map<int, DevNozzle>& GetNozzles() const { return m_nozzles;}
private:
void Reset();
private:
MachineObject* m_owner = nullptr;
int m_extder_exist = 0; //0- none exist 1-exist, unused
int m_state = 0; //0-idle 1-checking, unused
std::map<int, DevNozzle> m_nozzles;
};
class DevNozzleSystemParser
{
public:
static void ParseV1_0(const nlohmann::json& nozzletype_json, const nlohmann::json& diameter_json, DevNozzleSystem* system);
static void ParseV2_0(const json& nozzle_json, DevNozzleSystem* system);
};
};

View File

@@ -0,0 +1,280 @@
#include "DevPrintOptions.h"
#include "DevUtil.h"
#include "slic3r/GUI/DeviceManager.hpp"
namespace Slic3r
{
void DevPrintOptionsParser::Parse(DevPrintOptions* opts, const nlohmann::json& print_json)
{
try
{
if (print_json.contains("spd_lvl"))
{
opts->m_speed_level = static_cast<DevPrintingSpeedLevel>(print_json["spd_lvl"].get<int>());
}
if (print_json.contains("cfg"))
{
const std::string& cfg = print_json["cfg"].get<std::string>();
opts->m_speed_level = (DevPrintingSpeedLevel)DevUtil::get_flag_bits(cfg, 8, 3);
}
}
catch (const std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << "DevPrintOptionsParser::Parse: Failed to parse print options from JSON." << e.what();
}
}
void DevPrintOptionsParser::ParseDetectionV1_0(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json)
{
try {
if (print_json.contains("xcam")) {
if (time(nullptr) - opts->xcam_ai_monitoring_hold_start > HOLD_TIME_3SEC) {
if (print_json["xcam"].contains("printing_monitor")) {
// new protocol
opts->xcam_ai_monitoring = print_json["xcam"]["printing_monitor"].get<bool>();
} else {
// old version protocol
if (print_json["xcam"].contains("spaghetti_detector")) {
opts->xcam_ai_monitoring = print_json["xcam"]["spaghetti_detector"].get<bool>();
if (print_json["xcam"].contains("print_halt")) {
bool print_halt = print_json["xcam"]["print_halt"].get<bool>();
if (print_halt) { opts->xcam_ai_monitoring_sensitivity = "medium"; }
}
}
}
if (print_json["xcam"].contains("halt_print_sensitivity")) {
opts->xcam_ai_monitoring_sensitivity = print_json["xcam"]["halt_print_sensitivity"].get<std::string>();
}
}
if (time(nullptr) - opts->xcam_first_layer_hold_start > HOLD_TIME_3SEC) {
if (print_json["xcam"].contains("first_layer_inspector")) { opts->xcam_first_layer_inspector = print_json["xcam"]["first_layer_inspector"].get<bool>(); }
}
if (time(nullptr) - opts->xcam_buildplate_marker_hold_start > HOLD_TIME_3SEC) {
if (print_json["xcam"].contains("buildplate_marker_detector")) {
opts->xcam_buildplate_marker_detector = print_json["xcam"]["buildplate_marker_detector"].get<bool>();
obj->is_support_build_plate_marker_detect = true;
} else {
obj->is_support_build_plate_marker_detect = false;
}
}
}
} catch (...) {
;
}
}
void DevPrintOptionsParser::ParseDetectionV1_1(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json,bool enable)
{
if (print_json["module_name"].get<std::string>() == "first_layer_inspector") {
if (time(nullptr) - opts->xcam_first_layer_hold_start > HOLD_TIME_3SEC) {
opts->xcam_first_layer_inspector = enable;
}
} else if (print_json["module_name"].get<std::string>() == "buildplate_marker_detector") {
if (time(nullptr) - opts->xcam_buildplate_marker_hold_start > HOLD_TIME_3SEC) {
opts->xcam_buildplate_marker_detector = enable;
}
} else if (print_json["module_name"].get<std::string>() == "printing_monitor") {
if (time(nullptr) - opts->xcam_ai_monitoring_hold_start > HOLD_TIME_3SEC) {
opts->xcam_ai_monitoring = enable;
if (print_json.contains("halt_print_sensitivity")) {
opts->xcam_ai_monitoring_sensitivity = print_json["halt_print_sensitivity"].get<std::string>();
}
}
} else if (print_json["module_name"].get<std::string>() == "spaghetti_detector") {
if (time(nullptr) - opts->xcam_ai_monitoring_hold_start > HOLD_TIME_3SEC) {
// old protocol
opts->xcam_ai_monitoring = enable;
if (print_json.contains("print_halt")) {
if (print_json["print_halt"].get<bool>()) { opts->xcam_ai_monitoring_sensitivity = "medium"; }
}
}
}
}
void DevPrintOptionsParser::ParseDetectionV1_2(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json) {
try {
if (print_json.contains("option")) {
if (print_json["option"].is_number()) {
int option = print_json["option"].get<int>();
if (time(nullptr) - opts->xcam_auto_recovery_hold_start > HOLD_TIME_3SEC) { opts->xcam_auto_recovery_step_loss = ((option & 0x01) != 0); }
}
}
if (time(nullptr) - opts->xcam_auto_recovery_hold_start > HOLD_TIME_3SEC) {
if (print_json.contains("auto_recovery")) { opts->xcam_auto_recovery_step_loss = print_json["auto_recovery"].get<bool>(); }
}
} catch (...) {}
}
void DevPrintOptionsParser::ParseDetectionV2_0(DevPrintOptions *opts, std::string print_json)
{
if (time(nullptr) - opts->xcam_first_layer_hold_start > HOLD_TIME_3SEC) {
opts->xcam_first_layer_inspector = DevUtil::get_flag_bits(print_json, 12);
}
if (time(nullptr) - opts->xcam_ai_monitoring_hold_start > HOLD_COUNT_MAX) {
opts->xcam_ai_monitoring = DevUtil::get_flag_bits(print_json, 15);
switch (DevUtil::get_flag_bits(print_json, 13, 2)) {
case 0: opts->xcam_ai_monitoring_sensitivity = "never_halt"; break;
case 1: opts->xcam_ai_monitoring_sensitivity = "low"; break;
case 2: opts->xcam_ai_monitoring_sensitivity = "medium"; break;
case 3: opts->xcam_ai_monitoring_sensitivity = "high"; break;
default: break;
}
}
if (time(nullptr) - opts->xcam_auto_recovery_hold_start > HOLD_COUNT_MAX){
opts->xcam_auto_recovery_step_loss =DevUtil::get_flag_bits(print_json, 16);
}
if (time(nullptr) - opts->xcam_prompt_sound_hold_start > HOLD_TIME_3SEC) {
opts->xcam_allow_prompt_sound = DevUtil::get_flag_bits(print_json, 22);
}
if (time(nullptr) - opts->xcam_filament_tangle_detect_hold_start > HOLD_TIME_3SEC) {
opts->xcam_filament_tangle_detect = DevUtil::get_flag_bits(print_json, 23);
}
}
void DevPrintOptions::SetPrintingSpeedLevel(DevPrintingSpeedLevel speed_level)
{
if (speed_level >= SPEED_LEVEL_INVALID && speed_level < SPEED_LEVEL_COUNT)
{
m_speed_level = speed_level;
}
else
{
m_speed_level = SPEED_LEVEL_INVALID; // Reset to invalid if out of range
}
}
int DevPrintOptions::command_xcam_control_ai_monitoring(bool on_off, std::string lvl)
{
bool print_halt = (lvl == "never_halt") ? false : true;
xcam_ai_monitoring = on_off;
xcam_ai_monitoring_hold_start = time(nullptr);
xcam_ai_monitoring_sensitivity = lvl;
return command_xcam_control("printing_monitor", on_off, m_obj, lvl);
}
int DevPrintOptions::command_xcam_control_buildplate_marker_detector(bool on_off)
{
xcam_buildplate_marker_detector = on_off;
xcam_buildplate_marker_hold_start = time(nullptr);
return command_xcam_control("buildplate_marker_detector", on_off ,m_obj);
}
int DevPrintOptions::command_xcam_control_first_layer_inspector(bool on_off, bool print_halt)
{
xcam_first_layer_inspector = on_off;
xcam_first_layer_hold_start = time(nullptr);
return command_xcam_control("first_layer_inspector", on_off, m_obj);
}
int DevPrintOptions::command_xcam_control_auto_recovery_step_loss(bool on_off)
{
xcam_auto_recovery_step_loss = on_off;
xcam_auto_recovery_hold_start = time(nullptr);
return command_set_printing_option(on_off, m_obj);
}
int DevPrintOptions::command_xcam_control_allow_prompt_sound(bool on_off)
{
xcam_allow_prompt_sound = on_off;
xcam_prompt_sound_hold_start = time(nullptr);
return command_set_prompt_sound(on_off, m_obj);
}
int DevPrintOptions::command_xcam_control_filament_tangle_detect(bool on_off)
{
xcam_filament_tangle_detect = on_off;
xcam_filament_tangle_detect_hold_start = time(nullptr);
return command_set_filament_tangle_detect(on_off, m_obj);
}
void DevPrintOptions::parse_auto_recovery_step_loss_status(int flag) {
if (time(nullptr) - xcam_auto_recovery_hold_start > HOLD_TIME_3SEC) {
xcam_auto_recovery_step_loss = ((flag >> 4) & 0x1) != 0;
}
}
void DevPrintOptions::parse_allow_prompt_sound_status(int flag)
{
if (time(nullptr) - xcam_prompt_sound_hold_start > HOLD_TIME_3SEC) {
xcam_allow_prompt_sound = ((flag >> 17) & 0x1) != 0;
}
}
void DevPrintOptions::parse_filament_tangle_detect_status(int flag)
{
if (time(nullptr) - xcam_filament_tangle_detect_hold_start > HOLD_TIME_3SEC) {
xcam_filament_tangle_detect = ((flag >> 20) & 0x1) != 0;
}
}
int DevPrintOptions::command_xcam_control(std::string module_name, bool on_off , MachineObject *obj, std::string lvl)
{
json j;
j["xcam"]["command"] = "xcam_control_set";
j["xcam"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["xcam"]["module_name"] = module_name;
j["xcam"]["control"] = on_off;
j["xcam"]["enable"] = on_off; // old protocol
j["xcam"]["print_halt"] = true; // old protocol
if (!lvl.empty()) { j["xcam"]["halt_print_sensitivity"] = lvl; }
BOOST_LOG_TRIVIAL(info) << "command:xcam_control_set" << ", module_name:" << module_name << ", control:" << on_off << ", halt_print_sensitivity:" << lvl;
return obj->publish_json(j);
}
int DevPrintOptions::command_set_printing_option(bool auto_recovery, MachineObject *obj)
{
json j;
j["print"]["command"] = "print_option";
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["option"] = (int) auto_recovery;
j["print"]["auto_recovery"] = auto_recovery;
return obj->publish_json(j);
}
int DevPrintOptions::command_set_prompt_sound(bool prompt_sound, MachineObject *obj)
{
json j;
j["print"]["command"] = "print_option";
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["sound_enable"] = prompt_sound;
return obj->publish_json(j);
}
int DevPrintOptions::command_set_filament_tangle_detect(bool filament_tangle_detect, MachineObject *obj)
{
json j;
j["print"]["command"] = "print_option";
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["print"]["filament_tangle_detect"] = filament_tangle_detect;
return obj->publish_json(j);
}
}
// namespace Slic3r

View File

@@ -0,0 +1,91 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
#include <wx/string.h>
#include "DevDefs.h"
namespace Slic3r {
class MachineObject;
class DevPrintOptions
{
friend class DevPrintOptionsParser;
public:
DevPrintOptions(MachineObject* obj): m_obj(obj) {}
public:
void SetPrintingSpeedLevel(DevPrintingSpeedLevel speed_level);
DevPrintingSpeedLevel GetPrintingSpeedLevel() const { return m_speed_level;}
// detect options
int command_xcam_control_ai_monitoring(bool on_off, std::string lvl);
int command_xcam_control_first_layer_inspector(bool on_off, bool print_halt);
int command_xcam_control_buildplate_marker_detector(bool on_off);
int command_xcam_control_auto_recovery_step_loss(bool on_off);
int command_xcam_control_allow_prompt_sound(bool on_off);
int command_xcam_control_filament_tangle_detect(bool on_off);
int command_xcam_control(std::string module_name, bool on_off, MachineObject *obj ,std::string lvl = "");
// set print option
int command_set_printing_option(bool auto_recovery, MachineObject *obj);
// set prompt sound
int command_set_prompt_sound(bool prompt_sound, MachineObject *obj);
// set fliament tangle detect
int command_set_filament_tangle_detect(bool fliament_tangle_detect, MachineObject *obj);
void parse_auto_recovery_step_loss_status(int flag);
void parse_allow_prompt_sound_status(int flag);
void parse_filament_tangle_detect_status(int flag);
bool GetAiMonitoring() const { return xcam_ai_monitoring; };
bool GetFirstLayerInspector() const{ return xcam_first_layer_inspector; };
bool GetBuildplateMarkerDetector() const { return xcam_buildplate_marker_detector; };
bool GetAutoRecoveryStepLoss() const { return xcam_auto_recovery_step_loss; };
bool GetAllowPromptSound() const { return xcam_allow_prompt_sound; };
bool GetFilamentTangleDetect() const { return xcam_filament_tangle_detect; };
string GetAiMonitoringSensitivity() const { return xcam_ai_monitoring_sensitivity; };
private:
// print option
DevPrintingSpeedLevel m_speed_level = SPEED_LEVEL_INVALID;
// detect options
bool xcam_ai_monitoring{false};
std::string xcam_ai_monitoring_sensitivity;
bool xcam_buildplate_marker_detector{false};
bool xcam_first_layer_inspector{false};
bool xcam_auto_recovery_step_loss{false};
bool xcam_allow_prompt_sound{false};
bool xcam_filament_tangle_detect{false};
time_t xcam_ai_monitoring_hold_start = 0;
time_t xcam_buildplate_marker_hold_start = 0;
time_t xcam_first_layer_hold_start = 0;
time_t xcam_auto_recovery_hold_start = 0;
time_t xcam_prompt_sound_hold_start = 0;
time_t xcam_filament_tangle_detect_hold_start = 0;
MachineObject* m_obj;/*owner*/
};
class DevPrintOptionsParser
{
public:
static void Parse(DevPrintOptions* opts, const nlohmann::json& print_json);
//V1 stands for parse_json; V2 stands for parse_new_json
static void ParseDetectionV1_0(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json);
static void ParseDetectionV1_1(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json, bool enable);
static void ParseDetectionV1_2(DevPrintOptions *opts, MachineObject *obj, const nlohmann::json &print_json);
static void ParseDetectionV2_0(DevPrintOptions *opts, std::string print_json);
};
} // namespace Slic3r

View File

@@ -0,0 +1 @@
#include "DevPrintTaskInfo.h"

View File

@@ -0,0 +1,24 @@
#pragma once
// TODO classes to handle dev print task management and ratings
namespace Slic3r
{
struct DevPrintTaskRatingInfo
{
bool request_successful;
int http_code;
int rating_id;
int start_count;
bool success_printed;
std::string content;
std::vector<std::string> image_url_paths;
};
class DevPrintTaskInfo
{
};
}// end namespace Slic3r

View File

@@ -0,0 +1,34 @@
#include "DevStorage.h"
#include "slic3r/GUI/DeviceManager.hpp"
namespace Slic3r {
DevStorage::SdcardState Slic3r::DevStorage::set_sdcard_state(int state)
{
if (state < DevStorage::NO_SDCARD || state > DevStorage::SDCARD_STATE_NUM) {
m_sdcard_state = DevStorage::NO_SDCARD;
} else {
m_sdcard_state = DevStorage::SdcardState(state);
}
return m_sdcard_state;
}
void DevStorage::ParseV1_0(const json &print_json, DevStorage *system)
{
if (system)
{
if (print_json.contains("sdcard")) {
if (print_json["sdcard"].get<bool>())
system->m_sdcard_state = DevStorage::SdcardState::HAS_SDCARD_NORMAL;
else
system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD;
} else {
system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD;
}
}
}
} // namespace Slic3r

View File

@@ -0,0 +1,36 @@
#pragma once
#include <nlohmann/json.hpp>
#include "slic3r/Utils/json_diff.hpp"
namespace Slic3r {
class MachineObject;
class DevStorage
{
public:
DevStorage(MachineObject *obj) : m_owner(obj){}
public:
enum SdcardState : int {
NO_SDCARD = 0,
HAS_SDCARD_NORMAL = 1,
HAS_SDCARD_ABNORMAL = 2,
HAS_SDCARD_READONLY = 3,
SDCARD_STATE_NUM = 4
};
/* sdcard */
SdcardState get_sdcard_state() const { return m_sdcard_state; };
SdcardState set_sdcard_state(int state);
static void ParseV1_0(const json &print_json, DevStorage *system);
private:
MachineObject *m_owner;
SdcardState m_sdcard_state { NO_SDCARD };
};
} // namespace Slic3r

View File

@@ -0,0 +1,114 @@
#include "DevUtil.h"
#include "fast_float/fast_float.h"
namespace Slic3r
{
int DevUtil::get_flag_bits(std::string str, int start, int count)
{
try
{
unsigned long long decimal_value = std::stoull(str, nullptr, 16);
unsigned long long mask = (1ULL << count) - 1;
int flag = (decimal_value >> start) & mask;
return flag;
}
catch (const std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed";
}
return 0;
}
int DevUtil::get_flag_bits(int num, int start, int count, int base)
{
try
{
unsigned long long mask = (1ULL << count) - 1;
unsigned long long value;
if (base == 10)
{
value = static_cast<unsigned long long>(num);
}
else if (base == 16)
{
value = static_cast<unsigned long long>(std::stoul(std::to_string(num), nullptr, 16));
}
else
{
throw std::invalid_argument("Unsupported base");
}
int flag = (value >> start) & mask;
return flag;
}
catch (const std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed";
}
return 0;
}
float DevUtil::string_to_float(const std::string& str_value)
{
float value = 0.0f;
try
{
fast_float::from_chars(str_value.c_str(), str_value.c_str() + str_value.size(), value);
}
catch (const std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed";
}
return value;
}
std::string DevUtil::convertToIp(long long ip)
{
std::stringstream ss;
ss << ((ip >> 0) & 0xFF) << "." << ((ip >> 8) & 0xFF) << "." << ((ip >> 16) & 0xFF) << "." << ((ip >> 24) & 0xFF);
return ss.str();
}
std::string DevJsonValParser::get_longlong_val(const nlohmann::json& j)
{
try
{
if (j.is_number())
{
return std::to_string(j.get<long long>());
}
else if (j.is_string())
{
return j.get<std::string>();
}
}
catch (const nlohmann::json::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
catch (const std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
return std::string();
}
};// namespace Slic3r

View File

@@ -0,0 +1,71 @@
/**
* @file DevUtil.h
* @brief Provides common static utility methods for general use.
*
* This class offers a collection of static helper functions such as string manipulation,
* file operations, and other frequently used utilities.
*/
#pragma once
#include <string>
#include <sstream>
#include <stdexcept>
#include "nlohmann/json.hpp"
namespace Slic3r
{
class DevUtil
{
public:
DevUtil() = delete;
DevUtil(const DevUtil&) = delete;
DevUtil& operator=(const DevUtil&) = delete;
public:
static int get_flag_bits(std::string str, int start, int count = 1);
static int get_flag_bits(int num, int start, int count = 1, int base = 10);
static float string_to_float(const std::string& str_value);
static std::string convertToIp(long long ip);
};
class DevJsonValParser
{
public:
template<typename T>
static void ParseVal(const nlohmann::json& j, const std::string& key, T& val)
{
try
{
if (j.contains(key)) { val = j[key].get<T>(); }
}
catch (const nlohmann::json::exception& e)
{
assert(0 && __FUNCTION__);
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
}
template<typename T>
static void ParseVal(const nlohmann::json& j, const std::string& key, T& val, T default_val)
{
try
{
j.contains(key) ? (val = j[key].get<T>()) : (val = default_val);
}
catch (const nlohmann::json::exception& e)
{
assert(0 && __FUNCTION__);
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what();
}
}
public:
static std::string get_longlong_val(const nlohmann::json& j);
};
}; // namespace Slic3r