基于开放协议,
1.发送前缀+开放协议+结束尾缀,
前缀与尾缀不计算长度
以连接控制器为例:
前缀:0x07, 0x09, 0x07, 0x09, 0x02
数据长度:0020 (ASCII转Byte[])
内容:0001001 (长度16, 9个空格 ,ASCII转Byte[])
尾缀:0x00, 0x03
连接控制器
发送(十进制程序监控复制导出,自行转换16进制核对)
7,9,7,9,2,48,48,50,48,48,48,48,49,48,48,49,32,32,32,32,32,32,32,32,32,0,3
2.接收数据
前缀+内容+尾缀
前缀: 0x02
内容:与开发协议接收保持一致
尾缀:0x00 0x03
开放协议参考以前写过的博客,自行翻阅.
通信类库:
using BascInfo;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace Tor
{
public class Serial_Tor
{
private SerialPort SerialPort_sc;
private string ScName = "";
private const int BufferSize = 256;
private byte[] _readBuffer;
private AsyncCallback _readCallback;
MsgTips mt;
/// <summary>
/// 打开串口 串口序号简写Com1→1 , 波特率,数据位,停止位,校验位
/// </summary>
public bool OpenPort(string name, int portNum, int rate, int dataBits, int stopBits, int parity, MsgTips _mt)
{
mt=_mt;
if (SerialPort_sc != null)
{
SerialPort_sc.Close();
}
ScName=name;
SerialPort_sc = new SerialPort();
SerialPort_sc.PortName = "COM" + portNum.ToString();
SerialPort_sc.BaudRate = rate;
SerialPort_sc.DataBits = dataBits;
SerialPort_sc.StopBits = stopBits == 0 ? StopBits.None : (stopBits == 1 ? StopBits.One : StopBits.Two);
SerialPort_sc.Parity = parity == 0 ? Parity.None : (parity == 1 ? Parity.Odd : Parity.Even);
try
{
_readBuffer = new byte[BufferSize];
_readCallback = new AsyncCallback(OnReadComplete);
SerialPort_sc.Open();
SendCmdInfo(Commd.Connect);
BeginAsyncRead();
Task.Run(() => { SendQueMsg(); });
Task.Run(() => { SendDate(); });
return true;
}
catch (Exception ex)
{
mt.Show($"NG,拧紧串口{SerialPort_sc.PortName}打开异常,"+ex.Message, true);
return false;
}
}
private void BeginAsyncRead()
{
if (SerialPort_sc.IsOpen)
{
SerialPort_sc.BaseStream.BeginRead(_readBuffer, 0, BufferSize, _readCallback, null);
}
}
private void OnReadComplete(IAsyncResult ar)
{
try
{
int bytesRead = SerialPort_sc.BaseStream.EndRead(ar);
if (bytesRead > 0)
{
byte[] receivedData = new byte[bytesRead];
Array.Copy(_readBuffer, 0, receivedData, 0, bytesRead);
ChaiJie(receivedData);
BeginAsyncRead(); // 继续异步读取
}
}
catch (Exception ex)
{
mt.Show($"NG,拧紧串口{SerialPort_sc.PortName}打开异常,"+ex.Message, true);
}
}
List<byte> _queuedMsg = new List<byte>();
private byte Delimiter = 0x00;
private void ChaiJie(byte[] bt)
{
int tj = bt.Count();
for (int i = 0; i < tj; i++)
{
if (bt[i]==Delimiter)
{
byte[] msg = _queuedMsg.ToArray();
string Rcmsg = Encoding.ASCII.GetString(msg.ToArray());
_queuedMsg.Clear();
FenXi(Rcmsg);
}
else
{
if (bt[i]!=0x02 && bt[i]!=0x03)
{
_queuedMsg.Add(bt[i]);
}
}
}
}
private void FenXi(string Rcmsg)
{
if (Rcmsg.Length < 20)
{
return;
}
isSendCmd=false;
mt.Show($"Tor:接收信息:{Rcmsg}__{isKepCon},{isUnableDY},{isSendCmd}", false);
string jieguo = Rcmsg.Substring(4, 4);
switch (jieguo)
{
case "0002"://首次握手成功
isKepCon=true;
num_ConOverTime=0;
break;
case "0061":
num_ConOverTime=0;
SendCmdInfo(Commd.AckNowledgeTorResult);
//拧紧数据解析
JX(Rcmsg);
break;
case "9999":
num_ConOverTime=0;
break;
case "0004":
string cmd2 = Rcmsg.Substring(24, 2); //二次通信
if (cmd2 =="96")
{
isKepCon=true;
num_ConOverTime=0;
isUnableDY=true;
}
break;
case "0005":
string cmd3 = Rcmsg.Substring(20, 4);
if (cmd3 =="0060")
{
num_ConOverTime=0;
isUnableDY=true;
}
break;
default:
break;
}
}
private void JX(string msg)
{
if (msg.Length == 231)
{
//版本1 001或者3个空格
//string rev = msg.Substring(8, 3);
//string Vin = msg.Substring(59, 25);
bool rel = msg.Substring(107, 1) == "1" ? true : false;
string nj = msg.Substring(140, 6);
string jd = msg.Substring(169, 5);
//string id = msg.Substring(221, 10).Trim();
float f_nj = (float.Parse(nj) * 1.0f / 100.0f);
float f_jd = (float.Parse(jd) * 1.0f / 100.0f);
ScEventArgs e = new ScEventArgs(ScName, f_nj, f_jd, rel);
_MsgChange(e);
}
}
bool isRun = true;
public void Close()
{
isRun=false;
SerialPort_sc?.Close();
}
/// <summary>
/// 允许执行保持通信
/// </summary>
bool isKepCon = false;
/// <summary>
/// 不允许订阅
/// </summary>
bool isUnableDY = false;
/// <summary>
/// 是否发送了指令
/// </summary>
bool isSendCmd = false;
int num_ConOverTime = 0;
public void SendDate()
{
int js = 0;
while (isRun)
{
if (!isKepCon)
{
SendCmdInfo(Commd.Connect);
}
if (isKepCon && !isUnableDY && !isSendCmd)
{
SendCmdInfo(Commd.SubscribeTorResult);
isSendCmd = true;
}
if (isKepCon && !isSendCmd &js>=50)
{
//无指令交互情况下10秒发送一次保持通信
SendCmdInfo(Commd.KeepCon);
js=0;
isSendCmd=true;
}
js++;
num_ConOverTime++;
//应答超时
if (num_ConOverTime>=100)
{
isKepCon=false;
isUnableDY=false;
}
Thread.Sleep(200);
}
}
private ConcurrentQueue<byte[]> sendQue = new ConcurrentQueue<byte[]>();
public void SendCmdInfo(Commd Canshu, string msg = "")
{
switch (Canshu)
{
case Commd.LockGun:
msg = "0042001".PadRight(16, ' ');
break;
case Commd.UnLockGun:
msg = "0043001".PadRight(16, ' ');
break;
case Commd.Connect:
msg = "0001001".PadRight(16, ' ');
break;
case Commd.KeepCon:
msg = "9999001".PadRight(16, ' ');
break;
case Commd.DisConnect:
msg = "0003001".PadRight(16, ' ');
break;
case Commd.SubscribeTorResult:
msg = "0060001".PadRight(16, ' ');
break;
case Commd.AckNowledgeTorResult:
msg = "0062001".PadRight(16, ' ');
break;
//case Commd.UnSubscribeTorResult:
// msg = "0063001".PadRight(16, ' ');
// break;
case Commd.Pre:
msg = "0064001".PadRight(16, ' ') + msg.PadLeft(10, ' ');
break;
case Commd.Vin:
msg = "0050001".PadRight(16, ' ') + msg;
break;
case Commd.Channel:
msg = "0018001".PadRight(16, ' ') + msg.PadLeft(3, '0');
break;
case Commd.Job:
msg = "002200380010 00 "+ msg;
break;
default:
break;
}
byte[] t_head = new byte[] { 0x07, 0x09, 0x07, 0x09, 0x02 };
byte[] t_end = new byte[] { 0x00, 0x03 };
byte[] bt_Data = Encoding.ASCII.GetBytes(msg);
byte[] bt_head = Encoding.ASCII.GetBytes((bt_Data.Length + 4).ToString("0000"));
byte[] bt_send = t_head.Concat(bt_head).Concat(bt_Data).Concat(t_end).ToArray();
sendQue.Enqueue(bt_send);
}
string pattern = @"[^a-zA-Z0-9]+"; // 匹配一个或多个非字母数字字符
private void SendQueMsg()
{
byte[] buf = new byte[0];
while (isRun)
{
while (sendQue.TryDequeue(out buf))
{
mt.Show($"发送:{Regex.Replace(Encoding.ASCII.GetString(buf), pattern, "")}", false);
SerialPort_sc?.Write(buf, 0, buf.Length);
}
Thread.Sleep(200);
}
}
public delegate void MsgChange(object sender, ScEventArgs args);
public event MsgChange OnMsgChange;
protected virtual void _MsgChange(ScEventArgs e)
{
if (OnMsgChange != null)
{
OnMsgChange(this, e);
}
}
}
public class ScEventArgs : EventArgs
{
public string Name;
public float NJ;
public float JD;
public bool Result;
public ScEventArgs(string name, float nj, float jd, bool result)
{
Name=name;
NJ = nj;
JD = jd;
Result=result;
}
}
public enum Commd
{
/// <summary>
/// 连接 0001
/// </summary>
Connect,
/// <summary>
/// 断开 0003
/// </summary>
DisConnect,
/// <summary>
/// 锁枪 0042
/// </summary>
LockGun,
/// <summary>
/// 解枪 0043
/// </summary>
UnLockGun,
/// <summary>
/// 订阅拧紧数据 0060001
/// </summary>
SubscribeTorResult,
/// <summary>
/// 订阅信息收到回传 0062
/// </summary>
AckNowledgeTorResult,
/// <summary>
/// 取消订阅拧紧数据 0063
/// </summary>
UnSubscribeTorResult,
/// <summary>
/// 读取历史 0064
/// </summary>
Pre,
/// <summary>
/// 保持通信 9999
/// </summary>
KeepCon,
/// <summary>
/// 写入Vin 0050
/// </summary>
Vin,
/// <summary>
/// 写入通道 0018
/// </summary>
Channel,
/// <summary>
/// Job 请求
/// </summary>
Job
}
}