syntax = "proto3";

package agv.calibration.localization.external;

import "calibration_common.proto";

// =========================================================
// 文件作用：外部定位 / 真值参考接入执行代理协议
// 运行关系：
// Ubuntu 车间电脑(Linux) -> Windows 车端代理 / Linux 外部定位桥接服务
// 说明：
// 1) Linux 负责任务编排、基准求解、重复性分析、真值参考验收判断
// 2) 车端代理 / 桥接服务只负责采集数据、提供位姿流、执行必要检查
// 3) 本文件既支持“外部定位结果求解”，也支持“阶段0真值参考接入与确认”
// =========================================================

// =========================================================
// 服务：外部定位标定服务
// 运行位置：Windows 车端代理 或 Linux 外部定位桥接服务
// 调用方：Ubuntu 车间电脑
// =========================================================
service AgvCalibExternalLocalizationService {
  // 心跳保活
  rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
      returns (.agv.calibration.common.HeartbeatResponse);

  // 查询外部定位服务当前是否具备作为真值参考的条件
  rpc GetExternalLocalizationReadiness(.agv.calibration.common.AgentReadinessRequest)
      returns (ExternalLocalizationReadinessResponse);

  // 设置外部定位工作模式
  rpc SetExternalLocalizationWorkMode(ExternalLocalizationWorkModeRequest)
      returns (.agv.calibration.common.StandardResponse);

  // 查询外部定位能力
  rpc GetExternalLocalizationCapability(ExternalLocalizationCapabilityRequest)
      returns (ExternalLocalizationCapabilityResponse);

  // 启动一个外部定位任务
  rpc StartExternalLocalizationTask(ExternalLocalizationTaskRequest)
      returns (.agv.calibration.common.JobAccepted);

  // 查询外部定位任务状态
  rpc GetExternalLocalizationJobStatus(.agv.calibration.common.JobQuery)
      returns (.agv.calibration.common.JobStatus);

  // 查询外部定位任务结果
  rpc GetExternalLocalizationJobResult(.agv.calibration.common.JobQuery)
      returns (ExternalLocalizationJobResult);

  // 取消外部定位任务
  rpc CancelExternalLocalizationJob(.agv.calibration.common.JobQuery)
      returns (.agv.calibration.common.StandardResponse);

  // 打开外部定位遥测流
  rpc StreamExternalLocalizationTelemetry(StreamExternalLocalizationTelemetryRequest)
      returns (stream ExternalLocalizationTelemetry);

  // 写入外部定位标定结果
  rpc CommitExternalLocalizationResult(CommitExternalLocalizationResultRequest)
      returns (.agv.calibration.common.StandardResponse);

  // 查询当前已生效外部定位结果
  rpc GetAppliedExternalLocalizationResult(GetAppliedExternalLocalizationResultRequest)
      returns (AppliedExternalLocalizationResultResponse);

  // 紧急停止
  rpc EmergencyStop(.agv.calibration.common.Empty)
      returns (.agv.calibration.common.StandardResponse);
}

// =========================================================
// 服务：外部真值位姿下发服务
// 运行位置：Ubuntu 车间电脑 / 外部真值系统桥接进程
// 调用方：Windows 车端代理
// 传输介质：现场通过 WiFi 6 网络承载
// 作用：
// 1) 让车端在执行轨迹跟踪时获得车间坐标系下的实时位姿
// 2) 与 StreamExternalLocalizationTelemetry 使用同一位姿消息结构
// 3) 车端不得把底盘里程计当成默认全局位姿源，只可作为降级输入
// =========================================================
service AgvCalibExternalPoseFeedService {
  // 心跳保活，用于车端确认外部真值链路在线
  rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
      returns (.agv.calibration.common.HeartbeatResponse);

  // 车端订阅外部真值位姿流
  rpc StreamExternalPoseToVehicle(ExternalPoseFeedRequest)
      returns (stream ExternalLocalizationTelemetry);

  // 可选：外部真值系统主动推送单帧位姿到车端
  rpc PushExternalPoseToVehicle(ExternalLocalizationTelemetry)
      returns (.agv.calibration.common.StandardResponse);
}

// =========================================================
// 外部定位工作模式请求
// 作用：切换外部定位桥接服务到不同模式
// =========================================================
message ExternalLocalizationWorkModeRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头

  enum Mode {
    EXTERNAL_LOCALIZATION_MODE_UNSPECIFIED = 0; // 未指定
    NORMAL_MODE = 1;                            // 正常模式
    CALIBRATION_READY_MODE = 2;                 // 标定准备模式
    REFERENCE_COLLECTION_MODE = 3;              // 参考数据采集模式
    VALIDATION_MODE = 4;                        // 真值参考验证模式
  }

  Mode target_mode = 2; // 目标模式
  string reason = 3;    // 切换原因
}

// =========================================================
// 查询外部定位能力请求
// 作用：查询当前工位 / 服务支持的外部定位能力
// =========================================================
message ExternalLocalizationCapabilityRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
}

// =========================================================
// 查询外部定位能力响应
// 作用：返回当前支持的数据源与功能
// =========================================================
message ExternalLocalizationCapabilityResponse {
  bool success = 1; // 是否成功
  .agv.calibration.common.ErrorCode error_code = 2; // 错误码
  string message = 3; // 说明

  bool supports_truth_source_readiness_check = 4; // 是否支持真值源就绪检查
  bool supports_marker_alignment = 5;             // 是否支持基于标靶对齐
  bool supports_reference_pose_collection = 6;    // 是否支持参考位姿采集
  bool supports_truth_source_validation = 7;      // 是否支持真值参考验证
  bool supports_persistent_commit = 8;            // 是否支持持久化写入

  string localization_source_name = 9; // 外部定位源名称
  string localization_source_id = 10; // 外部定位源唯一 ID
  string workcell_zone_id = 11;       // 当前工位 / 区域 ID
}

// =========================================================
// 外部定位验证摘要
// 作用：表达当前外部定位是否适合作为真值参考输入
// 使用场景：
// 1) readiness 响应
// 2) 外部定位任务结果
// 3) 阶段0自动验收判断
// =========================================================
message ExternalLocalizationValidationSummary {
  bool time_sync_ok = 1;               // 时间同步是否达标
  bool coverage_ok = 2;                // 覆盖范围是否达标
  bool quality_ok = 3;                 // 观测质量是否达标
  bool tracking_stable = 4;            // 跟踪是否稳定
  bool recommended_as_truth_source = 5; // 是否推荐作为真值参考源

  double position_stddev_m = 6;        // 位置标准差
  double yaw_stddev_rad = 7;           // 航向标准差
  double tracking_loss_ratio = 8;      // 跟踪丢失比例
  double time_sync_offset_ms = 9;      // 时间同步偏差（ms）

  repeated .agv.calibration.common.ReadinessIssue issues = 10; // 不满足项列表
}

// =========================================================
// 外部定位就绪响应
// 作用：返回当前是否适合作为真值参考源
// 发送方：外部定位桥接服务
// 接收方：Ubuntu 车间电脑
// =========================================================
message ExternalLocalizationReadinessResponse {
  bool success = 1; // 是否成功
  .agv.calibration.common.ErrorCode error_code = 2; // 错误码
  string message = 3; // 说明

  bool agent_ready = 4; // 服务本身是否就绪
  bool ready_for_reference_validation = 5; // 是否可进入真值参考验证
  ExternalLocalizationValidationSummary validation_summary = 6; // 验证摘要
  int64 checked_timestamp_us = 7; // 检查时间
}

// =========================================================
// 参考位姿采集任务
// 作用：采集一批车辆静止位姿用于重复性分析或基准建立
// =========================================================
message ReferencePoseCollectionTask {
  uint32 sample_count = 1;         // 需要采集的样本数
  bool require_vehicle_static = 2; // 是否要求车辆静止
  double timeout_sec = 3;          // 超时时间
  double min_sample_interval_sec = 4; // 最小采样间隔
}

// =========================================================
// 标靶对齐任务
// 作用：通过标靶 / 标定板建立外部参考坐标关系
// =========================================================
message MarkerAlignmentTask {
  string target_board_id = 1;            // 标靶 / 标定板 ID
  uint32 min_valid_observation_count = 2; // 最少有效观测数
  double timeout_sec = 3;                // 超时时间
}

// =========================================================
// 真值参考验证任务
// 作用：验证外部定位输出的重复性、稳定性、时间同步与可用性
// =========================================================
message TruthSourceValidationTask {
  uint32 static_sample_count = 1;         // 静态样本数
  uint32 dynamic_sample_count = 2;        // 动态样本数
  bool require_short_motion_segment = 3;  // 是否要求短距离运动段验证

  double max_position_stddev_m = 4;       // 允许的最大位置标准差
  double max_yaw_stddev_rad = 5;          // 允许的最大航向标准差
  double max_tracking_loss_ratio = 6;     // 允许的最大跟踪丢失比例
  double max_time_sync_offset_ms = 7;     // 允许的最大时间同步偏差

  double timeout_sec = 8;                 // 超时时间
}

// =========================================================
// 外部定位任务请求
// 作用：启动一类外部定位任务
// 发送方：Ubuntu 车间电脑
// 接收方：Windows 车端代理 / Linux 桥接服务
// =========================================================
message ExternalLocalizationTaskRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
  string test_case_id = 2; // 测试用例 ID

  enum TaskPurpose {
    EXTERNAL_LOCALIZATION_TASK_PURPOSE_UNSPECIFIED = 0; // 未指定
    REFERENCE_READY_CHECK = 1;                          // 真值参考可用性检查
    DATA_COLLECTION = 2;                                // 数据采集
    SOLVING = 3;                                        // 求解
    VALIDATION = 4;                                     // 验证
  }

  TaskPurpose task_purpose = 3; // 任务目的

  oneof task {
    ReferencePoseCollectionTask reference_pose_collection = 4; // 参考位姿采集
    MarkerAlignmentTask marker_alignment = 5;                  // 标靶对齐
    TruthSourceValidationTask truth_source_validation = 6;     // 真值参考验证
  }

  string source_iteration_id = 7; // 来源迭代号
  string localization_source_id = 8; // 本次任务指定使用的外部定位源 ID
  string workcell_zone_id = 9;      // 本次任务所属工位 / 区域 ID
}

// =========================================================
// 外部定位遥测流请求
// 作用：指定外部定位数据上报内容
// =========================================================
message StreamExternalLocalizationTelemetryRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
  uint32 expected_hz = 2;                           // 期望上报频率
  bool include_pose = 3;                            // 是否包含位姿
  bool include_quality_metrics = 4;                 // 是否包含质量指标
  bool include_time_sync_metrics = 5;               // 是否包含时间同步指标
  bool include_tracking_state = 6;                  // 是否包含跟踪状态
}

// =========================================================
// 外部真值位姿下发请求
// 作用：车端通过 WiFi 6 请求工控机 / 外部真值桥接进程提供实时位姿流
// =========================================================
message ExternalPoseFeedRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
  string vehicle_id = 2;                            // 目标车辆 ID
  string localization_source_id = 3;                // 外部真值源 ID
  string workcell_zone_id = 4;                      // 工位 / 区域 ID
  uint32 expected_hz = 5;                           // 期望下发频率
  double max_pose_age_ms = 6;                       // 允许最大位姿延迟
  bool require_quality_metrics = 7;                 // 是否要求质量指标
}

// =========================================================
// 外部定位遥测
// 作用：回传外部定位实时观测结果
// 发送方：Windows 车端代理 / Linux 桥接服务
// 接收方：Ubuntu 车间电脑
// =========================================================
message ExternalLocalizationTelemetry {
  int64 hardware_timestamp_us = 1; // 硬件时间戳
  bool pose_valid = 2;             // 位姿是否有效

  .agv.calibration.common.Pose3D workshop_pose = 3; // 在车间参考系下的位姿

  double position_stddev_m = 4;    // 位置标准差
  double yaw_stddev_rad = 5;       // 航向标准差
  double tracking_loss_ratio = 6;  // 跟踪丢失比例
  double time_sync_offset_ms = 7;  // 时间同步偏差（ms）
  double quality_score = 8;        // 质量分数，数值越高越好

  uint32 observed_target_count = 9; // 当前观测到的目标数量
  string reference_source_name = 10; // 外部定位源名称
  string active_job_id = 11;         // 当前任务 ID
}

// =========================================================
// 外部定位标定结果
// 作用：表达车间参考系与外部定位参考系之间的结果关系
// =========================================================
message ExternalLocalizationCalibrationResult {
  string workshop_frame_id = 1; // 车间参考坐标系 ID
  string localization_frame_id = 2; // 外部定位坐标系 ID

  .agv.calibration.common.Pose3D workshop_to_localization = 3; // 车间系到定位系的位姿

  double position_repeatability_m = 4; // 位置重复性
  double yaw_repeatability_rad = 5;    // 航向重复性
  double residual_error_m = 6;         // 残差位置误差
  double residual_error_rad = 7;       // 残差姿态误差

  double tracking_loss_ratio = 8;      // 跟踪丢失比例
  double time_sync_offset_ms = 9;      // 时间同步偏差（ms）
  bool validated_as_truth_source = 10; // 是否已验证可作为真值参考源
  string localization_source_id = 11; // 该结果对应的外部定位源 ID
  string workcell_zone_id = 12;       // 该结果对应的工位 / 区域 ID
}

// =========================================================
// 外部定位结果写入请求
// 作用：将 Linux 求解出的外部定位结果写入系统
// =========================================================
message CommitExternalLocalizationResultRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
  string parameter_version = 2;                     // 结果版本号
  ExternalLocalizationCalibrationResult result = 3; // 外部定位结果
  string commit_reason = 4;                         // 写入原因
  .agv.calibration.common.FileDigest digest = 5;    // 摘要
  bool persistent_write = 6;                        // 是否持久化
}

// =========================================================
// 查询当前已生效外部定位结果请求
// =========================================================
message GetAppliedExternalLocalizationResultRequest {
  .agv.calibration.common.RequestHeader header = 1; // 请求头
}

// =========================================================
// 查询当前已生效外部定位结果响应
// =========================================================
message AppliedExternalLocalizationResultResponse {
  bool success = 1; // 是否成功
  .agv.calibration.common.ErrorCode error_code = 2; // 错误码
  string message = 3; // 说明
  string parameter_version = 4; // 当前版本
  ExternalLocalizationCalibrationResult result = 5; // 当前生效结果
  int64 applied_timestamp_us = 6; // 生效时间
}

// =========================================================
// 外部定位任务结果
// 作用：返回求解 / 验证后的结果摘要，供编排器判断是否进入下一阶段
// =========================================================
message ExternalLocalizationJobResult {
  bool success = 1; // 是否成功
  .agv.calibration.common.ErrorCode error_code = 2; // 错误码
  string message = 3; // 说明
  string job_id = 4;  // 任务 ID

  ExternalLocalizationTaskRequest.TaskPurpose task_purpose = 5; // 任务目的

  bool data_quality_passed = 6;   // 数据质量是否达标
  bool suitable_for_commit = 7;   // 是否适合写入
  string recommended_parameter_version = 8; // 推荐结果版本号

  ExternalLocalizationValidationSummary validation_summary = 9; // 真值参考验证摘要
  ExternalLocalizationCalibrationResult result = 10; // 结果内容
  repeated .agv.calibration.common.FileReference artifacts = 11; // 关联产物
}
