Repository navigation
AD5X IFS Serial Protocol
The Intelligent Filament Station (IFS) on the AD5X talks to the main printer controller over a dedicated UART. This document describes the hardware interface and the complete command protocol. It covers IFS firmware 3.0.1, 3.0.6, and 3.0.7.
| Property | Value |
|---|---|
| Device | /dev/ttyS4 |
| Baud Rate | 115200 |
| Data Bits | 8 |
| Parity | None |
| Stop Bits | 1 |
| Flow Control | None |
Opcode echo: Every reply starts with F<n> ok. and repeats the request opcode. Match a reply to its request by this prefix. Discard a stale or unsolicited line instead of parsing it as the latest answer.
Line framing: End every command with CR LF. The module acts on a line only after it receives CR or LF. A line that grows past 94 characters ends without a terminator. Do not rely on this. A semicolon starts a comment. The module ignores all text after a semicolon on the same line.
Send each command in one write: The module collects bytes that arrive in one burst. It drops a burst that holds only one or two bytes. Write the full command, the space, and CR LF with one call.
Host write pattern: The stock host writes the command, one space, and CR LF in a single write. It then waits 100 ms before it listens. It waits up to 2 s for the reply. The trailing space has no meaning. A driver does not need it.
Stray bytes: Extra bytes that arrive inside a command burst cause no harm. The module scans the line for the opcode letter and parameter letters. It ignores any other byte. No firmware version needs a trailing 0xFF byte. A lone byte sent after CR LF is dropped, because it forms a burst of one byte.
Reply framing: A reply carries no terminator. No CR and no LF appears in the reply. The reply ends when the module goes quiet. Do not read until a newline. Read until the port is silent. The first byte arrives about 105 ms after the command.
F21 is the only multi-line reply: It sends three lines with CR LF between them: the F21 ok. line, then the silk: line, then the stall: line. Read the whole reply. A one-line read leaves two lines in the buffer. They then answer the next two requests.
One reader only: The reply has no terminator, so two readers on the port corrupt each other quietly. Route every command and every poll through one reader.
Feed filament from a slot toward the nozzle. The IFS reports the channel as feeding.
Format: F10 C<slot> L<length> S<speed>
| Parameter | Description |
|---|---|
C<slot> |
Slot number (1–4) |
L<length> |
Feed length in mm |
S<speed> |
Feed speed in mm/min |
Example: F10 C2 L20 S600 → F10 ok. FFS channel 2 feeding.
The IFS sets FFS_state to 10, 21, 32, or 43 for slots 1 to 4. The state then changes as the feed advances. A status query right after the command can show 22 for slot 2.
Replies:
| Reply | Condition |
|---|---|
F10 ok. FFS channel <n> feeding. |
The feed started |
F10 ok. FFS not ready. |
FFS_state is not 5 |
F10 ok. FFS channel not exist. |
The slot number is not 1–4 |
F10 ok. No channel selected. |
The command has no C parameter |
Precondition, IFS 3.0.6: FFS_state must equal 5. If it does not, the IFS refuses the command. A driver can use this refusal as a free precondition check.
IFS 3.0.7: F10 runs even when no channel is clamped. Do not rely on the refusal as a safety check.
Host usage: The FourToOne panel sends F10 C<slot> L1000 S<speed>. It clamps the slot with F24 first, then polls F13 field 3 until it equals 5. It waits 1 second between polls.
Move filament out of the station. This command is the reverse of F10. The IFS reports the channel as exiting.
Format: F11 C<slot> L<length> S<speed>
The parameters match F10. The IFS negates the length value, so the motor runs in reverse.
Example: F11 C2 L20 S600 → F11 ok. FFS channel 2 exiting.
The IFS sets FFS_state to 14, 25, 36, or 47 for slots 1 to 4. The replies match the F10 set, with exiting in place of feeding.
Note: The IFS accepts only the C, L, and S parameters for F11. Do not send a color code.
Load Operation Flow (host):
- Send
F11 C<slot> L<length> S<speed> - Poll
F13to monitor progress - If field 3 returns 0x7F → send
F15to continue - Wait for field 3 = 5 (complete)
- Check filament sensor
- Send
F112to stop the IFS motors
Unload Operation Flow (host):
- Send
F11 C<slot> L<length> S<speed> - Send
M400(wait for motion buffer clear) - Poll
F13to monitor progress - If field 3 returns 0x7F → send
F15to continue - Wait for field 3 = 5 (complete)
- Verify the slot bit is clear in F13 field 5 (silk_state)
Stop all IFS motor movement at once. The command also sets FFS_state to 5 (idle). It stops a feed or an exit in progress.
Format: F112
Replies:
| IFS firmware | Reply | Meaning |
|---|---|---|
| 3.0.6 | F112 ok. |
The halt always runs |
| 3.0.7 | F112 ok. yes. |
The halt ran, FFS_state is now 5 |
| 3.0.7 | F112 ok. error. |
A driver error is pending, the halt did not run |
The IFS error latch:
The IFS keeps an internal error latch. No wire command can read, set, or clear it. The latch marks a motor driver error.
If a driver fails, the IFS stops all motors and resets both drivers. It sets FFS_state to 1 and sets the latch. The state machine then walks through states 1 to 4. At state 4, it reads the latch. If the latch is set, it sets FFS_state to 0x7F and clears the latch in the same step. This walk takes less than one second. The first visible sign is FFS_state 0x7F in the F13 reply. The latch is already clear at that point.
F15 stops the TMC motion and sets FFS_state to 5. It does not touch the latch.
Firmware 3.0.6 and 3.0.7 handle the latch in the same way. Only F112 differs. On 3.0.6, F112 always halts. On 3.0.7, F112 halts only when the latch is clear. If the latch is set, it replies F112 ok. error. and does not halt. The error routine has already stopped the motors.
If this happens, poll F13. If FFS_state is 0x7F, send F15. Send F112 again if needed.
The reply selection is not yet verified on hardware. Match the F112 ok prefix, not the full string. A driver that matches the exact 3.0.6 reply fails on 3.0.7.
Usage: The printer sends F112 when an error occurs during a load or an unload. The FourToOne panel also sends it from a debug button. This command does not finalize a load. It has no link to F13 field 3 = 5.
Returns the complete IFS state. This is the primary polling command.
Format: F13
Wire Reply:
F13 ok. FFS_state: <d> silk_state: <d> chan: <d> ffs_channels_insert: <d> stall_state: <d> jinsi_GCONF: <8 hex digits> qiehuan_GCONF: <8 hex digits>
Fields:
| Field | Meaning |
|---|---|
| FFS_state | State machine state. See the status codes below |
| silk_state | Filament presence bitmask (bits 0–3 = slots 1–4) |
| chan | Active channel |
| ffs_channels_insert | Pending thread request per slot. The module sets a bit when filament enters the slot. F23 clears the bit of that slot |
| stall_state | Odometer movement bitmask (bits 0–3 = slots 1–4). A set bit means the roller of that slot turns |
| jinsi_GCONF | TMC GCONF register of the feed driver, 4 bytes hex |
| qiehuan_GCONF | TMC GCONF register of the switch driver, 4 bytes hex |
Field Indexes: Split the reply on spaces and colons to get numbered sections. Use this mapping:
| Section | Field |
|---|---|
| 3 | FFS_state |
| 5 | silk_state |
| 7 | chan |
| 9 | ffs_channels_insert |
| 11 | stall_state |
FFS_state — Status Codes:
| Code | Meaning |
|---|---|
| 5 | Idle, or the last operation is complete |
| 0x7F (127) | The operation needs F15 to continue |
| 0x7E (126) | Error state |
silk_state — Filament Presence Bitmask:
| Bit | Slot |
|---|---|
| 0 | Slot 1 |
| 1 | Slot 2 |
| 2 | Slot 3 |
| 3 | Slot 4 |
stall_state — Stall Detection:
The module checks each odometer roller about 20 times per second. It sets the bit of a slot when its roller turns. It clears the bit when the roller stays static. If the bit of the active slot stays 0 during a print, a stall counter grows on the host. After 200 consecutive reads with no movement, error E0109 fires and the print pauses.
Polling Intervals:
| State | Interval |
|---|---|
| Idle | 200 ms |
| Printing | 1000 ms |
| IFS offline | 1000 ms (with retry) |
Special: F13 bypasses the IFS online check. Send it even when the IFS status flag is false.
Force the IFS back to the idle state. The command stops the TMC motion and sets FFS_state to 5.
Format: F15
The IFS ignores any text after the opcode. The stock host sends F15, F15 C, and F15 L1500 S<speed> at different call sites. All three have the same effect.
Recovery use: Send F15 when F13 field 3 returns 0x7F. The IFS returns to idle. Then resend the command that failed (F11, F24, or F39).
Query IFS firmware version and verify the module is alive.
Format: F19
Response: ok ... version:<version_string>
Special Properties:
- Bypasses IFS online check (like F13)
- Used after firmware update to verify new firmware is running
- Retried up to 3 times after firmware update
Clear the insert flag of a channel. The flag marks a lane that waits to be threaded. Send F23 after the lane is threaded. F112 and F39 do not clear the flag.
Format: F23 C<slotId>
| Parameter | Description |
|---|---|
C<slotId> |
Channel number (1–4) |
Typically called after load/unload operations, followed by F39 (release channel).
Clamp the filament of a slot. Send this command before a feed, an exit, or a slot change.
Format: F24 C<slot>
Example: F24 C2 → F24 ok. chan 2. — FFS_state 7.
Replies:
| Reply | Condition |
|---|---|
F24 ok. chan <n>. |
The clamp ran |
F24 ok. FFS channel not exist. |
The slot number is not 1–4 |
F24 ok. No channel selected. |
The command has no C parameter |
Operation Flow:
- Send
F24 C<slot> - Poll
F13field 3:- 5 → complete, exit
- 0x7F → send
F15 C, re-sendF24 C<slot>, reset retry counter - 0x7E → error, exit
- Retry count > 20 → timeout, exit
- Otherwise: increment retry, wait 1 s
Puts the IFS module into bootloader mode for firmware flashing.
Format: F37
Firmware Update Sequence:
- Send
F37to enter bootloader - Close serial port
- Execute:
/usr/prog/PROGRAM/control/IFSCommand /usr/prog/PROGRAM/control/ifs.hex /dev/ttyS4 - Sleep 5 seconds
- Reopen serial port
- Send
F19(up to 3 retries) to verify IFS is alive - Parse version from response
Recovery: If you send F37 by accident, run the IFS firmware update from the printer screen. The update restores normal operation.
Release the clamp of a slot. The command does not clear the insert flag. Send F23 for that.
Format: F39 C<slot>
Example: F39 C2 → F39 ok. FFS channel 2 release. — FFS_state 23 for slot 2.
The IFS sets FFS_state to 12, 23, 34, or 45 for slots 1 to 4.
Operation Flow: Same poll flow as F24, with a maximum of 10 retries.
Typical Sequence:
F11 C<slot> L<length> S<speed> → Load filament
[poll F13 until done]
F23 C<slot> → Clear channel status
F39 C<slot> → Release channel
[poll F13 until done]
Query the TMC stepper motor driver status register from the IFS module. Diagnostic command shown in Status screen UI.
Format: F44
Response: ok DRV_STATUS:<hex_value>
Only sent when the IFS present flag is true. The firmware displays the raw hex value without parsing individual bits.
Query the TMC stepper motor general status register (GSTAT). Reports over-temperature, short-to-ground, and driver error flags.
Format: F45
Response: ok GSTAT:<hex_value>
Only sent when the IFS present flag is true. The firmware displays the raw hex value without parsing individual bits.
Note on TMC registers: DRV_STATUS and GSTAT are standard Trinamic TMC stepper driver registers (likely TMC2209 or similar). The IFS firmware returns the raw register values — refer to the TMC2209 datasheet for bit-level definitions of these registers.
Replies only. The command changes nothing on the IFS.
Format: F20
Reply: F20 ok.
Use this command as a keepalive or a safe probe.
Format: F12
Reply: F12 ok. <d> <d> <d> <d>
Returns the raw filament sensor flag of each slot. Value 1 means the slot sensor detects filament. F13 builds silk_state from these four flags. The reply lists slot 4 first and slot 1 last.
Format: F14
Reply: F14 ok. stall: <d> <d> <d> <d>
Returns one movement flag per slot. Value 1 means the odometer roller of that slot turns. Value 0 means the roller is static. F13 builds stall_state from these four flags. The label stall is inverted. Value 1 means normal movement.
Format: F21
Reply: F21 ok. silk: <d> <d> <d> <d> stall: <d> <d> <d> <d>
Returns the averaged raw analog reading of each sensor, from 0 to 4095. The first four values are the filament presence sensors. The last four values are the second sensor group. These are live readings, not counters. They update about 20 times per second.
Format: F22
Reply: F22 ok. ffs_channels_insert: <d>
Returns the insert flags of the channels as one value. This is the same value as section 9 of the F13 reply.
Set the run current of a stepper motor driver. The IFS has two motors. Motor 1 feeds filament. Motor 2 turns the channel selector.
Format: F42 T<motor> I<value>
| Parameter | Description |
|---|---|
T<motor> |
Motor number. 1 = feeder, 2 = selector |
I<value> |
Run current scale, 0–31. The IFS clamps the value to this range |
Reply: F42 ok.stepper_motor: <d> stepper_motor_irun: <d>
The reply echoes the motor and the applied value.
What the value means: The value scales the current that the driver sends to the motor. A higher value gives more torque. It also gives more heat. A value that is too low makes the motor skip steps. A value that is too high overheats the motor and the driver.
Cautions:
- Send this command only when the IFS is idle. A current change during a move can lose steps.
- Raise the value in small steps. Test a feed after each change.
- The stock host does not send F42. The default value is not yet measured on hardware. Read the current value before you change it, and note the original.
Reply parsing note: The reply has no space after ok.. Match the F42 ok prefix, then read the two numbers.
Initialize both stepper motor drivers again.
Format: F43
Reply: F43 ok.
F18 forces the module state machine to its re-home state. The module then runs the motor re-home sequence. It replies F18 ok with no period.
F30 D<position> moves the slot selector motor to an absolute position. The module stores the number and steps the selector motor until it reaches that position. It replies F30 ok.
Both commands are factory test tools. They move motors without the normal guards. Do not send them from a driver.
All commands take no parameters. Each returns one raw register value in hex.
| Command | Register | Driver |
|---|---|---|
| F41, F50 | GCONF | 1 |
| F44, F53 | DRV_STATUS | 1 |
| F45, F51 | GSTAT | 1 |
| F52 | CHOPCONF | 1 |
| F54 | PWMCONF | 1 |
| F60 | GCONF | 2 |
| F61 | GSTAT | 2 |
| F62 | CHOPCONF | 2 |
| F63 | DRV_STATUS | 2 |
| F64 | PWMCONF | 2 |
F40 returns the stall counters: F40 ok.stall count: C1: <d> C2: <d> C3: <d> C4: <d>.
Commands F16, F17, F25–F29, F31–F36, F38, F46–F49, F55–F59, and F65–F111 return no reply. Send only the commands in this document.
| Command | Purpose | Parameters | Polls F13 |
|---|---|---|---|
| F10 | Feed filament (toward nozzle) | C<slot> L<length> S<speed> |
Yes |
| F11 | Exit filament (reverse) | C<slot> L<length> S<speed> |
Yes |
| F12 | Read filament sensor flags | (none) | No |
| F112 | Halt movement | (none) | No |
| F13 | Query IFS status | (none) | N/A |
| F14 | Read odometer movement flags | (none) | No |
| F15 | Return to idle | (none; extra text ignored) | No |
| F18 | Force motor re-home (test) | (none) | No |
| F19 | IFS version/probe | (none) | No |
| F20 | Ping | (none) | No |
| F21 | Read raw sensor values | (none) | No |
| F22 | Read insert flags | (none) | No |
| F23 | Clear channel status |
C<slot> (1–4) |
No |
| F24 | Clamp channel | C<slot> |
Yes (max 20) |
| F30 | Move slot selector to position (test) | D<position> |
No |
| F37 | Enter firmware update mode | (none) | No |
| F39 | Release channel | C<slot> |
Yes (max 10) |
| F40 | Read stall counters | (none) | No |
| F42 | Set motor current | T<motor> I<value> |
No |
| F43 | Reset motor drivers | (none) | No |
| F41, F44, F45, F50–F54 | TMC register query, driver 1 | (none) | No |
| F60–F64 | TMC register query, driver 2 | (none) | No |
| Topic | IFS 3.0.1 | IFS 3.0.6 | IFS 3.0.7 |
|---|---|---|---|
| F112 reply | F112 ok. |
F112 ok. |
F112 ok. yes. or F112 ok. error.
|
| F10 or F11 on an empty lane | Refused with FFS not ready.
|
Refused with FFS not ready.
|
Runs with no channel clamped |
| F19 version string | version: 3.0.1 |
version: 3.0.6 |
version: 3.0.7 |
| F54, F64 PWMCONF query | Not present | Present | Present |
| Serial framing | Same as 3.0.6 | CR LF lines, burst of 3 bytes minimum | Same as 3.0.6 |
Drivers that depend on the 3.0.6 refusal lose that safety net on 3.0.7. Check the lane state with F13 before you send F10 or F11.
| Code | Description | Trigger |
|---|---|---|
| E0100 | Channel 1 feeding timeout | Slot 1 load timeout |
| E0101 | Channel 2 feeding timeout | Slot 2 load timeout |
| E0102 | Channel 3 feeding timeout | Slot 3 load timeout |
| E0103 | Channel 4 feeding timeout | Slot 4 load timeout |
| E0104 | Channel 1 retracting timeout | Slot 1 unload timeout |
| E0105 | Channel 2 retracting timeout | Slot 2 unload timeout |
| E0106 | Channel 3 retracting timeout | Slot 3 unload timeout |
| E0107 | Channel 4 retracting timeout | Slot 4 unload timeout |
| E0108 | Failed to feed filament to extruder | Filament sensor timeout |
| E0109 | IFS odometer roller not moving | Stall count > 200 |
| E0114 | IFS homing error |
fourInOneLoadFristStep returns 10 |
The core filament swap routine (changeChannel) during multi-material printing:
-
M400— Wait for all moves to complete - Save current state (crash recovery)
-
M114— Get current position - Move nozzle to purge position
-
doLoadAndUnload()— Physical filament swap (unload old, load new via F11) - Calculate flush volume via
getFlushVol() - Run
cleanFilamentBox()1–2 times (2× if flush volume > 400) - Set fan speed:
SET_FAN_SPEED FAN=fanM106 SPEED=<value> - Move nozzle back to print position
-
G92 E0— Reset extruder position -
SDCARD_CLEAR_REFUELLING— Clear refuelling flag