// Copyright (c) 2022 Boston Dynamics, Inc.  All rights reserved.
//
// Downloading, reproducing, distributing or otherwise using the SDK Software
// is subject to the terms and conditions of the Boston Dynamics Software
// Development Kit License (20191101-BDSDK-SL).

syntax = "proto3";

package bosdyn.api;

option java_outer_classname = "EstopProto";

import "bosdyn/api/header.proto";
import "google/protobuf/duration.proto";

// An  to the robot software-E-Stop system.
message EstopEndpoint {
    // Role of this endpoint. Should be a user-friendly string, e.g. "OCU".
    string role = 1;

    // Name of this endpoint. Specifies a thing to fill the given role, e.g. "patrol-ocu01"
    string name = 2;

    // Unique ID assigned by the server.
    string unique_id = 3;

    // Maximum delay between challenge and response for this endpoint prior to soft power off
    // handling. After timeout seconds has passed, the robot will try to get to a safe state prior
    // to disabling motor power. The robot response is equivalent to an ESTOP_LEVEL_SETTLE_THEN_CUT
    // which may involve the robot sitting down in order to prepare for disabling motor power.
    google.protobuf.Duration timeout = 4;

    // Optional maximum delay between challenge and response for this endpoint prior to disabling
    // motor power. After cut_power_timeout seconds has passed, motor power will be disconnected
    // immediately regardless of current robot state. If this value is not set robot will default
    // to timeout plus a nominal expected duration to reach a safe state. In practice this
    // is typically 3-4 seconds. The response is equivalent to an ESTOP_LEVEL_CUT.
    google.protobuf.Duration cut_power_timeout = 5;
}

// The state of the E-Stop system.
enum EstopStopLevel {
    // Invalid stop level.
    ESTOP_LEVEL_UNKNOWN = 0;

    // Immediately cut power to the actuators.
    ESTOP_LEVEL_CUT = 1;

    // Prepare for loss of actuator power, then cut power.
    ESTOP_LEVEL_SETTLE_THEN_CUT = 2;

    // No-stop level. The endpoint believes the robot is safe to operate.
    ESTOP_LEVEL_NONE = 4;
}

// Configuration of a root / server.
message EstopConfig {
    // EstopEndpoints that are part of this configuration.
    // Unique IDs do not have to be filled out, but can be.
    repeated EstopEndpoint endpoints = 1;

    // Unique ID for this configuration.
    string unique_id = 2;
}

// EstopEndpoint with some extra status data.
message EstopEndpointWithStatus {
    // The endpoint.
    EstopEndpoint endpoint = 1;

    // Stop level most recently requested by the endpoint.
    EstopStopLevel stop_level = 2;

    // Time since a valid response was provided by the endpoint.
    google.protobuf.Duration time_since_valid_response = 3;
}

// Status of Estop system.
message EstopSystemStatus {
    // Status for all available endpoints.
    repeated EstopEndpointWithStatus endpoints = 3;

    // Current stop level for the system.
    // Will be the most-restrictive stop level specified by an endpoint, or a stop level
    // asserted by the system as a whole (e.g. if an endpoint timed out).
    EstopStopLevel stop_level = 4;

    // Human-readable information on the stop level.
    string stop_level_details = 5;
}


// Client request for setting/maintaining an E-Stop system level.
// After the first CheckIn, must include response to previous challenge.
message EstopCheckInRequest {
    // Common request header.
    RequestHeader header = 1;

    // The endpoint making the request.
    EstopEndpoint endpoint = 2;

    // Challenge being responded to.
    // Don't set if this is the first EstopCheckInRequest.
    uint64 challenge = 3;

    // Response to above challenge.
    // Don't set if this is the first EstopCheckInRequest.
    uint64 response = 4;

    // Assert this stop level.
    EstopStopLevel stop_level = 5;
}

// Server response to EstopCheckInRequest.
message EstopCheckInResponse {
    // Common response header.
    ResponseHeader header = 1;

    // Copy of initial request.
    EstopCheckInRequest request = 2;

    // Next challenge to answer.
    uint64 challenge = 3;

    enum Status {
        // Unknown error occurred.
        STATUS_UNKNOWN = 0;

        // Valid challenge has been returned.
        STATUS_OK = 1;

        // The endpoint specified in the request is not registered.
        STATUS_ENDPOINT_UNKNOWN = 2;


        // The challenge and/or response was incorrect.
        STATUS_INCORRECT_CHALLENGE_RESPONSE = 5;
    }
    // Status code for the response.
    Status status = 4;
}

// Register an endpoint.
// EstopEndpoints must be registered before they can send commands or request challenges.
message RegisterEstopEndpointRequest {
    // Common request header
    RequestHeader header = 1;

    // The endpoint to replace.
    // Set the endpoint's unique ID if replacing an active endpoint.
    EstopEndpoint target_endpoint = 2;

    // ID of the configuration we are registering against.
    string target_config_id = 3;

    // The description of the new endpoint.
    // Do not set the unique ID. It will be ignored.
    EstopEndpoint new_endpoint = 4;
}

// Response to registration request.
message RegisterEstopEndpointResponse {
    // Common response header
    ResponseHeader header = 1;

    // Copy of the initial request.
    RegisterEstopEndpointRequest request = 2;

    // The resulting endpoint on success.
    EstopEndpoint new_endpoint = 3;

    enum Status {
        // An unknown / unexpected error occurred.
        STATUS_UNKNOWN = 0;

        // Request succeeded.
        STATUS_SUCCESS = 1;

        // Target endpoint did not match.
        STATUS_ENDPOINT_MISMATCH = 2;

        // Registered to wrong configuration.
        STATUS_CONFIG_MISMATCH = 3;

        // New endpoint was invalid.
        STATUS_INVALID_ENDPOINT = 4;
    }
    // Status code for the response.
    Status status = 4;
}

// Deregister the specified E-Stop endpoint registration.
message DeregisterEstopEndpointRequest {
    // Common request header
    RequestHeader header = 1;

    // The endpoint to deregister.
    EstopEndpoint target_endpoint = 2;

    // ID of the configuration we are registering against.
    string target_config_id = 3;
}

// Response to E-Stop endpoint  deregistration request.
message DeregisterEstopEndpointResponse {
    // Common resonse header.
    ResponseHeader header = 1;

    // Copy of the initial request.
    DeregisterEstopEndpointRequest request = 2;

    enum Status {
        // An unknown / unexpected error occurred.
        STATUS_UNKNOWN = 0;

        // Request succeeded.
        STATUS_SUCCESS = 1;

        // Target endpoint did not match.
        STATUS_ENDPOINT_MISMATCH = 2;

        // Registered to wrong configuration.
        STATUS_CONFIG_MISMATCH = 3;

        // You cannot deregister an endpoint while the motors are on.
        STATUS_MOTORS_ON = 4;
    }
    // Status code for the response.
    Status status = 4;
}

// Get the active EstopConfig.
message GetEstopConfigRequest {
    // Common request header.
    RequestHeader header = 1;

    // The 'unique_id' of EstopConfig to get.
    string target_config_id = 4;
}

// Response to EstopConfigRequest.
message GetEstopConfigResponse {
    // Common response header.
    ResponseHeader header = 1;

    // Copy of the request.
    GetEstopConfigRequest request = 2;

    // The currently active configuration.
    EstopConfig active_config = 3;
}

// Set a new active EstopConfig.
message SetEstopConfigRequest {
    // Common request header.
    RequestHeader header = 1;

    // New configuration to set.
    EstopConfig config = 3;

    // The 'unique_id' of EstopConfig to replace, if replacing one.
    string target_config_id = 4;
}

// Response to EstopConfigRequest.
message SetEstopConfigResponse {
    // Common response header.
    ResponseHeader header = 1;

    // Copy of the request.
    SetEstopConfigRequest request = 2;

    // The currently active configuration.
    EstopConfig active_config = 3;

    enum Status {
        // An unknown / unexpected error occurred.
        STATUS_UNKNOWN = 0;

        // Request succeeded.
        STATUS_SUCCESS = 1;

        // Tried to replace a EstopConfig, but provided bad ID.
        STATUS_INVALID_ID = 2;


        // You cannot set a configuration while the motors are on.
        STATUS_MOTORS_ON = 4;
    }
    Status status = 4;
}

// Ask for the current status of the Estop system.
message GetEstopSystemStatusRequest {
    // Common request header.
    RequestHeader header = 1;
}

// Respond with the current Estop system status.
message GetEstopSystemStatusResponse {
    // Common response header.
    ResponseHeader header = 1;

    // Status of the Estop system.
    EstopSystemStatus status = 3;
}
