# OSRI / OSFI — One Shot Rising and Falling with Input

Source: https://rungs.dev/docs/structured-text/instructions/osri-osfi

> OSRI sets OutputBit for one scan when InputBit turns on; OSFI sets it for one scan when InputBit turns off. Both use the FBD_ONESHOT structure in rungs.dev Structured Text.

**One Shot Rising with Input (`OSRI`).** Structured Text one-shot function block that sets `OutputBit` for exactly one scan when `InputBit` goes from 0 to 1. Uses `FBD_ONESHOT`; the ST equivalent of ladder `OSR`.

**One Shot Falling with Input (`OSFI`).** Structured Text one-shot function block that sets `OutputBit` for exactly one scan when `InputBit` goes from 1 to 0. Uses `FBD_ONESHOT`; the ST equivalent of ladder `OSF`.

An _edge_ is the single scan a signal changes — not the state itself. A one-shot turns "the button is held down" into "the button was pressed just now," so counters count once per press instead of once per scan.

## Operands [#operands]

| Name      | Type          |
| --------- | ------------- |
| `oneShot` | `FBD_ONESHOT` |

Each edge you watch needs its **own** `FBD_ONESHOT` tag — the structure remembers the previous scan's `InputBit` internally.

## `FBD_ONESHOT` Tag Members [#fbd_oneshot-tag-members]

| Member       | Type   | Meaning                                                                                            |
| ------------ | ------ | -------------------------------------------------------------------------------------------------- |
| `.EnableIn`  | `BOOL` | Forced to `1` each scan by the instruction call — setting it `0` has no effect                     |
| `.InputBit`  | `BOOL` | Input the one-shot watches — assign it before calling the instruction each scan                    |
| `.EnableOut` | `BOOL` | `1` while the instruction is executing normally                                                    |
| `.OutputBit` | `BOOL` | `1` for exactly one scan after the watched `InputBit` edge — rising for `OSRI`, falling for `OSFI` |

## How They Work [#how-they-work]

Each scan, the instruction compares `InputBit` now against what it was on the previous scan:

- **`OSRI`** — `InputBit` goes 0 → 1: `OutputBit` is `1` for that one scan. While `InputBit` stays 1 (or stays 0), `OutputBit` is `0`.
- **`OSFI`** — `InputBit` goes 1 → 0: `OutputBit` is `1` for that one scan. A falling edge is not the same as "the input is off" — `OSFI` pulses only on the scan the input _turns off_.

Call the instruction every scan and assign `.InputBit` **before** the call — the edge is detected at the moment of the call:

```iecst
EdgeTag.InputBit := In_Signal;
OSRI(EdgeTag);
Out_Pulse := EdgeTag.OutputBit;
```

Neither instruction fires on the first scan for a signal that was already settled at startup. [Prescan](https://rungs.dev/docs/scan-cycle/the-scan-cycle#before-the-first-scan) arms the internal edge memory — `OSRI` treats an input that is already 1 as old news, and `OSFI` has no stored "1" for a falling edge to measure against.

```
InputBit   _____|‾‾‾‾‾‾‾‾|________|‾‾‾‾‾‾|___
OSRI       _____|‾|_______________|‾|________
OSFI       _____________|‾|______________|‾|_
```

## Example — Count Button Presses [#example--count-button-presses]

`OSRI` fires once per press no matter how long the button is held:

```iecst
One_Press.InputBit := In_Button;
OSRI(One_Press);

IF One_Press.OutputBit THEN
    Val_Count := Val_Count + 1;
END_IF;
```

## Example — Act When a Machine Stops [#example--act-when-a-machine-stops]

`OSFI` catches the moment `In_Running` drops, latching a done flag exactly once per cycle:

```iecst
One_Stopped.InputBit := In_Running;
OSFI(One_Stopped);

IF One_Stopped.OutputBit THEN
    Out_CycleDone := 1;
END_IF;
```

## Common Mistakes [#common-mistakes]

- Reading `.OutputBit` on a line **above** the instruction call — you get the previous scan's pulse, one scan late. Assign `.InputBit`, call the instruction, then read `.OutputBit`, in that order.
- Reusing one `FBD_ONESHOT` tag for two different signals (or calling the instruction twice on the same tag in one scan) — the second use consumes the edge memory. One tag per watched edge.
- Confusing a falling edge with an inverted input — `NOT In_Signal` is `1` the _whole time_ the signal is off; `OSFI` pulses for a _single scan_ when it turns off.
- Expecting a pulse on the first scan because the input starts at 1 — prescan arms the edge memory, so a settled input is not an edge. `OSFI` needs `InputBit` observed at 1 during a scan before the drop to 0 counts.

## Related [#related]

- [`OSR` / `OSF`](https://rungs.dev/docs/ladder-logic/instructions/osr-osf) — the ladder-logic equivalents
- [`ONS`](https://rungs.dev/docs/ladder-logic/instructions/one-shot-ons) — ladder rising-edge one-shot that conditions its own rung
- [`CTUD`](https://rungs.dev/docs/structured-text/instructions/ctud) — the ST counter, which has the same edge-armed prescan behavior on `CUEnable`/`CDEnable`