COP and CPS — Copy

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.

COP

Source

source

Dest

dest

Length

length

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

CPS

Source

source

Dest

dest

Length

length

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

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

NameTypeNotes
sourceDINT, INT, SINT, REAL, TIMER, COUNTER, CONTROLOne element — Buf[0], or a whole scalar tag
destDINT, INT, SINT, REAL, TIMER, COUNTER, CONTROLWhere it goes. Also one element
lengthDINT, INT or SINTHow many destination elements to copy. A tag or a number

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, which does accept the bare array name. The element you name is where the run starts.

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 wroteWhat happens
length fits both arraysThat many elements copy
length bigger than either arrayCopies as much as fits, then stops
length of 0Copies nothing
length from a tag holding a negativeCopies 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

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 SINTs into one DINT.

If you want the numbers converted, use MOVE or FLL instead.

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.

0

Reset

MOVE

Source

Baseline

Dest

Buffer[0]

1

Reset

COP

Source

Buffer[0]

Dest

Buffer[1]

Length

7

Structured Text

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

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

Common Mistakes

  • Naming the bare array — COP(Samples, Copy, 5). Name an element: Samples[0].
  • Expecting a DINTREAL 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.

On this page