297 lines
9.5 KiB
C#
297 lines
9.5 KiB
C#
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
|
||
}
|
||
}
|