Fix Moonraker AMS sync skipping loaded slots

The lane_data namespace (AFC / recent Happy Hare) was tried first and won
whenever any lane reported filament, shadowing a fully-populated Happy Hare
mmu object when lane_data was stale or only partially filled. Now both
sources are queried and the one reporting more loaded slots wins (lane_data
keeps priority on ties).

Also only advance max_lane_index for lanes that actually hold filament so
trailing empty lanes are trimmed, while interior empty lanes stay below the
highest filled index and are still emitted as empty placeholder slots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tome9111991
2026-05-31 18:09:19 +02:00
committed by viewit
parent 57a5442c11
commit 32723741bc

View File

@@ -710,27 +710,46 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id)
{
std::vector<AmsTrayData> trays;
int max_lane_index = 0;
int active_lane_index = -1;
auto count_loaded = [](const std::vector<AmsTrayData>& trays) {
int loaded = 0;
for (const auto& tray : trays) {
if (tray.has_filament) {
++loaded;
}
}
return loaded;
};
// Try Moonraker filament data (more generic, supports any filament changer
// software that reports lane data to Moonraker like AFC and recent Happy
// Hare as of Feb 15, 2026)
if (fetch_moonraker_filament_data(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Moonraker filament system with "
<< (max_lane_index + 1) << " lanes";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays, active_lane_index);
// Query both sources. The Moonraker lane_data namespace (AFC and recent Happy
// Hare as of Feb 15, 2026) is more generic, but it can be stale or only
// partially populated, while the Happy Hare mmu object carries the full gate
// inventory (or vice versa). Pick whichever source reports more loaded slots
// so a sparse database can't shadow a fully-populated changer.
std::vector<AmsTrayData> moonraker_trays;
int moonraker_max_lane = 0;
const bool moonraker_ok = fetch_moonraker_filament_data(moonraker_trays, moonraker_max_lane);
const int moonraker_loaded = moonraker_ok ? count_loaded(moonraker_trays) : 0;
std::vector<AmsTrayData> hh_trays;
int hh_max_lane = 0;
int hh_active_lane = -1; // KX/stable: 3-arg signature from PR #13719
const bool hh_ok = fetch_hh_filament_info(hh_trays, hh_max_lane, hh_active_lane);
const int hh_loaded = hh_ok ? count_loaded(hh_trays) : 0;
// Prefer Moonraker lane_data on ties to keep the original priority.
if (moonraker_ok && moonraker_loaded >= hh_loaded) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Using Moonraker filament data with "
<< moonraker_loaded << " loaded of " << (moonraker_max_lane + 1) << " lanes";
int ams_count = (moonraker_max_lane + 4) / 4;
build_ams_payload(ams_count, moonraker_max_lane, moonraker_trays);
return true;
}
// Attempt Happy Hare first (more widely adopted, supports more filament changers)
if (fetch_hh_filament_info(trays, max_lane_index, active_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Happy Hare MMU with "
<< (max_lane_index + 1) << " gates";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays, active_lane_index);
if (hh_ok) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Using Happy Hare MMU data with "
<< hh_loaded << " loaded of " << (hh_max_lane + 1) << " gates";
int ams_count = (hh_max_lane + 4) / 4;
build_ams_payload(ams_count, hh_max_lane, hh_trays);
return true;
}
@@ -992,7 +1011,13 @@ bool MoonrakerPrinterAgent::fetch_moonraker_filament_data(std::vector<AmsTrayDat
<< "' mapped_by='generic_fallback' tray_info_idx='" << tray.tray_info_idx << "'";
}
max_lane_index = std::max(max_lane_index, lane_index);
// Only advance max_lane_index for lanes that actually hold filament so trailing
// empty lanes are trimmed. Interior empty lanes (e.g. lane 0 empty, lane 1 loaded,
// lane 2 empty, lane 3 loaded) stay below the highest filled index and are still
// emitted as empty placeholder slots by build_ams_payload.
if (tray.has_filament) {
max_lane_index = std::max(max_lane_index, lane_index);
}
trays.push_back(tray);
}