diff --git a/src/AxiOmron.PcbCheck/Converters/ResultCodeToTagTextConverter.cs b/src/AxiOmron.PcbCheck/Converters/ResultCodeToTagTextConverter.cs index 28cf4f1..723f293 100644 --- a/src/AxiOmron.PcbCheck/Converters/ResultCodeToTagTextConverter.cs +++ b/src/AxiOmron.PcbCheck/Converters/ResultCodeToTagTextConverter.cs @@ -5,7 +5,7 @@ using AxiOmron.PcbCheck.Models; namespace AxiOmron.PcbCheck.Converters; /// -/// 将 (以 存储)映射为简短 Tag 文本。 +/// 将 (以 存储)映射为简短 Tag 文本。 /// /// /// 映射规则:Passed → "OK";Processing → "处理中";None → "-";其余视为 "NG"。 @@ -22,19 +22,20 @@ public sealed class ResultCodeToTagTextConverter : IValueConverter /// 简短标签文本。 public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - short code = value switch + ushort code = value switch { - short s => s, - int i => (short)i, - WorkflowResultCode rc => (short)rc, + ushort s => s, + short s when s >= 0 => (ushort)s, + int i when i >= 0 && i <= ushort.MaxValue => (ushort)i, + WorkflowResultCode rc => (ushort)rc, _ => 0 }; return code switch { - (short)WorkflowResultCode.Passed => "OK", - (short)WorkflowResultCode.Processing => "处理中", - (short)WorkflowResultCode.None => "-", + (ushort)WorkflowResultCode.Passed => "OK", + (ushort)WorkflowResultCode.Processing => "处理中", + (ushort)WorkflowResultCode.None => "-", _ => "NG" }; } diff --git a/src/AxiOmron.PcbCheck/DesignTime/DesignTimeAppStateStore.cs b/src/AxiOmron.PcbCheck/DesignTime/DesignTimeAppStateStore.cs index fac8ace..063cb9d 100644 --- a/src/AxiOmron.PcbCheck/DesignTime/DesignTimeAppStateStore.cs +++ b/src/AxiOmron.PcbCheck/DesignTime/DesignTimeAppStateStore.cs @@ -32,7 +32,7 @@ public sealed class DesignTimeAppStateStore : IAppStateStore CurrentBarcode = "PCB240417000128", ResultDescription = "已扫码,等待 SFTP 文件确认", FaultMessage = string.Empty, - ResultCode = (short)WorkflowResultCode.Processing, + ResultCode = (ushort)WorkflowResultCode.Processing, LastTriggeredAt = now.AddSeconds(-18), LastCompletedAt = now.AddMinutes(-2), IsBusy = true, @@ -44,7 +44,7 @@ public sealed class DesignTimeAppStateStore : IAppStateStore _snapshot.PlcMonitorItems.Add(new PlcMonitorItem { GroupName = "Inputs", Name = "PlcAckRelease", Address = "10003", CurrentValue = "False", LastUpdatedAt = now.AddSeconds(-1) }); _snapshot.PlcMonitorItems.Add(new PlcMonitorItem { GroupName = "Outputs", Name = "PcBusy", Address = "51", CurrentValue = "True", LastUpdatedAt = now.AddSeconds(-1) }); _snapshot.PlcMonitorItems.Add(new PlcMonitorItem { GroupName = "Outputs", Name = "ReleasePermit", Address = "52", CurrentValue = "False", LastUpdatedAt = now.AddSeconds(-1) }); - _snapshot.PlcMonitorItems.Add(new PlcMonitorItem { GroupName = "Registers", Name = "ResultCode", Address = "40001", CurrentValue = ((short)WorkflowResultCode.Processing).ToString(), LastUpdatedAt = now.AddSeconds(-1) }); + _snapshot.PlcMonitorItems.Add(new PlcMonitorItem { GroupName = "Registers", Name = "ResultCode", Address = "40001", CurrentValue = ((ushort)WorkflowResultCode.Processing).ToString(), LastUpdatedAt = now.AddSeconds(-1) }); _logs = new List { @@ -64,7 +64,7 @@ public sealed class DesignTimeAppStateStore : IAppStateStore Barcode = "PCB240417000125", ScanTryCount = 1, SftpTryCount = 1, - ResultCode = (short)WorkflowResultCode.Passed, + ResultCode = (ushort)WorkflowResultCode.Passed, ResultDescription = "OK 放行", ReleaseSent = true, ExceptionSummary = string.Empty @@ -76,7 +76,7 @@ public sealed class DesignTimeAppStateStore : IAppStateStore Barcode = "PCB240417000126", ScanTryCount = 3, SftpTryCount = 0, - ResultCode = (short)WorkflowResultCode.NgReleased, + ResultCode = (ushort)WorkflowResultCode.NgReleased, ResultDescription = "扫码失败后放行", ReleaseSent = true, ExceptionSummary = "扫码连续失败三次" @@ -88,7 +88,7 @@ public sealed class DesignTimeAppStateStore : IAppStateStore Barcode = "PCB240417000127", ScanTryCount = 1, SftpTryCount = 3, - ResultCode = (short)WorkflowResultCode.NgReleased, + ResultCode = (ushort)WorkflowResultCode.NgReleased, ResultDescription = "处理结果 NG,随后放行", ReleaseSent = true, ExceptionSummary = "SFTP 文件查询超时" @@ -97,8 +97,8 @@ public sealed class DesignTimeAppStateStore : IAppStateStore _snapshot.RecordStatisticDate = DateOnly.FromDateTime(now.LocalDateTime.Date); _snapshot.TodayProcessCount = _records.Count; - _snapshot.TodayOkCount = _records.Count(record => record.ResultCode == (short)WorkflowResultCode.Passed); - _snapshot.TodayNgCount = _records.Count(record => record.ResultCode != (short)WorkflowResultCode.Passed); + _snapshot.TodayOkCount = _records.Count(record => record.ResultCode == (ushort)WorkflowResultCode.Passed); + _snapshot.TodayNgCount = _records.Count(record => record.ResultCode != (ushort)WorkflowResultCode.Passed); _snapshot.RecordsLastUpdatedAt = now; foreach (BoardProcessRecord record in _records) { diff --git a/src/AxiOmron.PcbCheck/Models/RuntimeSnapshot.cs b/src/AxiOmron.PcbCheck/Models/RuntimeSnapshot.cs index 1911f6f..3b1c1f5 100644 --- a/src/AxiOmron.PcbCheck/Models/RuntimeSnapshot.cs +++ b/src/AxiOmron.PcbCheck/Models/RuntimeSnapshot.cs @@ -63,7 +63,7 @@ public sealed class RuntimeSnapshot /// /// 获取或设置结果代码。 /// - public short ResultCode { get; set; } + public ushort ResultCode { get; set; } /// /// 获取或设置上次触发时间。 diff --git a/src/AxiOmron.PcbCheck/Models/WorkflowModels.cs b/src/AxiOmron.PcbCheck/Models/WorkflowModels.cs index 06e9128..a4fb15a 100644 --- a/src/AxiOmron.PcbCheck/Models/WorkflowModels.cs +++ b/src/AxiOmron.PcbCheck/Models/WorkflowModels.cs @@ -69,7 +69,7 @@ public enum WorkflowState /// /// 表示最终结果代码定义。 /// -public enum WorkflowResultCode : short +public enum WorkflowResultCode : ushort { /// /// 无结果。 @@ -182,7 +182,7 @@ public sealed class PlcProcessState /// /// 获取或设置结果代码寄存器值。 /// - public short ResultCode { get; set; } + public ushort ResultCode { get; set; } /// /// 创建当前状态对象的浅拷贝。 @@ -496,7 +496,7 @@ public sealed class BoardProcessRecord /// /// 获取或设置结果代码。 /// - public short ResultCode { get; set; } + public ushort ResultCode { get; set; } /// /// 获取或设置结果描述。 diff --git a/src/AxiOmron.PcbCheck/Options/AppConfig.cs b/src/AxiOmron.PcbCheck/Options/AppConfig.cs index 87713c7..1ef4701 100644 --- a/src/AxiOmron.PcbCheck/Options/AppConfig.cs +++ b/src/AxiOmron.PcbCheck/Options/AppConfig.cs @@ -130,9 +130,9 @@ public sealed class PlcOptions public byte SourceNodeAddress { get; set; } = 25; /// - /// 获取或设置 PLC 寄存器字节序,默认使用 BADC 以匹配现场 D 区 Int16 高低字节顺序。 + /// 获取或设置 PLC 寄存器字节序,默认使用 ABCD 以避免 UInt16 结果代码发生高低字节交换。 /// - public string? EndianFormat { get; set; } = "BADC"; + public string? EndianFormat { get; set; } = "ABCD"; /// /// 获取或设置轮询周期,单位为毫秒。 diff --git a/src/AxiOmron.PcbCheck/Services/Implementations/CsvBoardRecordRepository.cs b/src/AxiOmron.PcbCheck/Services/Implementations/CsvBoardRecordRepository.cs index ea680eb..1f786de 100644 --- a/src/AxiOmron.PcbCheck/Services/Implementations/CsvBoardRecordRepository.cs +++ b/src/AxiOmron.PcbCheck/Services/Implementations/CsvBoardRecordRepository.cs @@ -247,10 +247,10 @@ public sealed class CsvBoardRecordRepository : IBoardRecordRepository { StatisticDate = date, TotalCount = records.Count, - OkCount = records.Count(record => record.ResultCode == (short)WorkflowResultCode.Passed), - NgCount = records.Count(record => record.ResultCode != (short)WorkflowResultCode.Passed - && record.ResultCode != (short)WorkflowResultCode.Processing - && record.ResultCode != (short)WorkflowResultCode.None), + OkCount = records.Count(record => record.ResultCode == (ushort)WorkflowResultCode.Passed), + NgCount = records.Count(record => record.ResultCode != (ushort)WorkflowResultCode.Passed + && record.ResultCode != (ushort)WorkflowResultCode.Processing + && record.ResultCode != (ushort)WorkflowResultCode.None), LastUpdatedAt = _timeProvider.GetLocalNow() }; @@ -400,7 +400,7 @@ public sealed class CsvBoardRecordRepository : IBoardRecordRepository || !DateTimeOffset.TryParse(fields[1], out DateTimeOffset completedAt) || !int.TryParse(fields[3], out int scanTryCount) || !int.TryParse(fields[4], out int sftpTryCount) - || !short.TryParse(fields[5], out short resultCode) + || !ushort.TryParse(fields[5], out ushort resultCode) || !bool.TryParse(fields[7], out bool releaseSent) || !bool.TryParse(fields[8], out bool alarmRaised)) { diff --git a/src/AxiOmron.PcbCheck/Services/Implementations/OmronFinsPlcService.cs b/src/AxiOmron.PcbCheck/Services/Implementations/OmronFinsPlcService.cs index 4e50ea2..e5630fa 100644 --- a/src/AxiOmron.PcbCheck/Services/Implementations/OmronFinsPlcService.cs +++ b/src/AxiOmron.PcbCheck/Services/Implementations/OmronFinsPlcService.cs @@ -89,7 +89,7 @@ public sealed class OmronFinsPlcService : IPlcService, IDisposable { PcBusy = ReadBoolean(ToDataMemoryAddress(_options.Outputs.PcBusy)), ReleasePermit = ReadBoolean(ToDataMemoryAddress(_options.Outputs.ReleasePermit)), - ResultCode = ReadInt16(ToDataMemoryAddress(_options.Registers.ResultCode)) + ResultCode = ReadUInt16(ToDataMemoryAddress(_options.Registers.ResultCode)) }, CapturedAt = capturedAt }; @@ -276,15 +276,15 @@ public sealed class OmronFinsPlcService : IPlcService, IDisposable } /// - /// 读取单个 D 区有符号 16 位整数。 + /// 读取单个 D 区无符号 16 位整数。 /// /// FINS 地址。 /// 读取到的寄存器值。 - private short ReadInt16(string address) + private ushort ReadUInt16(string address) { var client = _client ?? throw new InvalidOperationException("PLC 客户端尚未初始化。"); - var result = client.ReadInt16(address); - EnsureSuccess(result.IsSucceed, result.Err, $"读取 FINS Int16 失败,地址={address}"); + var result = client.ReadUInt16(address); + EnsureSuccess(result.IsSucceed, result.Err, $"读取 FINS UInt16 失败,地址={address}"); return result.Value; } @@ -295,10 +295,10 @@ public sealed class OmronFinsPlcService : IPlcService, IDisposable private void WriteChangedState(PlcProcessState state) { var previous = _lastWrittenState; - short? previousResultCode = previous is null ? null : previous.ResultCode; + ushort? previousResultCode = previous is null ? null : previous.ResultCode; WriteBooleanIfChanged(previous?.PcBusy, state.PcBusy, ToDataMemoryAddress(_options.Outputs.PcBusy)); WriteBooleanIfChanged(previous?.ReleasePermit, state.ReleasePermit, ToDataMemoryAddress(_options.Outputs.ReleasePermit)); - WriteInt16IfChanged(previousResultCode, state.ResultCode, ToDataMemoryAddress(_options.Registers.ResultCode)); + WriteUInt16IfChanged(previousResultCode, state.ResultCode, ToDataMemoryAddress(_options.Registers.ResultCode)); } /// @@ -320,12 +320,12 @@ public sealed class OmronFinsPlcService : IPlcService, IDisposable } /// - /// 仅当值发生变化时写入单个 D 区有符号 16 位整数。 + /// 仅当值发生变化时写入单个 D 区无符号 16 位整数。 /// /// 上一值。 /// 当前值。 /// FINS 地址。 - private void WriteInt16IfChanged(short? previous, short current, string address) + private void WriteUInt16IfChanged(ushort? previous, ushort current, string address) { if (previous.HasValue && previous.Value == current) { @@ -334,7 +334,7 @@ public sealed class OmronFinsPlcService : IPlcService, IDisposable var client = _client ?? throw new InvalidOperationException("PLC 客户端尚未初始化。"); var result = client.Write(address, current); - EnsureSuccess(result.IsSucceed, result.Err, $"写入 FINS Int16 失败,地址={address},值={current}"); + EnsureSuccess(result.IsSucceed, result.Err, $"写入 FINS UInt16 失败,地址={address},值={current}"); } /// diff --git a/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs b/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs index 25c8d8f..f34f8a7 100644 --- a/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs +++ b/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs @@ -848,7 +848,7 @@ public sealed class WorkflowHostedService : BackgroundService, IWorkflowControlS Barcode = _currentBarcode, ScanTryCount = _scanTryCount, SftpTryCount = _sftpTryCount, - ResultCode = (short)_resultCode, + ResultCode = (ushort)_resultCode, ResultDescription = GetResultDescription(_resultCode), ReleaseSent = _releaseSent, AlarmRaised = false, @@ -1082,7 +1082,7 @@ public sealed class WorkflowHostedService : BackgroundService, IWorkflowControlS lock (_stateSyncRoot) { updateAction(_plcState); - _plcState.ResultCode = (short)_resultCode; + _plcState.ResultCode = (ushort)_resultCode; snapshot = _plcState.Clone(); } @@ -1103,7 +1103,7 @@ public sealed class WorkflowHostedService : BackgroundService, IWorkflowControlS { DateTimeOffset? startedAt; string barcode; - short resultCode; + ushort resultCode; bool isBusy; string faultMessage; @@ -1111,7 +1111,7 @@ public sealed class WorkflowHostedService : BackgroundService, IWorkflowControlS { startedAt = _currentBoardStartedAt; barcode = _currentBarcode; - resultCode = (short)_resultCode; + resultCode = (ushort)_resultCode; isBusy = _plcState.PcBusy; faultMessage = _faultLatched ? description : string.Empty; } diff --git a/src/AxiOmron.PcbCheck/ViewModels/MainWindowViewModel.cs b/src/AxiOmron.PcbCheck/ViewModels/MainWindowViewModel.cs index 1102cf1..bdb5393 100644 --- a/src/AxiOmron.PcbCheck/ViewModels/MainWindowViewModel.cs +++ b/src/AxiOmron.PcbCheck/ViewModels/MainWindowViewModel.cs @@ -150,7 +150,7 @@ public partial class MainWindowViewModel : ObservableObject /// 获取或设置结果代码。 /// [ObservableProperty] - private short _resultCode; + private ushort _resultCode; /// /// 获取或设置最近触发时间。 @@ -557,6 +557,7 @@ public partial class MainWindowViewModel : ObservableObject await AppendLogOnUiAsync(entry).ConfigureAwait(false); } + /// /// 处理管理员解锁倒计时,超时后自动恢复锁定。 /// /// 事件源。 diff --git a/src/AxiOmron.PcbCheck/appConfig.json b/src/AxiOmron.PcbCheck/appConfig.json index 6eab135..65c240b 100644 --- a/src/AxiOmron.PcbCheck/appConfig.json +++ b/src/AxiOmron.PcbCheck/appConfig.json @@ -1,92 +1,92 @@ -{ - "Plc": { - "Host": "127.0.0.1", - "Port": 9600, - "UnitAddress": 0, - "SourceNodeAddress": 25, - "EndianFormat": "BADC", - "PollIntervalMs": 200, - "ConnectTimeoutMs": 3000, - "ReleasePulseMs": 500, - "ReleaseAckTimeoutMs": 2000, - "Inputs": { - "PcbArrived": 101, - "PlcReset": 102, - "PlcAckRelease": 103 - }, - "Outputs": { - "PcBusy": 51, - "ReleasePermit": 52 - }, - "Registers": { - "ResultCode": 401 - } - }, - "Scanner": { - "Scanner1": { - "Name": "扫码枪1", - "Host": "127.0.0.1", - "Port": 2001 - }, - "Scanner2": { - "Name": "扫码枪2", - "Host": "127.0.0.1", - "Port": 2001 - }, - "ConnectTimeoutMs": 3000, - "ReadTimeoutMs": 3000, - "TriggerCommand": "T", - "ResponseTerminator": "\\r", - "TriggerInParallel": true - }, - "FileCheck": { - "Provider": "Local", - "FileNamePattern": "${barcode}.txt", - "RetryIntervalSeconds": 2, - "MaxRetryCount": 3, - "Local": { - "RootPath": "D:\\PcbCheck\\Files" - } - }, - "Sftp": { - "Host": "127.0.0.1", - "Port": 22, - "Username": "uaesadmin", - "Password": "uaes,123", - "PrivateKeyPath": "", - "PrivateKeyPassphrase": "", - "RootPath": "/home/uaesadmin/", - "FileNamePattern": "${barcode}.txt", - "RetryIntervalSeconds": 2, - "MaxRetryCount": 3, - "ConnectTimeoutMs": 3000 - }, - "Andon": { - "Enable": false, - "Url": "https://shp.prod.aliyun.mit.uaes.com/api/mit/MAE/Station/Status/alarm", - "Method": "POST", - "TimeoutMs": 3000, - "AndonTheme": "SS7_Auto_Andon", - "Eid": "PR1965269806334783488", - "FromSign": "IOT", - "ServiceId": "4dccd822-86b2-47dd-89bd-ca472ba0d14d", - "EnableScanFailAlarm": true, - "EnableFileNotFoundAlarm": false, - "Headers": { - "Accept": "application/json" - } - }, - "Workflow": { - "RequireManualResetAfterFault": true, - "MaxUiLogEntries": 200, - "MaxBoardRecords": 100 - }, - "RecordPersistence": { - "DirectoryPath": "Data\\Records", - "DayChangeCheckIntervalSeconds": 30 - }, - "Security": { - "AdminPassword": "AxiOmron@123", - "AdminSessionTimeoutMinutes": 15 - } +{ + "Plc": { + "Host": "192.168.2.100", + "Port": 9600, + "UnitAddress": 0, + "SourceNodeAddress": 0, + "EndianFormat": "ABCD", + "PollIntervalMs": 200, + "ConnectTimeoutMs": 3000, + "ReleasePulseMs": 500, + "ReleaseAckTimeoutMs": 2000, + "Inputs": { + "PcbArrived": 101, + "PlcReset": 102, + "PlcAckRelease": 103 + }, + "Outputs": { + "PcBusy": 51, + "ReleasePermit": 52 + }, + "Registers": { + "ResultCode": 401 + } + }, + "Scanner": { + "Scanner1": { + "Name": "\u626B\u7801\u67AA1", + "Host": "192.168.2.13", + "Port": 2001 + }, + "Scanner2": { + "Name": "\u626B\u7801\u67AA2", + "Host": "192.168.2.14", + "Port": 2001 + }, + "ConnectTimeoutMs": 3000, + "TriggerCommand": "T", + "ResponseTerminator": "", + "TriggerInParallel": true, + "ReadTimeoutMs": 5000 + }, + "FileCheck": { + "Provider": "Local", + "FileNamePattern": "${barcode}.txt", + "RetryIntervalSeconds": 2, + "MaxRetryCount": 3, + "Local": { + "RootPath": "D:\\test" + } + }, + "Sftp": { + "Host": "127.0.0.1", + "Port": 22, + "Username": "uaesadmin", + "Password": "uaes,123", + "PrivateKeyPath": "", + "PrivateKeyPassphrase": "", + "RootPath": "/home/uaesadmin/", + "FileNamePattern": "${barcode}.txt", + "RetryIntervalSeconds": 2, + "MaxRetryCount": 3, + "ConnectTimeoutMs": 3000 + }, + "Andon": { + "Enable": false, + "Url": "https://shp.prod.aliyun.mit.uaes.com/api/mit/MAE/Station/Status/alarm", + "Method": "POST", + "TimeoutMs": 3000, + "AndonTheme": "SS7_Auto_Andon", + "Eid": "PR1965269806334783488", + "FromSign": "IOT", + "ServiceId": "4dccd822-86b2-47dd-89bd-ca472ba0d14d", + "EnableScanFailAlarm": false, + "EnableFileNotFoundAlarm": false, + "Headers": { + "Accept": "application/json" + } + }, + "Workflow": { + "RequireManualResetAfterFault": true, + "MaxUiLogEntries": 200, + "MaxBoardRecords": 100 + }, + "RecordPersistence": { + "DirectoryPath": "Data\\Records", + "DayChangeCheckIntervalSeconds": 30 + }, + "Security": { + "AdminPassword": "AxiOmron@123", + "AdminSessionTimeoutMinutes": 15 + } } \ No newline at end of file diff --git a/tests/AxiOmron.PcbCheck.Tests/CsvBoardRecordRepositoryTests.cs b/tests/AxiOmron.PcbCheck.Tests/CsvBoardRecordRepositoryTests.cs index c109899..94a1a49 100644 --- a/tests/AxiOmron.PcbCheck.Tests/CsvBoardRecordRepositoryTests.cs +++ b/tests/AxiOmron.PcbCheck.Tests/CsvBoardRecordRepositoryTests.cs @@ -37,10 +37,10 @@ public sealed class CsvBoardRecordRepositoryTests : IDisposable timeProvider); await repository.AppendAsync( - CreateRecord("PCB-001", new DateTimeOffset(2026, 4, 19, 8, 0, 0, TimeSpan.FromHours(8)), (short)WorkflowResultCode.Passed), + CreateRecord("PCB-001", new DateTimeOffset(2026, 4, 19, 8, 0, 0, TimeSpan.FromHours(8)), (ushort)WorkflowResultCode.Passed), CancellationToken.None); await repository.AppendAsync( - CreateRecord("PCB-002", new DateTimeOffset(2026, 4, 19, 8, 5, 0, TimeSpan.FromHours(8)), (short)WorkflowResultCode.NgReleased), + CreateRecord("PCB-002", new DateTimeOffset(2026, 4, 19, 8, 5, 0, TimeSpan.FromHours(8)), (ushort)WorkflowResultCode.NgReleased), CancellationToken.None); BoardRecordLoadResult result = await repository.LoadCurrentDayAsync(CancellationToken.None); @@ -100,7 +100,7 @@ public sealed class CsvBoardRecordRepositoryTests : IDisposable timeProvider); await repository.AppendAsync( - CreateRecord("PCB-OLD", new DateTimeOffset(2026, 4, 19, 23, 59, 55, TimeSpan.FromHours(8)), (short)WorkflowResultCode.Passed), + CreateRecord("PCB-OLD", new DateTimeOffset(2026, 4, 19, 23, 59, 55, TimeSpan.FromHours(8)), (ushort)WorkflowResultCode.Passed), CancellationToken.None); timeProvider.SetLocalNow(new DateTimeOffset(2026, 4, 20, 0, 0, 10, TimeSpan.FromHours(8))); @@ -131,7 +131,7 @@ public sealed class CsvBoardRecordRepositoryTests : IDisposable /// 完成时间。 /// 结果代码。 /// 测试记录。 - private static BoardProcessRecord CreateRecord(string barcode, DateTimeOffset completedAt, short resultCode) + private static BoardProcessRecord CreateRecord(string barcode, DateTimeOffset completedAt, ushort resultCode) { return new BoardProcessRecord { @@ -141,7 +141,7 @@ public sealed class CsvBoardRecordRepositoryTests : IDisposable ScanTryCount = 1, SftpTryCount = 1, ResultCode = resultCode, - ResultDescription = resultCode == (short)WorkflowResultCode.Passed ? "OK" : "NG", + ResultDescription = resultCode == (ushort)WorkflowResultCode.Passed ? "OK" : "NG", ReleaseSent = true, AlarmRaised = false, ExceptionSummary = string.Empty diff --git a/tests/AxiOmron.PcbCheck.Tests/MainWindowViewModelTests.cs b/tests/AxiOmron.PcbCheck.Tests/MainWindowViewModelTests.cs index 85eecdf..c08f786 100644 --- a/tests/AxiOmron.PcbCheck.Tests/MainWindowViewModelTests.cs +++ b/tests/AxiOmron.PcbCheck.Tests/MainWindowViewModelTests.cs @@ -50,7 +50,7 @@ public sealed class MainWindowViewModelTests Barcode = $"PCB-{index:D3}", ScanTryCount = 1, SftpTryCount = 1, - ResultCode = index % 2 == 0 ? (short)WorkflowResultCode.Passed : (short)WorkflowResultCode.NgReleased, + ResultCode = index % 2 == 0 ? (ushort)WorkflowResultCode.Passed : (ushort)WorkflowResultCode.NgReleased, ResultDescription = index % 2 == 0 ? "OK" : "NG", ReleaseSent = true, AlarmRaised = false diff --git a/tests/AxiOmron.PcbCheck.Tests/OmronFinsPlcServiceTests.cs b/tests/AxiOmron.PcbCheck.Tests/OmronFinsPlcServiceTests.cs index 5016fc4..79eee1a 100644 --- a/tests/AxiOmron.PcbCheck.Tests/OmronFinsPlcServiceTests.cs +++ b/tests/AxiOmron.PcbCheck.Tests/OmronFinsPlcServiceTests.cs @@ -11,16 +11,16 @@ namespace AxiOmron.PcbCheck.Tests; public sealed class OmronFinsPlcServiceTests { /// - /// 默认字节序应使用 BADC,以匹配现场 D 区 Int16 的高低字节顺序。 + /// 默认字节序应使用 ABCD,避免 UInt16 结果代码发生高低字节交换。 /// [Fact] - public void ResolveEndianFormat_ShouldUseBadc_WhenConfigurationIsDefault() + public void ResolveEndianFormat_ShouldUseAbcd_WhenConfigurationIsDefault() { var options = new PlcOptions(); EndianFormat result = OmronFinsPlcService.ResolveEndianFormat(options); - Assert.Equal(EndianFormat.BADC, result); + Assert.Equal(EndianFormat.ABCD, result); } /// diff --git a/tests/AxiOmron.PcbCheck.Tests/ResultCodeTypeTests.cs b/tests/AxiOmron.PcbCheck.Tests/ResultCodeTypeTests.cs index ca67826..3cc880d 100644 --- a/tests/AxiOmron.PcbCheck.Tests/ResultCodeTypeTests.cs +++ b/tests/AxiOmron.PcbCheck.Tests/ResultCodeTypeTests.cs @@ -5,29 +5,29 @@ using Xunit; namespace AxiOmron.PcbCheck.Tests; /// -/// 验证结果代码在模型与界面层统一使用 16 位有符号整数。 +/// 验证结果代码在模型与界面层统一使用 16 位无符号整数。 /// public sealed class ResultCodeTypeTests { /// - /// 结果代码枚举应以 Int16 作为底层类型,匹配 PLC 的 ResultCode 定义。 + /// 结果代码枚举应以 UInt16 作为底层类型,匹配 PLC 的 ResultCode 定义。 /// [Fact] - public void WorkflowResultCode_ShouldUseInt16UnderlyingType() + public void WorkflowResultCode_ShouldUseUInt16UnderlyingType() { - Assert.Equal(typeof(short), Enum.GetUnderlyingType(typeof(WorkflowResultCode))); + Assert.Equal(typeof(ushort), Enum.GetUnderlyingType(typeof(WorkflowResultCode))); } /// - /// 结果代码属性应统一使用 Int16,避免经过界面或快照时被误建模为 UInt16 或 Int32。 + /// 结果代码属性应统一使用 UInt16,避免经过界面或快照时被误建模为 Int16 或 Int32。 /// [Theory] [InlineData(typeof(RuntimeSnapshot))] [InlineData(typeof(PlcProcessState))] [InlineData(typeof(BoardProcessRecord))] [InlineData(typeof(MainWindowViewModel))] - public void ResultCodeProperties_ShouldUseInt16(Type ownerType) + public void ResultCodeProperties_ShouldUseUInt16(Type ownerType) { - Assert.Equal(typeof(short), ownerType.GetProperty("ResultCode")?.PropertyType); + Assert.Equal(typeof(ushort), ownerType.GetProperty("ResultCode")?.PropertyType); } } diff --git a/tests/AxiOmron.PcbCheck.Tests/WorkflowHostedServiceTests.cs b/tests/AxiOmron.PcbCheck.Tests/WorkflowHostedServiceTests.cs index e88a761..05b7c8f 100644 --- a/tests/AxiOmron.PcbCheck.Tests/WorkflowHostedServiceTests.cs +++ b/tests/AxiOmron.PcbCheck.Tests/WorkflowHostedServiceTests.cs @@ -148,12 +148,12 @@ public sealed class WorkflowHostedServiceTests Assert.True(scannerService.TriggerCount > 0); Assert.Contains(plcService.WrittenStates, state => state.ReleasePermit); - Assert.Contains(plcService.WrittenStates, state => state.ResultCode == (short)WorkflowResultCode.Passed); + Assert.Contains(plcService.WrittenStates, state => state.ResultCode == (ushort)WorkflowResultCode.Passed); RuntimeSnapshot snapshot = stateStore.GetSnapshot(); Assert.Contains(snapshot.PlcMonitorItems, item => item.Name == "PcbArrived" && item.CurrentValue == "False"); Assert.Contains(snapshot.PlcMonitorItems, item => item.Name == "PcBusy" && item.CurrentValue == "False"); - Assert.Contains(snapshot.PlcMonitorItems, item => item.Name == "ResultCode" && item.CurrentValue == ((short)WorkflowResultCode.Passed).ToString()); + Assert.Contains(snapshot.PlcMonitorItems, item => item.Name == "ResultCode" && item.CurrentValue == ((ushort)WorkflowResultCode.Passed).ToString()); Assert.All(snapshot.PlcMonitorItems, item => Assert.NotEqual(default, item.LastUpdatedAt)); } @@ -217,7 +217,7 @@ public sealed class WorkflowHostedServiceTests Assert.Equal(1, scannerService.TriggerCount); Assert.Equal("PCB-MERGED", fileCheckService.LastBarcode); - Assert.Contains(plcService.WrittenStates, state => state.ResultCode == (short)WorkflowResultCode.Passed); + Assert.Contains(plcService.WrittenStates, state => state.ResultCode == (ushort)WorkflowResultCode.Passed); } /// @@ -304,7 +304,7 @@ public sealed class WorkflowHostedServiceTests Barcode = "PCB-RESTORED", ScanTryCount = 1, SftpTryCount = 1, - ResultCode = (short)WorkflowResultCode.Passed, + ResultCode = (ushort)WorkflowResultCode.Passed, ResultDescription = "OK", ReleaseSent = true } @@ -409,7 +409,7 @@ public sealed class WorkflowHostedServiceTests RuntimeSnapshot snapshot = stateStore.GetSnapshot(); Assert.NotEqual(WorkflowState.Faulted, snapshot.WorkflowState); - Assert.Equal((short)WorkflowResultCode.Passed, snapshot.ResultCode); + Assert.Equal((ushort)WorkflowResultCode.Passed, snapshot.ResultCode); } private sealed class FakePlcService : IPlcService