using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Device.TemperatureController;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MECF.Framework.Common.Device.ResistivityProbe
{
    public enum TemperatureVariableType
    {
        Decade=0,
        Kilo=1,
        Buffer=2,
        SignedDecade=3,
        Alarm=4
    }
    public class TemperatureSerialDevice
    {
        #region Delegate
        public delegate void UpdateVariableValueChanged(string name,byte address, string variableName, object variableValue);
        #endregion

        #region 常量
        private const byte SOH = 0x01;
        private const byte STX = 0x02;
        private const byte ETX = 0x03;
        private const byte ENQ = 0x05;
        private const byte ACK = 0x06;
        private const byte CR = 0x0D;
        private const byte ADD_FLAG = 0x30;
        private const byte MINUS_FLAG = 0x2D;
        #endregion

        #region 内部变量
        /// <summary>
        /// 串口
        /// </summary>
        private SerialPort _serialPort;
        /// <summary>
        /// 连接状态
        /// </summary>
        private bool _connected;
        /// <summary>
        /// 模块名称
        /// </summary>
        private string _name;
        /// <summary>
        /// 重连
        /// </summary>
        private bool _reconnect;
        /// <summary>
        /// 队列锁
        /// </summary>
        private object _locker = new object();
        /// <summary>
        /// 发送队列
        /// </summary>
        private List<TemperatureSendData> _sendQueueDatas = new List<TemperatureSendData>();
        /// <summary>
        /// 定时器
        /// </summary>
        private PeriodicJob _periodJob;
        /// <summary>
        /// 离线时间
        /// </summary>
        private DateTime _offlineDateTime;
        /// <summary>
        /// 接收超时
        /// </summary>
        private int _receiveTimeOut;
        /// <summary>
        /// 错误
        /// </summary>
        private string _errorMsg = "";
        /// <summary>
        /// 首次连接成功
        /// </summary>
        private bool _isFirstConnected = false;
        #endregion

        #region 事件
        /// <summary>
        /// 变量变更事件
        /// </summary>
        public event UpdateVariableValueChanged OnUpdateVariableValueChanged;
        #endregion

        #region 属性
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool Connected
        {
            get { return _connected; }
            set 
            {
                _connected = value;

            }
        }
        #endregion
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="portName"></param>
        /// <param name="baudRate"></param>
        /// <param name="stopBits"></param>
        /// <param name="dataBits"></param>
        /// <param name="parity"></param>
        public TemperatureSerialDevice(string name, string portName, int baudRate = 9600, StopBits stopBits = StopBits.One, int dataBits = 8, Parity parity = Parity.None,bool reconnect=false,int receiveTimeout=2000)
        {
            _serialPort = new SerialPort();
            _serialPort.BaudRate = baudRate;
            _serialPort.StopBits = stopBits;
            _serialPort.DataBits = dataBits;
            _serialPort.Parity = parity;
            _serialPort.PortName = portName;
            _serialPort.ReadTimeout = receiveTimeout;
            _serialPort.ErrorReceived += SerialPort_ErrorReceived;
            _name = name;
            _reconnect = reconnect;
            _receiveTimeOut = receiveTimeout;
            _periodJob = new PeriodicJob(50, OnTimer, $"{_name}_sender", false, true);
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public void Initialize()
        {
            _periodJob.Start();
        }
        /// <summary>
        /// 启动
        /// </summary>
        public void Start()
        {
            Open();
        }
        /// <summary>
        /// 打开 
        /// </summary>
        private void Open()
        {
            if (!_connected)
            {
                try
                {
                    if (!_serialPort.IsOpen)
                    {
                        _serialPort.Open();
                    }
                    _connected = true;
                    if (!_isFirstConnected)
                    {
                        _isFirstConnected = true;
                    }
                    LOG.WriteLog(eEvent.INFO_TEMPERATURE, _name, $"connect {_serialPort.PortName} Success");
                }
                catch (Exception ex)
                {
                    WriteErrorMsg(ex.Message);
                }
            }
        }
        /// <summary>
        /// 关闭
        /// </summary>
        public void Close()
        {
            try
            {
                _connected = false;
                _serialPort.Close();
            }
            catch (Exception ex)
            {
                WriteErrorMsg(ex.Message);
            }
        }
        /// <summary>
        /// 出现错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            LOG.WriteLog(eEvent.ERR_TEMPERATURE, _name, e.EventType.ToString());
        }
        /// <summary>
        /// 定时器
        /// </summary>
        /// <returns></returns>
        private bool OnTimer()
        {
            if (!_connected)
            {
                ///离线超过5秒清理发送队列
                if(DateTime.Now.Subtract(_offlineDateTime).TotalSeconds>=5&&_sendQueueDatas.Count>0)
                {
                    ClearSendQueue();
                }
                if (_reconnect)
                {
                    if (_isFirstConnected)
                    {
                        Open();
                    }
                }
                else
                {
                    _periodJob.Stop();
                }
                return true;
            }
            else
            {
                SendData();
            }
            return true;
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        private void SendData()
        {
            int queueCount = _sendQueueDatas.Count;
            if (_sendQueueDatas.Count != 0)
            {
                lock (_locker)
                {
                    TemperatureSendData data = _sendQueueDatas[0];
                    _sendQueueDatas.RemoveAt(0);
                    if (data != null)
                    {
                        if (data.Type == 0)//设置
                        {
                            WriteInfoMsg(0, $"execute set {data.Type} queue length {queueCount}");
                            try
                            {
                                SettingOperation(data.Id, data.Command, data.Data);
                            }
                            catch (Exception ex)
                            {
                                WriteErrorMsg(ex.Message);
                            }
                        }
                        else//读取变量
                        {
                            WriteInfoMsg(0, $"execute read {data.Type} queue length {queueCount}");
                            ReadVariableData(data);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 读取变量
        /// </summary>
        /// <param name="data"></param>
        private void ReadVariableData(TemperatureSendData data)
        {
            switch(data.VariableType)
            {
                case TemperatureVariableType.Decade:
                    if (ReadDecadeParam(data.Id, data.Command, out double decadeValue))
                    {
                        _errorMsg = "";
                        UpdateVariableValue(data,decadeValue);
                    }
                    break;
                case TemperatureVariableType.Kilo:
                    if (ReadKiloParam(data.Id, data.Command, out int kiloValue))
                    {
                        _errorMsg = "";
                        UpdateVariableValue(data,kiloValue);
                    }
                    break;
                case TemperatureVariableType.SignedDecade:
                    if(ReadSignedDecadeParam(data.Id,data.Command,out double signedDecadeValue))
                    {
                        _errorMsg = "";
                        UpdateVariableValue(data,signedDecadeValue);
                    }
                    break;
                case TemperatureVariableType.Buffer:
                    if(ReadBufferParam(data.Id,data.Command,out byte[] buffer,11))
                    {
                        _errorMsg = "";
                        UpdateVariableValue(data,BitConverter.ToString(buffer));
                    }
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 变量数据
        /// </summary>
        /// <param name="data"></param>
        private void UpdateVariableValue(TemperatureSendData data,object variableValue)
        {
            data.VariableValue = variableValue;
            if(OnUpdateVariableValueChanged!=null)
            {
                OnUpdateVariableValueChanged(_name,data.Id, data.VariableName, data.VariableValue);
            }
        }

        /// <summary>
        /// 清空发送队列
        /// </summary>
        private void ClearSendQueue()
        {
            try
            {
                while (_sendQueueDatas.Count != 0)
                {
                    _sendQueueDatas.Clear();
                }
            }
            catch(Exception ex)
            {
                WriteErrorMsg(ex.Message,false);
            }
        }

        /// <summary>
        /// 插入数据
        /// </summary>
        /// <param name="data"></param>
        private void InsertDataToQueue(TemperatureSendData data)
        {
            lock (_locker)
            {
                _sendQueueDatas.Insert(0, data);
            }
        }

        /// 插入数据
        /// </summary>
        /// <param name="data"></param>
        private void AddDataToQueue(TemperatureSendData data)
        {
            lock (_locker)
            {
                _sendQueueDatas.Add(data);
            }
        }

        #region Temperature
        /// <summary>
        /// 插入数据
        /// </summary>
        /// <param name="data"></param>
        private void InsertDatasToQueue(TemperatureSendData data,TemperatureSendData readData)
        {
            lock(_locker)
            {
                _sendQueueDatas.Insert(0, readData);
                _sendQueueDatas.Insert(0, data);
            }
        }
        /// <summary>
        /// 设置温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public bool SetTargetTemperature(byte id,double temperature)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Command = 0x31;
            data.Data=GetDecadeBytes(temperature);
            data.Type = 0;
            TemperatureSendData readData = GetReadTargetTemperature(id);
            InsertDatasToQueue(data,readData);
            return true;
        }
        /// <summary>
        /// 获取读取目标温度指令
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private TemperatureSendData GetReadTargetTemperature(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1; 
            data.Command = 0x31;
            data.VariableName = "TargetTemperature";
            data.VariableType = TemperatureVariableType.Decade;
            return data;
        }
        /// <summary>
        /// 读取温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void ReadTargetTemperature(byte id)
        {
            TemperatureSendData data=GetReadTargetTemperature(id);
            AddDataToQueue(data);
        }

        /// <summary>
        /// 读取Heat Exchanger温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void ReadHeatExchangerInternelSensorTemperature(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.Command = 0x32;
            data.VariableName = "HeatExchangerTemperature";
            data.VariableType = TemperatureVariableType.Decade;
            AddDataToQueue(data);
        }
        /// <summary>
        /// 读取Reservior温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void ReadReserviorExtendSensorTemperature(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.Command = 0x33;
            data.VariableName = "ReserviorTemperature";
            data.VariableType = TemperatureVariableType.Decade;
            AddDataToQueue(data);
        }
        
        #endregion

        #region Alarm
        /// <summary>
        /// 读取Alarm状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public void ReadAlarmStatus(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "Alarm";
            data.Command = 0x34;
            data.VariableType = TemperatureVariableType.Buffer;
            AddDataToQueue(data);
        }
        #endregion

        #region Offset
        /// <summary>
        /// 设置温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetOffsetValue(byte id, double temperature)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x36;
            data.Data = GetOffsetBytes(temperature);
            TemperatureSendData readData = GetReadOffsetData(id);
            InsertDatasToQueue(data,readData);
        }
        /// <summary>
        /// 获取读取Offset数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private TemperatureSendData GetReadOffsetData(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "Offset";
            data.Command = 0x36;
            data.VariableType = TemperatureVariableType.SignedDecade;
            return data;
        }
        /// <summary>
        /// 读取Alarm状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public void ReadOffsetValue(byte id)
        {
            TemperatureSendData data=GetReadOffsetData(id);
            AddDataToQueue(data);
        }
        #endregion

        #region Control Operation Model
        /// <summary>
        /// 设置Control Operation模式
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetControlOperationModel(byte id, int controlOperationModel)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x39;
            data.Data = GetKiloBytes(controlOperationModel);
            TemperatureSendData readData=GetReadControlOperationData(id);
            InsertDatasToQueue(data, readData);
        }
        /// <summary>
        /// 获取读取操作模式的数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private TemperatureSendData GetReadControlOperationData(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "ControlOperationModel";
            data.Command = 0x39;
            data.VariableType = TemperatureVariableType.Kilo;
            return data;
        }

        /// <summary>
        /// 读取Control Operation Model
        /// </summary>
        /// <param name="id"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public void ReadControlOperationModel(byte id)
        {
            TemperatureSendData data = GetReadControlOperationData(id);
            InsertDataToQueue(data);
        }
        #endregion

        #region PB Range
        /// <summary>
        /// 设置PB范围
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetPBRange(byte id, double pbrange)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x41;
            data.Data = GetDecadeBytes(pbrange);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取PB范围
        /// </summary>
        /// <param name="id"></param>
        /// <param name="pbrange"></param>
        /// <returns></returns>
        public void ReadPBRange(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "PBRange";
            data.Command = 0x41;
            data.VariableType = TemperatureVariableType.Decade;
            AddDataToQueue(data);
        }
        #endregion

        #region ARW
        /// <summary>
        /// 设置ARW范围
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetARWRange(byte id, double arwRange)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x42;
            data.Data = GetDecadeBytes(arwRange);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取Heat Exchanger温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadARWRange(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "ARWRange";
            data.Command = 0x42;
            data.VariableType = TemperatureVariableType.Decade;
            AddDataToQueue(data);
        }
        #endregion

        #region I constant
        /// <summary>
        /// 设置I Constant
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetIConstant(byte id, int iConstant)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x43;
            data.Data = GetKiloBytes(iConstant);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取Heat Exchanger温度
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadIConstant(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "IConstant";
            data.Command = 0x43;
            data.VariableType = TemperatureVariableType.Kilo;
            AddDataToQueue(data);
        }
        #endregion

        #region D constant
        /// <summary>
        /// 设置D Constant
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetDConstant(byte id, int dConstant)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x44;
            data.Data = GetDecadeBytes(dConstant);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取D Constant
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadDConstant(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "DConstant";
            data.Command = 0x44;
            data.VariableType = TemperatureVariableType.Decade;
            AddDataToQueue(data);
        }
        #endregion

        #region Output Ratio
        /// <summary>
        /// Output 比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetOutputRatio(byte id, int outputRatio)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x45;
            data.Data = GetKiloBytes(outputRatio);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取output比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadOutputRatio(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "OutputRatio";
            data.Command = 0x45;
            data.VariableType = TemperatureVariableType.Kilo;
            AddDataToQueue(data);
        }
        #endregion

        #region Heating Power upper limit
        /// <summary>
        /// Heating Power upper limit 比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetHeatingPowerUpperLimit(byte id, int upperLimit)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x46;
            data.Data = GetKiloBytes(upperLimit);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取output比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadHeatingPowerUpperLimit(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "HeatingPowerUpperLimit";
            data.Command = 0x46;
            data.VariableType = TemperatureVariableType.Kilo;
            AddDataToQueue(data);
        }
        #endregion

        #region Cooling Power upper limit
        /// <summary>
        /// Heating Power upper limit 比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SetCoolingPowerUpperLimit(byte id, int upperLimit)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x47;
            data.Data = GetKiloBytes(upperLimit);
            InsertDataToQueue(data);
        }
        /// <summary>
        /// 读取output比例
        /// </summary>
        /// <param name="id"></param>
        /// <param name="arwrange"></param>
        /// <returns></returns>
        public void ReadCoolingPowerUpperLimit(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 1;
            data.VariableName = "CoolingPowerUpperLimit";
            data.Command = 0x47;
            data.VariableType = TemperatureVariableType.Kilo;
            AddDataToQueue(data);
        }
        #endregion

        #region Saving RAM to EEPROM
        /// <summary>
        /// 将RAM保存至EEPROM
        /// </summary>
        /// <param name="id"></param>
        /// <param name="temperature"></param>
        /// <returns></returns>
        public void SaveRAMToEEPROM(byte id)
        {
            TemperatureSendData data = new TemperatureSendData();
            data.Id = id;
            data.Type = 0;
            data.Command = 0x48;
            data.Data = new byte[] { };
            InsertDataToQueue(data);
        }
        #endregion

        /// <summary>
        /// 读取千单位数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool ReadKiloParam(byte id,byte command,out int param,int responseLength=12)
        {
            param = 0;
            try
            {
                byte[] response = AfterSendDataWithResponse(id, command,responseLength);
                if (response==null)
                {
                    return false;
                }
                //解析
                if (response[0] == SOH && response[11] == CR && response[3] == command)
                {
                    if (response[1] == GetSendByteData(id))
                    {
                        byte[] byt = new byte[4];
                        Array.Copy(response, 4, byt, 0, byt.Length);
                        param = GetOriginalData(byt[0]) * 1000 + GetOriginalData(byt[1]) * 100 + GetOriginalData(byt[2]) * 10 + GetOriginalData(byt[3]);
                        return true;
                    }
                    else
                    {
                        string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
                        WriteErrorMsg(msg, false);
                        return false;
                    }
                }
                else
                {
                    string msg = "response data invalid";
                    WriteErrorMsg(msg, false);
                    return false;
                }
            }
            catch (Exception ex)
            {
                WriteErrorMsg(ex.Message);
                return false;
            }
        }
        /// <summary>
        /// 根据十单位数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <param name="decadeValue"></param>
        /// <returns></returns>
        private bool ReadDecadeParam(byte id, byte command, out double decadeValue, int responseLength = 12)
        {
            decadeValue = 0;
            byte[] response = AfterSendDataWithResponse(id, command,responseLength);
            if(response==null)
            {
                return false;
            }
            //解析
            if (response[0] == SOH && response[11] == CR && response[3] == command)
            {
                if (response[1] == GetSendByteData(id))
                {
                    byte[] tmpData = new byte[4];
                    Array.Copy(response, 4, tmpData, 0, tmpData.Length);
                    decadeValue = GetOriginalData(tmpData[0]) * 10 + GetOriginalData(tmpData[1]) + GetOriginalData(tmpData[2]) * 0.1 + GetOriginalData(tmpData[3]) * 0.01;
                    return true;
                }
                else
                {
                    string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
                    WriteErrorMsg(msg, false);
                    return false;
                }
            }
            else
            {
                string msg = "response data invalid";
                WriteErrorMsg(msg,false);
                return false;
            }
        }
        /// <summary>
        /// 根据有符号十单位数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <param name="signedDecadeValue"></param>
        /// <returns></returns>
        private bool ReadSignedDecadeParam(byte id, byte command, out double signedDecadeValue, int responseLength = 12)
        {
            signedDecadeValue = 0;
            byte[] response = AfterSendDataWithResponse(id, command, responseLength);
            if (response == null)
            {
                return false;
            }
            string err = "response data invalid";
            //解析
            if (response[0] == SOH && response[11] == CR && response[3] == command)
            {
                if (response[1] == GetSendByteData(id))
                {
                    byte[] byt = new byte[4];
                    Array.Copy(response, 4, byt, 0, byt.Length);
                    double tmp = GetOriginalData(byt[1]) + GetOriginalData(byt[2]) * 0.1 + GetOriginalData(byt[3]) * 0.01;
                    if (byt[0] == MINUS_FLAG)
                    {
                        signedDecadeValue = -tmp;
                        return true;
                    }
                    else if (byt[0] == ADD_FLAG)
                    {
                        signedDecadeValue = tmp;
                        return true;
                    }
                    else
                    {
                        WriteErrorMsg(err, false);
                        return false;
                    }
                }
                else
                {
                    string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
                    WriteErrorMsg(msg, false);
                    return false;
                }
            }
            else
            {
                WriteErrorMsg(err, false);
                return false;
            }
        }
        /// <summary>
        /// 根据数组数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <param name="signedDecadeValue"></param>
        /// <returns></returns>
        private bool ReadBufferParam(byte id, byte command, out byte[] buffer, int responseLength = 12)
        {
            buffer = null;
            byte[] response = AfterSendDataWithResponse(id, command, responseLength);
            if (response == null)
            {
                return false;
            }
            //解析
            if (response[0] == SOH && response[responseLength-1] == CR && response[3] == command)
            {
                if (response[1] == GetSendByteData(id))
                {
                    buffer = new byte[responseLength - 8];
                    Array.Copy(response, 4, buffer, 0, buffer.Length);
                    return true;
                }
                else
                {
                    string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
                    WriteErrorMsg(msg, false);
                    return false;
                }
            }
            else
            {
                string err = "response data invalid";
                WriteErrorMsg(err,false);
                return false;
            }
        }
        /// <summary>
        /// 设置操作
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <param name="byt"></param>
        /// <returns></returns>
        private bool SettingOperation(byte id, byte command, byte[] byt)
        {
            ClearPreCache();
            byte ut = GetSendByteData(id);
            byte[] data = new byte[byt.Length + 8];
            data[0] = SOH;
            data[1] = ut;
            data[2] = STX;
            data[3] = command;
            if (byt != null && byt.Length != 0)
            {
                Array.Copy(byt, 0, data, 4, byt.Length);
            }
            data[data.Length - 4] = ETX;
            data[data.Length - 3] = 0;
            data[data.Length - 2] = 0;
            data[data.Length - 1] = CR;
            //检验
            byte[] checksumData = new byte[data.Length - 5];
            //从数据第2位至ETX前所有数组
            Array.Copy(data, 1, checksumData, 0, checksumData.Length);
            byte[] checkSumByte = CalculateCheckSum(checksumData);
            Array.Copy(checkSumByte, 0, data, data.Length - 3, checkSumByte.Length);
            _serialPort.Write(data, 0, data.Length);
            WriteInfoMsg(1, data);
            //接收
            byte[] response = ReadData(id,command,3);
            if (response != null)
            {
                if (response[0] == ACK && response[2] == CR && response[1] == ut)
                {
                    return true;
                }
                else
                {
                    string err = "response data invalid";
                    WriteErrorMsg(err, false);
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 发送数据后获取数组
        /// </summary>
        /// <param name="id"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private byte[] AfterSendDataWithResponse(byte id,byte command,int responseLength=12)
        {
            try
            {
                ClearPreCache();
                byte ut = GetSendByteData(id);
                byte[] data = new byte[7] { SOH, ut, ENQ, command, 0, 0, CR };
                //检验
                byte[] checksumData = new byte[data.Length - 4];
                //从数据第2位至ETX前所有数组
                Array.Copy(data, 1, checksumData, 0, checksumData.Length);
                byte[] checkSumByte = CalculateCheckSum(checksumData);
                Array.Copy(checkSumByte, 0, data, data.Length - 3, checkSumByte.Length);
                _serialPort.Write(data, 0, data.Length);
                WriteInfoMsg(1, data);
                //接收
                byte[] response = ReadData(id,command,responseLength);
                if (response == null)
                {
                    return null;
                }
                //ack
                byte[] ack = new byte[] { ACK, ut, CR };
                _serialPort.Write(ack, 0, ack.Length);
                WriteInfoMsg(1, ack);
                return response;
            }
            catch(Exception ex)
            { 
                _connected = false;
                WriteErrorMsg(ex.Message);
                return null;
            }
        }
        /// <summary>
        /// 计算获取检验和数组
        /// </summary>
        /// <param name="checkSumData"></param>
        /// <returns></returns>
        private byte[] CalculateCheckSum(byte[] checkSumData)
        {
            short checksum = 0;
            for(int i=0;i<checkSumData.Length;i++)
            {
                checksum += checkSumData[i];
            }

            byte[] byt=BitConverter.GetBytes(checksum);
            byte[] data = new byte[2];
            data[0] = GetSendByteData((byte)(byt[0]/16));
            data[1] = GetSendByteData((byte)(byt[0]&0x0F));
            return data;
        }
        /// <summary>
        /// 获取温度数组(10|1|0.1|0.01)
        /// </summary>
        /// <param name="temperature"></param>
        /// <returns></returns>
        private byte[] GetDecadeBytes(double temperature)
        {
            byte decade = GetSendByteData((byte)Math.Floor(temperature / 10));
            byte unit = GetSendByteData((byte)Math.Floor(temperature % 10));
            byte digital = GetSendByteData((byte)Math.Floor(temperature * 10 % 10));
            return new byte[4] { decade, unit, digital, ADD_FLAG };
        }
        /// <summary>
        /// 获取Offset数组(正/负|1|0.1|0.01)
        /// </summary>
        /// <param name="temperature"></param>
        /// <returns></returns>
        private byte[] GetOffsetBytes(double temperature)
        {
            byte decade = temperature>0?ADD_FLAG:MINUS_FLAG;
            byte unit = GetSendByteData((byte)Math.Floor(temperature % 10));
            byte digital = GetSendByteData((byte)Math.Floor(temperature * 10 % 10));
            byte digital2 = GetSendByteData((byte)Math.Floor(temperature * 100 % 10));
            return new byte[4] { decade, unit, digital, digital2 };
        }
        /// <summary>
        /// 获取Control Operation Model(1000|100|10|1)
        /// </summary>
        /// <param name="controlOperationModel"></param>
        /// <returns></returns>
        private byte[] GetKiloBytes(int controlOperationModel)
        {
            byte kilo= GetSendByteData((byte)(controlOperationModel / 1000));
            byte hundred = GetSendByteData((byte)(controlOperationModel %1000/ 100));
            byte decade = GetSendByteData((byte)(controlOperationModel %100/ 10));
            byte unit = GetSendByteData((byte)(controlOperationModel % 10));
            return new byte[4] { kilo, hundred, decade, unit };
        }
        /// <summary>
        /// 获取发送位数据
        /// </summary>
        /// <param name="originalData"></param>
        /// <returns></returns>
        private byte GetSendByteData(byte originalData)
        {
            return (byte)(ADD_FLAG + originalData);
        }
        /// <summary>
        /// 解析源数据
        /// </summary>
        /// <param name="receivedData"></param>
        /// <returns></returns>
        private byte GetOriginalData(byte receivedData)
        {
            return (byte)(receivedData - ADD_FLAG);
        }
        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private byte[] ReadData(byte id,byte command ,int length)
        {
            byte[] response=new byte[length];
            DateTime dt = DateTime.Now;
            int count = 0;
            while (true)
            {
                int bytLength = _serialPort.BytesToRead;
                if (bytLength > 0)
                {
                    byte[] bytes = new byte[bytLength];
                    _serialPort.Read(bytes,0,bytes.Length);
                    WriteInfoMsg(0, bytes);
                    if (bytLength + count >= length)
                    {
                        Array.Copy(bytes, 0, response, count, length-count);
                        break;
                    }
                    else
                    {
                        Array.Copy(bytes, 0, response, count, bytLength);
                    }
                    count += bytLength;
                }
                if (DateTime.Now.Subtract(dt).TotalMilliseconds >= _receiveTimeOut)
                {
                    string err =$"receive id {id} command {command.ToString("X2")} timeout {length}";
                    TemperatureConfigManager.Instance.UpdataTCPowerConnectDic(_name + '-' + id.ToString(),false);//读取数据超时认为TC断联
                    WriteErrorMsg(err,false);
                    return null;
                }
                else
                {
                    TemperatureConfigManager.Instance.UpdataTCPowerConnectDic(_name + '-' + id.ToString(),true);
                }
                Thread.Sleep(2);
            }
            WriteInfoMsg(0, response);
            return response;
        }

        /// <summary>
        /// 记录错误信息
        /// </summary>
        /// <param name="msg"></param>
        private void WriteErrorMsg(string msg,bool disConnected=true)
        {
            if (disConnected)
            {
                _connected = false;
                _offlineDateTime = DateTime.Now;
            }
            bool enableLog = false;
            if (SC.ContainsItem("Log.EnableTemperatureLog"))
            {
                enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
            }
            if (enableLog)
            {
                if (_errorMsg != msg)
                {
                    _errorMsg = msg;
                    LOG.WriteBackgroundLog(eEvent.ERR_TEMPERATURE, _name, msg);
                }
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="bytes"></param>
        private void WriteInfoMsg(int logType, byte[] bytes)
        {
            bool enableLog = false;
            if (SC.ContainsItem("Log.EnableTemperatureLog"))
            {
                enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
            }
            if (enableLog)
            {
                string str = string.Join(" ", Array.ConvertAll(bytes, x => x.ToString("X2")));
                string type = logType == 0 ? "receive" : "send";
                LOG.WriteBackgroundLog(eEvent.INFO_TEMPERATURE, _name, $"{type} {str}");
            }
        }
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="bytes"></param>
        private void WriteInfoMsg(int logType, string str)
        {
            bool enableLog = false;
            if (SC.ContainsItem("Log.EnableTemperatureLog"))
            {
                enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
            }
            if (enableLog)
            {
                string type = logType == 0 ? "receive" : "send";
                LOG.WriteBackgroundLog(eEvent.INFO_TEMPERATURE, _name, $"{type} {str}");
            }
        }
        /// <summary>
        /// 清除前面的缓存
        /// </summary>
        private void ClearPreCache()
        {
            while (_serialPort.BytesToRead != 0)
            {
                byte[] bytes = new byte[_serialPort.BytesToRead];
                _serialPort.Read(bytes, 0, bytes.Length);
            }
        }
    }
    /// <summary>
    /// 发送数据类
    /// </summary>
    internal class TemperatureSendData
    {
        public byte Id { get; set; }

        public byte Command { get; set; }

        public byte[] Data { get; set; }
        /// <summary>
        /// 0-set,1-get
        /// </summary>
        public byte Type { get; set; }
        /// <summary>
        /// 变量
        /// </summary>
        public string VariableName { get; set; }
        /// <summary>
        /// 变量数值
        /// </summary>
        public object VariableValue { get; set; }
        /// <summary>
        /// 变量类型(0-十位数据,1-千位数据,2-数组,3-有符号十位数据)
        /// </summary>
        public TemperatureVariableType VariableType { get; set; }
    }
}