using System.Diagnostics;
using System.IO.Ports;
namespace UHFHelper
{
public class UHF_RS485_Helper
{
private SerialPort? _serialPort;
private SerialParam? _serialParam;
///
/// 单例模式
///
private static UHF_RS485_Helper? Instance { get; set; }
public static UHF_RS485_Helper GetInstance()
{
if (Instance == null)
{
Instance = new UHF_RS485_Helper();
}
return Instance;
}
///
/// 打开串口
///
///
public void Open(SerialParam param)
{
_serialParam = param;
_serialPort = new SerialPort(_serialParam.PortName, _serialParam.BaudRate, _serialParam.PortParity, _serialParam.DataBits);
_serialPort.Open();
}
///
/// 获取串口状态
///
///
public bool GetSerialPortState()
{
if (_serialPort!=null)
{
return _serialPort.IsOpen;
}
else
{
return false;
}
}
///
/// 关闭串口
///
public void Close()
{
if (_serialPort == null) return;
_serialPort.Close();
_serialPort.Dispose();
_serialPort = null;
}
///
/// 读卡方法,返回读卡器数据
///
/// 设备读取地址
///
public async Task ReadCard(int adr)
{
DKoutput dKoutput = new();
var readByte = ReadByte(adr);
var result = await SendMessageAsync(readByte, TimeSpan.FromSeconds(1), 18);
if (result == null)
{
return null;
}
else
{
//获取校验码
var crc = result.Skip(16).Take(2).ToArray();
//获取卡号
var cardNo = result.Skip(6).Take(10).ToArray();
//获取读卡器数据
var readData = result.Skip(0).Take(16).ToArray();
//获取读卡器地址
var address = result.Skip(1).Take(1).ToArray();
//判断数据是否合法
var temcrc = CRC16.ToCRC16(readData);
if (crc.ByteArrayToHexString() == temcrc.ByteArrayToHexString())
{
dKoutput.Address = address.ByteArrayToHexString();
dKoutput.ResData = cardNo.ByteArrayToHexString();
return dKoutput;
}
else
{
return null;
}
}
}
///
/// 生成读取命令
///
///
private byte[] ReadByte(int adr)
{
//根据读取地址生成读取命令
byte[] data1 = new byte[3] { 04, (byte)adr, 01 };
//生成crc校验码
byte[] data2 = CRC16.ToCRC16(data1);
byte[] data3 = new byte[data1.Length + data2.Length];
data1.CopyTo(data3, 0);
data2.CopyTo(data3, data1.Length);
return data3;
}
///
/// 获取本机可用串口
///
///
public string[] GetLocalSerialPortNames()
{
return SerialPort.GetPortNames();
}
///
/// 发送数据
///
/// 数据
/// 超时时间
/// 串口回复字节数
///
public byte[]? SendMessage(byte[] msg, TimeSpan timeout, int count)
{
if (_serialPort == null) return null;
var stopwatch = Stopwatch.StartNew();
var originalWriteTimeout = _serialPort.WriteTimeout;
var originalReadTimeout = _serialPort.ReadTimeout;
try
{
_serialPort.WriteTimeout = (int)Math.Max((timeout - stopwatch.Elapsed).TotalMilliseconds, 0);
_serialPort.Write(msg, 0, msg.Length);
var tmpCount = count;
byte[] buffer = new byte[tmpCount];
int offset = 0;
while (tmpCount > 0)
{
_serialPort.ReadTimeout = (int)Math.Max((timeout - stopwatch.Elapsed).TotalMilliseconds, 0);
var readCount = _serialPort.Read(buffer, offset, tmpCount);
if (readCount==6)
{
tmpCount = 0;
continue;
}
offset += readCount;
tmpCount -= readCount;
}
_serialPort.DiscardInBuffer();
return buffer;
}catch(Exception ex)
{
return null;
}
finally
{
_serialPort.ReadTimeout = originalReadTimeout;
_serialPort.WriteTimeout = originalWriteTimeout;
}
}
///
/// 发送数据
///
/// 数据
/// 超时时间
/// 串口回复字节数
///
public async Task SendMessageAsync(byte[] msg, TimeSpan timeout, int count)
{
var sendTask = Task.Run(() => SendMessage(msg, timeout, count));
try
{
await Task.WhenAny(sendTask, Task.Delay(timeout));
}
catch (TaskCanceledException)
{
throw new TimeoutException();
}
return await sendTask;
}
///
/// 发出蜂鸣声音3次,代表扣款成功!
///
public async void OpenBeep(int addr)
{
byte[] sendData = new byte[]{ 0x07, (byte)addr, 0x33, 0x08, 0x02, 0x03, 0x33,0xB1 };
await SendMessageAsync(sendData, TimeSpan.FromSeconds(1), 6);
}
}
public class SerialParam
{
public string PortName { get; set; } = "COM3";
public int BaudRate { get; set; } = 57600;
public int DataBits { get; set; } = 8;
public Parity PortParity { get; set; } = Parity.None;
public StopBits PortStopBits { get; set; } = StopBits.One;
}
}