From d3fe91302a865241b98c3454de492644fc55f6cc Mon Sep 17 00:00:00 2001 From: su Date: Thu, 20 Aug 2026 16:51:04 +0800 Subject: [PATCH] Release DLL-only UPM package v0.1.8 --- CHANGELOG.md | 7 + Documentation~/SDK_API_Reference.md | 636 ++++++++++++++++++---------- Documentation~/SDK_Configuration.md | 163 +++++-- Editor/Aisu.SIM1.Face.Editor.dll | Bin 20480 -> 22528 bytes Runtime/Aisu.SIM1.Face.Runtime.dll | Bin 124928 -> 125440 bytes package.json | 2 +- 6 files changed, 543 insertions(+), 265 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab52bb1..d66c52a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.8 + +- Added detailed API documentation for result codes, face state codes, module statuses, directions, image DPI, feature types, bio types, configuration enums, model fields, license statuses, and license features. +- Added configuration documentation for auto-verify exclusive command policies and runtime status code entry points. +- Updated `FaceModuleManager.Instance` to lazily create and open the manager during Play Mode. +- Added read-only `FaceModuleManager` Inspector config display and an Editor menu for creating or selecting the scene manager. + ## 0.1.7 - Fixed Unity runtime license binding so cached application parameters are used safely outside the Unity main thread. diff --git a/Documentation~/SDK_API_Reference.md b/Documentation~/SDK_API_Reference.md index bfa970d..cc2aa0b 100644 --- a/Documentation~/SDK_API_Reference.md +++ b/Documentation~/SDK_API_Reference.md @@ -1,188 +1,241 @@ -# SDK API Reference +# SI-M1 Face SDK 接口文档 -中文说明见 [SDK_API_Reference.zh-CN.md](SDK_API_Reference.zh-CN.md). +本文列出 SDK 对业务层推荐使用的公开 API。命名空间统一为 `Aisu.SIM1.Face.*`。 -This document lists the business-level API exposed by `xin.aisu.si-m1.face`. +## 1. 命名空间 -## Namespaces - -| Namespace | Description | +| 命名空间 | 说明 | |---|---| -| `Aisu.SIM1.Face.Core` | Manager, settings, callback adapter, logging, main-thread dispatch | -| `Aisu.SIM1.Face.Commands` | Business services, command service, encryption adapter | -| `Aisu.SIM1.Face.Protocol` | Protocol enums, packet build/parse helpers, encoding helpers | -| `Aisu.SIM1.Face.Transport` | Transport interface, serial transport, mock transport | -| `Aisu.SIM1.Face.Models` | Reply, note, user, verification, enrollment, image, and UVC models | +| `Aisu.SIM1.Face.Core` | Manager、配置、回调适配、日志、主线程调度 | +| `Aisu.SIM1.Face.Commands` | 业务服务、命令服务、加密接口 | +| `Aisu.SIM1.Face.Protocol` | 协议枚举、封包、拆包、编码工具 | +| `Aisu.SIM1.Face.Transport` | 通信接口、串口、Mock | +| `Aisu.SIM1.Face.Models` | Reply、Note、用户、验证、录入、图片、UVC 等模型 | -## FaceModuleManager +## 2. FaceModuleManager -Use `FaceModuleManager` as the recommended single entry point: +`FaceModuleManager` 是 SDK 推荐的统一入口。 ```csharp using Aisu.SIM1.Face.Core; ``` -### Properties +### 属性 -| Property | Type | Description | +| 属性 | 类型 | 说明 | |---|---|---| -| `Basic` | `FaceBasicService` | Basic module commands | -| `Verify` | `FaceVerifyService` | Face verification service | -| `Enrollment` | `FaceEnrollmentService` | Face enrollment service | -| `Users` | `FaceUserService` | User management service | -| `QrCode` | `FaceQrCodeService` | QR code service | -| `Images` | `FaceImageService` | Image capture and photo enrollment service | -| `Features` | `FaceFeatureService` | Feature read/write service | -| `Uvc` | `FaceUvcService` | UVC and advanced parameter service | -| `Encryption` | `FaceEncryptionService` | Encryption service | -| `Callback` | `FaceModuleCallbackAdapter` | Callback-style API adapter | -| `IsOpen` | `bool` | Whether the transport is open | -| `IsReady` | `bool` | Whether READY has been received | -| `CurrentStatus` | `FaceModuleStatus` | Current module status | -| `LastError` | `string` | Latest error message | -| `CurrentCommand` | `string` | Current command name | -| `Config` | `FaceModuleConfig` | Current runtime config | -| `Settings` | `FaceSdkSettings` | Bound settings asset | +| `Basic` | `FaceBasicService` | 基础命令服务 | +| `Verify` | `FaceVerifyService` | 人脸验证服务 | +| `Enrollment` | `FaceEnrollmentService` | 人脸录入服务 | +| `Users` | `FaceUserService` | 用户管理服务 | +| `QrCode` | `FaceQrCodeService` | 二维码服务 | +| `Images` | `FaceImageService` | 图片抓拍与照片注册服务 | +| `Features` | `FaceFeatureService` | 特征读写服务 | +| `Uvc` | `FaceUvcService` | UVC 和高级参数服务 | +| `Encryption` | `FaceEncryptionService` | 加密相关服务 | +| `Callback` | `FaceModuleCallbackAdapter` | 回调式 API 适配 | +| `IsOpen` | `bool` | 通信是否打开 | +| `IsReady` | `bool` | 是否收到 READY | +| `CurrentStatus` | `FaceModuleStatus` | 当前模组状态 | +| `LastError` | `string` | 最近错误文本 | +| `CurrentCommand` | `string` | 当前命令名 | +| `Config` | `FaceModuleConfig` | 当前运行配置 | +| `Settings` | `FaceSdkSettings` | 当前绑定配置资产 | -### Methods +### 方法 -| Method | Description | +| 方法 | 说明 | |---|---| -| `ConfigureTransport(IFaceModuleTransport transport)` | Inject a custom transport | -| `Configure(bool useMockInEditor, string portName, int baudRate)` | Quick configuration for legacy code | -| `ApplySettings(FaceSdkSettings sdkSettings)` | Apply ScriptableObject settings and rebuild transport | -| `Open()` | Open transport | -| `Close()` | Stop active face operations and close transport | -| `CloseAsync()` | Stop active face operations and close transport asynchronously | -| `StopFaceOperationAsync()` | Stop auto verify or reset the current face flow | -| `StartAutoVerifyAsync(byte timeout)` | Start auto verify and return the control command result | -| `StopAutoVerifyAsync(byte timeout = 1)` | Stop auto verify and return the control command result | -| `WaitReadyAsync(int timeoutMs = 5000)` | Wait for READY note | -| `ProbeReadyByStatusAsync()` | Query status and mark manager ready | -| `SendRawBytes(byte[] bytes)` | Send raw protocol bytes | -| `RefreshStatus()` | Asynchronously refresh `CurrentStatus` | +| `ConfigureTransport(IFaceModuleTransport transport)` | 注入自定义通信层 | +| `Configure(bool useMockInEditor, string portName, int baudRate)` | 兼容旧代码的快速配置入口 | +| `ApplySettings(FaceSdkSettings sdkSettings)` | 应用 ScriptableObject 配置并重建 transport | +| `Open()` | 打开通信 | +| `Close()` | 同步安全关闭硬件流程并关闭串口 | +| `CloseAsync()` | 异步安全关闭硬件流程并关闭串口 | +| `StopFaceOperationAsync()` | 停止当前人脸流程,优先关闭自动验证 | +| `StartAutoVerifyAsync(byte timeout)` | 开启自动验证,返回开关命令结果 | +| `StopAutoVerifyAsync(byte timeout = 1)` | 关闭自动验证,返回开关命令结果 | +| `WaitReadyAsync(int timeoutMs = 5000)` | 等待 READY NOTE | +| `ProbeReadyByStatusAsync()` | 主动查询状态并标记 READY | +| `SendRawBytes(byte[] bytes)` | 发送原始协议 bytes | +| `RefreshStatus()` | 异步刷新 `CurrentStatus` | -### Events +真实串口运行前会自动校验 SDK 授权。授权文件默认路径: -| Event | Description | +```text +Assets/StreamingAssets/si-m1_face.dat +``` + +### 事件 + +| 事件 | 说明 | |---|---| -| `OnReady` | First READY event | -| `OnStatusChanged(FaceModuleStatus)` | Module status changed | -| `OnReplyReceived(FaceReply)` | REPLY packet received | -| `OnNoteReceived(FaceNote)` | NOTE packet received | -| `OnFaceStateUpdated(FaceFaceStateNote)` | Face state NOTE received | -| `OnAutoVerifyResult(FaceAutoVerifyResult)` | Auto verify result NOTE received | -| `OnQrCodeReceived(string)` | QR code NOTE received | -| `OnFeatureReceived(byte[])` | Feature data packet received | -| `OnDataPacketReceived(FacePacket)` | Image/template data packet received | -| `OnError(FaceResultCode, string)` | Error reported | -| `OnRawLog(string)` | Raw TX/RX log | +| `OnReady` | 首次 READY | +| `OnStatusChanged(FaceModuleStatus)` | 当前状态变化 | +| `OnReplyReceived(FaceReply)` | 收到 REPLY 包 | +| `OnNoteReceived(FaceNote)` | 收到 NOTE 包 | +| `OnFaceStateUpdated(FaceFaceStateNote)` | 收到人脸状态 NOTE | +| `OnAutoVerifyResult(FaceAutoVerifyResult)` | 收到自动验证识别结果 NOTE | +| `OnQrCodeReceived(string)` | 收到二维码 NOTE | +| `OnFeatureReceived(byte[])` | 收到读取特征数据包 | +| `OnDataPacketReceived(FacePacket)` | 收到 ImageOrTemplate 数据包 | +| `OnError(FaceResultCode, string)` | 错误上报 | +| `OnRawLog(string)` | 原始 TX / RX 日志 | -## Async Services +## 3. 基础服务 FaceBasicService -### FaceBasicService +访问路径: -Access path: `manager.Basic` +```csharp +manager.Basic +``` -| Method | Return | Description | +| 方法 | 返回 | 说明 | |---|---|---| -| `ResetAsync()` | `Task` | Reset module | -| `FaceResetAsync()` | `Task` | Cancel current face flow | -| `GetStatusAsync()` | `Task` | Get module status | -| `GetVersionAsync()` | `Task` | Get firmware version | -| `GetSnAsync()` | `Task` | Get device serial number | -| `SetDemoModeAsync(bool enable)` | `Task` | Set Demo Mode | -| `UpgradeFirmwareAsync()` | `Task` | Start firmware upgrade command | +| `ResetAsync()` | `Task` | 复位模组 | +| `FaceResetAsync()` | `Task` | 取消当前人脸流程 | +| `GetStatusAsync()` | `Task` | 获取模组状态 | +| `GetVersionAsync()` | `Task` | 获取固件版本 | +| `GetSnAsync()` | `Task` | 获取设备序列号 | +| `SetDemoModeAsync(bool enable)` | `Task` | 设置 Demo Mode | +| `UpgradeFirmwareAsync()` | `Task` | 启动固件升级命令 | -### FaceVerifyService +## 4. 验证服务 FaceVerifyService -Access path: `manager.Verify` +访问路径: -| Method | Return | Description | +```csharp +manager.Verify +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `VerifyAsync(byte timeout, byte maxRecognitionTimes = 30)` | `Task` | Run one face verification | -| `AutoVerifyAsync(bool enable, byte timeout)` | `Task` | Low-level auto verify control command | +| `VerifyAsync(byte timeout, byte maxRecognitionTimes = 30)` | `Task` | 单次人脸验证 | +| `AutoVerifyAsync(bool enable, byte timeout)` | `Task` | 底层自动验证开关命令,只表示开关命令 ACK | -For application code, prefer `FaceModuleManager.StartAutoVerifyAsync()` and `FaceModuleManager.StopAutoVerifyAsync()`. Recognition results are delivered through `OnAutoVerifyResult`. +推荐业务层使用 `FaceModuleManager.StartAutoVerifyAsync()` 和 `FaceModuleManager.StopAutoVerifyAsync()` 控制自动验证,识别结果通过 `OnAutoVerifyResult` 获取。 -### FaceEnrollmentService +```csharp +var control = await manager.StartAutoVerifyAsync(10); +if (control.Success) +{ + manager.OnAutoVerifyResult += result => + { + Debug.Log("自动验证结果: " + result.ResultCode); + }; +} +``` -Access path: `manager.Enrollment` +`StartAutoVerifyAsync()` / `StopAutoVerifyAsync()` 的返回值是 `FaceAutoVerifyControlResult`,表示开启或关闭命令是否成功,不表示识别结果。 -| Method | Return | Description | +## 5. 录入服务 FaceEnrollmentService + +访问路径: + +```csharp +manager.Enrollment +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `EnrollAsync(bool admin, string userName, FaceDirection direction, byte timeout)` | `Task` | Interactive multi-direction enrollment | -| `EnrollSingleAsync(bool admin, string userName, byte timeout)` | `Task` | Single-frame enrollment | -| `EnrollIntegratedAsync(bool admin, string userName, FaceDirection direction, byte timeout, bool singleFrame = false, bool duplicateCheck = true)` | `Task` | Integrated enrollment | -| `EnrollSnapFaceImageAsync(bool admin, string userName)` | `Task` | Capture face image and enroll | +| `EnrollAsync(bool admin, string userName, FaceDirection direction, byte timeout)` | `Task` | 交互式多方向录入 | +| `EnrollSingleAsync(bool admin, string userName, byte timeout)` | `Task` | 单帧录入 | +| `EnrollIntegratedAsync(bool admin, string userName, FaceDirection direction, byte timeout, bool singleFrame = false, bool duplicateCheck = true)` | `Task` | 集成式录入 | +| `EnrollSnapFaceImageAsync(bool admin, string userName)` | `Task` | 抓拍人脸后注册 | -### FaceUserService +## 6. 用户服务 FaceUserService -Access path: `manager.Users` +访问路径: -| Method | Return | Description | +```csharp +manager.Users +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `DeleteUserAsync(int userId)` | `Task` | Delete a user | -| `DeleteAllAsync()` | `Task` | Delete all users | -| `GetUserInfoAsync(int userId)` | `Task` | Query one user | -| `GetAllUserIdsAsync()` | `Task>` | Query all user IDs | -| `GetAllUserIds2Async()` | `Task>` | Query all user IDs with extended command | -| `GetAllUserInfosAsync()` | `Task>` | Query all user details | -| `GetAllUserInfos2Async()` | `Task>` | Query all user details with extended command | +| `DeleteUserAsync(int userId)` | `Task` | 删除指定用户 | +| `DeleteAllAsync()` | `Task` | 删除全部用户 | +| `GetUserInfoAsync(int userId)` | `Task` | 查询用户信息 | +| `GetAllUserIdsAsync()` | `Task>` | 查询用户 ID 列表 | +| `GetAllUserIds2Async()` | `Task>` | 使用扩展命令查询用户 ID 列表 | +| `GetAllUserInfosAsync()` | `Task>` | 查询全部用户详情 | +| `GetAllUserInfos2Async()` | `Task>` | 使用扩展命令查询全部用户详情 | -### FaceQrCodeService +## 7. 二维码服务 FaceQrCodeService -Access path: `manager.QrCode` +访问路径: -| Method | Return | Description | +```csharp +manager.QrCode +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `ScanQrCodeAsync(byte timeout)` | `Task` | Scan QR code and return content | +| `ScanQrCodeAsync(byte timeout)` | `Task` | 扫描二维码并返回内容 | -### FaceImageService +## 8. 图片服务 FaceImageService -Access path: `manager.Images` +访问路径: -| Method | Return | Description | +```csharp +manager.Images +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `SnapUploadImageAsync()` | `Task` | Capture normal image | -| `SnapUploadFaceImageAsync()` | `Task` | Capture face image | -| `SnapUploadLargeImageAsync(ImageDpi dpi)` | `Task` | Capture large image | -| `EnrollWithPhotoAsync(byte[] photoBytes, BioType type, string userName = null, bool duplicateCheck = true, Action onProgress = null)` | `Task` | Enroll with photo | -| `EnrollWithPhotoAndIdAsync(int userId, byte[] photoBytes, BioType type, string userName = null, bool duplicateCheck = true, Action onProgress = null)` | `Task` | Enroll photo with specified user ID | +| `SnapUploadImageAsync()` | `Task` | 抓拍普通图片 | +| `SnapUploadFaceImageAsync()` | `Task` | 抓拍人脸图片 | +| `SnapUploadLargeImageAsync(ImageDpi dpi)` | `Task` | 抓拍大图 | +| `EnrollWithPhotoAsync(byte[] photoBytes, BioType type, string userName = null, bool duplicateCheck = true, Action onProgress = null)` | `Task` | 照片注册 | +| `EnrollWithPhotoAndIdAsync(int userId, byte[] photoBytes, BioType type, string userName = null, bool duplicateCheck = true, Action onProgress = null)` | `Task` | 指定用户 ID 照片注册 | -### FaceFeatureService +## 9. 特征服务 FaceFeatureService -Access path: `manager.Features` +访问路径: -| Method | Return | Description | +```csharp +manager.Features +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `ReadFeatureAsync(int userId, FeatureType type)` | `Task` | Read user feature | -| `WriteFeatureAsync(byte[] featureBytes, FeatureType type, string userName = null, Action onProgress = null)` | `Task` | Write feature and enroll | +| `ReadFeatureAsync(int userId, FeatureType type)` | `Task` | 读取指定用户特征 | +| `WriteFeatureAsync(byte[] featureBytes, FeatureType type, string userName = null, Action onProgress = null)` | `Task` | 写入特征并注册 | -### FaceUvcService +## 10. UVC 和高级参数 FaceUvcService -Access path: `manager.Uvc` +访问路径: -| Method | Return | Description | +```csharp +manager.Uvc +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `ReadUsbUvcParametersAsync()` | `Task` | Read USB/UVC parameters | -| `SetUsbUvcParametersAsync(UsbUvcParameters parameters)` | `Task` | Set USB/UVC parameters | -| `SetFaceLocationDisplayAsync(bool visible)` | `Task` | Set face rectangle display | -| `SetRgbLevelAsync(byte level)` | `Task` | Set RGB level | -| `SetDuplicateCheckAsync(bool enableCheck)` | `Task` | Set duplicate check | -| `ReadDuplicateCheckAsync()` | `Task` | Read duplicate check state | +| `ReadUsbUvcParametersAsync()` | `Task` | 读取 USB / UVC 参数 | +| `SetUsbUvcParametersAsync(UsbUvcParameters parameters)` | `Task` | 设置 USB / UVC 参数 | +| `SetFaceLocationDisplayAsync(bool visible)` | `Task` | 设置人脸框显示 | +| `SetRgbLevelAsync(byte level)` | `Task` | 设置 RGB 阈值 | +| `SetDuplicateCheckAsync(bool enableCheck)` | `Task` | 设置查重 | +| `ReadDuplicateCheckAsync()` | `Task` | 读取查重状态 | -### FaceEncryptionService +## 11. 加密服务 FaceEncryptionService -Access path: `manager.Encryption` +访问路径: -| Method | Return | Description | +```csharp +manager.Encryption +``` + +| 方法 | 返回 | 说明 | |---|---|---| -| `SetReleaseEncryptionKeyAsync(byte[] key16)` | `Task` | Set release encryption key | -| `SetDebugEncryptionKeyAsync(byte[] key16)` | `Task` | Set debug encryption key | -| `InitEncryptionAsync(byte[] seed4, byte mode)` | `Task` | Initialize encryption | -| `EnableEncryption(IFaceModuleCrypto crypto)` | `void` | Enable local crypto adapter | -| `DisableEncryption()` | `void` | Disable local crypto adapter | +| `SetReleaseEncryptionKeyAsync(byte[] key16)` | `Task` | 设置 Release 加密密钥 | +| `SetDebugEncryptionKeyAsync(byte[] key16)` | `Task` | 设置 Debug 加密密钥 | +| `InitEncryptionAsync(byte[] seed4, byte mode)` | `Task` | 初始化加密流程 | +| `EnableEncryption(IFaceModuleCrypto crypto)` | `void` | 设置本地加密算法适配器 | +| `DisableEncryption()` | `void` | 关闭本地加密算法适配器 | + +`IFaceModuleCrypto`: ```csharp public interface IFaceModuleCrypto @@ -193,108 +246,239 @@ public interface IFaceModuleCrypto } ``` -## Callback API +## 12. 回调式 API -`FaceModuleManager.Callback` is useful for Unity UI, button events, legacy callback-style code, or workflows where `await` is inconvenient. +`FaceModuleManager.Callback` 适合 Unity Button、旧项目回调风格或不方便使用 `await` 的业务。 -Callbacks use a consistent pattern: +```csharp +manager.Callback.Verify( + timeout: 10, + success: result => Debug.Log(result.UserId), + error: message => Debug.LogError(message)); +``` -- `success` is invoked on success. -- `error` receives an error message on failure. -- Photo enrollment and feature writing support `progress(current, total)`. -- Callbacks are dispatched back to the Unity main thread through `FaceModuleMainThreadDispatcher`. +回调特点: -### Lifecycle and Transport +- 所有 API 统一使用 `success` 和 `error`。 +- 照片注册、特征写入支持 `progress(current, total)`。 +- 回调会通过 `FaceModuleMainThreadDispatcher` 回到 Unity 主线程。 -| Method | Success Callback | Description | -|---|---|---| -| `ConfigureTransport(IFaceModuleTransport transport, Action success, Action error)` | `Action` | Inject custom transport | -| `Configure(bool useMockInEditor, string portName, int baudRate, Action success, Action error)` | `Action` | Configure default transport parameters | -| `Open(Action success, Action error)` | `Action` | Open transport | -| `Close(Action success, Action error)` | `Action` | Close transport | -| `StopFaceOperation(Action success, Action error)` | `Action` | Stop auto verify or reset current face flow | -| `SendRawBytes(byte[] bytes, Action success, Action error)` | `Action` | Send raw bytes | -| `WaitReady(int timeoutMs, Action success, Action error)` | `Action` | Wait for READY | -| `ProbeReadyByStatus(Action success, Action error)` | `Action` | Probe status and mark ready | +## 13. 主要模型 -### Basic Commands - -| Method | Success Callback | Description | -|---|---|---| -| `Reset(Action success, Action error)` | `Action` | Reset module | -| `FaceReset(Action success, Action error)` | `Action` | Cancel current face flow | -| `GetStatus(Action success, Action error)` | `Action` | Get module status | -| `GetVersion(Action success, Action error)` | `Action` | Get firmware version | -| `GetSn(Action success, Action error)` | `Action` | Get device serial number | -| `SetDemoMode(bool enable, Action success, Action error)` | `Action` | Set Demo Mode | -| `UpgradeFirmware(Action success, Action error)` | `Action` | Start firmware upgrade | - -### Verification and Enrollment - -| Method | Success Callback | Description | -|---|---|---| -| `Verify(byte timeout, Action success, Action error, byte maxRecognitionTimes = 30)` | `Action` | Run face verification | -| `AutoVerify(bool enable, byte timeout, Action success, Action error)` | `Action` | Low-level auto verify control command | -| `StartAutoVerify(byte timeout, Action success, Action error)` | `Action` | Start auto verify | -| `StopAutoVerify(byte timeout, Action success, Action error)` | `Action` | Stop auto verify | -| `Enroll(bool admin, string userName, FaceDirection direction, byte timeout, Action success, Action error)` | `Action` | Interactive enrollment | -| `EnrollSingle(bool admin, string userName, byte timeout, Action success, Action error)` | `Action` | Single-frame enrollment | -| `EnrollIntegrated(bool admin, string userName, FaceDirection direction, byte timeout, bool singleFrame, bool duplicateCheck, Action success, Action error)` | `Action` | Integrated enrollment | -| `EnrollSnapFaceImage(bool admin, string userName, Action success, Action error)` | `Action` | Capture face image and enroll | - -### Users - -| Method | Success Callback | Description | -|---|---|---| -| `DeleteUser(int userId, Action success, Action error)` | `Action` | Delete user | -| `DeleteAll(Action success, Action error)` | `Action` | Delete all users | -| `GetUserInfo(int userId, Action success, Action error)` | `Action` | Query one user | -| `GetAllUserIds(Action> success, Action error)` | `Action>` | Query all user IDs | -| `GetAllUserIds2(Action> success, Action error)` | `Action>` | Query all user IDs with extended command | -| `GetAllUserInfos(Action> success, Action error)` | `Action>` | Query all user details | -| `GetAllUserInfos2(Action> success, Action error)` | `Action>` | Query all user details with extended command | - -### QR Code, Images, and Features - -| Method | Success Callback | Description | -|---|---|---| -| `ScanQrCode(byte timeout, Action success, Action error)` | `Action` | Scan QR code | -| `SnapUploadImage(Action success, Action error)` | `Action` | Capture normal image | -| `SnapUploadFaceImage(Action success, Action error)` | `Action` | Capture face image | -| `SnapUploadLargeImage(ImageDpi dpi, Action success, Action error)` | `Action` | Capture large image | -| `EnrollWithPhoto(byte[] photoBytes, BioType type, string userName, bool duplicateCheck, Action success, Action error, Action progress = null)` | `Action` | Enroll with photo | -| `EnrollWithPhotoAndId(int userId, byte[] photoBytes, BioType type, string userName, bool duplicateCheck, Action success, Action error, Action progress = null)` | `Action` | Enroll photo with specified user ID | -| `ReadFeature(int userId, FeatureType type, Action success, Action error)` | `Action` | Read user feature | -| `WriteFeature(byte[] featureBytes, FeatureType type, string userName, Action success, Action error, Action progress = null)` | `Action` | Write feature and enroll | - -### UVC and Encryption - -| Method | Success Callback | Description | -|---|---|---| -| `ReadUsbUvcParameters(Action success, Action error)` | `Action` | Read USB/UVC parameters | -| `SetUsbUvcParameters(UsbUvcParameters parameters, Action success, Action error)` | `Action` | Set USB/UVC parameters | -| `SetFaceLocationDisplay(bool visible, Action success, Action error)` | `Action` | Set face rectangle display | -| `SetRgbLevel(byte level, Action success, Action error)` | `Action` | Set RGB level | -| `SetDuplicateCheck(bool enableCheck, Action success, Action error)` | `Action` | Set duplicate check | -| `ReadDuplicateCheck(Action success, Action error)` | `Action` | Read duplicate check state | -| `SetReleaseEncryptionKey(byte[] key16, Action success, Action error)` | `Action` | Set release encryption key | -| `SetDebugEncryptionKey(byte[] key16, Action success, Action error)` | `Action` | Set debug encryption key | -| `InitEncryption(byte[] seed4, byte mode, Action success, Action error)` | `Action` | Initialize encryption | -| `EnableEncryption(IFaceModuleCrypto crypto, Action success, Action error)` | `Action` | Enable local crypto adapter | -| `DisableEncryption(Action success, Action error)` | `Action` | Disable local crypto adapter | - -## Main Models - -| Type | Description | +| 类型 | 说明 | |---|---| -| `FaceReply` | REPLY packet parse result | -| `FaceNote` | NOTE packet parse result | -| `FaceFaceStateNote` | Face state NOTE | -| `FaceAutoVerifyResult` | Auto verify recognition result | -| `FaceAutoVerifyControlResult` | Auto verify start/stop command result | -| `FaceUserInfo` | User ID, name, and admin flag | -| `FaceVerifyResult` | Verification result, user info, unlock status | -| `FaceEnrollResult` | Enrollment result, user ID, direction | -| `FaceImageResult` | Image bytes, `Texture2D`, user ID | -| `UsbUvcParameters` | USB/UVC parameters | -| `FaceCommandException` | Exception thrown for unsuccessful command replies | +| `FaceReply` | REPLY 包解析结果 | +| `FaceNote` | NOTE 包解析结果 | +| `FaceFaceStateNote` | 人脸状态 NOTE | +| `FaceUserInfo` | 用户 ID、姓名、管理员标记 | +| `FaceVerifyResult` | 验证结果、用户信息、开锁状态 | +| `FaceAutoVerifyResult` | 自动验证识别结果 | +| `FaceAutoVerifyControlResult` | 自动验证开启/关闭命令结果 | +| `FaceEnrollResult` | 录入结果、用户 ID、方向 | +| `FaceImageResult` | 图片 bytes、Texture2D、用户 ID | +| `UsbUvcParameters` | USB / UVC 参数 | +| `FaceCommandException` | 底层命令 REPLY 非成功时抛出的异常 | + +高层业务 Result 类型统一使用 `Success` 和 `ResultCode`。`FaceReply` 是底层 REPLY 模型,也统一只暴露 `Success` 和 `ResultCode`。 + +### 13.1 常用模型字段 + +| 类型 | 字段 | 说明 | +|---|---|---| +| `FaceReply` | `Mid` | 对应的命令 ID | +| `FaceReply` | `Success` | `ResultCode == FaceResultCode.Success` | +| `FaceReply` | `ResultCode` | 模组返回结果码 | +| `FaceReply` | `Data` | REPLY 业务数据,不包含命令 ID 和结果码 | +| `FaceNote` | `Nid` | NOTE 类型 | +| `FaceNote` | `Data` | NOTE 业务数据,不包含 NOTE ID | +| `FaceFaceStateNote` | `State` | 人脸状态码 | +| `FaceFaceStateNote` | `Left` / `Top` / `Right` / `Bottom` | 人脸框坐标 | +| `FaceFaceStateNote` | `Yaw` / `Pitch` / `Roll` | 人脸姿态角 | +| `FaceUserInfo` | `UserId` | 用户 ID | +| `FaceUserInfo` | `UserName` | 用户名 | +| `FaceUserInfo` | `IsAdmin` | 是否管理员 | +| `FaceVerifyResult` | `Success` / `ResultCode` | 验证是否成功及结果码 | +| `FaceVerifyResult` | `UserId` / `UserName` / `IsAdmin` | 验证成功时的用户信息 | +| `FaceVerifyResult` | `UnlockStatus` | 模组返回的开锁状态 | +| `FaceAutoVerifyResult` | `Success` / `ResultCode` | 自动验证 NOTE 的识别结果 | +| `FaceAutoVerifyResult` | `VerifyResult` | 成功时解析出的验证结果详情 | +| `FaceAutoVerifyControlResult` | `Success` / `ResultCode` | 自动验证开关命令结果 | +| `FaceAutoVerifyControlResult` | `Enabled` | 本次命令目标状态 | +| `FaceAutoVerifyControlResult` | `Reply` | 底层开关命令 REPLY | +| `FaceEnrollResult` | `Success` / `ResultCode` | 录入是否成功及结果码 | +| `FaceEnrollResult` | `UserId` | 录入成功后分配或写入的用户 ID | +| `FaceEnrollResult` | `Direction` | 录入方向 | +| `FaceImageResult` | `Success` / `ResultCode` | 图片命令是否成功及结果码 | +| `FaceImageResult` | `UserId` | 照片注册相关用户 ID | +| `FaceImageResult` | `Bytes` | 图片原始 bytes | +| `FaceImageResult` | `Texture` | Unity `Texture2D` | +| `UsbUvcParameters` | `UsbType` | USB 输出类型 | +| `UsbUvcParameters` | `BitrateMbps` | 码率,单位 Mbps | +| `UsbUvcParameters` | `MjpgQuality` | MJPG 质量 | +| `UsbUvcParameters` | `Mirror` | 是否镜像 | +| `UsbUvcParameters` | `Rotate180` | 是否旋转 180 度 | + +### 13.2 FaceResultCode 结果码 + +`FaceResultCode` 会出现在 `FaceReply.ResultCode`、高层业务 Result、`OnError`、`FaceCommandException.ResultCode` 中。可使用 `FaceProtocolEncoding.ResultMessage(code)` 获取中文提示。 + +| 值 | 名称 | 说明 | +|---:|---|---| +| 0 | `Success` | 成功 | +| 1 | `Rejected` | 模组拒绝命令 | +| 2 | `Aborted` | 操作已终止 | +| 4 | `CameraOpenFailed` | 相机打开失败 | +| 5 | `UnknownReason` | 未知错误 | +| 6 | `InvalidParam` | 参数无效 | +| 7 | `NoMemory` | 内存不足 | +| 8 | `UnknownUser` | 未找到用户或没有已录入用户 | +| 9 | `MaxUser` | 超过最大用户数量 | +| 10 | `FaceEnrolled` | 人脸已录入 | +| 12 | `LivenessCheckFailed` | 活体检测失败 | +| 13 | `Timeout` | 操作超时 | +| 14 | `AuthorizationFailed` | 模组侧授权失败 | +| 19 | `ReadFileFailed` | 读文件失败 | +| 20 | `WriteFileFailed` | 写文件失败 | +| 21 | `NoEncrypt` | 通信未加密 | +| 23 | `NoRgbImage` | RGB 图像未就绪 | +| 24 | `JpgPhotoTooLarge` | JPG 照片过大 | +| 25 | `JpgPhotoTooSmall` | JPG 照片过小 | +| 26 | `DetectQr` | 识别过程中检测到二维码 | + +### 13.3 FaceStateCode 人脸状态码 + +`FaceStateCode` 来自 `OnFaceStateUpdated(FaceFaceStateNote)`,主要用于录入、检测和 UI 引导。可使用 `FaceProtocolEncoding.FaceStateMessage(code)` 获取中文提示。 + +| 值 | 名称 | 说明 | +|---:|---|---| +| 0 | `Normal` | 人脸正常 | +| 1 | `NoFace` | 未检测到人脸 | +| 2 | `TooUp` | 人脸太靠上 | +| 3 | `TooDown` | 人脸太靠下 | +| 4 | `TooLeft` | 人脸太靠左 | +| 5 | `TooRight` | 人脸太靠右 | +| 6 | `Far` | 距离太远 | +| 7 | `Close` | 距离太近 | +| 8 | `EyebrowOcclusion` | 眉毛遮挡 | +| 9 | `EyeOcclusion` | 眼睛遮挡 | +| 10 | `FaceOcclusion` | 脸部遮挡 | +| 11 | `DirectionError` | 录入方向错误 | +| 12 | `EyeCloseStatusOpenEye` | 闭眼检测中发现睁眼 | +| 13 | `EyeCloseStatus` | 当前为闭眼状态 | +| 14 | `EyeCloseUnknownStatus` | 无法判定睁闭眼状态 | +| 128 | `PalmDetected` | 检测到手掌信息 | + +### 13.4 业务常用枚举 + +| 枚举 | 值 | 说明 | +|---|---|---| +| `FaceModuleStatus` | `Standby = 0` | 模组待机 | +| `FaceModuleStatus` | `Busy = 1` | 模组忙碌 | +| `FaceModuleStatus` | `Error = 2` | 模组错误 | +| `FaceModuleStatus` | `Invalid = 3` | SDK 未知或无效状态 | +| `FaceDirection` | `Undefined = 0x00` | 未定义方向 | +| `FaceDirection` | `Middle = 0x01` | 正脸 | +| `FaceDirection` | `Right = 0x02` | 向右 | +| `FaceDirection` | `Left = 0x04` | 向左 | +| `FaceDirection` | `Down = 0x08` | 向下 | +| `FaceDirection` | `Up = 0x10` | 向上 | +| `BioType` | `NormalPhoto = 0` | 普通照片 | +| `BioType` | `EncryptedPhoto = 1` | 加密照片 | +| `BioType` | `NormalFeature = 2` | 普通特征 | +| `BioType` | `CompressedFeature = 3` | 压缩特征 | +| `FeatureType` | `ColorFace = 1` | 彩色人脸特征 | +| `FeatureType` | `ColorAndIrFace = 2` | 彩色加红外人脸特征 | +| `FeatureType` | `Palm = 3` | 手掌特征 | +| `ImageDpi` | `Dpi480x640 = 0` | 480x640 大图 | +| `ImageDpi` | `Dpi600x800 = 1` | 600x800 大图 | +| `ImageDpi` | `Dpi1200x1600 = 2` | 1200x1600 大图 | + +### 13.5 配置枚举 + +| 枚举 | 值 | 说明 | +|---|---|---| +| `FaceTransportMode` | `Auto = 0` | 默认通信模式,当前串口实现下等价于串口,Editor 可按 Mock 配置切换 | +| `FaceTransportMode` | `SerialPort = 1` | 强制使用串口通信 | +| `FaceTransportMode` | `Mock = 3` | 使用 Mock 模组 | +| `FaceExclusiveCommandPolicy` | `RejectWhenAutoVerifyEnabled = 0` | 自动验证开启时拒绝独占命令 | +| `FaceExclusiveCommandPolicy` | `StopAutoVerify = 1` | 独占命令前自动关闭自动验证 | +| `FaceExclusiveCommandPolicy` | `Ignore = 2` | 不处理自动验证状态,由业务自行保证不冲突 | + +## 14. 协议和通信底层 + +业务层通常不需要直接使用底层 API。需要协议调试或自定义通信时可使用: + +| 类型 | 说明 | +|---|---| +| `FacePacketBuilder` | 封包 | +| `FacePacketParser` | 拆包 | +| `FaceProtocolEncoding` | 用户名、ID、结果文本等编码工具 | +| `IFaceModuleTransport` | 通信接口 | +| `SerialPortTransport` | 串口实现 | +| `MockFaceModuleTransport` | Mock 实现 | + +## 15. 授权 API + +命名空间: + +```csharp +using Aisu.SIM1.Face.Core; +``` + +| 类型 | 说明 | +|---|---| +| `FaceLicenseManager` | 加载、验证授权 token,查询授权状态 | +| `FaceLicensePayload` | 授权 payload 数据 | +| `FaceLicenseStatus` | 授权状态枚举 | +| `FaceLicenseException` | 授权异常 | +| `FaceLicenseFeatures` | 功能授权常量 | +| `FaceUnityRuntimeBinding` | 读取 `identifier`、`companyName`、`productName`、`version`、`unityVersion` | + +常用方法: + +| 方法 | 说明 | +|---|---| +| `FaceLicenseManager.LoadAndVerify()` | 读取默认授权文件并验签 | +| `FaceLicenseManager.VerifyOrThrow()` | 授权无效时抛出异常 | +| `FaceLicenseManager.VerifyFeatureOrThrow(string feature)` | 功能未授权时抛出异常 | +| `FaceLicenseManager.IsFeatureEnabled(string feature)` | 查询功能是否授权 | +| `FaceLicenseVerifier.VerifyToken(string token)` | 验签并校验授权 payload | +| `FaceLicenseVerifier.ValidatePayload(FaceLicensePayload payload)` | 校验 payload 字段、有效期、功能和 Unity 绑定 | +| `FaceLicenseVerifier.GetBeijingNow()` | 获取 SDK 授权使用的当前北京时间 | +| `FaceLicenseVerifier.FormatBeijingTime(DateTimeOffset value)` | 格式化授权北京时间字符串 | +| `FaceLicenseVerifier.GetRemainingDays(FaceLicensePayload payload)` | 计算授权剩余天数 | + +### 15.1 FaceLicenseStatus + +| 值 | 名称 | 说明 | +|---:|---|---| +| 0 | `Unknown` | 尚未验证或状态未知 | +| 1 | `Valid` | 授权有效 | +| 2 | `MissingFile` | 授权文件不存在 | +| 3 | `InvalidFormat` | 授权格式无效 | +| 4 | `InvalidSignature` | 授权签名无效 | +| 5 | `ProductMismatch` | 产品 ID 不匹配 | +| 6 | `BindingMismatch` | Unity 绑定参数不匹配 | +| 7 | `Expired` | 授权已过期 | +| 8 | `FeatureDenied` | 功能未授权 | +| 9 | `PublicKeyInvalid` | SDK 公钥无效 | +| 10 | `ReadFailed` | 授权读取失败 | +| 11 | `NotYetValid` | 授权尚未生效 | + +### 15.2 FaceLicenseFeatures + +| 名称 | 说明 | +|---|---| +| `SerialRuntime` | 串口运行时 | +| `Basic` | 基础命令 | +| `Verify` | 人脸验证和自动验证 | +| `Enroll` | 人脸录入 | +| `UserManage` | 用户管理 | +| `QrCode` | 二维码 | +| `Image` | 图片抓拍、照片注册 | +| `Feature` | 特征读写 | +| `Uvc` | UVC 和高级参数 | +| `Encryption` | 加密通信 | +| `Firmware` | 固件升级 | + +Runtime 不提供 token 签发 API,也不提供公钥覆盖 API。授权签发只应存在于内部 Editor DLL 或独立授权工具中。 diff --git a/Documentation~/SDK_Configuration.md b/Documentation~/SDK_Configuration.md index f4060d1..6e292fc 100644 --- a/Documentation~/SDK_Configuration.md +++ b/Documentation~/SDK_Configuration.md @@ -1,75 +1,162 @@ -# SDK Configuration +# SI-M1 Face SDK 配置与 Editor 工具 -中文说明见 [SDK_Configuration.zh-CN.md](SDK_Configuration.zh-CN.md). +SDK 使用 `FaceSdkSettings` 作为推荐配置方式。该配置是 `ScriptableObject`,可在项目中复用,并可同步到场景中的 `FaceModuleManager`。 -The SDK uses `FaceSdkSettings` as the recommended configuration asset. `FaceModuleManager` can read this asset and synchronize the values into its runtime config. +## 1. 默认配置资产 -## Default Settings Asset +默认路径: ```text Assets/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset ``` -Open `AISU/SI-M1 Face SDK/Settings` to load, edit, and save the asset. +打开菜单 `AISU/SI-M1 Face SDK/Settings` 后,Editor 会加载该路径。若文件不存在,点击 `Load Default` 会创建默认资产。 -## FaceSdkSettings Fields +## 2. FaceSdkSettings 字段 -| Field | Type | Description | +| 字段 | 类型 | 说明 | |---|---|---| -| `TransportMode` | `FaceTransportMode` | `Auto`, `SerialPort`, or `Mock` | -| `UseMockInEditor` | `bool` | Force mock transport in Unity Editor | -| `PortName` | `string` | Runtime serial port | -| `BaudRate` | `int` | Runtime baud rate | -| `ReadBufferSize` | `int` | Runtime read buffer size | -| `UseEditorSerialDebugParameters` | `bool` | Use separate serial parameters in Editor | -| `EditorPortName` | `string` | Editor debug serial port | -| `EditorBaudRate` | `int` | Editor debug baud rate | -| `EditorReadBufferSize` | `int` | Editor debug read buffer size | -| `MockResponseDelayFrames` | `int` | Mock response delay in frames | -| `AutoVerifyOnOpen` | `bool` | Start auto verify after READY | -| `AutoVerifyTimeout` | `byte` | Auto verify protocol timeout in seconds | -| `AutoVerifyResultIntervalMs` | `int` | Minimum interval between auto verify result events | -| `StopAutoVerifyBeforeExclusiveCommand` | `bool` | Stop auto verify before exclusive commands | -| `ExclusiveCommandPolicy` | `FaceExclusiveCommandPolicy` | Policy when exclusive commands run during auto verify | -| `DebugLogEnabled` | `bool` | Enable SDK debug logs | -| `RawLogEnabled` | `bool` | Dispatch raw TX/RX logs | -| `LogPrefix` | `string` | Log prefix | +| `TransportMode` | `FaceTransportMode` | 通信模式:`Auto`、`SerialPort`、`Mock` | +| `UseMockInEditor` | `bool` | Editor 下是否强制使用 Mock | +| `PortName` | `string` | Player / 运行时串口号 | +| `BaudRate` | `int` | Player / 运行时波特率 | +| `ReadBufferSize` | `int` | Player / 运行时读取缓冲区 | +| `UseEditorSerialDebugParameters` | `bool` | Editor 下连接真实串口时是否使用单独参数 | +| `EditorPortName` | `string` | Editor 调试串口号 | +| `EditorBaudRate` | `int` | Editor 调试波特率 | +| `EditorReadBufferSize` | `int` | Editor 调试读取缓冲区 | +| `MockResponseDelayFrames` | `int` | Mock 响应延迟帧数 | +| `AutoVerifyOnOpen` | `bool` | READY 后是否自动开启验证 | +| `AutoVerifyTimeout` | `byte` | 自动验证协议超时时间,单位秒 | +| `AutoVerifyResultIntervalMs` | `int` | 自动验证结果最小派发间隔,0 表示不节流 | +| `StopAutoVerifyBeforeExclusiveCommand` | `bool` | 独占业务命令前是否自动关闭自动验证 | +| `ExclusiveCommandPolicy` | `FaceExclusiveCommandPolicy` | 自动验证开启时的独占命令处理策略 | +| `DebugLogEnabled` | `bool` | 是否启用 SDK Debug 日志 | +| `RawLogEnabled` | `bool` | 是否派发原始 TX / RX 日志 | +| `LogPrefix` | `string` | 日志前缀 | -## TransportMode +## 3. TransportMode 选择 -| Mode | Behavior | +| 模式 | 行为 | |---|---| -| `Auto` | Editor chooses mock or serial based on `UseMockInEditor`; Player uses serial | -| `SerialPort` | Use `SerialPortTransport` | -| `Mock` | Use `MockFaceModuleTransport` | +| `Auto` | Editor 根据 `UseMockInEditor` 选择 Mock 或串口;Player 使用串口 | +| `SerialPort` | 使用 `SerialPortTransport` | +| `Mock` | 使用 `MockFaceModuleTransport` | -When `UseMockInEditor = true`, the Editor uses mock transport and does not open a real serial port. +Editor 下有一个额外优先级: -## Auto Verify +```text +UseMockInEditor = true 时,强制使用 Mock,不打开真实串口。 +``` -`AutoVerifyTimeout` is sent to the SI-M1 module as the recognition timeout. +因此 Editor 中如果需要连接真实串口,必须将 `UseMockInEditor` 设为 `false`。 -`AutoVerifyResultIntervalMs` is handled by the Unity SDK. It limits how frequently `OnAutoVerifyResult` is dispatched when the module sends continuous auto verify NOTE packets. Set it to `0` to dispatch every result. +## 4. Editor Serial Debug 参数 -`StopAutoVerifyBeforeExclusiveCommand` and `ExclusiveCommandPolicy` control how enrollment, user management, QR code, image capture, and feature operations behave while auto verify is active. +Editor 连接真实硬件时,建议开启: -## Runtime Usage +```text +UseEditorSerialDebugParameters = true +``` + +开启后,Editor 中串口使用: + +- `EditorPortName` +- `EditorBaudRate` +- `EditorReadBufferSize` + +Player 中仍使用: + +- `PortName` +- `BaudRate` +- `ReadBufferSize` + +这样可以避免 Editor 调试口和发布运行口互相覆盖。 + +## 5. Editor 工具按钮 + +配置窗口按钮: + +| 按钮 | 行为 | +|---|---| +| `Load Default` | 固定加载或创建默认路径的 `FaceSdkSettings.asset` | +| `Save` | 保存当前配置并同步场景中的 Manager | +| `Save and Create/Update Manager` | 保存配置后创建或更新场景 Manager | + +同步 Manager 时会写入: + +- `m_settings` +- `m_config.TransportMode` +- `m_config.UseMockInEditor` +- 串口参数 +- Editor 串口参数 +- Mock 延迟 +- 自动验证配置 +- Raw Log 开关 + +PlayMode 中同步配置时,会调用 `FaceModuleManager.ApplySettings(settings)`,立即重建当前 transport。 + +## 6. Manager 配置方式 + +推荐方式: ```csharp manager.ApplySettings(settings); manager.Open(); ``` -Quick configuration: +兼容方式: ```csharp manager.Configure(useMockInEditor: true, portName: "COM3", baudRate: 115200); manager.Open(); ``` -Custom transport: +外部通信层注入: ```csharp manager.ConfigureTransport(customTransport); manager.Open(); ``` + +## 7. 场景约束 + +每个场景建议只保留一个 `FaceModuleManager`。 + +多个 Manager 可能导致: + +- 多次打开同一串口。 +- 重复接收和派发事件。 +- UI 状态不一致。 + +`Create Manager GameObject` 菜单会校验 Manager 数量,并在存在多个 Manager 时停止创建。 + +## 8. 自动验证配置 + +`AutoVerifyTimeout` 是发送给模组的协议超时时间,不是结果间隔。 + +`AutoVerifyResultIntervalMs` 是 Unity SDK 侧的事件节流间隔。自动验证开启后,硬件可能持续通过 NOTE 上报识别结果,SDK 会按该间隔派发 `OnAutoVerifyResult`,避免 UI 或业务层被连续结果刷爆。 + +关闭连接时,`FaceModuleManager.Close()` 和 `CloseAsync()` 会先尝试关闭自动验证,再执行 `FaceResetAsync()`,最后关闭串口。`OnApplicationQuit()` 也会走同一套安全关闭流程,避免应用退出后硬件继续检测。 + +## 9. 独占命令策略 + +自动验证开启后,模组会持续进行检测。录入、删除、查询、照片注册等业务命令可能与自动验证互相冲突。`FaceExclusiveCommandPolicy` 用于控制 SDK 在执行这些命令前如何处理自动验证状态。 + +| 值 | 行为 | 适用场景 | +|---|---|---| +| `RejectWhenAutoVerifyEnabled` | 自动验证开启时直接拒绝独占命令 | 希望业务层显式控制状态切换 | +| `StopAutoVerify` | SDK 在独占命令前自动关闭自动验证 | 默认推荐,减少业务层重复处理 | +| `Ignore` | SDK 不处理自动验证状态 | 调试或自定义流程,业务层自行保证不冲突 | + +## 10. 运行时状态码入口 + +配置项会影响以下运行时状态和返回值,详细枚举表见 `SDK_API_Reference.md`。 + +| 类型 | 使用位置 | 说明 | +|---|---|---| +| `FaceResultCode` | `ResultCode`、`OnError`、`FaceCommandException` | 命令和业务结果码 | +| `FaceStateCode` | `OnFaceStateUpdated` | 人脸位置、遮挡、闭眼等状态 | +| `FaceModuleStatus` | `CurrentStatus`、`GetStatusAsync()` | 模组待机、忙碌、错误状态 | +| `FaceTransportMode` | `FaceSdkSettings.TransportMode` | 通信模式 | +| `FaceExclusiveCommandPolicy` | `FaceSdkSettings.ExclusiveCommandPolicy` | 自动验证与独占命令冲突策略 | diff --git a/Editor/Aisu.SIM1.Face.Editor.dll b/Editor/Aisu.SIM1.Face.Editor.dll index 8716ef1966178bb323d238fe815097384fd6e33c..f2e0b6b5ae58cca843d4d43c9b3efe68503954a4 100644 GIT binary patch literal 22528 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

kqdcy7 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 TG5>^J56{;9ZtxxMF^&EkM