Skip to content

Instruction Set API

Tier: Stable Core

Instruction blocks, conditions, and copy/casting modifiers.

pyrung.out

out(
    target: Tag | BlockRange | ImmediateRef,
    oneshot: bool = False,
) -> Tag | BlockRange | ImmediateRef

Output coil instruction (OUT).

Sets target to True when rung is true. Resets to False when rung goes false.

Example

with Rung(Button): out(Light) out(Y.select(1, 4))

pyrung.latch

latch(
    target: Tag | BlockRange | ImmediateRef,
) -> Tag | BlockRange | ImmediateRef

Latch/Set instruction (SET).

Sets target to True. Unlike OUT, does NOT reset when rung goes false. Use reset() to turn off.

Example

with Rung(StartButton): latch(MotorRunning) latch(C.select(1, 8))

pyrung.reset

reset(
    target: Tag | BlockRange | ImmediateRef,
) -> Tag | BlockRange | ImmediateRef

Reset/Unlatch instruction (RST).

Sets target to its default value (False for bits, 0 for ints).

Example

with Rung(StopButton): reset(MotorRunning) reset(C.select(1, 8))

pyrung.copy

copy(
    source: Any,
    target: Tag | IndirectRef | IndirectExprRef,
    oneshot: bool = False,
) -> Tag | IndirectRef | IndirectExprRef

Copy instruction (CPY/MOV).

Copies source value to target.

Example

with Rung(Button): copy(5, StepNumber)

pyrung.run_function

run_function(
    fn: Callable[..., dict[str, Any]],
    ins: dict[
        str, Tag | IndirectRef | IndirectExprRef | Any
    ]
    | None = None,
    outs: dict[str, Tag | IndirectRef | IndirectExprRef]
    | None = None,
    *,
    oneshot: bool = False,
) -> None

Execute a synchronous function when rung power is true.

pyrung.run_enabled_function

run_enabled_function(
    fn: Callable[..., dict[str, Any]],
    ins: dict[
        str, Tag | IndirectRef | IndirectExprRef | Any
    ]
    | None = None,
    outs: dict[str, Tag | IndirectRef | IndirectExprRef]
    | None = None,
) -> None

Execute a synchronous function every scan with rung enabled state.

pyrung.blockcopy

blockcopy(
    source: Any, dest: Any, oneshot: bool = False
) -> None

Block copy instruction.

Copies values from source BlockRange to dest BlockRange. Both ranges must have the same length.

Example

with Rung(CopyEnable): blockcopy(DS.select(1, 10), DD.select(1, 10))

Parameters:

Name Type Description Default
source Any

Source BlockRange or IndirectBlockRange from .select().

required
dest Any

Dest BlockRange or IndirectBlockRange from .select().

required
oneshot bool

If True, execute only once per rung activation.

False

pyrung.fill

fill(value: Any, dest: Any, oneshot: bool = False) -> None

Fill instruction.

Writes a constant value to every element in a BlockRange.

Example

with Rung(ClearEnable): fill(0, DS.select(1, 100))

Parameters:

Name Type Description Default
value Any

Value to write (literal, Tag, or Expression).

required
dest Any

Dest BlockRange or IndirectBlockRange from .select().

required
oneshot bool

If True, execute only once per rung activation.

False

pyrung.pack_bits

pack_bits(
    bit_block: Any, dest: Any, oneshot: bool = False
) -> None

Pack BOOL tags from a BlockRange into a register destination.

pyrung.pack_text

pack_text(
    source_range: Any,
    dest: Any,
    *,
    allow_whitespace: bool = False,
    oneshot: bool = False,
) -> None

Pack Copy text mode: parse a TXT/CHAR range into a numeric destination.

pyrung.pack_words

pack_words(
    word_block: Any, dest: Any, oneshot: bool = False
) -> None

Pack two 16-bit tags from a BlockRange into a 32-bit destination.

pyrung.unpack_to_bits

unpack_to_bits(
    source: Any, bit_block: Any, oneshot: bool = False
) -> None

Unpack a register source into BOOL tags in a BlockRange.

pyrung.unpack_to_words

unpack_to_words(
    source: Any, word_block: Any, oneshot: bool = False
) -> None

Unpack a 32-bit register source into two 16-bit tags in a BlockRange.

pyrung.calc

calc(
    expression: Any, dest: Tag, oneshot: bool = False
) -> Tag

Calc instruction.

Evaluates an expression and stores the result in dest, with truncation to the destination tag's bit width (modular wrapping).

Key differences from copy(): - Truncates result to destination tag's type width - Division by zero produces 0 (not infinity) - Infers decimal/hex behavior from referenced tag types

Example

with Rung(Enable): calc(DS1 * DS2 + DS3, Result) calc(MaskA & MaskB, MaskResult)

Parameters:

Name Type Description Default
expression Any

Expression, Tag, or literal to evaluate.

required
dest Tag

Destination tag (type determines truncation width).

required
oneshot bool

If True, execute only once per rung activation.

False

Returns:

Type Description
Tag

The dest tag.

pyrung.call

call(target: str | SubroutineFunc) -> None

Call a subroutine instruction.

Executes the named subroutine when the rung is true. Accepts either a string name or a @subroutine-decorated function.

Example

with Rung(Button): call("init_sequence")

with subroutine("init_sequence"): with Rung(): out(Light)

Or with decorator:

@subroutine("init") def init_sequence(): with Rung(): out(Light)

with Program() as logic: with Rung(Button): call(init_sequence)

pyrung.return_early

return_early() -> None

Return from the current subroutine.

Example

with subroutine("my_sub"): with Rung(Abort): return_early()

pyrung.count_up

count_up(
    done_bit: Tag, accumulator: Tag, *, preset: Tag | int
) -> CountUpBuilder

Count Up instruction (CTU) - Click-style.

Creates a counter that increments every scan while the rung condition is True. Use rise() on the condition for edge-triggered counting.

Example

with Rung(rise(PartSensor)): count_up(done_bit, acc, preset=100).reset(ResetBtn)

This is a terminal instruction. Requires .reset() chaining.

Parameters:

Name Type Description Default
done_bit Tag

Tag to set when accumulator >= preset.

required
accumulator Tag

Tag to increment while rung condition is True.

required
preset Tag | int

Target value (Tag or int).

required

Returns:

Type Description
CountUpBuilder

Builder for chaining .down() and .reset().

pyrung.count_down

count_down(
    done_bit: Tag, accumulator: Tag, *, preset: Tag | int
) -> CountDownBuilder

Count Down instruction (CTD) - Click-style.

Creates a counter that decrements every scan while the rung condition is True. Use rise() on the condition for edge-triggered counting.

Example

with Rung(rise(Dispense)): count_down(done_bit, acc, preset=25).reset(Reload)

This is a terminal instruction. Requires .reset() chaining.

Parameters:

Name Type Description Default
done_bit Tag

Tag to set when accumulator <= -preset.

required
accumulator Tag

Tag to decrement while rung condition is True.

required
preset Tag | int

Target value (Tag or int).

required

Returns:

Type Description
CountDownBuilder

Builder for chaining .reset().

pyrung.event_drum

event_drum(
    *,
    outputs: Sequence[Tag],
    events: Sequence[Condition | Tag],
    pattern: Sequence[Sequence[bool | int]],
    current_step: Tag,
    completion_flag: Tag,
) -> EventDrumBuilder

pyrung.search

search(
    condition: str,
    value: Any,
    search_range: BlockRange | IndirectBlockRange,
    result: Tag,
    found: Tag,
    continuous: bool = False,
    oneshot: bool = False,
) -> Tag

Search instruction.

Scans a selected range and writes the first matching address into result. Writes found True on hit; on miss writes result=-1 and found=False.

pyrung.shift

shift(
    bit_range: BlockRange | IndirectBlockRange,
) -> ShiftBuilder

Shift register instruction builder.

Data input comes from current rung power. Use .clock(...) then .reset(...) to finalize and add the instruction.

Example

with Rung(DataBit): shift(C.select(2, 7)).clock(ClockBit).reset(ResetBit)

pyrung.on_delay

on_delay(
    done_bit: Tag,
    accumulator: Tag,
    *,
    preset: Tag | int,
    unit: TimeUnit = TimeUnit.Tms,
) -> OnDelayBuilder

On-Delay Timer instruction (TON/RTON) - Click-style.

Accumulates time while rung is true.

Example

with Rung(MotorRunning): on_delay(done_bit, acc, preset=5000) # TON on_delay(done_bit, acc, preset=5000).reset(ResetBtn) # RTON

Without .reset(), this is TON and remains composable in-rung. With .reset(), this is RTON and becomes terminal in the current flow.

Parameters:

Name Type Description Default
done_bit Tag

Tag to set when accumulator >= preset.

required
accumulator Tag

Tag to increment while enabled.

required
preset Tag | int

Target value in time units (Tag or int).

required
unit TimeUnit

Time unit for accumulator (default: Tms).

Tms

Returns:

Type Description
OnDelayBuilder

Builder for optional .reset() chaining.

pyrung.off_delay

off_delay(
    done_bit: Tag,
    accumulator: Tag,
    *,
    preset: Tag | int,
    unit: TimeUnit = TimeUnit.Tms,
) -> OffDelayBuilder

Off-Delay Timer instruction (TOF) - Click-style.

Done bit is True while enabled. After disable, counts until preset, then done bit goes False. Auto-resets when re-enabled.

Example

with Rung(MotorCommand): off_delay(done_bit, acc, preset=10000)

Off-delay timers are composable in-rung (not terminal).

Parameters:

Name Type Description Default
done_bit Tag

Tag that stays True for preset time after rung goes false.

required
accumulator Tag

Tag to increment while disabled.

required
preset Tag | int

Delay time in time units (Tag or int).

required
unit TimeUnit

Time unit for accumulator (default: Tms).

Tms

Returns:

Type Description
OffDelayBuilder

Builder for the off_delay instruction.

pyrung.time_drum

time_drum(
    *,
    outputs: Sequence[Tag],
    presets: Sequence[Tag | int],
    unit: TimeUnit = TimeUnit.Tms,
    pattern: Sequence[Sequence[bool | int]],
    current_step: Tag,
    accumulator: Tag,
    completion_flag: Tag,
) -> TimeDrumBuilder

pyrung.rise

rise(tag: Tag | ImmediateRef) -> RisingEdgeCondition

Rising edge contact (RE).

True only on 0->1 transition. Requires PLCRunner to track previous values.

Example

with Rung(rise(Button)): latch(MotorRunning) # Latches on button press, not while held

pyrung.fall

fall(tag: Tag | ImmediateRef) -> FallingEdgeCondition

Falling edge contact (FE).

True only on 1->0 transition. Requires PLCRunner to track previous values.

Example

with Rung(fall(Button)): reset(MotorRunning) # Resets when button is released

pyrung.all_of

all_of(
    *conditions: Condition
    | Tag
    | ImmediateRef
    | tuple[Condition | Tag | ImmediateRef, ...]
    | list[Condition | Tag | ImmediateRef],
) -> AllCondition

AND condition - true when all sub-conditions are true.

This is equivalent to comma-separated rung conditions, but useful when building grouped condition trees with any_of() or &.

Example

with Rung(all_of(Ready, AutoMode)): out(StartPermissive)

Equivalent operator form:

with Rung((Ready & AutoMode) | RemoteStart): out(StartPermissive)

pyrung.any_of

any_of(
    *conditions: Condition | Tag | ImmediateRef,
) -> AnyCondition

OR condition - true when any sub-condition is true.

Use this to combine multiple conditions with OR logic within a rung. Multiple conditions passed directly to Rung() are ANDed together.

Example

with Rung(Step == 1, any_of(Start, CmdStart)): out(Light) # True if Step==1 AND (Start OR CmdStart)

Also works with | operator:

with Rung(Step == 1, Start | CmdStart): out(Light)

Grouped AND inside OR (explicit):

with Rung(any_of(Start, all_of(AutoMode, Ready), RemoteStart)): out(Light)

Parameters:

Name Type Description Default
conditions Condition | Tag | ImmediateRef

Conditions to OR together.

()

Returns:

Type Description
AnyCondition

AnyCondition that evaluates True if any sub-condition is True.

pyrung.immediate

immediate(
    value: Tag | BlockRange | ImmediateRef,
) -> ImmediateRef

Wrap a tag or block range as an immediate operand.

pyrung.as_value

as_value(source: Any) -> CopyModifier

pyrung.as_ascii

as_ascii(source: Any) -> CopyModifier

pyrung.as_text

as_text(
    source: Any,
    *,
    suppress_zero: bool = True,
    pad: int | None = None,
    exponential: bool = False,
    termination_code: int | str | None = None,
) -> CopyModifier

pyrung.as_binary

as_binary(source: Any) -> CopyModifier