diff --git a/CHANGELOG.md b/CHANGELOG.md index 19aba6a..f993d79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.1.6 + +- Added `FaceModuleManager` singleton lifecycle validation. +- Added default `FaceSdkSettings` loading from `Resources/AISU/SI-M1 Face SDK/FaceSdkSettings`. +- Added auto verify state, start/stop APIs, auto verify result event dispatch, and exclusive operation conflict handling. +- Added auto verify configuration fields to `FaceSdkSettings`. +- Limited Editor menu entries to Settings and License. +- Updated samples to use explicit auto verify start/stop and exclusive operation preparation. + ## 0.1.5 - Fixed Unity 2021 compatibility for the obfuscated Runtime and Editor DLLs by removing invalid `System.Private.CoreLib` assembly references introduced during obfuscation. diff --git a/Editor/Aisu.SIM1.Face.Editor.dll b/Editor/Aisu.SIM1.Face.Editor.dll index e2ef8c4..3588558 100644 Binary files a/Editor/Aisu.SIM1.Face.Editor.dll and b/Editor/Aisu.SIM1.Face.Editor.dll differ diff --git a/Resources.meta b/Resources.meta new file mode 100644 index 0000000..6ed41eb --- /dev/null +++ b/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38a8adf823e04ed4ba6e7819d0d6f001 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Resources/AISU.meta b/Resources/AISU.meta new file mode 100644 index 0000000..76756fd --- /dev/null +++ b/Resources/AISU.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38a8adf823e04ed4ba6e7819d0d6f002 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Resources/AISU/SI-M1 Face SDK.meta b/Resources/AISU/SI-M1 Face SDK.meta new file mode 100644 index 0000000..b619310 --- /dev/null +++ b/Resources/AISU/SI-M1 Face SDK.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38a8adf823e04ed4ba6e7819d0d6f003 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset b/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset new file mode 100644 index 0000000..96e153c --- /dev/null +++ b/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset @@ -0,0 +1,31 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8f79a6ea36b743d49ac4f2de7f2ea81f, type: 3} + m_Name: FaceSdkSettings + m_EditorClassIdentifier: + m_transportMode: 0 + m_useMockInEditor: 0 + m_portName: COM3 + m_baudRate: 115200 + m_readBufferSize: 4096 + m_useEditorSerialDebugParameters: 1 + m_editorPortName: COM3 + m_editorBaudRate: 115200 + m_editorReadBufferSize: 4096 + m_mockResponseDelayFrames: 1 + m_autoVerifyOnOpen: 0 + m_autoVerifyTimeout: 10 + m_stopAutoVerifyBeforeExclusiveCommand: 1 + m_exclusiveCommandPolicy: 1 + m_debugLogEnabled: 1 + m_rawLogEnabled: 1 + m_logPrefix: '[FaceModule]' diff --git a/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset.meta b/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset.meta new file mode 100644 index 0000000..806aaa7 --- /dev/null +++ b/Resources/AISU/SI-M1 Face SDK/FaceSdkSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38a8adf823e04ed4ba6e7819d0d6f004 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Aisu.SIM1.Face.Runtime.dll b/Runtime/Aisu.SIM1.Face.Runtime.dll index ff7671c..e2be0d4 100644 Binary files a/Runtime/Aisu.SIM1.Face.Runtime.dll and b/Runtime/Aisu.SIM1.Face.Runtime.dll differ diff --git a/Samples~/Face Detection Demo/Scripts/FaceDetectionDemoController.cs b/Samples~/Face Detection Demo/Scripts/FaceDetectionDemoController.cs index e021961..faa0335 100644 --- a/Samples~/Face Detection Demo/Scripts/FaceDetectionDemoController.cs +++ b/Samples~/Face Detection Demo/Scripts/FaceDetectionDemoController.cs @@ -64,6 +64,7 @@ namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo m_manager.OnError += OnManagerError; m_manager.OnReady += OnManagerReady; m_manager.OnFaceStateUpdated += OnFaceStateUpdated; + m_manager.OnAutoVerifyResult += OnAutoVerifyResult; } if (m_serialDropdown != null) @@ -132,6 +133,7 @@ namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo m_manager.OnError -= OnManagerError; m_manager.OnReady -= OnManagerReady; m_manager.OnFaceStateUpdated -= OnFaceStateUpdated; + m_manager.OnAutoVerifyResult -= OnAutoVerifyResult; m_manager.Close(); } @@ -350,6 +352,17 @@ namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo SetResult("人脸状态: " + FaceProtocolEncoding.FaceStateMessage(state.State)); } + private void OnAutoVerifyResult(FaceAutoVerifyResult result) + { + if (result.Success) + { + SetResult("自动检测成功,UserID=" + result.VerifyResult.UserId + ",姓名=" + result.VerifyResult.UserName); + return; + } + + SetResult("自动检测结果: " + FaceProtocolEncoding.ResultMessage(result.ResultCode)); + } + private void OnManagerError(FaceResultCode _, string message) { LogError("SDK 错误: " + message); @@ -383,6 +396,12 @@ namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo private async Task EnsureModuleStandbyAsync(string operationName) { + if (m_manager.IsAutoVerifyEnabled) + { + await m_manager.EnsureExclusiveOperationReadyAsync(operationName); + return; + } + var status = await m_manager.Basic.GetStatusAsync(); if (status == FaceModuleStatus.Busy) { diff --git a/Samples~/SI-M1 Face Demo/Scripts/Core/FaceModuleKeyboardTester.cs b/Samples~/SI-M1 Face Demo/Scripts/Core/FaceModuleKeyboardTester.cs index a244ffa..687c932 100644 --- a/Samples~/SI-M1 Face Demo/Scripts/Core/FaceModuleKeyboardTester.cs +++ b/Samples~/SI-M1 Face Demo/Scripts/Core/FaceModuleKeyboardTester.cs @@ -361,8 +361,15 @@ namespace Aisu.SIM1.Face.Core { try { - var result = await Manager.Verify.AutoVerifyAsync(AutoVerifyEnable, VerifyTimeout); - Log("自动验证完成:成功=" + result.Success + ",用户ID=" + result.UserId); + if (AutoVerifyEnable) + { + await Manager.StartAutoVerifyAsync(VerifyTimeout); + Log("自动验证已开启,识别结果通过事件回调。"); + return; + } + + await Manager.StopAutoVerifyAsync(VerifyTimeout); + Log("自动验证已关闭。"); } catch (Exception ex) { LogError("自动验证失败:" + ex.Message); } } diff --git a/Samples~/SI-M1 Face Demo/UI/Pages/FaceModulePages.cs b/Samples~/SI-M1 Face Demo/UI/Pages/FaceModulePages.cs index 4530c3b..a5b8763 100644 --- a/Samples~/SI-M1 Face Demo/UI/Pages/FaceModulePages.cs +++ b/Samples~/SI-M1 Face Demo/UI/Pages/FaceModulePages.cs @@ -401,6 +401,7 @@ namespace Aisu.SIM1.Face.UI.Pages base.Init(manager, logPanel, loadingView); m_boundManager = m_manager; m_manager.OnFaceStateUpdated += OnFaceState; + m_manager.OnAutoVerifyResult += OnAutoVerifyResult; } private void OnDestroy() @@ -417,9 +418,14 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; - var result = m_autoToggle.isOn - ? await m_manager.Verify.AutoVerifyAsync(true, ReadByte(m_timeoutInput, 10)) - : await m_manager.Verify.VerifyAsync(ReadByte(m_timeoutInput, 10), ReadByte(m_maxTimesInput, 30)); + if (m_autoToggle.isOn) + { + await m_manager.StartAutoVerifyAsync(ReadByte(m_timeoutInput, 10)); + SetResult("自动验证已开启"); + return; + } + + var result = await m_manager.Verify.VerifyAsync(ReadByte(m_timeoutInput, 10), ReadByte(m_maxTimesInput, 30)); ShowResult(result); }); } @@ -430,7 +436,19 @@ namespace Aisu.SIM1.Face.UI.Pages /// public void StopVerify() { - RunAsync(async () => { if (RequireConnected()) { await m_manager.Basic.ResetAsync(); SetResult("已停止验证"); } }); + RunAsync(async () => + { + if (!RequireConnected()) return; + if (m_manager.IsAutoVerifyEnabled) + { + await m_manager.StopAutoVerifyAsync(); + SetResult("自动验证已关闭"); + return; + } + + await m_manager.Basic.ResetAsync(); + SetResult("已停止验证"); + }); } /// @@ -455,11 +473,17 @@ namespace Aisu.SIM1.Face.UI.Pages SetResult(result.Success ? "验证成功" : FaceProtocolEncoding.ResultMessage(result.ResultCode)); } + private void OnAutoVerifyResult(FaceAutoVerifyResult result) + { + ShowResult(result.VerifyResult); + } + private void UnbindManagerEvents() { if (m_boundManager != null) { m_boundManager.OnFaceStateUpdated -= OnFaceState; + m_boundManager.OnAutoVerifyResult -= OnAutoVerifyResult; m_boundManager = null; } } @@ -545,6 +569,8 @@ namespace Aisu.SIM1.Face.UI.Pages return; } + await m_manager.EnsureExclusiveOperationReadyAsync("人脸录入"); + FaceEnrollResult result; if (m_modeDropdown.value == 1) { @@ -594,7 +620,7 @@ namespace Aisu.SIM1.Face.UI.Pages /// public void CancelEnroll() { - RunAsync(async () => { if (RequireConnected()) { await m_manager.Basic.FaceResetAsync(); SetResult("已取消录入"); } }); + RunAsync(async () => { if (RequireConnected()) { await m_manager.EnsureExclusiveOperationReadyAsync("取消录入"); await m_manager.Basic.FaceResetAsync(); SetResult("已取消录入"); } }); } /// @@ -674,6 +700,7 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; + await m_manager.EnsureExclusiveOperationReadyAsync("查询用户"); var info = await m_manager.Users.GetUserInfoAsync(ReadInt(m_userIdInput, 0)); m_detailText.text = $"用户详情: ID={info.UserId} Name={info.UserName} Admin={info.IsAdmin}"; SetResult("查询成功"); @@ -688,6 +715,7 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; + await m_manager.EnsureExclusiveOperationReadyAsync("删除用户"); await m_manager.Users.DeleteUserAsync(ReadInt(m_userIdInput, 0)); SetResult("删除成功"); await RefreshIds(false); @@ -716,6 +744,7 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; + await m_manager.EnsureExclusiveOperationReadyAsync("删除全部用户"); await m_manager.Users.DeleteAllAsync(); SetResult("全部用户已删除"); await RefreshIds(false); @@ -743,6 +772,7 @@ namespace Aisu.SIM1.Face.UI.Pages /// private async System.Threading.Tasks.Task RefreshIds(bool useV2) { + await m_manager.EnsureExclusiveOperationReadyAsync("刷新用户列表"); var ids = useV2 ? await m_manager.Users.GetAllUserIds2Async() : await m_manager.Users.GetAllUserIdsAsync(); m_listText.text = string.Join("\n", ids.ConvertAll(id => "UserID: " + id)); SetResult("用户列表已刷新"); @@ -791,6 +821,7 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; + await m_manager.EnsureExclusiveOperationReadyAsync("扫码"); var qr = await m_manager.QrCode.ScanQrCodeAsync(ReadByte(m_timeoutInput, 10)); m_qrText.text = "二维码内容: " + qr; SetResult(string.IsNullOrEmpty(qr) ? "二维码为空" : "扫码成功"); @@ -802,7 +833,7 @@ namespace Aisu.SIM1.Face.UI.Pages /// public void AutoScan() { - RunAsync(async () => { if (RequireReady()) { await m_manager.Verify.AutoVerifyAsync(true, ReadByte(m_timeoutInput, 10)); SetResult("自动探测已启动"); } }); + RunAsync(async () => { if (RequireReady()) { await m_manager.StartAutoVerifyAsync(ReadByte(m_timeoutInput, 10)); SetResult("自动探测已启动"); } }); } /// @@ -810,7 +841,19 @@ namespace Aisu.SIM1.Face.UI.Pages /// public void Stop() { - RunAsync(async () => { if (RequireConnected()) { await m_manager.Basic.ResetAsync(); SetResult("已停止"); } }); + RunAsync(async () => + { + if (!RequireConnected()) return; + if (m_manager.IsAutoVerifyEnabled) + { + await m_manager.StopAutoVerifyAsync(); + SetResult("自动探测已停止"); + return; + } + + await m_manager.Basic.ResetAsync(); + SetResult("已停止"); + }); } /// @@ -883,6 +926,7 @@ namespace Aisu.SIM1.Face.UI.Pages RunAsync(async () => { if (!RequireReady()) return; + await m_manager.EnsureExclusiveOperationReadyAsync("图片抓拍"); FaceImageResult result; if (type == "Face") result = await m_manager.Images.SnapUploadFaceImageAsync(); else if (type == "Large") result = await m_manager.Images.SnapUploadLargeImageAsync((ImageDpi)m_dpiDropdown.value); diff --git a/package.json b/package.json index d4627dc..db315a9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xin.aisu.si-m1.face", "displayName": "AISU SI-M1 Face SDK", - "version": "0.1.0", + "version": "0.1.6", "unity": "2021.3", "description": "Unity UPM package for the AISU SI-M1 face recognition module protocol, transport, command services, lifecycle manager, tests, and demo sample.", "author": {