ATLS PF4000 串口通信协议

基于开放协议,

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
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanwenhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值