2021-05-28

using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.Threading;
using System;
using System.Text;
using System.Xml;

namespace ZX_DEVICE
{
    /// <summary>
    /// 设备通信组件
    /// </summary>
    public class DeviceComponent : MonoBehaviour
    {
        /// <summary>
        /// 设备通信组件对象
        /// </summary>
        public static DeviceComponent Instance;

        SerialPort port;//串口实例
        Thread recvThread;//接收数据线程
        byte[] receiveBytes;//接收数据字节组
        int SendTime, TimeOut = 500;//发送指令时的时间;任务超时的检测时间
        List<TaskBase> MyTaskTable = new List<TaskBase>();
        StringBuilder receiveStr = new StringBuilder();//接收消息的字符序列
        bool IsTimer, ThreadRuning, Receiving;//是否开始计时;读取数据线程控制符;是否等待信号返回中,T为是

        //--------------------------------------------------------------------------------

        /// <summary>
        /// 打开设备连接
        /// </summary>
        public bool OpenDeviceConnect(string comName) { return OpenSerialPort(comName); }

        /// <summary>
        /// 关闭设备连接(程序退出时会自动调用一次)
        /// </summary>
        public void CloseDeviceConnect()
        {
            if (recvThread != null && recvThread.IsAlive)
            {
                ThreadRuning = false;
                Debug.Log("设备接收线程成功关闭");
            }
            else
                Debug.Log("设备接收线程关闭失败");

            if (port != null && port.IsOpen)
            {
                port.Close(); port = null;
                Debug.Log("设备串口成功关闭");
            }
            else
                Debug.Log("设备串口关闭失败");
        }

        /// <summary>
        /// 获取应答结果
        /// </summary>
        /// <returns>第一个参数是命令的应答状态,第二个是应答返回结果</returns>
        public (bool, string) GetReceiveMessage()
        {
            string tmp;
            if (!string.IsNullOrEmpty(receiveStr.ToString()))
            {
                tmp = receiveStr.ToString();
                receiveStr.Clear();
                return (true, tmp);
            }
            else
                return (false, null);
        }

        /// <summary>
        /// 获取通信的连接状态
        /// </summary>
        /// <returns></returns>
        public bool GetConnectState() { return ThreadRuning; }

        /// <summary>
        /// 设置命令超时的检测时间:发送一个命令后,在此时间内没有收到处理结果,则认为该命令处理失败。组件将移除该命令
        /// (默认是500毫秒)
        /// </summary>
        /// <param name="timeOut">超时时间</param>
        public void SetOrderTimeOut(int timeOut) { TimeOut = timeOut; }

        #region 外部调用命令集

        /// <summary>
        /// 发送心跳命令
        /// </summary>
        public void SendHeartOrder(AddressCode receive, AddressCode send = AddressCode.Host) { AddTaskFunction(new TaskBase(CmdType.Heart, send, receive)); }

        /// <summary>
        /// 发送开始检测命令(预留接口,暂未使用)
        /// </summary>
        public void SendStartCheckOrder(AddressCode receive, AddressCode send = AddressCode.Host) { AddTaskFunction(new TaskBase(CmdType.StartCheck, send, receive)); }

        /// <summary>
        /// 发送结束检测命令(预留接口,暂未使用)
        /// </summary>
        public void SendOverCheckOrder(AddressCode receive, AddressCode send = AddressCode.Host) { AddTaskFunction(new TaskBase(CmdType.OverCheck, send, receive)); }

        /// <summary>
        /// 发送状态查询命令
        /// </summary>
        public void SendStateQueryOrder(AddressCode receive, AddressCode send = AddressCode.Host) { AddTaskFunction(new TaskBase(CmdType.StateQuery, send, receive)); }

        /// <summary>
        /// 发送编码器清零命令(预留接口,暂未使用)
        /// </summary>
        public void SendClearEncoderOrder(AddressCode receive, AddressCode send = AddressCode.Host) { AddTaskFunction(new TaskBase(CmdType.ClearEncoder, send, receive)); }

        //-----------------------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 发送控制AED按键灯命令(数字输出控制)
        /// </summary>
        public void SendAEDLightOrder(AEDLightType lightType, AddressCode send = AddressCode.Host)
        {
            switch (lightType)
            {
                case AEDLightType.AllOff:
                    AddTaskFunction(new TaskBase(CmdType.OutPutCtrl, send, AddressCode.AED, "0x1F"));
                    break;
                case AEDLightType.AllOn:
                    AddTaskFunction(new TaskBase(CmdType.OutPutCtrl, send, AddressCode.AED, "0x12"));
                    break;
                case AEDLightType.Prower:
                    AddTaskFunction(new TaskBase(CmdType.OutPutCtrl, send, AddressCode.AED, "0x08"));
                    break;
                default:
                    Debug.LogError("未找到对应AED灯光类型");
                    break;
            }
        }

        /// <summary>
        /// 发送控制模型人脉搏命令(模拟输出控制)
        /// </summary>
        public void SendPulseCtrlOrder(bool IsJump, AddressCode send = AddressCode.Host)
        {
            if (IsJump)
                AddTaskFunction(new TaskBase(CmdType.DragCtrl, send, AddressCode.Human, "0209C4"));
            else
                AddTaskFunction(new TaskBase(CmdType.DragCtrl, send, AddressCode.Human, "020000"));
        }

        /// <summary>
        /// 发送AED音频控制命令
        /// </summary>
        public void SendAEDAudioOrder(AEDAudioType audioType, AddressCode send = AddressCode.Host)
        {
            switch (audioType)
            {
                case AEDAudioType.ReadyTip:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0100"));
                    break;
                case AEDAudioType.NotDefibrillate:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0200"));
                    break;
                case AEDAudioType.OverDefibrillate:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0300"));
                    break;
                case AEDAudioType.Charging:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0400"));
                    break;
                case AEDAudioType.DisCharging:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0500"));
                    break;
                case AEDAudioType.ReadyTipAgain:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0600"));
                    break;
                case AEDAudioType.DontTouch:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0700"));
                    break;
                case AEDAudioType.LowBattery:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.AED, "0800"));
                    break;
                default:
                    Debug.LogError("AED音频类型不正确");
                    break;
            }
        }

        /// <summary>
        /// 发送除颤仪心率显示状态命令
        /// </summary>
        public void SendHeartRateStateOrder(int rate, AddressCode send = AddressCode.Host)
        {
            if (rate > 249) rate = 249;
            if (rate < 0) rate = 0;

            if (rate == 0)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "010" + Convert.ToString(rate, 16)));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "01" + Convert.ToString(rate, 16)));
        }

        /// <summary>
        /// 发送电极连接显示状态命令(预留接口,暂未使用)
        /// </summary>
        public void SendElectrodesStateOrder(bool IsShow, AddressCode send = AddressCode.Host)
        {
            if (IsShow)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0201"));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0200"));
        }

        /// <summary>
        /// 发送波形显示状态命令
        /// </summary>
        public void SendWaveformStateOrder(WaveformType waveform, AddressCode send = AddressCode.Host)
        {
            switch (waveform)
            {
                case WaveformType.None:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0300"));
                    break;
                case WaveformType.Die:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0301"));
                    break;
                case WaveformType.VF:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0302"));
                    break;
                case WaveformType.Normal:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0303"));
                    break;
                default:
                    Debug.LogError("波形类型错误");
                    break;
            }
        }

        /// <summary>
        /// 发送同步开关显示状态命令
        /// </summary>
        public void SendSyncStateOrder(SyncType syncType, AddressCode send = AddressCode.Host)
        {
            switch (syncType)
            {
                case SyncType.None:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0400"));
                    break;
                case SyncType.OFF:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0401"));
                    break;
                case SyncType.ON:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0402"));
                    break;
                default:
                    Debug.LogError("同步开关类型错误");
                    break;
            }
        }

        /// <summary>
        /// 发送充电显示状态命令
        /// </summary>
        public void SendChargeStateOrder(ChargeType chargeType, AddressCode send = AddressCode.Host)
        {
            switch (chargeType)
            {
                case ChargeType.None:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0500"));
                    break;
                case ChargeType.Charge:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0501"));
                    break;
                case ChargeType.Disarm:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0502"));
                    break;
                default:
                    Debug.LogError("充电类型错误");
                    break;
            }
        }

        /// <summary>
        /// 发送充电标识显示状态命令
        /// </summary>
        public void SendChargeSignStateOrder(bool IsShow, AddressCode send = AddressCode.Host)
        {
            if (IsShow)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0601"));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0600"));
        }

        /// <summary>
        /// 发送放电显示状态命令
        /// </summary>
        public void SendShockStateOrder(bool IsShow, AddressCode send = AddressCode.Host)
        {
            if (IsShow)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0701"));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0700"));
        }

        /// <summary>
        /// 发送放电标识显示状态命令
        /// </summary>
        public void SendShockSignStateOrder(bool IsShow, AddressCode send = AddressCode.Host)
        {
            if (IsShow)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0801"));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0800"));
        }

        /// <summary>
        /// 发送能量显示状态命令
        /// </summary>
        public void SendEnergyStateOrder(EnergyType energyType, AddressCode send = AddressCode.Host)
        {
            switch (energyType)
            {
                case EnergyType.ON:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0900"));
                    break;
                case EnergyType.Twenty:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0914"));
                    break;
                case EnergyType.Forty:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0928"));
                    break;
                case EnergyType.Eighty:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0950"));
                    break;
                case EnergyType.OneHundredAndTwenty:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0978"));
                    break;
                case EnergyType.OneHundredAndFifty:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0996"));
                    break;
                case EnergyType.TwoHundred:
                    AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "09C8"));
                    break;
                default:
                    Debug.LogError("能量类型错误");
                    break;
            }
        }

        /// <summary>
        /// 发送背景显示状态命令
        /// </summary>
        public void SendBackGroundStateOrder(bool IsShow, AddressCode send = AddressCode.Host)
        {
            if (IsShow)
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0A01"));
            else
                AddTaskFunction(new TaskBase(CmdType.AedCtrl, send, AddressCode.Defibrillator, "0A00"));
        }

        #endregion

        //public void SetReceivingState() { Receiving = false; }
        //--------------------------------------------------------------------------------
        private void Awake()
        {
            if (Instance != null)
            {
                Debug.LogError("设备串口组件已经存在,不要重复添加!");
                DestroyImmediate(gameObject);
            }
            else
                Instance = this;
        }
        private void Update()
        {
            return;
            Debug.LogAssertion(GetConnectState());

            if (Input.GetKeyDown(KeyCode.D))
                OpenDeviceConnect("COM5");
            if (Input.GetKeyDown(KeyCode.Keypad9))
                CloseDeviceConnect();
            //查询结果
            if (Input.GetKeyDown(KeyCode.PageUp))
            {
                bool b; string str;
                (b, str) = GetReceiveMessage();
                Debug.LogError(b + ">>>>>>>" + str);
            }
            //心跳
            if (Input.GetKeyDown(KeyCode.Q))
                SendHeartOrder(AddressCode.Defibrillator);
            if (Input.GetKeyDown(KeyCode.W))
                SendHeartOrder(AddressCode.AED);
            if (Input.GetKeyDown(KeyCode.E))
                SendHeartOrder(AddressCode.Human);
            //状态查询
            if (Input.GetKeyDown(KeyCode.R))
                SendStateQueryOrder(AddressCode.Defibrillator);
            if (Input.GetKeyDown(KeyCode.T))
                SendStateQueryOrder(AddressCode.AED);
            if (Input.GetKeyDown(KeyCode.Y))
                SendStateQueryOrder(AddressCode.Human);
            //AED灯光
            if (Input.GetKeyDown(KeyCode.U))
                SendAEDLightOrder(AEDLightType.AllOff);
            if (Input.GetKeyDown(KeyCode.I))
                SendAEDLightOrder(AEDLightType.AllOn);
            if (Input.GetKeyDown(KeyCode.O))
                SendAEDLightOrder(AEDLightType.Prower);
            //模型人脉搏
            if (Input.GetKeyDown(KeyCode.P))
                SendPulseCtrlOrder(true);
            if (Input.GetKeyDown(KeyCode.A))
                SendPulseCtrlOrder(false);
            //AED语音
            if (Input.GetKeyDown(KeyCode.S))
                SendAEDAudioOrder(AEDAudioType.Charging);
            if (Input.GetKeyDown(KeyCode.F))
                SendAEDAudioOrder(AEDAudioType.DisCharging);
            if (Input.GetKeyDown(KeyCode.G))
                SendAEDAudioOrder(AEDAudioType.DontTouch);
            if (Input.GetKeyDown(KeyCode.H))
                SendAEDAudioOrder(AEDAudioType.LowBattery);
            if (Input.GetKeyDown(KeyCode.J))
                SendAEDAudioOrder(AEDAudioType.NotDefibrillate);
            if (Input.GetKeyDown(KeyCode.K))
                SendAEDAudioOrder(AEDAudioType.OverDefibrillate);
            if (Input.GetKeyDown(KeyCode.L))
                SendAEDAudioOrder(AEDAudioType.ReadyTip);
            if (Input.GetKeyDown(KeyCode.Z))
                SendAEDAudioOrder(AEDAudioType.ReadyTipAgain);
            //除颤仪心率
            if (Input.GetKeyDown(KeyCode.X))
                SendHeartRateStateOrder(100);
            if (Input.GetKeyDown(KeyCode.C))
                SendHeartRateStateOrder(0);
            //除颤仪波形
            if (Input.GetKeyDown(KeyCode.V))
                SendWaveformStateOrder(WaveformType.Die);
            if (Input.GetKeyDown(KeyCode.B))
                SendWaveformStateOrder(WaveformType.None);
            if (Input.GetKeyDown(KeyCode.N))
                SendWaveformStateOrder(WaveformType.Normal);
            if (Input.GetKeyDown(KeyCode.M))
                SendWaveformStateOrder(WaveformType.VF);
            //同步开关
            if (Input.GetKeyDown(KeyCode.Alpha1))
                SendSyncStateOrder(SyncType.None);
            if (Input.GetKeyDown(KeyCode.Alpha2))
                SendSyncStateOrder(SyncType.OFF);
            if (Input.GetKeyDown(KeyCode.Alpha3))
                SendSyncStateOrder(SyncType.ON);
            //充电显示
            if (Input.GetKeyDown(KeyCode.Alpha4))
                SendChargeStateOrder(ChargeType.Charge);
            if (Input.GetKeyDown(KeyCode.Alpha5))
                SendChargeStateOrder(ChargeType.Disarm);
            if (Input.GetKeyDown(KeyCode.Alpha6))
                SendChargeStateOrder(ChargeType.None);
            //充电标识显示
            if (Input.GetKeyDown(KeyCode.Alpha7))
                SendChargeSignStateOrder(true);
            if (Input.GetKeyDown(KeyCode.Alpha8))
                SendChargeSignStateOrder(false);
            //放电显示
            if (Input.GetKeyDown(KeyCode.Alpha9))
                SendShockStateOrder(true);
            if (Input.GetKeyDown(KeyCode.Alpha0))
                SendShockStateOrder(false);
            //放电标识
            if (Input.GetKeyDown(KeyCode.UpArrow))
                SendShockSignStateOrder(true);
            if (Input.GetKeyDown(KeyCode.DownArrow))
                SendShockSignStateOrder(false);
            //能量选择
            if (Input.GetKeyDown(KeyCode.Keypad0))
                SendEnergyStateOrder(EnergyType.ON);
            if (Input.GetKeyDown(KeyCode.Keypad1))
                SendEnergyStateOrder(EnergyType.Twenty);
            if (Input.GetKeyDown(KeyCode.Keypad2))
                SendEnergyStateOrder(EnergyType.Forty);
            if (Input.GetKeyDown(KeyCode.Keypad3))
                SendEnergyStateOrder(EnergyType.Eighty);
            if (Input.GetKeyDown(KeyCode.Keypad4))
                SendEnergyStateOrder(EnergyType.OneHundredAndTwenty);
            if (Input.GetKeyDown(KeyCode.Keypad5))
                SendEnergyStateOrder(EnergyType.OneHundredAndFifty);
            if (Input.GetKeyDown(KeyCode.Keypad6))
                SendEnergyStateOrder(EnergyType.TwoHundred);
            //背景显示
            if (Input.GetKeyDown(KeyCode.Keypad7))
                SendBackGroundStateOrder(true);
            if (Input.GetKeyDown(KeyCode.Keypad8))
                SendBackGroundStateOrder(false);
        }
        private void FixedUpdate()
        {
            TaskTimeOutFun();
        }

        /// <summary>
        /// 任务超时检测(500毫秒)
        /// </summary>
        private void TaskTimeOutFun()
        {
            if (IsTimer)
            {
                if (GetTime() - SendTime > TimeOut && MyTaskTable.Count > 0)//任务发送后500毫秒未收到响应,就移除当前任务
                {
                    MyTaskTable.Remove(MyTaskTable[0]);
                    receiveStr.Clear();
                    Receiving = IsTimer = false;//进入非等待响应状态 并且 关闭定时
                    Debug.Log("当前任务超时,移除任务");
                }
            }
        }

        /// <summary>
        /// 打开设备串口
        /// </summary>
        private bool OpenSerialPort(string comName)
        {
            try
            {
                if (port != null && port.IsOpen)
                {
                    Debug.LogError("设备串口已开启,请勿重复启动"); return false;
                }

                port = new SerialPort(comName, 115200, Parity.None, 8, StopBits.One);

                //串口初始化
                if (!port.IsOpen)
                    port.Open();

                recvThread = new Thread(ReceiveData); //该线程用于接收串口数据
                ThreadRuning = true;
                recvThread.Start();
                return true;
            }
            catch (Exception ex)
            {
                Debug.LogError("设备串口打开错误:" + ex);
                return false;
            }
        }

        /// <summary>
        /// 添加任务
        /// </summary>
        private void AddTaskFunction(TaskBase task)
        {
            //int cacheID = MyTaskTable.Count;//在这里设置ID
            if (port != null && port.IsOpen)
            {
                MyTaskTable.Add(task);//Debug.LogError("添加任务");
            }
            else
                Debug.LogError("主机串口未打开,请检查设备连接!");
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        private void SendData()
        {
            if (MyTaskTable.Count <= 0)
                return;
            TaskBase task = MyTaskTable[0];

            #region 拼接命令
            Byte[] bytes;
            switch (task.cmdType)//根据命令的不同,决定数据长度与内容;
            {
                case CmdType.Heart://心跳
                    bytes = new Byte[9];
                    bytes[2] = 0x01;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.StartCheck://开始检测
                    bytes = new Byte[9];
                    bytes[2] = 0x02;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.OverCheck://结束检测
                    bytes = new Byte[9];
                    bytes[2] = 0x03;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.StateQuery://状态查询
                    bytes = new Byte[9];
                    bytes[2] = 0x04;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.OutPutCtrl://输出控制
                    bytes = new Byte[9];
                    bytes[2] = 0x05;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.DragCtrl://阻力控制
                    bytes = new Byte[11];
                    bytes[2] = 0x06;//命令
                    bytes[5] = 0x03;//长度
                    bytes[6] = (byte)Convert.ToInt32("0x" + task.data.Substring(0, 2), 16);//数据
                    bytes[7] = (byte)Convert.ToInt32("0x" + task.data.Substring(2, 2), 16); //数据
                    bytes[8] = (byte)Convert.ToInt32("0x" + task.data.Substring(4, 2), 16);// 数据
                    break;
                case CmdType.ClearEncoder://编码器清零
                    bytes = new Byte[9];
                    bytes[2] = 0x07;//命令
                    bytes[5] = 0x01;//长度
                    bytes[6] = (byte)Convert.ToInt32(task.data, 16);//数据
                    break;
                case CmdType.AedCtrl://除颤仪/AED控制
                    bytes = new Byte[10];
                    bytes[2] = 0x08;//命令
                    bytes[5] = 0x02;//长度
                    bytes[6] = (byte)Convert.ToInt32("0x" + task.data.Substring(0, 2), 16);//数据
                    bytes[7] = (byte)Convert.ToInt32("0x" + task.data.Substring(2, 2), 16); //数据
                    break;
                default:
                    Debug.LogError("命令类型不正确,请检查");
                    return;
            }

            switch (task.receiveAddress)//接收地址
            {
                case AddressCode.Host:
                    bytes[3] = 0x00;
                    break;
                case AddressCode.Pad:
                    bytes[3] = 0x10;
                    break;
                case AddressCode.AED:
                    bytes[3] = 0x20;
                    break;
                case AddressCode.Defibrillator:
                    bytes[3] = 0x30;
                    break;
                case AddressCode.Human:
                    bytes[3] = 0x40;
                    break;
                default:
                    break;
            }

            switch (task.sendAddress)//发送地址
            {
                case AddressCode.Host:
                    bytes[4] = 0x00;
                    break;
                case AddressCode.Pad:
                    bytes[4] = 0x10;
                    break;
                case AddressCode.AED:
                    bytes[4] = 0x20;
                    break;
                case AddressCode.Defibrillator:
                    bytes[4] = 0x30;
                    break;
                case AddressCode.Human:
                    bytes[4] = 0x40;
                    break;
                default:
                    break;
            }

            bytes[0] = 0x90;//固定起始帧头
            bytes[1] = 0xEB;//固定起始帧头
            #endregion

            #region 计算数据的校验和
            int SumInt = 0;
            for (int i = 0; i < bytes.Length - 4; i++)
                SumInt += Convert.ToInt32(bytes[i + 2]);
            SumInt = 65535 - SumInt;
            string SumStr = Convert.ToString(SumInt, 16);
            bytes[bytes.Length - 2] = (byte)Convert.ToInt32("0x" + SumStr.Substring(2, 2), 16);
            bytes[bytes.Length - 1] = (byte)Convert.ToInt32("0x" + SumStr.Substring(0, 2), 16);
            #endregion

            #region 打印预备发送的数据
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                sb.Append(Convert.ToString(bytes[i], 16));
                if (i != bytes.Length - 1) sb.Append("-");
            }
            Debug.Log("发送的数据:" + sb.ToString() + "         数据长度为:" + bytes.Length);
            #endregion

            DataSend(bytes, bytes.Length);//发送数据
            SendTime = GetTime();//获取发送数据的时间
            IsTimer = true;
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        private void ReceiveData()
        {
            try
            {
                if (port.IsOpen)
                    Debug.Log("成功打开串口:" + port.PortName);

                while (ThreadRuning)
                {
                    Thread.Sleep(30);

                    if (!port.IsOpen)//串口没开-跳出线程
                        return;

                   // Debug.Log("接收线程运行中...");

                    int datalength = port.BytesToRead;
                    if (datalength == 0)//长度为0-无返回数据
                    {
                        //Debug.Log("无返回数据...当前任务数量:" + MyTaskTable.Count + Receiving);

                        if (MyTaskTable.Count > 0 && !Receiving)//判断是否有后续任务 并且 是否正在等待响应
                        {
                            Debug.Log("无返回数据...但有缓存任务");
                            SendData(); Receiving = true;//有任务未发送且不等待响应,则发送下一个任务,并且进入等待响应
                        }
                    }
                    else
                    {
                        receiveBytes = new byte[datalength];
                        port.Read(receiveBytes, 0, datalength);

                        if (datalength < 9) { Debug.LogError("接受的数据总长度低于最小数据长度,请校验"); continue; }//9是长度,因为最小data为1,算上其他固定数据。就是9;

                        if (int.Parse(Convert.ToString(receiveBytes[3], 10)) != 0) { Debug.LogAssertion("<接收到数据,但接收地址不是主机,过滤掉了>"); continue; }

                        bool result = CheckSumFun(receiveBytes);
                        if (result)
                        {
                            receiveStr.Clear();
                            for (int i = 0; i < datalength; i++)
                            {
                                receiveStr.Append(Convert.ToString(receiveBytes[i], 16));
                                if (i < datalength - 1)
                                    receiveStr.Append("-");
                            }
                            // Debug.LogError("接收的数据:" + receiveStr.ToString() + "***数据总长度:" + datalength + "***有效数据长度:" + Convert.ToString(receiveBytes[5], 10) + "***本次处理时长:" + (GetTime() - SendTime) + "毫秒");

                            //接收过一次返回后,清空本次任务,并且进入非等待接收状态,关闭计时(要在单主机情况下进行
                            if (MyTaskTable.Count > 0)
                                MyTaskTable.Remove(MyTaskTable[0]);
                            IsTimer = false;
                        }
                        else
                        {
                            Debug.LogError("接收数据检验和结果不正确");
                        }

                        Receiving = false;//进入非等待响应状态
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogError("接收串口数据错误:" + ex);
                port = null; ThreadRuning = false;
            }
        }

        /// <summary>
        /// 检查校验和  T:合法 F:非法
        /// </summary>
        private bool CheckSumFun(byte[] receiveBytes)
        {
            #region 检测命令是否正确
            if (Convert.ToInt32(receiveBytes[2]) == 0)
            {
                Debug.LogError("返回数据指出上一次发送的命令是错误的!");
                return false;
            }
            #endregion

            #region 计算数据的校验和是否与返回数据的校验和一致
            int SumInt = 0;
            for (int i = 0; i < receiveBytes.Length - 4; i++)
                SumInt += Convert.ToInt32(receiveBytes[i + 2]);
            SumInt = 65535 - SumInt;
            string SumStr = Convert.ToString(SumInt, 16);

            if (SumStr.Substring(0, 2) == Convert.ToString(receiveBytes[receiveBytes.Length - 1], 16) &&
                SumStr.Substring(2, 2) == Convert.ToString(receiveBytes[receiveBytes.Length - 2], 16))
            {
                return true;
            }
            else
            {
                return false;
            }
            #endregion
        }

        /// <summary>
        /// 获取当前系统时间(毫秒
        /// </summary>
        /// <returns></returns>
        private int GetTime()
        {
            string timeStr = DateTime.Now.ToString("ss:fff");
            string[] strs = timeStr.Split(':');
            int currentTime = int.Parse(strs[0]) * 1000;
            return currentTime += int.Parse(strs[1]);
        }

        /// <summary>
        /// 数据发送
        /// </summary>
        /// <param name="data"></param>
        /// <param name="count"></param>
        private void DataSend(Byte[] data, int count)
        {
            port.Write(data, 0, count);
        }
        private void OnApplicationQuit()
        {
            CloseDeviceConnect();
        }
    }

    /// <summary>
    /// 任务基类
    /// </summary>
    internal class TaskBase
    {
        //public int id;//任务唯一ID
        public CmdType cmdType;//命令类型
        public AddressCode sendAddress;//发送地址
        public AddressCode receiveAddress;//接收地址
        public string data;//数据
        public TaskBase(CmdType cmdType, AddressCode sendAddress, AddressCode receiveAddress, string data = "0x00")
        {
            this.cmdType = cmdType;
            this.sendAddress = sendAddress;
            this.receiveAddress = receiveAddress;
            this.data = data;
        }
    }

    /// <summary>
    /// 命令类型
    /// </summary>
    public enum CmdType
    {
        /// <summary>
        /// 心跳0x01
        /// </summary>
        Heart,
        /// <summary>
        /// 开始检测0x02
        /// </summary>
        StartCheck,
        /// <summary>
        /// 结束检测0x03
        /// </summary>
        OverCheck,
        /// <summary>
        /// 状态查询0x04
        /// </summary>
        StateQuery,
        /// <summary>
        /// 数字输出控制0x05
        /// </summary>
        OutPutCtrl,
        /// <summary>
        /// 模拟输出控制0x06
        /// </summary>
        DragCtrl,
        /// <summary>
        /// 清除编码器0x07
        /// </summary>
        ClearEncoder,
        /// <summary>
        /// AED控制0x08
        /// </summary>
        AedCtrl
    }

    /// <summary>
    /// 地址编码
    /// </summary>
    public enum AddressCode
    {
        /// <summary>
        /// 主机0x00
        /// </summary>
        Host,
        /// <summary>
        /// 平板0x10
        /// </summary>
        Pad,
        /// <summary>
        /// AED 0x20
        /// </summary>
        AED,
        /// <summary>
        /// 除颤仪0x30
        /// </summary>
        Defibrillator,
        /// <summary>
        /// 模型人0x40
        /// </summary>
        Human
    }

    /// <summary>
    /// 数据长度
    /// </summary>
    public enum DataLength
    {
        /// <summary>
        /// 一个字节
        /// </summary>
        One,
        /// <summary>
        /// 两个字节
        /// </summary>
        Two
    }

    /// <summary>
    /// AED灯光类型
    /// </summary>
    public enum AEDLightType
    {
        /// <summary>
        /// 全关
        /// </summary>
        AllOff,
        /// <summary>
        /// 全开
        /// </summary>
        AllOn,
        /// <summary>
        /// 只开电源
        /// </summary>
        Prower
    }

    /// <summary>
    /// AED音频类型
    /// </summary>
    public enum AEDAudioType
    {
        /// <summary>
        /// 按照图示,将电极贴在病人胸部的皮肤上,将电极插头插入插座上
        /// </summary>
        ReadyTip,
        /// <summary>
        /// 不建议除颤
        /// </summary>
        NotDefibrillate,
        /// <summary>
        /// 除颤完成,开始心肺复苏
        /// </summary>
        OverDefibrillate,
        /// <summary>
        /// 建议除颤,正在充电,不要接触病人身体
        /// </summary>
        Charging,
        /// <summary>
        /// 立刻进行除颤,按橘黄色按钮
        /// </summary>
        DisCharging,
        /// <summary>
        /// 贴上电极,插入插头
        /// </summary>
        ReadyTipAgain,
        /// <summary>
        /// 正在分析病人,不要触碰病人
        /// </summary>
        DontTouch,
        /// <summary>
        /// 电量不足,请充电
        /// </summary>
        LowBattery,
    }

    /// <summary>
    /// 除颤仪波形类型
    /// </summary>
    public enum WaveformType
    {
        /// <summary>
        /// 不显示
        /// </summary>
        None,//
        /// <summary>
        /// 死亡
        /// </summary>
        Die,
        /// <summary>
        /// 室颤
        /// </summary>
        VF,
        /// <summary>
        /// 正常
        /// </summary>
        Normal
    }

    /// <summary>
    /// 同步开关类型
    /// </summary>
    public enum SyncType
    {
        /// <summary>
        /// 不显示
        /// </summary>
        None,
        /// <summary>
        /// 关
        /// </summary>
        OFF,
        /// <summary>
        /// 开
        /// </summary>
        ON,
    }

    /// <summary>
    /// 充电类型
    /// </summary>
    public enum ChargeType
    {
        /// <summary>
        /// 不显示
        /// </summary>
        None,
        /// <summary>
        /// 充电
        /// </summary>
        Charge,
        /// <summary>
        /// 释放
        /// </summary>
        Disarm,
    }

    /// <summary>
    /// 除颤仪能量类型
    /// </summary>
    public enum EnergyType
    {
        /// <summary>
        /// 不显示
        /// </summary>
        ON,
        /// <summary>
        /// 20
        /// </summary>
        Twenty,
        /// <summary>
        /// 40
        /// </summary>
        Forty,
        /// <summary>
        /// 80
        /// </summary>
        Eighty,
        /// <summary>
        /// 120
        /// </summary>
        OneHundredAndTwenty,
        /// <summary>
        /// 150
        /// </summary>
        OneHundredAndFifty,
        /// <summary>
        /// 200
        /// </summary>
        TwoHundred
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值