# FFL and FFU — FIFO Queue

Source: https://rungs.dev/docs/ladder-logic/instructions/ffl-ffu

> FFL and FFU in rungs.dev build a first-in first-out queue in an array — load a value at one end, take the oldest out at the other. Use them to track parts waiting their turn.

Puts a value into the next free slot of a queue on each rising edge, and stops once the queue holds .LEN of them.

Takes the oldest value out of a queue on each rising edge, shifting the rest down one place.

## What a FIFO is [#what-a-fifo-is]

**FIFO** means _first in, first out_ — a queue, like people waiting at a counter. The first
value you put in is the first one you get back out.

Use one whenever something has to wait its turn: part numbers queuing for an inspection
station, recipe steps waiting to run, alarm codes waiting to be shown.

The queue lives in an array you declare, and its state lives in a
[`CONTROL`](https://rungs.dev/docs/ladder-logic/instructions/array-instructions#control-tag-members) tag. `FFL` loads; `FFU` unloads. They
normally **share one control tag** — that is how they agree on how full the queue is.

## Operands [#operands]

### FFL [#ffl]

| Name       | Type      | Notes                                        |
| ---------- | --------- | -------------------------------------------- |
| `source`   | numeric   | The value to put in. A tag or a number       |
| `array`    | numeric[] | Where the queue starts — `Buf` or `Buf[2]`   |
| `control`  | `CONTROL` | The queue's state                            |
| `length`   | number    | How many slots the queue has                 |
| `position` | number    | How many are in use at start-up. Usually `0` |

### FFU [#ffu]

| Name          | Type      | Notes                               |
| ------------- | --------- | ----------------------------------- |
| `array`       | numeric[] | Where the queue starts              |
| `destination` | numeric   | Where the unloaded value goes       |
| `control`     | `CONTROL` | The same control tag the `FFL` uses |
| `length`      | number    | Same as the `FFL`'s                 |
| `position`    | number    | Same as the `FFL`'s                 |

The array can be `DINT`, `INT`, `SINT` or `REAL`. A value of a different type converts on the
way in and out, exactly as [`MOVE`](https://rungs.dev/docs/ladder-logic/instructions/move) does.

## How It Works [#how-it-works]

Both act on the **rising edge**. Holding the rung true loads or unloads once and no more.

| Event              | `FFL`                                            | `FFU`                                                                    |
| ------------------ | ------------------------------------------------ | ------------------------------------------------------------------------ |
| Rung goes true     | Writes `source` at `.POS`, then `.POS` goes up 1 | Reads the element at the start, shifts the rest down, `.POS` goes down 1 |
| Queue already full | Loads nothing                                    | —                                                                        |
| Queue empty        | —                                                | Writes `0` to the destination and leaves the array alone                 |
| Rung false         | `.EN` goes to `0`. Nothing else changes          | `.EU` goes to `0`. Nothing else changes                                  |

After either one runs, `.DN` and `.EM` are worked out again from `.POS`:

- `.DN` is on when the queue is **full** — `.POS` has reached `.LEN`.
- `.EM` is on when the queue is **empty** — `.POS` is `0`.

> **INFO**
>
> **.DN and .EM are results, not switches**
>
> They are recomputed from `.POS` every time the instruction runs, so writing `.DN := 1`
> yourself does **not** stop the next load. If you want to stop a load, condition the rung.

## Example — A Parts Queue [#example--a-parts-queue]

Each part detected joins the queue; each press of `Take` pulls the oldest one out.

```ladder
XIC(PartSeen)FFL(PartId,Queue,QCtl,?,?);XIC(Take)FFU(Queue,NextPart,QCtl,?,?);XIC(QCtl.EM)OTE(QueueEmpty)

QCtl.LEN = 8
QCtl.POS = 0
```

Both instructions name `QCtl`, so the load and the unload see the same queue.

## Where Length comes from [#where-length-comes-from]

`length` and `position` are written into the control tag once, when the program starts — the
instruction reads `.LEN` and `.POS` from the tag after that. See
[Array Instructions](https://rungs.dev/docs/ladder-logic/instructions/array-instructions#where-the-length-comes-from).

## Common Mistakes [#common-mistakes]

- Giving the `FFL` and the `FFU` **different** control tags. They then disagree about how full
  the queue is. One queue, one control.
- Adding an `ONS` in front — unnecessary. Both already act on the rising edge.
- Expecting `FFU` to leave the destination alone when the queue is empty. It writes `0`.
- Declaring the array shorter than `length`. It stops the program with a major fault.

## Related [#related]

- [Array instructions overview](https://rungs.dev/docs/ladder-logic/instructions/array-instructions) — the `CONTROL` members
- [LFL and LFU](https://rungs.dev/docs/ladder-logic/instructions/lfl-lfu) — a stack instead of a queue
- [RES](https://rungs.dev/docs/ladder-logic/instructions/res) — empties the queue by clearing `.POS`