# COP and CPS — Copy

Source: https://rungs.dev/docs/ladder-logic/instructions/cop-cps

> COP and CPS in rungs.dev copy a run of elements from one array into another. Use them to snapshot a buffer, replicate a value, or move a batch of readings in one rung.

Copies a run of elements from one array into another, stopping at whichever array runs out first.

Copies a run of elements the way COP does, holding the copy so nothing else can change the data part-way through.

## What they do [#what-they-do]

`COP` moves a **batch** of values in one rung — a whole array of readings into a working copy,
a few elements of a recipe into the active recipe, one element replicated across a buffer.

`CPS` is the same copy with a guarantee: nothing else touches the data while it runs. On a real
controller that matters, because an input module can update a tag between one element and the
next. Studio runs one thing at a time, so the two behave identically here.

Unlike the timers and counters, these are **not** edge-triggered: they copy on every scan the
rung is true.

## Operands [#operands]

| Name     | Type                                                                   | Notes                                                        |
| -------- | ---------------------------------------------------------------------- | ------------------------------------------------------------ |
| `source` | `DINT`, `INT`, `SINT`, `REAL`, `STRING`, `TIMER`, `COUNTER`, `CONTROL` | One element — `Buf[0]`, or a whole scalar tag                |
| `dest`   | `DINT`, `INT`, `SINT`, `REAL`, `STRING`, `TIMER`, `COUNTER`, `CONTROL` | Where it goes. Also one element                              |
| `length` | `DINT`, `INT` or `SINT`                                                | How many **destination** elements to copy. A tag or a number |

> **INFO**
>
> **One element, not the array**
>
> Both operands must name a single element: `COP(Samples[0], Copy[0], 5)`, never
> `COP(Samples, Copy, 5)`. That is the opposite of [`BSL`](https://rungs.dev/docs/ladder-logic/instructions/bsl-bsr), which does accept the bare
> array name. The element you name is where the run **starts**.

## How many elements actually move [#how-many-elements-actually-move]

`length` counts **destination** elements, and the copy stops at whichever tag runs out first.
So all three of these are safe and none of them faults:

| What you wrote                         | What happens                       |
| -------------------------------------- | ---------------------------------- |
| `length` fits both arrays              | That many elements copy            |
| `length` bigger than either array      | Copies as much as fits, then stops |
| `length` of `0`                        | Copies nothing                     |
| `length` from a tag holding a negative | Copies the whole remaining run     |

A negative length copying _everything_ looks odd, and it is: the controller counts bytes
without a sign, so `-3` reads as a very large number and then clamps. Studio does the same.
Nothing at compile time can see what a tag holds, so this is decided while the program runs.

## Copying between different types [#copying-between-different-types]

`COP` moves **raw bytes**, it does not convert. Copy a `DINT` array into a `REAL` array and you
get the bit patterns read as floats, not the numbers converted. That is deliberate and it is
what a real controller does — it is how you unpack a device word into bytes, or pack four
`SINT`s into one `DINT`.

If you want the numbers converted, use [`MOVE`](https://rungs.dev/docs/ladder-logic/instructions/move) or [`FLL`](https://rungs.dev/docs/ladder-logic/instructions/fll) instead.

## Copying a STRING [#copying-a-string]

A `STRING` copies byte for byte too, to and from a `SINT`, `INT`, `DINT` or `REAL` array. Its
bytes are 88 in all: `.LEN` as four bytes, lowest first, then the 82 bytes of `.DATA`, then two
spare bytes. So `COP(Msg, Bytes[0], 88)` lays the text out as numbers, and
`COP(Reply[0], Msg, 1)` turns a buffer back into text, taking `.LEN` from its first four bytes.
A `length` past the 88 bytes stops at the end of the `STRING`.

A `STRING` copies into another `STRING`, `.LEN` and all of `.DATA`, but not into a `TIMER`,
`COUNTER` or `CONTROL`.

To move only the characters, name the first one: `COP(Reply[0], Msg.DATA[0], 12)` copies 12
bytes into `.DATA` and leaves `.LEN` as it was, so set `.LEN` yourself afterwards. This is how a
scanner's bytes become text. The copy starts at the character you name and runs on through the
two spare bytes, stopping only at the end of the `STRING`, or of the whole array when `Msg` is
an element of one. `COP(Msg.DATA[0], Bytes[0], 10)` copies the first 10 characters out.

## Example — Replicate One Value [#example--replicate-one-value]

Fill element 0, then copy it along the array. This is the classic replicate idiom, and it works
because an overlapping copy propagates forward: each element is written, then read for the next.

```ladder
XIC(Reset)MOVE(Baseline,Buffer[0]);XIC(Reset)COP(Buffer[0],Buffer[1],7)
```

## Structured Text [#structured-text]

Both have a Structured Text form, with the same three arguments:

```iecst
COP(Samples[0], Snapshot[0], 10);
CPS(Samples[0], Snapshot[0], 10);
```

## Common Mistakes [#common-mistakes]

- Naming the bare array — `COP(Samples, Copy, 5)`. Name an element: `Samples[0]`.
- Expecting a `DINT` → `REAL` copy to convert. It reinterprets the bits. Use `MOVE`.
- Expecting a fault when `length` is too big. It clamps quietly, which is why a copy that
  "did nothing" is usually a source that had nothing left from its start element.
- Leaving the rung permanently true and wondering why the destination never keeps an edit —
  it is overwritten every scan.

## Related [#related]

- [Array instructions overview](https://rungs.dev/docs/ladder-logic/instructions/array-instructions)
- [FLL](https://rungs.dev/docs/ladder-logic/instructions/fll) — write one value into every element instead
- [MOVE](https://rungs.dev/docs/ladder-logic/instructions/move) — one value, converted rather than reinterpreted