`robot.Rws.Rapid` is the service of the program the robot runs. This page covers the tasks the program is split into, starting and stopping the execution, and moving the program pointer. The variables of the program are on [RAPID variables & symbols](/abb/documentation/rws-rapid-symbols), the source of the modules on [RAPID modules & program files](/abb/documentation/rws-rapid-modules).

Reading never needs anything special. Every write of this page needs the `Rapid` [mastership](/abb/documentation/rws-mastership), and most of them also need the controller to be in the right operation mode. None of these resources answers while the controller runs in boot mode.

## Tasks

A controller runs one RAPID task per robot, plus the background tasks the system needs. `GetTasks` lists them all, `GetTask` returns everything the controller knows about one of them.

**C# : RapidTaskList**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidTaskList
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Every RAPID task of the controller
        foreach (RapidTaskItem task in robot.Rws.Rapid.GetTasks())
        {
            Console.WriteLine(task.Name);                 // T_ROB1
            Console.WriteLine(task.Type);                 // Normal, Static or SemiStatic
            Console.WriteLine(task.TaskState);            // Linked when the program is ready to run
            Console.WriteLine(task.ExecutionState);       // Started, Stopped, Ready
            Console.WriteLine(task.Active);               // null when the controller did not report it
            Console.WriteLine(task.MotionTask);           // true for the task that drives the robot
        }

        // Everything the controller knows about one task
        RapidTaskInfo info = robot.Rws.Rapid.GetTask("T_ROB1");
        Console.WriteLine(info.ExecutionLevel);           // Normal, Trap, User, None
        Console.WriteLine(info.ExecutionCycle);           // Forever, Once, OnceDone
        Console.WriteLine(info.ExecutionMode);            // Continuous, StepIn, StepOver, ...
        Console.WriteLine(info.ProductionEntryPoint);
        Console.WriteLine(info.Trust);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidTaskList**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# Every RAPID task of the controller
for task in robot.rws.rapid.get_tasks():
    print(task.name)             # T_ROB1
    print(task.type)             # Normal, Static or SemiStatic
    print(task.task_state)       # Linked when the program is ready to run
    print(task.execution_state)  # Started, Stopped, Ready
    print(task.active)           # None when the controller did not report it
    print(task.motion_task)      # True for the task that drives the robot

# Everything the controller knows about one task
info = robot.rws.rapid.get_task("T_ROB1")
print(info.execution_level)   # Normal, Trap, User, None
print(info.execution_cycle)   # Forever, Once, OnceDone
print(info.execution_mode)    # Continuous, StepIn, StepOver, ...
print(info.production_entry_point)
print(info.trust)
##

robot.disconnect()
```

**Matlab : RapidTaskList**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.ABB.dll'));
import UnderAutomation.ABB.*

robot = AbbController();
robot.Connect('192.168.0.1');

%%
tasks = robot.Rws.Rapid.GetTasks();

for i = 1:tasks.Length
    task = tasks(i);

    % char() gives the name of an enumeration value: Started, Stopped, Ready...
    fprintf('%s: %s, %s\n', char(task.Name), char(task.Type), char(task.ExecutionState));
end
%%

robot.Disconnect();
```

| `RapidTaskType` | What the task is                                                        |
| --------------- | ----------------------------------------------------------------------- |
| `Normal`        | A task holding a program an operator starts and stops                   |
| `Static`        | A task started with the controller and never stopped                    |
| `SemiStatic`    | A task started with the controller and restarted at every program reset |
| `Unknown`       | The controller reported a type the SDK does not know                    |

`TaskState` says whether the task can run. Only `Linked` means that the modules of the task were turned into a runnable program. `Empty` means the task holds nothing, `Loaded` that the modules are there but not linked yet.

| `RapidTaskExecutionState` | Meaning                                     |
| ------------------------- | ------------------------------------------- |
| `Ready`                   | The task is ready to run but is not running |
| `Started`                 | The task is running                         |
| `Stopped`                 | The task was stopped before its end         |
| `Uninitialized`           | The task is not usable yet                  |

### Activate and deactivate a task

A deactivated task is not started when the program starts. The selection panel of the FlexPendant shows the same thing, `GetTaskSelection` reads it. `UserModify` says whether an operator is allowed to change the selection of that task from the pendant.

**C# : RapidTaskActivation**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidTaskActivation
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Which tasks the operator panel has selected, and which of them an operator may change
        foreach (RapidTaskSelectionItem item in robot.Rws.Rapid.GetTaskSelection())
        {
            Console.WriteLine(item.Name + " selected=" + item.Selected + " userModify=" + item.UserModify);
        }

        // Activating or deactivating a task is a write, so it needs the mastership
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            robot.Rws.Rapid.ActivateTask("T_ROB1");
            robot.Rws.Rapid.DeactivateTask("T_ROB2");

            // Same thing for every task at once
            robot.Rws.Rapid.ActivateTasks();
            robot.Rws.Rapid.DeactivateTasks();
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidTaskActivation**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
# Which tasks the operator panel has selected, and which of them an operator may change
for item in robot.rws.rapid.get_task_selection():
    print(f"{item.name} selected={item.selected} userModify={item.user_modify}")

# Activating or deactivating a task is a write, so it needs the mastership
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    robot.rws.rapid.activate_task("T_ROB1")
    robot.rws.rapid.deactivate_task("T_ROB2")

    # Same thing for every task at once
    robot.rws.rapid.activate_tasks()
    robot.rws.rapid.deactivate_tasks()
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

`GetTaskProgramPointerSyncState` and `GetTaskMotionPointerSyncState`, listed below, are described in the program pointer section of this page.

**Methods of RapidService**
```csharp
// Activates one task (synchronous)
void ActivateTask(string task);

// Activates every task of the controller (synchronous)
void ActivateTasks();

// Deactivates one task (synchronous)
void DeactivateTask(string task);

// Deactivates every task of the controller (synchronous)
void DeactivateTasks();

// Gets everything the controller reports about one task (synchronous)
RapidTaskInfo GetTask(string task);

// Gets whether the motion pointer of one task is synchronized with the others (synchronous)
RapidPointerSyncState GetTaskMotionPointerSyncState(string task);

// Gets whether the program pointer of one task is synchronized with the others (synchronous)
RapidPointerSyncState GetTaskProgramPointerSyncState(string task);

// Gets the task selection panel: which tasks are selected, and which of them an operator is allowed to change the selection of (synchronous)
RapidTaskSelectionItem[] GetTaskSelection();

// Gets every RAPID task of the controller and what each of them is doing (synchronous)
RapidTaskItem[] GetTasks();
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidTaskItem**
```csharp
public class RapidTaskItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidTaskItem" data-throw-if-not-resolved="false"></xref> class
    public RapidTaskItem()

    // Whether the task is active, null when the controller did not report it
    public bool? Active { get; set; }

    // Whether the task is running, and whether it could be
    public RapidTaskExecutionState ExecutionState { get; set; }

    // Whether the task can move a mechanical unit, null when the controller did not report it
    public bool? MotionTask { get; set; }

    // Name of the task, for example "T_ROB1"
    public string Name { get; set; }

    // How far the controller has got in preparing the program of the task
    public RapidTaskState TaskState { get; set; }

    // Returns a string representation of this task
    public override string ToString()

    // Kind of task, which decides when the controller runs it
    public RapidTaskType Type { get; set; }
}
```

**Members of Rws.Data.RapidTaskInfo**
```csharp
public class RapidTaskInfo : RapidTaskItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidTaskInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidTaskInfo()

    // Whether the task is bound to a configured task number, null when the controller did not report it
    public bool? BindReference { get; set; }

    // Number of cycles the task is set to run.
    // 
    // <p>Only reported over a connection established with version 2, and left to
    // <xref href="UnderAutomation.ABB.Rws.Data.RapidExecutionCycle.Unknown" data-throw-if-not-resolved="false"></xref> otherwise.</p>
    public RapidExecutionCycle ExecutionCycle { get; set; }

    // Level at which the code of the task is currently executing
    public RapidExecutionLevel ExecutionLevel { get; set; }

    // Stepping mode the task was last started with
    public RapidTaskExecutionMode ExecutionMode { get; set; }

    // What kind of code the task is currently running
    public RapidExecutionType ExecutionType { get; set; }

    // Routine the program pointer moves to when it is reset, for example "main"
    public string ProductionEntryPoint { get; set; }

    // Identifier of the task, null when the controller did not report it
    public int? TaskId { get; set; }

    // Name of the task running in the foreground, empty when there is none
    public string TaskInForeground { get; set; }

    // What the controller does to the system when this task stops unexpectedly
    public RapidTaskTrustLevel Trust { get; set; }
}
```

**Members of Rws.Data.RapidTaskSelectionItem**
```csharp
public class RapidTaskSelectionItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidTaskSelectionItem" data-throw-if-not-resolved="false"></xref> class
    public RapidTaskSelectionItem()

    // Whether the task can move a mechanical unit, null when the controller did not report it
    public bool? MotionTask { get; set; }

    // Name of the task, for example "T_ROB1"
    public string Name { get; set; }

    // Whether the task is selected, null when the controller did not report it
    public bool? Selected { get; set; }

    // Returns a string representation of this task selection
    public override string ToString()

    // Whether an operator is allowed to change the selection of this task, null when the
    // controller did not report it
    public bool? UserModify { get; set; }
}
```

**Members of Rws.Data.RapidTaskType**
```csharp
public enum RapidTaskType {
    // A task started and stopped together with the program
    Normal = 1

    // A task restarted from its beginning every time the controller starts
    SemiStatic = 3

    // A task that keeps its program pointer where it was when the controller was switched off
    Static = 2

    // The controller reported a type this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidTaskState**
```csharp
public enum RapidTaskState {
    // The task holds no program
    Empty = 1

    // The task has been created but its program is not linked yet
    Initiated = 2

    // The program of the task is linked and ready to run
    Linked = 3

    // A program is loaded into the task but not linked yet
    Loaded = 4

    // The task is not initialized
    Uninitialized = 5

    // The controller reported a state this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidTaskExecutionState**
```csharp
public enum RapidTaskExecutionState {
    // The task is ready to be started
    Ready = 1

    // The task is running
    Started = 3

    // The task was running and has been stopped
    Stopped = 2

    // The task is not initialized
    Uninitialized = 4

    // The controller reported a state this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidTaskExecutionMode**
```csharp
public enum RapidTaskExecutionMode {
    // The task runs without stepping
    Continuous = 1

    // The task steps backwards
    StepBack = 5

    // The task steps into the routine calls
    StepIn = 3

    // The task steps to the last instruction
    StepLast = 6

    // The task steps out of the current routine
    StepOutOf = 4

    // The task steps over the routine calls
    StepOver = 2

    // The task advances one instruction at a time
    StepWise = 7

    // The controller reported a mode this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidTaskTrustLevel**
```csharp
public enum RapidTaskTrustLevel {
    // The system carries on
    None = 1

    // The whole system fails
    SystemFailure = 2

    // The system halts
    SystemHalt = 3

    // The system stops
    SystemStop = 4

    // The controller reported a level this library does not know
    Unknown = 0
}
```

## Build a task

`BuildTask` links the modules a task holds into a runnable program. The controller accepts the request even when the program does not compile, so read `GetBuildErrors` afterwards and check that the task state became `Linked`.

**C# : RapidBuildTask**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidBuildTask
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // Link the modules of the task into a runnable program
            robot.Rws.Rapid.BuildTask("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        // The controller does not fail the build request, it reports what it refused afterwards
        foreach (RapidBuildError error in robot.Rws.Rapid.GetBuildErrors("T_ROB1"))
        {
            Console.WriteLine(error.ModuleName + " " + error.Row + "," + error.Column + ": " + error.Error);
        }

        // The task is runnable when its state is Linked
        Console.WriteLine(robot.Rws.Rapid.GetTask("T_ROB1").TaskState);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidBuildTask**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # Link the modules of the task into a runnable program
    robot.rws.rapid.build_task("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

# The controller does not fail the build request, it reports what it refused afterwards
for error in robot.rws.rapid.get_build_errors("T_ROB1"):
    print(f"{error.module_name} {error.row},{error.column}: {error.error}")

# The task is runnable when its state is Linked
print(robot.rws.rapid.get_task("T_ROB1").task_state)
##

robot.disconnect()
```

The build errors are described in [RAPID modules & program files](/abb/documentation/rws-rapid-modules).

**Methods of RapidService**
```csharp
// Links the program of a task, which is what turns the modules it holds into something runnable (synchronous) Read GetBuildErrors() afterwards to find out what the controller refused.
void BuildTask(string task);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

## Load a module

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes. Only an OmniCore answers with the name of the module that was loaded, an IRC5 returns null.

`LoadModule` loads one module file into a task. The file has to be on the file system of the controller already, so upload it first with the [file system service](/abb/documentation/rws-files). Set `replace` to `true` when a module of the same name is already loaded, otherwise the controller refuses the request.

**C# : RapidLoadModule**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidLoadModule
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // The file has to be on the controller already. Upload it first with robot.Rws.File.
            // On OmniCore the call answers the name of what was loaded, on IRC5 it answers null.
            string loaded = robot.Rws.Rapid.LoadModule("T_ROB1", "$HOME/mymodule.mod", true);
            Console.WriteLine(loaded);

            robot.Rws.Rapid.UnloadModule("T_ROB1", "mymodule");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidLoadModule**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # The file has to be on the controller already. Upload it first with robot.rws.file.
    # On OmniCore the call answers the name of what was loaded, on IRC5 it answers None.
    loaded = robot.rws.rapid.load_module("T_ROB1", "$HOME/mymodule.mod", True)
    print(loaded)

    robot.rws.rapid.unload_module("T_ROB1", "mymodule")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

`UnloadModule` takes the name of the module, not the name of the file. A module that was never saved is lost when it is unloaded.

Loading a whole program instead of one module is done with `LoadProgram`, see [RAPID modules & program files](/abb/documentation/rws-rapid-modules).

**Methods of RapidService**
```csharp
// Loads a module file into a task (synchronous)
string LoadModule(string task, string modulePath, bool replace = false);

// Unloads a module from a task (synchronous)
void UnloadModule(string task, string module);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

## Start and stop the program

Starting a program from your application fails when one of these conditions is not met:

1. The controller is in automatic mode, or in manual mode with the enabling device held. The mode is read with the [control panel service](/abb/documentation/rws-panel).
2. The motors are on, `Panel.SetControllerState(ControllerState.MotorsOn)`.
3. The task is active and its state is `Linked`.
4. The program pointer is set, which `ResetProgramPointer` does for every task.
5. Your connection holds the `Rapid` [mastership](/abb/documentation/rws-mastership).

**C# : RapidStartProgram**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidStartProgram
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // 1. The controller has to be in automatic mode
        if (robot.Rws.Panel.GetOperationMode() != OperationMode.Automatic)
            throw new Exception("Turn the key of the controller to automatic mode");

        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // 2. Motors on
            robot.Rws.Panel.SetControllerState(ControllerState.MotorsOn);

            // 3. Program pointer back to the entry point of every task
            robot.Rws.Rapid.ResetProgramPointer();

            // 4. Start
            robot.Rws.Rapid.Start(RapidRegainMode.Continue,
                                  RapidExecutionMode.Continue,
                                  RapidExecutionCycle.Forever,
                                  RapidStartCondition.None,
                                  false,   // do not stop at breakpoints
                                  false);  // normal tasks only
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        // 5. Check that it really started, the call above only means the request was accepted
        RapidExecutionInfo execution = robot.Rws.Rapid.GetExecutionState();
        Console.WriteLine(execution.State);   // Running or Stopped
        Console.WriteLine(execution.Cycle);   // Forever, Once, OnceDone
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidStartProgram**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.controller_state import ControllerState
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.operation_mode import OperationMode
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle
from underautomation.abb.rws.data.rapid_execution_mode import RapidExecutionMode
from underautomation.abb.rws.data.rapid_regain_mode import RapidRegainMode
from underautomation.abb.rws.data.rapid_start_condition import RapidStartCondition

robot = AbbController()
robot.connect("192.168.0.1")

##
# 1. The controller has to be in automatic mode
if robot.rws.panel.get_operation_mode() != OperationMode.Automatic:
    raise Exception("Turn the key of the controller to automatic mode")

robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # 2. Motors on
    robot.rws.panel.set_controller_state(ControllerState.MotorsOn)

    # 3. Program pointer back to the entry point of every task
    robot.rws.rapid.reset_program_pointer()

    # 4. Start
    robot.rws.rapid.start(RapidRegainMode.Continue_,
                          RapidExecutionMode.Continue_,
                          RapidExecutionCycle.Forever,
                          RapidStartCondition.None_,
                          False,   # do not stop at breakpoints
                          False)   # normal tasks only
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

# 5. Check that it really started, the call above only means the request was accepted
execution = robot.rws.rapid.get_execution_state()
print(execution.state)  # Running or Stopped
print(execution.cycle)  # Forever, Once, OnceDone
##

robot.disconnect()
```

`Start` returns as soon as the controller accepts the request, not when the robot moves. Read `GetExecutionState` afterwards to know what really happened.

| `RapidRegainMode` | What the robot does when execution resumes                       |
| ----------------- | ---------------------------------------------------------------- |
| `Continue`        | Resume from the current position, without going back to the path |
| `Regain`          | Move back onto the path first                                    |
| `Clear`           | Drop the path and resume from the current position               |
| `EnterConsume`    | Resume by entering the path already computed                     |

| `RapidExecutionMode` | How far the program advances                                             |
| -------------------- | ------------------------------------------------------------------------ |
| `Continue`           | Run until something stops it                                             |
| `StepIn`             | Enter the routine called by the current instruction                      |
| `StepOver`           | Run the current instruction whole, without entering the routine it calls |
| `StepOut`            | Run until the current routine returns                                    |
| `StepBack`           | Step one instruction backwards                                           |
| `StepLast`           | Step to the last instruction                                             |
| `StepMotion`         | Step to the next motion instruction                                      |

`RapidStartCondition.CallChain` asks the controller to start only when the call chain of the program pointer is still valid, which is a way to refuse a start after the source was edited.

### Cycles and entry point

`SetExecutionCycle` takes `Once` or `Forever`, the other values of the enum are only reported by the controller. `StartFromProductionEntry` starts at the production entry point of the task instead of the current program pointer.

`AbortExecutionLevel` leaves the routine running now and goes back to the level under it. This is how a trap or a service routine started by hand is abandoned without stopping the program below it.

**C# : RapidExecutionCycles**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidExecutionCycles
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // Only Once and Forever are accepted here
            robot.Rws.Rapid.SetExecutionCycle(RapidExecutionCycle.Once);

            // Start from the production entry point instead of the current program pointer
            robot.Rws.Rapid.StartFromProductionEntry();

            // Leave the routine that is running now and go back to the level below it.
            // This is how a trap or a service routine is abandoned without stopping the program under it.
            robot.Rws.Rapid.AbortExecutionLevel("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidExecutionCycles**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle

robot = AbbController()
robot.connect("192.168.0.1")

##
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # Only Once and Forever are accepted here
    robot.rws.rapid.set_execution_cycle(RapidExecutionCycle.Once)

    # Start from the production entry point instead of the current program pointer
    robot.rws.rapid.start_from_production_entry()

    # Leave the routine that is running now and go back to the level below it.
    # This is how a trap or a service routine is abandoned without stopping the program under it.
    robot.rws.rapid.abort_execution_level("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

### Stop

**C# : RapidStopProgram**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidStopProgram
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Stop at the end of the current instruction, normal tasks only
        robot.Rws.Rapid.Stop(RapidStopMode.Stop, RapidTaskScope.Normal);

        // Let the robot finish the cycle it is in, then stop
        robot.Rws.Rapid.Stop(RapidStopMode.Cycle, RapidTaskScope.Normal);

        // Stop everything at once, including the static and semi static tasks
        robot.Rws.Rapid.Stop(RapidStopMode.QuickStop, RapidTaskScope.AllTasks);

        // Wait until the controller confirms the program is stopped
        while (robot.Rws.Rapid.GetExecutionState().State != RapidExecutionState.Stopped)
            System.Threading.Thread.Sleep(200);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidStopProgram**
```python
import time

from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.rapid_execution_state import RapidExecutionState
from underautomation.abb.rws.data.rapid_stop_mode import RapidStopMode
from underautomation.abb.rws.data.rapid_task_scope import RapidTaskScope

robot = AbbController()
robot.connect("192.168.0.1")

##
# Stop at the end of the current instruction, normal tasks only
robot.rws.rapid.stop(RapidStopMode.Stop, RapidTaskScope.Normal)

# Let the robot finish the cycle it is in, then stop
robot.rws.rapid.stop(RapidStopMode.Cycle, RapidTaskScope.Normal)

# Stop everything at once, including the static and semi static tasks
robot.rws.rapid.stop(RapidStopMode.QuickStop, RapidTaskScope.AllTasks)

# Wait until the controller confirms the program is stopped
while robot.rws.rapid.get_execution_state().state != RapidExecutionState.Stopped:
    time.sleep(0.2)
##

robot.disconnect()
```

| `RapidStopMode` | How the program stops                              |
| --------------- | -------------------------------------------------- |
| `Cycle`         | At the end of the current cycle                    |
| `Instruction`   | At the end of the current instruction              |
| `Stop`          | As soon as the robot can decelerate along its path |
| `QuickStop`     | As fast as the robot can, leaving the path         |

`RapidTaskScope.Normal` stops the normal tasks only, `AllTasks` also stops the static and semi static ones. `Stop` returns before the robot has stopped, so wait until `GetExecutionState` reports `Stopped`.

### Hold-to-run

In manual mode the program only runs while a client keeps saying that the hold-to-run control is held. Send `Press`, then `Held` about every two seconds. The controller stops the program as soon as it stops hearing from your application.

**C# : RapidHoldToRun**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidHoldToRun
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Manual mode only. Press, then keep sending Held, the controller stops the
        // program as soon as it stops hearing from your application.
        robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Press);

        robot.Rws.Rapid.Start(RapidRegainMode.Continue, RapidExecutionMode.Continue);

        for (int i = 0; i < 10; i++)
        {
            robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Held);
            System.Threading.Thread.Sleep(1000);
        }

        robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Release);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidHoldToRun**
```python
import time

from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.rapid_execution_mode import RapidExecutionMode
from underautomation.abb.rws.data.rapid_hold_to_run_state import RapidHoldToRunState
from underautomation.abb.rws.data.rapid_regain_mode import RapidRegainMode

robot = AbbController()
robot.connect("192.168.0.1")

##
# Manual mode only. Press, then keep sending Held, the controller stops the
# program as soon as it stops hearing from your application.
robot.rws.rapid.set_hold_to_run(RapidHoldToRunState.Press)

robot.rws.rapid.start(RapidRegainMode.Continue_, RapidExecutionMode.Continue_)

for i in range(10):
    robot.rws.rapid.set_hold_to_run(RapidHoldToRunState.Held)
    time.sleep(1)

robot.rws.rapid.set_hold_to_run(RapidHoldToRunState.Release)
##

robot.disconnect()
```

This is only honoured by a virtual controller, and only for a client the controller considers local. A real cabinet expects the physical device.

A complete example, with the checks around it, is given in [Start & stop a RAPID program](/abb/documentation/start-stop-rapid-program).

**Methods of RapidService**
```csharp
// Abandons the routine the task is currently running and returns to the level below it (synchronous) This is how a trap or a service routine started by hand is left without stopping the program underneath it.
void AbortExecutionLevel(string task);

// Gets whether the controller is executing RAPID code, and how many cycles it is set to run (synchronous)
RapidExecutionInfo GetExecutionState();

// Moves the program pointer of every task back to the entry point of its program (synchronous)
void ResetProgramPointer();

// Sets how many times the program runs before stopping (synchronous)
void SetExecutionCycle(RapidExecutionCycle cycle);

// Drives the hold-to-run control that lets the program run in manual mode (synchronous) Send RapidHoldToRunState.Press to allow execution to start, then RapidHoldToRunState.Held about every two seconds to keep it running; the controller stops the program as soon as it stops hearing from the client. Send RapidHoldToRunState.Release to stop it at once.
void SetHoldToRun(RapidHoldToRunState state);

// Starts executing the RAPID program from where the program pointer stands (synchronous) The controller has to be in automatic mode with the motors on, or in manual mode with the enabling device held. Reset the program pointer first with RapidService.ResetProgramPointer to start from the beginning.
void Start(RapidRegainMode regain = RapidRegainMode.Continue, RapidExecutionMode executionMode = RapidExecutionMode.Continue, RapidExecutionCycle cycle = RapidExecutionCycle.Forever, RapidStartCondition condition = RapidStartCondition.None, bool stopAtBreakpoint = false, bool allTasksBySelection = false);

// Starts executing from the production entry point of the program rather than from where the program pointer stands (synchronous)
void StartFromProductionEntry();

// Starts recording the RAPID execution trace into a file (synchronous) The trace names every instruction the controller runs, which is what it takes to find out why a program took a branch it should not have.
void StartSpy(string logFile);

// Stops the RAPID execution (synchronous)
void Stop(RapidStopMode stopMode = RapidStopMode.Stop, RapidTaskScope scope = RapidTaskScope.Normal);

// Stops recording the RAPID execution trace (synchronous)
void StopSpy();
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidExecutionInfo**
```csharp
public class RapidExecutionInfo {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidExecutionInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidExecutionInfo()

    // Number of cycles the program is set to run
    public RapidExecutionCycle Cycle { get; set; }

    // Whether RAPID code is currently running
    public RapidExecutionState State { get; set; }

    // Returns a string representation of this execution state
    public override string ToString()
}
```

**Members of Rws.Data.RapidExecutionState**
```csharp
public enum RapidExecutionState {
    // RAPID execution is running
    Running = 1

    // RAPID execution is stopped
    Stopped = 2

    // The controller reported a state this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidExecutionCycle**
```csharp
public enum RapidExecutionCycle {
    // The cycle currently configured is left untouched
    AsIs = 2

    // The program runs again every time it reaches its end
    Forever = 1

    // The program runs once and stops at its end
    Once = 3

    // The program was asked to run once and has finished doing so
    OnceDone = 4

    // The controller reported a cycle this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidExecutionMode**
```csharp
public enum RapidExecutionMode {
    // Run until something stops it
    Continue = 0

    // Step one instruction backwards
    StepBack = 4

    // Step into the routine called by the current instruction
    StepIn = 1

    // Step to the last instruction
    StepLast = 5

    // Step to the next motion instruction
    StepMotion = 6

    // Run until the current routine returns
    StepOut = 3

    // Run the current instruction whole, without entering the routine it calls
    StepOver = 2
}
```

**Members of Rws.Data.RapidRegainMode**
```csharp
public enum RapidRegainMode {
    // Drop the path and resume from the current position
    Clear = 2

    // Resume from the current position without moving back to the path
    Continue = 0

    // Resume by entering the consumption of the already generated path
    EnterConsume = 3

    // Move back onto the path before resuming
    Regain = 1
}
```

**Members of Rws.Data.RapidStopMode**
```csharp
public enum RapidStopMode {
    // Stop when the current cycle ends
    Cycle = 0

    // Stop when the current instruction ends
    Instruction = 1

    // Stop as fast as the robot can, leaving the path
    QuickStop = 3

    // Stop as soon as the robot can decelerate along its path
    Stop = 2
}
```

**Members of Rws.Data.RapidStartCondition**
```csharp
public enum RapidStartCondition {
    // Start only when the call chain of the program pointer is still valid
    CallChain = 1

    // Start without any additional check
    None = 0
}
```

**Members of Rws.Data.RapidTaskScope**
```csharp
public enum RapidTaskScope {
    // Apply to every task of the system
    AllTasks = 1

    // Apply to the tasks the task selection panel has enabled
    Normal = 0
}
```

**Members of Rws.Data.RapidHoldToRunState**
```csharp
public enum RapidHoldToRunState {
    // Confirm that execution may keep running, which has to be repeated about every two seconds
    Held = 1

    // Ask for execution to be allowed to start
    Press = 0

    // Stop execution immediately
    Release = 2
}
```

## Execution trace

The controller can write every instruction it runs into a file. It is the fastest way to find out why a program took a branch it should not have. The two calls take the mastership by themselves, your code does not have to.

**C# : RapidSpy**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidSpy
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // The trace names every instruction the controller runs. No mastership needed,
        // the controller takes it by itself for these two calls.
        robot.Rws.Rapid.StartSpy("$HOME/trace.log");

        Console.WriteLine(robot.Rws.Rapid.GetSpyStatus());   // Logging or NotLogging

        System.Threading.Thread.Sleep(5000);

        robot.Rws.Rapid.StopSpy();

        // Then download the file with the file service
        string trace = robot.Rws.File.GetFileAsText("$HOME/trace.log");
        Console.WriteLine(trace);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidSpy**
```python
import time

from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# The trace names every instruction the controller runs. No mastership needed,
# the controller takes it by itself for these two calls.
robot.rws.rapid.start_spy("$HOME/trace.log")

print(robot.rws.rapid.get_spy_status())  # Logging or NotLogging

time.sleep(5)

robot.rws.rapid.stop_spy()

# Then download the file with the file service
trace = bytes(robot.rws.file.get_file_as_bytes("$HOME/trace.log")).decode("utf-8")
print(trace)
##

robot.disconnect()
```

The file is written on the controller, download it afterwards with the [file system service](/abb/documentation/rws-files). A trace grows fast, do not leave it running.

**Methods of RapidService**
```csharp
// Gets whether the controller is recording the RAPID execution trace to a file (synchronous)
RapidSpyStatus GetSpyStatus();
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidSpyStatus**
```csharp
public enum RapidSpyStatus {
    // The execution trace is being written
    Logging = 1

    // No execution trace is being written
    NotLogging = 2

    // The controller reported a status this library does not know
    Unknown = 0
}
```

## Program pointer and motion pointer

Each task has two pointers. The program pointer says which instruction runs next, the motion pointer which one the robot is really executing. They drift apart because the controller plans the path ahead of the movement.

**C# : RapidProgramPointer**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidProgramPointer
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Where the two pointers of the task stand
        RapidPointers pointers = robot.Rws.Rapid.GetPointers("T_ROB1");

        if (pointers.ProgramPointer.Available)
        {
            Console.WriteLine(pointers.ProgramPointer.Module + "/" + pointers.ProgramPointer.Routine);
            Console.WriteLine(pointers.ProgramPointer.BeginRow + "," + pointers.ProgramPointer.BeginColumn);
        }

        // The motion pointer is behind the program pointer, the controller plans the path
        // ahead of the movement. It is not available in a task that has not moved yet.
        Console.WriteLine(pointers.MotionPointer.Available);

        // The piece of source the program pointer covers. The controller refuses the request
        // when the task has no program pointer, reset it or start the program first.
        RapidProgramCounterPosition position = robot.Rws.Rapid.GetProgramCounterPosition("T_ROB1");
        Console.WriteLine(position.Module + " " + position.StartLine + "," + position.StartColumn);

        // Moving the pointer is a write, it needs the RAPID mastership
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // To the beginning of a routine. The module name is used by an IRC5 only,
            // an OmniCore looks the routine up in the whole task.
            robot.Rws.Rapid.SetProgramPointerToRoutine("T_ROB1", "MainModule", "main");

            // To a service routine, which has to be entered at user level
            robot.Rws.Rapid.SetProgramPointerToRoutineUrl("T_ROB1", "RAPID/T_ROB1/BASEFUN/LoadIdentify", true);

            // To one position of the source. The routine name is used by an IRC5 only,
            // an OmniCore works it out from the position itself.
            robot.Rws.Rapid.SetProgramPointerToCursor("T_ROB1", "MainModule", "main", 12, 1);

            // One instruction forward or backward, automatic mode only
            robot.Rws.Rapid.SetProgramPointerToNextInstruction("T_ROB1");
            robot.Rws.Rapid.SetProgramPointerToPreviousInstruction("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidProgramPointer**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
# Where the two pointers of the task stand
pointers = robot.rws.rapid.get_pointers("T_ROB1")

if pointers.program_pointer.available:
    print(pointers.program_pointer.module + "/" + pointers.program_pointer.routine)
    print(f"{pointers.program_pointer.begin_row},{pointers.program_pointer.begin_column}")

# The motion pointer is behind the program pointer, the controller plans the path
# ahead of the movement. It is not available in a task that has not moved yet.
print(pointers.motion_pointer.available)

# The piece of source the program pointer covers. The controller refuses the request
# when the task has no program pointer, reset it or start the program first.
position = robot.rws.rapid.get_program_counter_position("T_ROB1")
print(f"{position.module} {position.start_line},{position.start_column}")

# Moving the pointer is a write, it needs the RAPID mastership
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # To the beginning of a routine. The module name is used by an IRC5 only,
    # an OmniCore looks the routine up in the whole task.
    robot.rws.rapid.set_program_pointer_to_routine("T_ROB1", "MainModule", "main")

    # To a service routine, which has to be entered at user level
    robot.rws.rapid.set_program_pointer_to_routine_url("T_ROB1", "RAPID/T_ROB1/BASEFUN/LoadIdentify", True)

    # To one position of the source. The routine name is used by an IRC5 only,
    # an OmniCore works it out from the position itself.
    robot.rws.rapid.set_program_pointer_to_cursor("T_ROB1", "MainModule", "main", 12, 1)

    # One instruction forward or backward, automatic mode only
    robot.rws.rapid.set_program_pointer_to_next_instruction("T_ROB1")
    robot.rws.rapid.set_program_pointer_to_previous_instruction("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes. An IRC5 needs the module and the routine name, an OmniCore works them out from the position alone.

`SetProgramPointerToRoutine` takes a module name and `SetProgramPointerToCursor` a routine name. An IRC5 refuses the request without them, an OmniCore ignores them and finds the routine by itself. Pass them in both cases, your code then works on the two generations.

A few things to know before moving the pointer:

- Moving the pointer needs the `Rapid` [mastership](/abb/documentation/rws-mastership), and the program has to be stopped.
- `SetProgramPointerToNextInstruction` and `SetProgramPointerToPreviousInstruction` are refused outside automatic mode.
- A service routine has to be entered at user level, so pass `true` for `userLevel`. `GetServiceRoutines` gives the paths `SetProgramPointerToRoutineUrl` takes.
- `GetProgramCounterPosition` is refused when the task has no program pointer at all. Reset it or start the program first.
- `GetProgram` returns the name of the program the task holds and the routine `ResetProgramPointer` goes back to.

### Synchronization and change counters

`GetProgramPointerSyncState` and `GetMotionPointerSyncState` say whether the pointers of the tasks are synchronized with each other, for the whole controller or for one task. `GetStructuralChangeCount` returns two counters that only move when something changed in the task, which is cheaper than downloading the modules again to find out that nothing moved.

**C# : RapidPointerSync**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidPointerSync
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // For the whole controller
        RapidPointerSyncState program = robot.Rws.Rapid.GetProgramPointerSyncState();
        RapidPointerSyncState motion = robot.Rws.Rapid.GetMotionPointerSyncState();
        Console.WriteLine(program + " / " + motion);   // On or Off

        // For one task
        Console.WriteLine(robot.Rws.Rapid.GetTaskProgramPointerSyncState("T_ROB1"));
        Console.WriteLine(robot.Rws.Rapid.GetTaskMotionPointerSyncState("T_ROB1"));

        // Two counters that say whether anything changed in the task, cheaper than
        // downloading the modules again to find out that nothing moved
        RapidStructuralChangeCount counters = robot.Rws.Rapid.GetStructuralChangeCount("T_ROB1");
        Console.WriteLine(counters.ChangeCount);
        Console.WriteLine(counters.StructuralChangeCount);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidPointerSync**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# For the whole controller
program = robot.rws.rapid.get_program_pointer_sync_state()
motion = robot.rws.rapid.get_motion_pointer_sync_state()
print(f"{program} / {motion}")  # On or Off

# For one task
print(robot.rws.rapid.get_task_program_pointer_sync_state("T_ROB1"))
print(robot.rws.rapid.get_task_motion_pointer_sync_state("T_ROB1"))

# Two counters that say whether anything changed in the task, cheaper than
# downloading the modules again to find out that nothing moved
counters = robot.rws.rapid.get_structural_change_count("T_ROB1")
print(counters.change_count)
print(counters.structural_change_count)
##

robot.disconnect()
```

**Methods of RapidService**
```csharp
// Gets whether the motion pointers of every task are synchronized with each other (synchronous)
RapidPointerSyncState GetMotionPointerSyncState();

// Gets where the program pointer and the motion pointer of a task stand (synchronous) The program pointer says which instruction runs next, the motion pointer which one the robot is actually executing; they drift apart because the controller plans the path ahead of the movement.
RapidPointers GetPointers(string task);

// Gets the program loaded into a task (synchronous)
RapidProgramInfo GetProgram(string task);

// Gets which piece of source the program pointer of a task points at (synchronous)
RapidProgramCounterPosition GetProgramCounterPosition(string task);

// Gets whether the program pointers of every task are synchronized with each other (synchronous)
RapidPointerSyncState GetProgramPointerSyncState();

// Gets the two counters a task keeps of what has changed in it (synchronous) Comparing them with what a previous reading gave is cheaper than fetching the modules again to find out that nothing moved.
RapidStructuralChangeCount GetStructuralChangeCount(string task);

// Moves the program pointer of a task to a position of a module (synchronous)
void SetProgramPointerToCursor(string task, string module, string routine, int row, int column);

// Moves the program pointer of a task forward by one instruction (synchronous)
void SetProgramPointerToNextInstruction(string task);

// Moves the program pointer of a task back by one instruction (synchronous)
void SetProgramPointerToPreviousInstruction(string task);

// Moves the program pointer of a task to the beginning of a routine (synchronous)
void SetProgramPointerToRoutine(string task, string module, string routine, bool userLevel = false);

// Moves the program pointer of a task to a routine named by its path (synchronous) This is what the paths GetServiceRoutines() reports are for.
void SetProgramPointerToRoutineUrl(string task, string routineUrl, bool userLevel = false);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidPointers**
```csharp
public class RapidPointers {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidPointers" data-throw-if-not-resolved="false"></xref> class
    public RapidPointers()

    // Instruction the robot is currently moving for
    public RapidPointerPosition MotionPointer { get; set; }

    // Instruction the task will execute next
    public RapidPointerPosition ProgramPointer { get; set; }

    // Returns a string representation of the two pointers
    public override string ToString()
}
```

**Members of Rws.Data.RapidPointerPosition**
```csharp
public class RapidPointerPosition {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidPointerPosition" data-throw-if-not-resolved="false"></xref> class
    public RapidPointerPosition()

    // Whether the controller reported a position for this pointer at all
    public bool Available { get; set; }

    // Column the pointer begins at, null when the controller did not report it
    public int? BeginColumn { get; set; }

    // Line the pointer begins at, null when the controller did not report it
    public int? BeginRow { get; set; }

    // How many times the pointer has been moved, null when the controller did not report it
    public int? ChangeCount { get; set; }

    // Column the pointer ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the pointer ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // What kind of code the pointer is standing in
    public RapidExecutionType ExecutionType { get; set; }

    // Name of the module the pointer stands in
    public string Module { get; set; }

    // Name of the routine the pointer stands in
    public string Routine { get; set; }

    // Returns a string representation of this pointer position
    public override string ToString()
}
```

**Members of Rws.Data.RapidProgramCounterPosition**
```csharp
public class RapidProgramCounterPosition {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidProgramCounterPosition" data-throw-if-not-resolved="false"></xref> class
    public RapidProgramCounterPosition()

    // Column the pointed instruction ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the pointed instruction ends at, null when the controller did not report it
    public int? EndLine { get; set; }

    // Name of the module the pointer stands in
    public string Module { get; set; }

    // Name of the routine the pointer stands in
    public string Routine { get; set; }

    // Column the pointed instruction starts at, null when the controller did not report it
    public int? StartColumn { get; set; }

    // Line the pointed instruction starts at, null when the controller did not report it
    public int? StartLine { get; set; }

    // Returns a string representation of this position
    public override string ToString()
}
```

**Members of Rws.Data.RapidPointerSyncState**
```csharp
public enum RapidPointerSyncState {
    // The pointers are not synchronized
    Off = 2

    // The pointers are synchronized
    On = 1

    // The controller reported a state this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidStructuralChangeCount**
```csharp
public class RapidStructuralChangeCount {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidStructuralChangeCount" data-throw-if-not-resolved="false"></xref> class
    public RapidStructuralChangeCount()

    // Counter the controller increments whenever anything relevant changes in the task
    public int? ChangeCount { get; set; }

    // Counter the controller increments when a module is loaded, unloaded or renamed.
    // 
    // <p>A rename counts as an unload followed by a load.</p>
    public int? StructuralChangeCount { get; set; }

    // Returns a string representation of these counters
    public override string ToString()
}
```

**Members of Rws.Data.RapidExecutionType**
```csharp
public enum RapidExecutionType {
    // An event routine is running
    EventRoutine = 6

    // An external interrupt is running
    ExternalInterrupt = 4

    // An interrupt is running
    Interrupt = 3

    // Nothing is running
    None = 1

    // The normal program is running
    Normal = 2

    // The controller reported a type this library does not know
    Unknown = 0

    // A user routine is running
    UserRoutine = 5
}
```

## Call stack

`GetActivationRecord` reads one frame of the call stack. Frame 1 holds the program pointer, and the number grows towards the entry point of the program. The controller refuses the request when the task has no program pointer, or when the stack is not that deep.

**C# : RapidCallStack**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidCallStack
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Frame 1 is the one holding the program pointer, the number grows towards the entry point
        for (int frame = 1; frame <= 5; frame++)
        {
            RapidActivationRecord record = robot.Rws.Rapid.GetActivationRecord("T_ROB1", frame);

            Console.WriteLine(record.RoutineUrl);
            Console.WriteLine(record.BeginRow + "," + record.BeginColumn);
            Console.WriteLine(record.ExecutionLevel);
        }

        // The routines the program pointer may be moved to, service routines included
        foreach (RapidServiceRoutineItem routine in robot.Rws.Rapid.GetServiceRoutines("T_ROB1"))
        {
            Console.WriteLine(routine.Name + " -> " + routine.Url + " service=" + routine.IsServiceRoutine);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidCallStack**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# Frame 1 is the one holding the program pointer, the number grows towards the entry point
for frame in range(1, 6):
    record = robot.rws.rapid.get_activation_record("T_ROB1", frame)

    print(record.routine_url)
    print(f"{record.begin_row},{record.begin_column}")
    print(record.execution_level)

# The routines the program pointer may be moved to, service routines included
for routine in robot.rws.rapid.get_service_routines("T_ROB1"):
    print(f"{routine.name} -> {routine.url} service={routine.is_service_routine}")
##

robot.disconnect()
```

| `RapidExecutionLevel` | Where execution stands                                  |
| --------------------- | ------------------------------------------------------- |
| `Normal`              | In the program itself                                   |
| `Trap`                | In a trap routine                                       |
| `User`                | In a routine started by hand, such as a service routine |
| `None`                | Nothing is running at this level                        |
| `Unknown`             | The controller reported a level the SDK does not know   |

**Methods of RapidService**
```csharp
// Gets one frame of the call stack of a task: which routine is running and where execution stands in it (synchronous)
RapidActivationRecord GetActivationRecord(string task, int stackFrame = 1);

// Gets the routines of a task the program pointer can be moved to (synchronous)
RapidServiceRoutineItem[] GetServiceRoutines(string task, int? start = null, int? limit = null);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidActivationRecord**
```csharp
public class RapidActivationRecord {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidActivationRecord" data-throw-if-not-resolved="false"></xref> class
    public RapidActivationRecord()

    // Column the executing statement starts at, null when the controller did not report it
    public int? BeginColumn { get; set; }

    // Line the executing statement starts at, null when the controller did not report it
    public int? BeginRow { get; set; }

    // Column the executing statement ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the executing statement ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // Level at which this frame is executing
    public RapidExecutionLevel ExecutionLevel { get; set; }

    // Path of the routine this frame is executing
    public string RoutineUrl { get; set; }

    // Path identifying this stack frame, which the UI instruction resources also take
    public string StackUrl { get; set; }

    // Returns a string representation of this stack frame
    public override string ToString()
}
```

**Members of Rws.Data.RapidServiceRoutineItem**
```csharp
public class RapidServiceRoutineItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidServiceRoutineItem" data-throw-if-not-resolved="false"></xref> class
    public RapidServiceRoutineItem()

    // Whether this is a service routine rather than an ordinary one, null when the controller
    // did not report it
    public bool? IsServiceRoutine { get; set; }

    // Name of the routine, for example "LoadIdentify"
    public string Name { get; set; }

    // Returns a string representation of this routine
    public override string ToString()

    // Path of the routine, which <code>RapidService.SetProgramPointerToRoutineUrl()</code> takes
    public string Url { get; set; }
}
```

**Members of Rws.Data.RapidExecutionLevel**
```csharp
public enum RapidExecutionLevel {
    // Nothing is executing
    None = 1

    // The normal user code is executing
    Normal = 2

    // A trap routine is executing
    Trap = 3

    // The controller reported a level this library does not know
    Unknown = 0

    // A user routine is executing
    User = 4
}
```

## Answer an operator dialogue

A RAPID program can stop and ask the operator something. The controller then reports one pending instruction, and the program waits until it is answered. `GetActiveUiInstruction` returns `null` when nothing is pending.

**C# : RapidUiInstructions**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidUiInstructions
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Null when the program is not asking the operator for anything right now
        RapidUiInstruction question = robot.Rws.Rapid.GetActiveUiInstruction();

        if (question != null)
        {
            Console.WriteLine(question.Instruction);   // name of the RAPID instruction waiting
            Console.WriteLine(question.Message);
            Console.WriteLine(question.Event);         // Send, Post or Abort

            // What the program passed in, and what it is waiting for. The names of the
            // parameters depend on the instruction, so read them before writing one.
            foreach (RapidUiInstructionParameter parameter in
                     robot.Rws.Rapid.GetUiInstructionParameters(question.StackUrl))
            {
                Console.WriteLine(parameter.Name + " = " + parameter.Value);
            }

            // Answering is a write, so it needs the mastership
            robot.Rws.Mastership.Request(MastershipDomain.Rapid);
            try
            {
                // Write the parameter carrying the answer, then the one marking it as completed
                robot.Rws.Rapid.SetUiInstructionParameter(question.StackUrl, "TPCompleted", "TRUE");
            }
            finally
            {
                robot.Rws.Mastership.Release(MastershipDomain.Rapid);
            }

            Console.WriteLine(robot.Rws.Rapid.GetUiInstructionParameter(question.StackUrl, "TPCompleted"));
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidUiInstructions**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
# None when the program is not asking the operator for anything right now
question = robot.rws.rapid.get_active_ui_instruction()

if question is not None:
    print(question.instruction)  # name of the RAPID instruction waiting
    print(question.message)
    print(question.event)        # Send, Post or Abort

    # What the program passed in, and what it is waiting for. The names of the
    # parameters depend on the instruction, so read them before writing one.
    for parameter in robot.rws.rapid.get_ui_instruction_parameters(question.stack_url):
        print(f"{parameter.name} = {parameter.value}")

    # Answering is a write, so it needs the mastership
    robot.rws.mastership.request(MastershipDomain.Rapid)
    try:
        # Write the parameter carrying the answer, then the one marking it as completed
        robot.rws.rapid.set_ui_instruction_parameter(question.stack_url, "TPCompleted", "TRUE")
    finally:
        robot.rws.mastership.release(MastershipDomain.Rapid)

    print(robot.rws.rapid.get_ui_instruction_parameter(question.stack_url, "TPCompleted"))
##

robot.disconnect()
```

The names of the parameters depend on the instruction the program used, so read them with `GetUiInstructionParameters` before writing one. The answer is written first, then the parameter marking the dialogue as completed. Writing a parameter needs the `Rapid` mastership, and fails when the instruction is no longer pending.

**Methods of RapidService**
```csharp
// Gets the dialogue a running RAPID program is currently asking an operator for (synchronous) Answering it means writing its parameters with String%2cSystem.String), addressed by the path this returns.
RapidUiInstruction GetActiveUiInstruction();

// Gets the value of one parameter of a pending UI instruction (synchronous)
string GetUiInstructionParameter(string stackUrl, string parameter);

// Gets every parameter of a pending UI instruction: what the program passed in, and what it is waiting for (synchronous)
RapidUiInstructionParameter[] GetUiInstructionParameters(string stackUrl);

// Answers a pending UI instruction by writing one of its parameters (synchronous) An instruction is normally answered by writing the parameter carrying the answer and then the one marking it as completed.
void SetUiInstructionParameter(string stackUrl, string parameter, string value);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidUiInstruction**
```csharp
public class RapidUiInstruction {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidUiInstruction" data-throw-if-not-resolved="false"></xref> class
    public RapidUiInstruction()

    // What the instruction is asking of the client
    public RapidUiInstructionEvent Event { get; set; }

    // Level at which the instruction is executing
    public RapidExecutionLevel ExecutionLevel { get; set; }

    // Name of the RAPID instruction that opened the dialogue, for example "TPReadNum"
    public string Instruction { get; set; }

    // Text the instruction displays
    public string Message { get; set; }

    // Path identifying the call, which the parameter methods take
    public string StackUrl { get; set; }

    // Returns a string representation of this instruction
    public override string ToString()
}
```

**Members of Rws.Data.RapidUiInstructionParameter**
```csharp
public class RapidUiInstructionParameter {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidUiInstructionParameter" data-throw-if-not-resolved="false"></xref> class
    public RapidUiInstructionParameter()

    // Name of the parameter, for example "TPCompleted"
    public string Name { get; set; }

    // Returns a string representation of this parameter
    public override string ToString()

    // Value of the parameter, written the way RAPID writes it
    public string Value { get; set; }
}
```

**Members of Rws.Data.RapidUiInstructionEvent**
```csharp
public enum RapidUiInstructionEvent {
    // The instruction has been abandoned and no answer is expected any more
    Abort = 3

    // The instruction only displays something and expects no answer
    Post = 2

    // The instruction is waiting for an answer
    Send = 1

    // The controller reported an event this library does not know
    Unknown = 0
}
```

## Signals renamed by the program

A RAPID program can give another name to an I/O signal. `GetAliasIo` lists these names as long as the program declaring them is loaded. The signals themselves are read and written with the [I/O service](/abb/documentation/rws-io).

**C# : RapidAliasIo**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidAliasIo
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // The signals a loaded program gave another name to. Empty when no program declares any.
        foreach (RapidAliasIoItem alias in robot.Rws.Rapid.GetAliasIo())
        {
            Console.WriteLine(alias.AliasName + " -> " + alias.SignalName + " (" + alias.Type + ")");
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidAliasIo**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# The signals a loaded program gave another name to. Empty when no program declares any.
for alias in robot.rws.rapid.get_alias_io():
    print(f"{alias.alias_name} -> {alias.signal_name} ({alias.type})")
##

robot.disconnect()
```

**Methods of RapidService**
```csharp
// Gets the I/O signals a running RAPID program has given an alias to (synchronous)
RapidAliasIoItem[] GetAliasIo(int? start = null, int? limit = null);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidAliasIoItem**
```csharp
public class RapidAliasIoItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidAliasIoItem" data-throw-if-not-resolved="false"></xref> class
    public RapidAliasIoItem()

    // Name the RAPID program refers to the signal by
    public string AliasName { get; set; }

    // Name of the I/O signal the alias points at
    public string SignalName { get; set; }

    // Returns a string representation of this alias
    public override string ToString()

    // Type of the aliased signal
    public IoSignalType Type { get; set; }
}
```

## Position of the robot

The position of the robot, its mechanical units and the external axes of a task are read from the [motion system service](/abb/documentation/rws-motion).

## Try it in the demo application

Everything on this page can be tried without writing code, in the **RAPID (RWS)** page of the [demo application](/abb/documentation/demo-app).

![RAPID (RWS) page of the ABB SDK demo application](/abb/WinformsScreenshots/RwsRapid.jpg)

Its C# source is [RwsRapidControl.cs](https://github.com/underautomation/ABB.NET/blob/main/UnderAutomation.ABB.Showcase.Forms/Components/RwsRapidControl.cs).