Read safety status, current position, I/O state, error history, installed features, registers, and system variables from the Fanuc controller via FTP.

## Safety, position, I/O, and errors

**C# : FtpDiagnosticsSafety**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Common.Files.Diagnosis;

public class FtpDiagnosticsSafety
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        // Safety status
        SafetyStatus safetyStatus = robot.Ftp.GetSafetyStatus();
        Console.WriteLine($"Emergency Stop: {safetyStatus.ExternalEStop}");
        Console.WriteLine($"Teach Pendant Enabled: {safetyStatus.TPEnable}");

        // Current position
        CurrentPosition currentPosition = robot.Ftp.GetCurrentPosition();

        // I/O state
        IOState ioState = robot.Ftp.GetIOState();

        // Error history
        var errors = robot.Ftp.GetAllErrorsList();
        /**/
    }
}
```

**Python : FtpDiagnosticsSafety**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Safety status
safety_status = robot.ftp.get_safety_status()
print(f"Emergency Stop: {safety_status.external_e_stop}")
print(f"Teach Pendant Enabled: {safety_status.tp_enable}")

# Current position
current_position = robot.ftp.get_current_position()

# I/O state
io_state = robot.ftp.get_io_state()

# Error history
errors = robot.ftp.get_all_errors_list()
##
```

**Members of Common.Files.Diagnosis.SafetyStatus**
```csharp
public class SafetyStatus : IFanucContent {
    public SafetyStatus()

    // Belt broken signal is active
    public bool BeltBroken { get; }

    public override bool Equals(object obj)

    // External emergency stop active
    public bool ExternalEStop { get; }

    // Safety fence is open
    public bool FenceOpen { get; }

    public override int GetHashCode()

    // Hand broken signal is active
    public bool HandBroken { get; }

    // Low air pressure alarm is active
    public bool LowAirAlarm { get; }

    // File name : sftysig.dg
    public string Name { get; }

    // Non-teacher enable signal is active
    public bool NonTeacherEnb { get; }

    // Over travel limit is active
    public bool OverTravel { get; }

    // Emergency stop active by SOP signal
    public bool SOPEStop { get; }

    // Servo off detection is active
    public bool SVOFFDetect { get; }

    // The deadman switch of the teach pendant is active
    public bool TPDeadman { get; }

    // Emergency stop active on teach peandant
    public bool TPEStop { get; }

    // Teach pendant is enabled
    public bool TPEnable { get; }

    public override string ToString()
}
```

**Members of Common.Files.Diagnosis.CurrentPosition**
```csharp
public class CurrentPosition : IFanucContent {
    public CurrentPosition()

    // Position of each robots handled by this controller
    public GroupPosition[] GroupsPosition { get; }

    // File name : curpos.dg
    public string Name { get; }

    public override string ToString()
}
```

**Members of Common.Files.Diagnosis.GroupPosition**
```csharp
public class GroupPosition {
    public GroupPosition()

    public override bool Equals(object obj)

    public override int GetHashCode()

    // Group ID
    public int Id { get; }

    // Joint positions : the position of each robot angles
    public JointsPosition JointsPosition { get; }

    public override string ToString()

    // Position of each tools in each user frames
    public CartesianPositionWithUserFrame[] UserFramePositions { get; }

    // Position of each tools in world coordinates
    public CartesianPositionWithTool[] WorldPositions { get; }
}
```

**Members of Common.Files.Diagnosis.IOState**
```csharp
public class IOState : IFanucContent {
    public IOState()

    // File name : iostate.dg
    public string Name { get; }

    // Status of all controller inputs and outputs
    public IOStatus[] States { get; }

    public override string ToString()
}
```

**Members of Common.IOStatus**
```csharp
public class IOStatus {
    public IOStatus()

    public override bool Equals(object obj)

    public override int GetHashCode()

    // Digital port ID
    public int Id { get; }

    // IO Name
    public string Name { get; }

    // Digital port type
    public DigitalPorts Port { get; }

    // String representation like : DIN[1]=True
    public override string ToString()

    // Digital port value
    public bool Value { get; }
}
```

**Members of Common.DigitalPorts**
```csharp
public enum DigitalPorts {
    // Digital input
    DIN = 0

    // Digital outputs
    DOUT = 1

    // Flags
    FLG = 8

    // Robot inputs
    RI = 6

    // Robot outputs
    RO = 7

    // SI
    SI = 4

    // SO
    SO = 5

    // User inputs
    UI = 2

    // User outputs
    UO = 3
}
```

## Read variables

Variables are read in bulk from `.va` files stored on the controller.

**C# : FtpDiagnosticsVariables**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Common.Files.Variables;

public class FtpDiagnosticsVariables
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        // Get all variables from all files
        var allVariables = robot.Ftp.GetAllVariables();
        foreach (var file in allVariables)
            foreach (var variable in file.Variables)
                Console.WriteLine($"{variable.Name} = {variable.Value}");

        // Get variables from a specific file
        var variables = robot.Ftp.GetVariablesFromFile("SYSVARS.va");

        // Access commonly used system variables directly
        int rmtMaster = robot.Ftp.KnownVariableFiles.GetSystemFile().RmtMaster;
        /**/
    }
}
```

**Python : FtpDiagnosticsVariables**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Get all variables from all files
all_variables = robot.ftp.get_all_variables()
for file in all_variables:
    for variable in file.variables:
        print(f"{variable.name} = {variable.value}")

# Get variables from a specific file
variables = robot.ftp.get_variables_from_file("SYSVARS.va")

# Access commonly used system variables directly
rmt_master = robot.ftp.known_variable_files.get_system_file().rmt_master
##
```

## Read registers

Registers are read in bulk via FTP variable files.

**C# : FtpDiagnosticsRegisters**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Common.Files.Variables;

public class FtpDiagnosticsRegisters
{
  public static void Main()
  {
    // Create a FanucRobot instance
    FanucRobot robot = new FanucRobot();

    // Set connection parameters (example values)
    ConnectionParameters parameters = new ConnectionParameters("192.168.0.1");
    parameters.Ftp.Enable = true;
    parameters.Ftp.FtpUser = "user";
    parameters.Ftp.FtpPassword = "ftp password";

    // Connect to the robot with FTP enabled
    robot.Connect(parameters);

    // 1) Reading Numeric Registers
    ReadNumericRegisters(robot);

    // 2) Reading Position Registers
    ReadPositionRegisters(robot);

    // 3) Reading String Registers
    ReadStringRegisters(robot);
  }

  private static void ReadNumericRegisters(FanucRobot robot)
  {
    NumregFile numregFile = robot.Ftp.KnownVariableFiles.GetNumregFile();

    for (int i = 0; i < numregFile.Numreg.Length; i++)
    {
      double value = numregFile.Numreg[i];
      Console.WriteLine($"📊 Numeric R[{i}] = {value}");
    }
  }

  private static void ReadPositionRegisters(FanucRobot robot)
  {
    PosregFile posregFile = robot.Ftp.KnownVariableFiles.GetPosregFile();

    // posregFile.Posreg is a 3D array: dimension [1] = group, [2] = register index
    for (int group = 0; group < posregFile.Posreg.GetLength(1); group++)
    {
      Console.WriteLine($"\n🤖 Reading position registers for Group {group}:");

      for (int i = 0; i < posregFile.Posreg.GetLength(2); i++)
      {
        PositionRegister value = posregFile.Posreg[group, i];
        Console.WriteLine($" - PR[{i}] :");
        Console.WriteLine($"    X = {value.CartesianPosition.X}");
        Console.WriteLine($"    Y = {value.CartesianPosition.Y}");
        Console.WriteLine($"    Z = {value.CartesianPosition.Z}");
        Console.WriteLine($"    W = {value.CartesianPosition.W}");
        Console.WriteLine($"    P = {value.CartesianPosition.P}");
        Console.WriteLine($"    R = {value.CartesianPosition.R}");
        Console.WriteLine("    Configuration :");
        Console.WriteLine($"       ArmFrontBack = {value.CartesianPosition.Configuration.ArmFrontBack}");
        Console.WriteLine($"       ArmLeftRight = {value.CartesianPosition.Configuration.ArmLeftRight}");
        Console.WriteLine($"       ArmUpDown = {value.CartesianPosition.Configuration.ArmUpDown}");
        Console.WriteLine($"       WristFlip = {value.CartesianPosition.Configuration.WristFlip}");
      }
    }
  }

  private static void ReadStringRegisters(FanucRobot robot)
  {
    StrregFile strregFile = robot.Ftp.KnownVariableFiles.GetStrregFile();

    for (int i = 0; i < strregFile.Strreg.Length; i++)
    {
      string value = strregFile.Strreg[i];
      Console.WriteLine($"💬 String SR[{i}] = '{value}'");
    }
  }
}
```

**Python : FtpDiagnosticsRegisters**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Read numeric registers
numreg_file = robot.ftp.known_variable_files.get_numreg_file()
for i in range(len(numreg_file.numreg)):
    value = numreg_file.numreg[i]
    print(f"R[{i}] = {value}")

# Read position registers
posreg_file = robot.ftp.known_variable_files.get_posreg_file()

# Read string registers
strreg_file = robot.ftp.known_variable_files.get_strreg_file()
for i in range(len(strreg_file.strreg)):
    value = strreg_file.strreg[i]
    print(f"SR[{i}] = '{value}'")
##
```

## Installed features (options)

Detect available options on the controller to check protocol availability.

**C# : FtpDiagnosticsFeatures**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Common.Files.Diagnosis;

public class FtpDiagnosticsFeatures
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        Features features = robot.Ftp.GetSummaryDiagnostic().Features;

        // Check specific capabilities
        bool hasSnpx = features.HasSnpx;
        bool hasTelnet = features.HasTelnet;

        // List all installed features
        foreach (var feature in features.FeaturesList)
            Console.WriteLine($"{feature.Name} ({feature.OrderNo})");
        /**/
    }
}
```

**Python : FtpDiagnosticsFeatures**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
features = robot.ftp.get_summary_diagnostic().features

# Check specific capabilities
has_snpx = features.has_snpx
has_telnet = features.has_telnet

# List all installed features
for feature in features.features_list:
    print(f"{feature.name} ({feature.order_number})")
##
```

## Complete example

**C# : FtpDiagnostics**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Common.Files.Diagnosis;

public class FtpDiagnostics
{
  static void Main()
  {
    FanucRobot robot = new FanucRobot();
    ConnectionParameters parameters = new ConnectionParameters("192.168.0.1");
    parameters.Ftp.Enable = true;
    parameters.Ftp.FtpUser = "";
    parameters.Ftp.FtpPassword = "";
    robot.Connect(parameters);

    /**/
    // Read safety status
    SafetyStatus safetyStatus = robot.Ftp.GetSafetyStatus();
    Console.WriteLine($"Emergency Stop: {safetyStatus.ExternalEStop}");
    Console.WriteLine($"Teach Pendant Enabled: {safetyStatus.TPEnable}");

    // Read current position (joints, world, user frames)
    CurrentPosition currentPosition = robot.Ftp.GetCurrentPosition();

    // Read I/O state
    IOState ioState = robot.Ftp.GetIOState();

    // Read all errors
    var errors = robot.Ftp.GetAllErrorsList();

    // Read all variables from all files
    var allVariables = robot.Ftp.GetAllVariables();
    foreach (var file in allVariables)
      foreach (var variable in file.Variables)
        Console.WriteLine($"{variable.Name} = {variable.Value}");

    // Access well-known system variables
    int rmtMaster = robot.Ftp.KnownVariableFiles.GetSystemFile().RmtMaster;

    // Get installed features
    Features features = robot.Ftp.GetSummaryDiagnostic().Features;
    bool hasSnpx = features.HasSnpx;
    /**/
  }
}
```

**Python : FtpDiagnostics**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Read safety status
safety_status = robot.ftp.get_safety_status()
print(f"Emergency Stop: {safety_status.external_e_stop}")
print(f"Teach Pendant Enabled: {safety_status.tp_enable}")

# Read current position (joints, world, user frames)
current_position = robot.ftp.get_current_position()

# Read I/O state
io_state = robot.ftp.get_io_state()

# Read all errors
errors = robot.ftp.get_all_errors_list()

# Read all variables from all files
all_variables = robot.ftp.get_all_variables()
for file in all_variables:
    for variable in file.variables:
        print(f"{variable.name} = {variable.value}")

# Access well-known system variables
rmt_master = robot.ftp.known_variable_files.get_system_file().rmt_master

# Get installed features
features = robot.ftp.get_summary_diagnostic().features
has_snpx = features.has_snpx
##
```

## API reference

**Members of Common.Files.Diagnosis.SummaryDiagnosis**
```csharp
public class SummaryDiagnosis : IFanucContent {
    public SummaryDiagnosis()

    // Current position of each robots and groups handled by this controller
    public CurrentPosition CurrentPosition { get; }

    // Controller features status
    public Features Features { get; }

    // Controller IO status
    public IOState IOs { get; }

    // File name : summary.dg
    public string Name { get; }

    // Controller program states
    public ProgramStates ProgramStates { get; }

    // Controller safety information
    public SafetyStatus Safety { get; }

    public override string ToString()
}
```

**Members of Common.Files.Diagnosis.Features**
```csharp
public class Features {
    public Features()

    public override bool Equals(object obj)

    // List of features
    public Feature[] FeaturesList { get; }

    public override int GetHashCode()

    // Indicates if the robot has the ASCII upload feature enabled : R507 ("ASCII Upload" on older controllers) or R796 ("ASCII Program Loader" on most recent controllers).
    public bool HasAsciiUpload { get; }

    // Indicates if the robot has the SNPX feature enabled (R553 or R651).
    public bool HasSnpx { get; }

    // Indicates if the robot has the TELNET feature enabled (TELN).
    public bool HasTelnet { get; }

    public override string ToString()
}
```