2025-11-20 14:44:46 +08:00

297 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Logging;
using RIZO.Model.Mes.Scanner;
using RIZO.Service.Mes.IMesService.Scanner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RIZO.Service.Mes.Scanner
{
public class ScannerService : IScannerService, IDisposable
{
private readonly ILogger<ScannerService> _logger;
private SerialPort? _serialPort;
private ScannerConfig _config = new();
private bool _isInitialized = false;
public bool IsConnected => _serialPort?.IsOpen == true;
// 事件定义
public event EventHandler<ScanData>? OnScanDataReceived;
public event EventHandler<string>? OnScannerError;
public ScannerService(ILogger<ScannerService> logger)
{
_logger = logger;
}
public async Task<bool> InitializeAsync(ScannerConfig config)
{
try
{
_config = config;
await Task.Run(() =>
{
_serialPort = new SerialPort(
_config.PortName,
_config.BaudRate,
ParseParity(_config.Parity),
_config.DataBits,
ParseStopBits(_config.StopBits))
{
Encoding = System.Text.Encoding.UTF8,
ReadTimeout = 1000,
WriteTimeout = 1000
};
_serialPort.DataReceived += SerialPort_DataReceived;
});
_isInitialized = true;
_logger.LogInformation($"扫码服务初始化成功 - 端口:{_config.PortName} 波特率:{_config.BaudRate}");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "扫码服务初始化失败");
OnScannerError?.Invoke(this, $"初始化失败: {ex.Message}");
return false;
}
}
public async Task<bool> StartAsync()
{
if (!_isInitialized || _serialPort == null)
{
OnScannerError?.Invoke(this, "扫码服务未初始化");
return false;
}
try
{
if (!_serialPort.IsOpen)
{
await Task.Run(() => _serialPort.Open());
_logger.LogInformation("串口扫码枪启动成功");
}
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "启动串口扫码枪失败");
OnScannerError?.Invoke(this, $"启动失败: {ex.Message}");
return false;
}
}
public async Task<bool> StopAsync()
{
if (_serialPort?.IsOpen == true)
{
await Task.Run(() => _serialPort.Close());
_logger.LogInformation("串口扫码枪已停止");
}
return true;
}
/// <summary>
/// 串口数据接收事件处理
/// </summary>
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (sender is SerialPort sp)
{
string scannedData = sp.ReadExisting().Trim();
if (!string.IsNullOrEmpty(scannedData))
{
_logger.LogInformation($"接收到扫码数据: {scannedData}");
// 异步处理扫码数据
_ = Task.Run(async () =>
{
var result = await ProcessScanCodeAsync(scannedData);
if (result.Success && result.Data != null)
{
OnScanDataReceived?.Invoke(this, result.Data);
}
});
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "处理扫码数据时发生错误");
OnScannerError?.Invoke(this, $"数据处理错误: {ex.Message}");
}
}
/// <summary>
/// 处理扫码数据业务逻辑
/// </summary>
public async Task<ScanResult> ProcessScanCodeAsync(string scanCode)
{
try
{
_logger.LogInformation($"开始处理扫码数据: {scanCode}");
var scanData = new ScanData
{
Code = scanCode.ToUpper(),
ScanTime = DateTime.Now
};
// ============ 业务逻辑判断 ============
// 判断是否为产品条码(根据你的业务规则修改)
if (IsProductCode(scanCode))
{
scanData.CodeType = "Product";
await ProcessProductCodeAsync(scanData);
}
// 判断是否为物料条码
else if (IsMaterialCode(scanCode))
{
scanData.CodeType = "Material";
await ProcessMaterialCodeAsync(scanData);
}
// 判断是否为追溯码
else if (IsTraceCode(scanCode))
{
scanData.CodeType = "Trace";
await ProcessTraceCodeAsync(scanData);
}
else
{
scanData.CodeType = "Unknown";
scanData.IsValid = false;
scanData.ErrorMessage = "未知条码类型";
await ProcessUnknownCodeAsync(scanData);
}
return new ScanResult
{
Success = scanData.IsValid,
Message = scanData.IsValid ? "处理成功" : scanData.ErrorMessage,
Data = scanData
};
}
catch (Exception ex)
{
_logger.LogError(ex, $"处理扫码数据时发生错误: {scanCode}");
return new ScanResult
{
Success = false,
Message = $"处理失败: {ex.Message}"
};
}
}
#region -
private bool IsProductCode(string code)
{
// 根据你的业务规则判断是否为产品条码
return code.Length == 20 || code.StartsWith("P") || code.StartsWith("PROD");
}
private bool IsMaterialCode(string code)
{
// 根据你的业务规则判断是否为物料条码
return code.Length == 15 || code.StartsWith("M") || code.StartsWith("MAT");
}
private bool IsTraceCode(string code)
{
// 根据你的业务规则判断是否为追溯码
return code.Contains("TRACE") || code.Contains(GetCurrentLineName());
}
private async Task ProcessProductCodeAsync(ScanData scanData)
{
_logger.LogInformation($"处理产品条码: {scanData.Code}");
// 这里实现产品条码处理逻辑
// 例如更新数据库、与PLC通信、更新界面等
// 模拟异步处理
await Task.Delay(10);
// 示例:更新全局状态
// global.ScanCode = scanData.Code;
}
private async Task ProcessMaterialCodeAsync(ScanData scanData)
{
_logger.LogInformation($"处理物料条码: {scanData.Code}");
// 这里实现物料条码处理逻辑
await Task.Delay(10);
}
private async Task ProcessTraceCodeAsync(ScanData scanData)
{
_logger.LogInformation($"处理追溯码: {scanData.Code}");
// 这里实现追溯码处理逻辑
await Task.Delay(10);
}
private async Task ProcessUnknownCodeAsync(ScanData scanData)
{
_logger.LogWarning($"未知条码类型: {scanData.Code}");
// 处理未知条码
await Task.Delay(10);
}
private string GetCurrentLineName()
{
// 返回当前生产线名称,根据你的业务逻辑实现
return "LINE001";
}
#endregion
#region
private Parity ParseParity(string parity)
{
return parity.ToUpper() switch
{
"N" or "NONE" => Parity.None,
"E" or "EVEN" => Parity.Even,
"O" or "ODD" => Parity.Odd,
"M" or "MARK" => Parity.Mark,
"S" or "SPACE" => Parity.Space,
_ => Parity.None
};
}
private StopBits ParseStopBits(string stopBits)
{
return stopBits.ToUpper() switch
{
"1" or "ONE" => StopBits.One,
"1.5" or "ONEPOINTFIVE" => StopBits.OnePointFive,
"2" or "TWO" => StopBits.Two,
_ => StopBits.One
};
}
public void Dispose()
{
_serialPort?.Close();
_serialPort?.Dispose();
_logger.LogInformation("扫码服务资源已释放");
}
#endregion
}
}