-
Notifications
You must be signed in to change notification settings - Fork 236
nfc_sequence_diagrams
Companion to nfc_handoff.md. Describes the runtime flow of the three main NFC
use cases. Code lives on the private_rfid branch.
Participants (abbreviated): NfcManager = per-unit MmuNfcManager;
NfcEndstop = MmuNfcEndstop (virtual, per gate reader); Reader = the driver
(RC522 / PN532 / PN7160); Controller = the MMU controller
(_nfc_tag_read / _check_pending_filament / _apply_metadata_to_gate);
Moonraker = components/mmu_server.py (all Spoolman / SpoolmanDB socket I/O).
One drip-home to a first-wins compound of [gate_switch, nfc_reader];
whichever fires first decides the follow-up move. Only engages when the gate's
reader is present + enabled, homing is non-encoder, and the preload endstop
(gate_preload_endstop, defaults to gate_homing_endstop) is a real MCU switch.
Otherwise it falls back to the normal full-load path.
sequenceDiagram
autonumber
actor U as GCode / User
participant CMD as MMU_PRELOAD
participant PG as _preload_gate(_with_nfc)
participant RAIL as Gear rail
participant CE as CompoundEndstop
participant NM as NfcManager
participant ES as NfcEndstop
participant RD as Reader
participant GM as Gate map
participant MR as Moonraker
U->>CMD: MMU_PRELOAD GATE=x
CMD->>CMD: guards + select_gate
CMD->>PG: _preload_gate()
PG->>PG: gate_es = gate_preload_endstop, nfc_viable? (reader on, non-encoder, MCU switch)
alt nfc_viable
PG->>RAIL: get_extra_endstop(gate) + (nfc)
PG->>RAIL: add_compound_endstop([gate_switch, nfc])
Note over PG,RD: Phase 1 — drip-home to compound (first wins)
PG->>CE: move_filament(homing_move=1)
CE->>ES: home_start (+ gate switch)
ES->>NM: start_homing_poll
NM->>RD: clear_uid() + tight poll
RD-->>CE: gate switch fires OR tag UID read
CE-->>PG: home_wait → triggered
alt NFC first
PG->>NM: read_gate(gate)
NM->>GM: apply metadata (_nfc_tag_read)
opt Spoolman on
NM->>MR: resolve UID→spool (async)
end
PG->>RAIL: continue-home to gate switch
else Gate switch first
opt nfc_read_window[1] > 0
PG->>ES: chase forward up to +window
RD-->>NM: UID on hit → read_gate → GM/MR
PG->>RAIL: backward re-home to gate switch
end
end
PG->>PG: park (gate_preload_parking_distance)
PG->>GM: set GATE_AVAILABLE
PG->>PG: _check_pending_filament(gate)
PG->>RAIL: remove_compound_endstop()
else no reader / encoder / not a switch
PG->>PG: full-load fallback (_load_gate + _unload_gate x attempts)
end
PG-->>CMD: POST_PRELOAD macro, restore gate
A shared reader can't know which gate a tag belongs to, so a read is staged
(pending_metadata, or a resolved pending_spool_id from Spoolman) and applied
to whichever gate the next load/preload targets. A resolved Spoolman spool takes
precedence over staged tag metadata.
sequenceDiagram
autonumber
participant RX as Reactor timer
participant NM as NfcManager (shared)
participant RD as Shared reader
participant C as Controller
participant MR as Moonraker
participant PG as _preload_gate
participant GM as Gate map
Note over RX,MR: Phase A — user presents a spool tag at the shared reader
RX->>NM: _poll_shared_reader (periodic)
NM->>RD: live read (deep if enabled)
RD-->>NM: UID (new tag)
NM->>C: _nfc_tag_read(uid, gate=None, metadata)
C->>C: _stage_pending_metadata → pending_metadata, arm timeout timer
opt Spoolman active
C->>MR: _spoolman_get_spool_by_uid(uid, gate=None)
MR-->>C: (async) MMU_GATE_MAP NEXT_SPOOLID=id
C->>C: set_pending_spool_id(id) (supersedes pending_metadata)
end
Note over PG,GM: Phase B — later: MMU_PRELOAD GATE=x seats filament
PG->>PG: seat filament at gate
PG->>C: _check_pending_filament(gate)
alt pending_spool_id > 0
C->>GM: assign_spool_id(gate, id)
opt PUSH / READONLY
C->>MR: push / update filament attrs
end
else pending_metadata staged
C->>GM: _apply_metadata_to_gate(gate, uid, meta)
end
C->>C: _clear_pending()
The fast-path pre-read means no motion at all if the tag already sits on the
reader; otherwise it jogs the configured window to bring the tag to the reader.
Homes to the NFC reader alone (no gate endstop, no compound), so it is
encoder-agnostic — the gate endstop type only matters for the re-park, which uses
the normal _load_gate/_unload_gate (both handle encoder natively).
sequenceDiagram
autonumber
actor U as GCode / User
participant CMD as MMU_NFC_SCAN
participant JS as _jog_scan
participant NM as NfcManager
participant RD as Reader
participant ES as NfcEndstop
participant GM as Gate map
U->>CMD: MMU_NFC_SCAN GATE=x
CMD->>CMD: guards + select_gate
CMD->>JS: _jog_scan()
JS->>JS: read nfc_read_window, snapshot+deactivate other readers, activate target
Note over JS,RD: Fast path — tag may already be on the reader
JS->>NM: clear_gate_reader(gate)
NM->>RD: clear_uid() (release held target)
JS->>NM: read_gate(gate)
NM->>RD: live read
alt tag already at reader
RD-->>NM: UID
NM->>GM: apply (_nfc_tag_read)
Note over JS: found → NO filament motion
else no tag yet — jog to find it
loop each window direction (longer first)
JS->>ES: move_filament(home to mmu_nfc_gate)
ES->>NM: start_homing_poll
NM->>RD: clear_uid + tight poll
RD-->>ES: UID on hit → trigger
opt homed (tag found)
JS->>NM: read_gate(gate) → GM
JS->>JS: re-park (_unload_gate fwd / _load_gate back)
end
end
end
JS->>JS: restore reader active flags + gate selection
-
read_gate(gate)always does a fresh live read and, on a UID, dispatches_nfc_tag_read→ applies deep-read metadata to the gate map and (if Spoolman is active) initiates the async Moonraker UID→spool resolution. It's the single "read + apply" primitive used by preload, jog_scan, and the shared/per-gate polls. -
start_homing_pollclears the reader (clear_uid) before each homing move and suppresses the shared-reader poll (_homing_endstop is not None) so a shared physical reader can't be polled from two roles at once. -
Drip-homing budget (
toolhead.py: ~50ms safe / ~151ms hard): host-polling the reader inside a drip move must stay short. RC522 (SPI) fits; PN532/PN7160 (I²C framed) must be bench-measured. The preload compound adds no extra host polling beyond the single NFC endstop.
(\_/)
( *,*)
(")_(") Happy Hare ReadyCopyright (C) 2022-2026 Paul Morgan
*** NEW V4 DOC IS HERE ***
1. Introduction
2. Installation
3. Essential Configuration
5. Operation
-- YOUR MMU IS READY TO PLAY WITH --
6. Slicer-MMU Setup
-- NOW YOU ARE READY TO PRINT! --
7. Tuning
8. Optional Feature Setup
9. Advanced Configuration
10. Advanced Concepts
- State Persistence
- Statistics and Counters
- Tool and Gate Maps
- Filament Bypass
- Runout/Clog Detection
- Consumption Counters
- Synchronized Gear/Extruder
11. Quick References
12. Troubleshooting
13. FAQ
14. MCU Board Reference 🆕
15. Change Log
Happy Hare Discord