Fix sending print jobs to Bambu H2C printer

This commit is contained in:
SoftFever
2026-07-13 18:13:15 +08:00
parent 79aa0bd4a2
commit 35ffe49b17
3 changed files with 88 additions and 1 deletions

View File

@@ -3452,6 +3452,13 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
if (z_offset != nullptr)
m_z_offset = z_offset->value;
// Reprocessing an existing g-code (from-previous reload / imported g-code) reaches apply_config
// through this DynamicPrintConfig overload; rebuild the per-filament nozzle grouping onto the
// result so the multi-nozzle device GUI can map filaments to physical nozzles. The normal
// streaming export uses the PrintConfig overload and hands the live grouping over separately, so
// it is intentionally not touched here.
ensure_nozzle_group_result(static_cast<int>(m_result.filaments_count));
}
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
@@ -6575,6 +6582,75 @@ void GCodeProcessor::init_filament_maps_and_nozzle_type_when_import_only_gcode()
}
}
// Surface a per-filament nozzle grouping onto m_result when reprocessing an already-generated g-code
// (from-previous reload / imported g-code) — process_file does not otherwise rebuild it, so the
// multi-nozzle device GUI would find nozzle_group_result == NULL and the rack print-dispatch mapping
// request fails with code -1. Only invoked from the DynamicPrintConfig apply_config (the reprocess /
// import path); the normal streaming export keeps handing the live grouping over separately.
void GCodeProcessor::ensure_nozzle_group_result(int min_filament_count)
{
if (m_nozzle_group_result) {
// A grouping was already seeded from the reloaded result (initialize_from_context). Publish it
// onto m_result so extract_result() carries it. (The reference relies on the streaming-export
// handover for this and returns early here; the reprocess path has no such handover.)
m_result.nozzle_group_result = m_nozzle_group_result;
return;
}
int filament_count = std::max(1, min_filament_count);
filament_count = std::max(filament_count, static_cast<int>(m_filament_maps.size()));
std::vector<int> filament_map = m_filament_maps;
if (filament_map.empty()) {
filament_map.assign(filament_count, 0);
} else if (static_cast<int>(filament_map.size()) < filament_count) {
filament_map.resize(filament_count, filament_map.front());
}
int min_value = *std::min_element(filament_map.begin(), filament_map.end());
if (min_value >= 1) {
for (int &value : filament_map) {
value -= 1;
}
}
for (int &value : filament_map) {
value = std::max(0, value);
}
int max_extruder_id = *std::max_element(filament_map.begin(), filament_map.end());
max_extruder_id = std::max(0, max_extruder_id);
std::string nozzle_diameter = format_diameter_to_str(DEFAULT_TOOLPATH_WIDTH);
std::vector<MultiNozzleUtils::NozzleInfo> nozzle_list;
nozzle_list.reserve(static_cast<size_t>(max_extruder_id + 1));
for (int extruder_id = 0; extruder_id <= max_extruder_id; ++extruder_id) {
MultiNozzleUtils::NozzleInfo info;
info.diameter = nozzle_diameter;
info.volume_type = NozzleVolumeType::nvtStandard;
info.extruder_id = extruder_id;
info.group_id = extruder_id;
nozzle_list.emplace_back(std::move(info));
}
std::vector<int> filament_nozzle_map(filament_count, 0);
for (int i = 0; i < filament_count; ++i) {
filament_nozzle_map[i] = filament_map[i];
}
std::vector<unsigned int> used_filaments;
used_filaments.reserve(filament_count);
for (int i = 0; i < filament_count; ++i) {
used_filaments.push_back(static_cast<unsigned int>(i));
}
auto result = MultiNozzleUtils::LayeredNozzleGroupResult::create(filament_nozzle_map, nozzle_list, used_filaments);
if (result) {
m_nozzle_group_result = std::make_shared<MultiNozzleUtils::LayeredNozzleGroupResult>(*result);
m_result.nozzle_group_result = m_nozzle_group_result;
}
}
bool GCodeProcessor::use_multi_nozzle_change_time_model() const
{
// Multi-nozzle context = a printer that can incur nozzle-change events the single-arg model

View File

@@ -1197,6 +1197,11 @@ class Print;
public:
GCodeProcessor();
void init_filament_maps_and_nozzle_type_when_import_only_gcode();
// Reprocessing an already-generated g-code (from-previous / imported g-code) does not rebuild
// the per-filament nozzle grouping the multi-nozzle device GUI needs. Surface it onto the
// result: keep an already-seeded grouping (from initialize_from_context), otherwise synthesize
// a default one from the filament map so the result is never left without it.
void ensure_nozzle_group_result(int min_filament_count);
// check whether the gcode path meets the filament_map grouping requirements
bool check_multi_extruder_gcode_valid(const int extruder_size,
const Pointfs plate_printable_area,

View File

@@ -4260,13 +4260,19 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
const Vec3d origin = this->get_plate_origin();
processor.set_xy_offset(origin(0), origin(1));
// Reloaded sliced projects re-estimate with the same nozzle-grouping slot context as the
// original export; harmless when the result carries none (slot 0).
// original export; process_file re-derives the device-side nozzle grouping onto the result
// (via ensure_nozzle_group_result), so the multi-nozzle send/monitor mapping survives here.
if (result != nullptr && result->nozzle_group_result)
processor.initialize_from_context(result->nozzle_group_result);
//processor.enable_producers(true);
processor.process_file(file);
// filament seq is loaded from file, processor result will override the value
auto filament_seq_loaded = result->filament_change_sequence;
auto nozzle_seq_loaded = result->nozzle_change_sequence;
*result = std::move(processor.extract_result());
result->filament_change_sequence = filament_seq_loaded;
result->nozzle_change_sequence = nozzle_seq_loaded;
} catch (std::exception & /* ex */) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found errors when process gcode file %1%") %file.c_str();
throw Slic3r::RuntimeError(