syntax = "proto3";

package agv.calibration.common;

// ├── msg/
// │   ├── Vector3D.msg
// │   ├── Pose3D.msg
// │   ├── RequestHeader.msg
// │   ├── ErrorCode.msg
// │   ├── StandardResponse.msg
// │   ├── JobState.msg
// │   ├── JobAccepted.msg
// │   ├── JobQuery.msg
// │   ├── JobStatus.msg
// │   ├── HeartbeatRequest.msg
// │   ├── HeartbeatResponse.msg
// │   ├── AgentReadinessRequest.msg
// │   ├── ReadinessIssue.msg
// │   ├── FileDigest.msg
// │   ├── FileReference.msg
// │   └── KeyValuePair.msg
// ├── srv/
// │   ├── Heartbeat.srv
// │   ├── QueryJobStatus.srv
// │   └── GetAgentReadiness.srv
// └── action/
//     └── MonitorJob.action

// =========================================================
// 文件作用：自动化标定车间公共协议定义
// 使用范围：
// 1) Ubuntu 车间电脑内部服务之间
// 2) Ubuntu 车间电脑 与 Windows 车端代理服务之间
// 3) 所有专项标定服务的公共基础消息
// =========================================================

// =========================================================
// 空消息
// 作用：无参数 RPC 使用
// =========================================================
message Empty {}

// =========================================================
// 三维向量（兼容命名 1）
// 作用：用于表达三轴偏置、平移量、加速度等三维数据
// =========================================================
message Vector3D {
  double x = 1;  // X 轴分量
  double y = 2;  // Y 轴分量
  double z = 3;  // Z 轴分量
}


// =========================================================
// 六自由度位姿（兼容命名 1）
// 作用：用于表达 base_link、传感器、外部定位坐标系之间的位姿关系
// 说明：
// 1) 平移单位为米
// 2) 旋转单位为弧度
// 3) 采用 xyz + rpy 表达，便于工程实现与人工检查
// =========================================================
message Pose3D {
  double x_m = 1;        // X 方向平移（m）
  double y_m = 2;        // Y 方向平移（m）
  double z_m = 3;        // Z 方向平移（m）
  double roll_rad = 4;   // 绕 X 轴旋转（rad）
  double pitch_rad = 5;  // 绕 Y 轴旋转（rad）
  double yaw_rad = 6;    // 绕 Z 轴旋转（rad）
}

// =========================================================
// 通用请求头
// 作用：带齐一次会话、任务、车辆、请求追踪信息
// 发送方：通常为 Ubuntu 车间电脑
// 接收方：Linux 内部服务 或 Windows 车端代理
// =========================================================
message RequestHeader {
  string session_id = 1;               // 本次整车标定会话 ID
  string task_id = 2;                  // 当前任务 ID / 阶段 ID
  string vehicle_id = 3;               // 车辆 ID
  string request_id = 4;               // 本次请求唯一 ID
  int64 client_send_timestamp_us = 5;  // 请求发送时间戳（微秒）
  string operator_id = 6;              // 操作员工号 / 工位号
  string workshop_host = 7;            // Ubuntu 车间电脑主机名
}

// =========================================================
// 统一错误码
// 作用：所有服务统一返回，便于编排器与状态机处理
// =========================================================
enum ErrorCode {
  ERROR_CODE_UNSPECIFIED = 0;   // 未指定
  OK = 1;                       // 正常
  INVALID_ARGUMENT = 2;         // 参数非法
  INVALID_STATE = 3;            // 当前状态不允许执行
  VEHICLE_BUSY = 4;             // 车辆当前忙
  NOT_READY = 5;                // 未准备好
  TIMEOUT = 6;                  // 超时
  NETWORK_LOSS = 7;             // 网络异常
  SAFETY_TRIGGERED = 8;         // 安全保护触发
  HARDWARE_FAULT = 9;           // 硬件故障
  FILE_NOT_FOUND = 10;          // 文件不存在
  CHECKSUM_MISMATCH = 11;       // 校验失败
  INTERNAL_ERROR = 12;          // 内部错误
  UNSUPPORTED_CAPABILITY = 13;  // 当前车辆不支持该能力
  RESOURCE_LOCKED = 14;         // 资源已被其他会话占用
  MANUAL_CONFIRM_REQUIRED = 15; // 需要人工确认后继续
  APPROVAL_REQUIRED = 16;       // 需要人工审批后继续
  VALIDATION_FAILED = 17;       // 验证未通过
  ROLLBACK_REQUIRED = 18;       // 需要参数回滚
  DATA_QUALITY_INSUFFICIENT = 19; // 数据质量不足
}

// =========================================================
// 通用短响应
// 作用：用于同步 RPC 的标准响应
// 发送方：服务端
// 接收方：调用方
// =========================================================
message StandardResponse {
  bool success = 1;           // 是否成功
  ErrorCode error_code = 2;   // 错误码
  string message = 3;         // 说明文字
}

// =========================================================
// 长任务状态
// 作用：用于异步任务状态表达
// =========================================================
enum JobState {
  JOB_STATE_UNSPECIFIED = 0;  // 未指定
  PENDING = 1;                // 已受理，等待执行
  RUNNING = 2;                // 执行中
  WAITING_MANUAL = 3;         // 等待人工操作 / 确认
  WAITING_APPROVAL = 4;       // 等待审批
  SUCCEEDED = 5;              // 成功
  FAILED = 6;                 // 失败
  CANCELED = 7;               // 已取消
  ROLLED_BACK = 8;            // 已回滚
}

// =========================================================
// 长任务受理响应
// 作用：耗时任务先返回 job_id，后续轮询状态
// 发送方：服务端
// 接收方：Ubuntu 车间电脑
// =========================================================
message JobAccepted {
  bool accepted = 1;          // 是否受理成功
  ErrorCode error_code = 2;   // 未受理时的错误码
  string message = 3;         // 说明
  string job_id = 4;          // 长任务 ID
}

// =========================================================
// 长任务查询请求
// 作用：通过 job_id 查询执行状态
// 发送方：Ubuntu 车间电脑
// 接收方：Linux 服务 或 Windows 车端代理
// =========================================================
message JobQuery {
  RequestHeader header = 1;   // 请求头
  string job_id = 2;          // 任务 ID
}

// =========================================================
// 长任务状态响应
// 作用：返回任务执行状态、进度、错误信息
// 发送方：服务端
// 接收方：Ubuntu 车间电脑
// =========================================================
message JobStatus {
  string job_id = 1;               // 任务 ID
  JobState state = 2;              // 当前状态
  double progress = 3;             // 进度，建议范围 0.0 ~ 1.0
  ErrorCode error_code = 4;        // 当前错误码
  string message = 5;              // 状态说明
  int64 server_timestamp_us = 6;   // 服务端时间戳
  bool safe_to_retry = 7;          // 是否适合自动重试
}

// =========================================================
// 心跳请求
// 作用：保持 Linux 与 Windows 车端之间的在线状态
// 发送方：Ubuntu 车间电脑
// 接收方：Windows 车端代理 / Linux 子服务
// =========================================================
message HeartbeatRequest {
  RequestHeader header = 1;            // 请求头
  string agent_name = 2;               // 服务名 / 代理名
  int32 expect_next_heartbeat_ms = 3;  // 下次期望心跳间隔（ms）
}

// =========================================================
// 心跳响应
// 作用：反馈当前是否在线、是否可接任务
// 发送方：服务端
// 接收方：调用方
// =========================================================
message HeartbeatResponse {
  bool success = 1;               // 是否正常
  ErrorCode error_code = 2;       // 错误码
  string message = 3;             // 说明文字
  int64 server_timestamp_us = 4;  // 响应时间戳
  bool vehicle_ready = 5;         // 车辆 / 服务是否准备好接任务
}

// =========================================================
// Agent 就绪查询请求
// 作用：用于查询某个服务 / 代理 / 资源集合当前是否具备执行条件
// 使用场景：
// 1) 外部定位就绪检查
// 2) 车端控制服务就绪检查
// 3) 底盘服务就绪检查
// 4) 传感器服务就绪检查
// =========================================================
message AgentReadinessRequest {
  RequestHeader header = 1;             // 请求头
  string agent_name = 2;                // 目标服务 / 代理名称
  repeated string target_resource_ids = 3; // 指定资源 ID 列表，例如 sensor_id
  bool include_details = 4;             // 是否返回详细问题列表
}

// =========================================================
// 就绪问题项
// 作用：表达“当前为什么还不能执行任务”
// 使用场景：各专项服务 readiness 响应中的 issues 列表
// =========================================================
message ReadinessIssue {
  string issue_code = 1;                // 问题代码，便于程序识别
  string message = 2;                   // 问题说明
  ErrorCode mapped_error_code = 3;      // 映射到统一错误码
  bool blocking = 4;                    // 是否为阻塞问题
  string related_resource_id = 5;       // 关联资源 ID，例如某个传感器 ID
  repeated KeyValuePair metadata = 6;   // 扩展元数据
}

// =========================================================
// 文件摘要
// 作用：用于参数包、URDF、数据文件校验
// =========================================================
message FileDigest {
  string checksum_type = 1;   // 摘要算法，例如 sha256
  string checksum_value = 2;  // 摘要值
}

// =========================================================
// 文件引用
// 作用：用于报告、参数包、数据集、日志包等产物追溯
// =========================================================
message FileReference {
  string file_name = 1;           // 文件名
  string file_uri = 2;            // 文件路径 / URI
  int64 size_bytes = 3;           // 文件大小（字节）
  string description = 4;         // 文件说明
  FileDigest digest = 5;          // 文件摘要
}

// =========================================================
// 键值对
// 作用：用于扩展元数据，避免每次新增少量字段都改协议
// =========================================================
message KeyValuePair {
  string key = 1;     // 键
  string value = 2;   // 值
}
