# Example: Broken Input Detection

With a 0-10 V input, a reading of 0 V is indistinguishable from an open circuit; both read zero. A 4-20 mA current-loop input distinguishes the two: a healthy loop never reads below 4 mA, so anything under that indicates a wire break.

This example modifies the [Analog Threshold Control](analog-threshold-control.md) program to read a 4-20 mA transmitter and detect loop faults.

## Hardware

| Slot | Module |
|---|---|
| 1 | **SLM-AI-8-mA** (8-channel 0-20 mA analog input, used here with a 4-20 mA transmitter) |
| 2 | **SLM-DCO-15P** (15-channel sourcing DC output) |

Wire channel 1 of the analog module to a 4-20 mA transmitter. Wire indicator lamps to output channels 1 through 4.

## Backplane configuration

Add both modules in order. Leave the analog module's **Reading Format** on **Raw counts** and **Counts Scaling** on **Module resolution**, the defaults. The SLM-AI-8-mA has a 13-bit converter, so the input arrives as a `UINT` from 0 to 8191 across its 0-20 mA range.

The generated addresses:

| Slot | Channel | Address | Alias |
|---|---|---|---|
| 1 | AI1 | `%IW0` | `Level_Raw` |
| 2 | DO1 | `%QX0.0` | `Bar_1` |
| 2 | DO2 | `%QX0.1` | `Bar_2` |
| 2 | DO3 | `%QX0.2` | `Bar_3` |
| 2 | DO4 | `%QX0.3` | `Bar_4` |

## The program

### Variables

`````{tab-set}
````{tab-item} Variables table
| Name | Class | Type | Location | Initial Value | Documentation |
|---|---|---|---|---|---|
| `level_raw` | Local | `UINT` | `Level_Raw` | | 0-20 mA as 0-8191 counts |
| `bar_1` | Local | `BOOL` | `Bar_1` | | First lamp |
| `bar_2` | Local | `BOOL` | `Bar_2` | | Second lamp |
| `bar_3` | Local | `BOOL` | `Bar_3` | | Third lamp |
| `bar_4` | Local | `BOOL` | `Bar_4` | | Fourth lamp |
| `level_ma` | Local | `REAL` | | | Scaled reading, in milliamps |
| `segments` | Local | `INT` | | | How many lamps should be lit |
| `loop_fault` | Local | `BOOL` | | | Set when the loop reads below live zero |
````

````{tab-item} Text mode
```pascal
  VAR
    level_raw : UINT AT Level_Raw; (* 0-20 mA as 0-8191 counts *)
    bar_1 : BOOL AT Bar_1; (* First lamp *)
    bar_2 : BOOL AT Bar_2; (* Second lamp *)
    bar_3 : BOOL AT Bar_3; (* Third lamp *)
    bar_4 : BOOL AT Bar_4; (* Fourth lamp *)
    level_ma : REAL; (* Scaled reading, in milliamps *)
    segments : INT; (* How many lamps should be lit *)
    loop_fault : BOOL; (* Set when the loop reads below live zero *)
  END_VAR
```
````
`````

### Code body

```pascal
level_ma   := UINT_TO_REAL(level_raw) / 8191.0 * 20.0;
loop_fault := level_ma < 3.5;

IF loop_fault THEN
  bar_1 := FALSE;
  bar_2 := FALSE;
  bar_3 := FALSE;
  bar_4 := FALSE;
ELSE
  (* Map 4-20 mA onto 0-4 lit segments *)
  IF    level_ma >= 18.0 THEN segments := 4;
  ELSIF level_ma >= 14.0 THEN segments := 3;
  ELSIF level_ma >= 10.0 THEN segments := 2;
  ELSIF level_ma >=  6.0 THEN segments := 1;
  ELSE                        segments := 0;
  END_IF;

  bar_1 := segments >= 1;
  bar_2 := segments >= 2;
  bar_3 := segments >= 3;
  bar_4 := segments >= 4;
END_IF;
```

A reading below 3.5 mA is treated as a broken loop. All lamps are driven off until the loop recovers.
