using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.Address;
using HslCommunication.Core.IMessage;
using HslCommunication.Core.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;

#if !NETSTANDARD2_0
using System.IO.Ports;
#endif

namespace HslCommunication.ModBus
{
    /// <summary>
    /// Modbus的虚拟服务器,同时支持Tcp和Rtu的机制,支持线圈,离散输入,寄存器和输入寄存器的读写操作,可以用来当做系统的数据交换池
    /// </summary>
    /// <remarks>
    /// 可以基于本类实现一个功能复杂的modbus服务器,在传统的.NET版本里,还支持modbus-rtu指令的收发,.NET Standard版本服务器不支持rtu操作。服务器支持的数据池如下:
    /// <list type="number">
    /// <item>线圈,功能码对应01,05,15</item>
    /// <item>离散输入,功能码对应02</item>
    /// <item>寄存器,功能码对应03,06,16</item>
    /// <item>输入寄存器,功能码对应04,输入寄存器在服务器端可以实现读写的操作</item>
    /// </list>
    /// </remarks>
    /// <example>
    /// 读写的地址格式为富文本地址,具体请参照下面的示例代码。
    /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Modbus\ModbusTcpServer.cs" region="ModbusTcpServerExample" title="ModbusTcpServer示例" />
    /// </example>
    public class ModbusTcpServer : NetworkDataServerBase
    {
        #region Constructor

        /// <summary>
        /// 实例化一个Modbus Tcp的服务器,支持数据读写操作
        /// </summary>
        public ModbusTcpServer()
        {
            // 四个数据池初始化,线圈,输入线圈,寄存器,只读寄存器
            coilBuffer = new SoftBuffer(DataPoolLength);
            inputBuffer = new SoftBuffer(DataPoolLength);
            registerBuffer = new SoftBuffer(DataPoolLength * 2);
            inputRegisterBuffer = new SoftBuffer(DataPoolLength * 2);

            subscriptions = new List<ModBusMonitorAddress>();
            subcriptionHybirdLock = new SimpleHybirdLock();
            ByteTransform = new ReverseWordTransform();
            WordLength = 1;

#if !NETSTANDARD2_0
            serialPort               = new SerialPort( );
#endif
        }

        #endregion

        #region Public Members

        /// <summary>
        /// 获取或设置数据解析的格式,默认ABCD,可选BADC,CDAB,DCBA格式
        /// </summary>
        /// <remarks>
        /// 对于Int32,UInt32,float,double,Int64,UInt64类型来说,存在多地址的电脑情况,需要和服务器进行匹配
        /// </remarks>
        public DataFormat DataFormat
        {
            get { return ByteTransform.DataFormat; }
            set { ByteTransform.DataFormat = value; }
        }

        /// <summary>
        /// 字符串数据是否按照字来反转
        /// </summary>
        public bool IsStringReverse
        {
            get { return ((ReverseWordTransform)ByteTransform).IsStringReverse; }
            set { ((ReverseWordTransform)ByteTransform).IsStringReverse = value; }
        }

        /// <summary>
        /// 获取或设置服务器的站号信息,对于rtu模式,只有站号对了,才会反馈回数据信息。默认为1。
        /// </summary>
        public int Station
        {
            get { return station; }
            set { station = value; }
        }

        #endregion

        #region Data Persistence

        /// <summary>
        /// 将数据源的内容生成原始数据,等待缓存
        /// </summary>
        /// <returns>原始的数据内容</returns>
        protected override byte[] SaveToBytes()
        {
            byte[] buffer = new byte[DataPoolLength * 6];
            Array.Copy(coilBuffer.GetBytes(), 0, buffer, 0, DataPoolLength);
            Array.Copy(inputBuffer.GetBytes(), 0, buffer, DataPoolLength, DataPoolLength);
            Array.Copy(registerBuffer.GetBytes(), 0, buffer, DataPoolLength * 2, DataPoolLength * 2);
            Array.Copy(inputRegisterBuffer.GetBytes(), 0, buffer, DataPoolLength * 4, DataPoolLength * 2);
            return buffer;
        }

        /// <summary>
        /// 从原始的数据复原数据
        /// </summary>
        /// <param name="content">原始的数据</param>
        protected override void LoadFromBytes(byte[] content)
        {
            if (content.Length < DataPoolLength * 6) throw new Exception("File is not correct");

            coilBuffer.SetBytes(content, 0, 0, DataPoolLength);
            inputBuffer.SetBytes(content, DataPoolLength, 0, DataPoolLength);
            registerBuffer.SetBytes(content, DataPoolLength * 2, 0, DataPoolLength * 2);
            inputRegisterBuffer.SetBytes(content, DataPoolLength * 4, 0, DataPoolLength * 2);
        }

        #endregion

        #region Coil Read Write

        /// <summary>
        /// 读取地址的线圈的通断情况
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public bool ReadCoil(string address)
        {
            ushort add = ushort.Parse(address);
            return coilBuffer.GetByte(add) != 0x00;
        }

        /// <summary>
        /// 批量读取地址的线圈的通断情况
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="length">读取长度</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public bool[] ReadCoil(string address, ushort length)
        {
            ushort add = ushort.Parse(address);
            return coilBuffer.GetBytes(add, length).Select(m => m != 0x00).ToArray();
        }

        /// <summary>
        /// 写入线圈的通断值
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="data">是否通断</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public void WriteCoil(string address, bool data)
        {
            ushort add = ushort.Parse(address);
            coilBuffer.SetValue((byte)(data ? 0x01 : 0x00), add);
        }

        /// <summary>
        /// 写入线圈数组的通断值
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="data">是否通断</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public void WriteCoil(string address, bool[] data)
        {
            if (data == null) return;

            ushort add = ushort.Parse(address);
            coilBuffer.SetBytes(data.Select(m => (byte)(m ? 0x01 : 0x00)).ToArray(), add);
        }

        #endregion

        #region Discrete Read Write

        /// <summary>
        /// 读取地址的离散线圈的通断情况
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public bool ReadDiscrete(string address)
        {
            ushort add = ushort.Parse(address);
            return inputBuffer.GetByte(add) != 0x00;
        }

        /// <summary>
        /// 批量读取地址的离散线圈的通断情况
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="length">读取长度</param>
        /// <returns><c>True</c>或是<c>False</c></returns>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public bool[] ReadDiscrete(string address, ushort length)
        {
            ushort add = ushort.Parse(address);
            return inputBuffer.GetBytes(add, length).Select(m => m != 0x00).ToArray();
        }

        /// <summary>
        /// 写入离散线圈的通断值
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="data">是否通断</param>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public void WriteDiscrete(string address, bool data)
        {
            ushort add = ushort.Parse(address);
            inputBuffer.SetValue((byte)(data ? 0x01 : 0x00), add);
        }

        /// <summary>
        /// 写入离散线圈数组的通断值
        /// </summary>
        /// <param name="address">起始地址,示例:"100"</param>
        /// <param name="data">是否通断</param>
        /// <exception cref="IndexOutOfRangeException"></exception>
        public void WriteDiscrete(string address, bool[] data)
        {
            if (data == null) return;

            ushort add = ushort.Parse(address);
            inputBuffer.SetBytes(data.Select(m => (byte)(m ? 0x01 : 0x00)).ToArray(), add);
        }

        #endregion

        #region NetworkDataServerBase Override

        /// <summary>
        /// 读取自定义的寄存器的值。按照字为单位
        /// </summary>
        /// <param name="address">起始地址,示例:"100","x=4;100"</param>
        /// <param name="length">数据长度</param>
        /// <exception cref="IndexOutOfRangeException"></exception>
        /// <returns>byte数组值</returns>
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            OperateResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, true, ModbusInfo.ReadRegister);
            if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysis);

            if (analysis.Content.Function == ModbusInfo.ReadRegister)
            {
                return OperateResult.CreateSuccessResult(registerBuffer.GetBytes(analysis.Content.Address * 2, length * 2));
            }
            else if (analysis.Content.Function == ModbusInfo.ReadInputRegister)
            {
                return OperateResult.CreateSuccessResult(inputRegisterBuffer.GetBytes(analysis.Content.Address * 2, length * 2));
            }
            else
            {
                return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
            }
        }

        /// <summary>
        /// 写入自定义的数据到数据内存中去
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">数据值</param>
        /// <returns>是否写入成功的结果对象</returns>
        public override OperateResult Write(string address, byte[] value)
        {
            OperateResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, true, ModbusInfo.ReadRegister);
            if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysis);

            if (analysis.Content.Function == ModbusInfo.ReadRegister)
            {
                registerBuffer.SetBytes(value, analysis.Content.Address * 2);
                return OperateResult.CreateSuccessResult();
            }
            else if (analysis.Content.Function == ModbusInfo.ReadInputRegister)
            {
                inputRegisterBuffer.SetBytes(value, analysis.Content.Address * 2);
                return OperateResult.CreateSuccessResult();
            }
            else
            {
                return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
            }
        }

        /// <summary>
        /// 写入寄存器数据,指定字节数据
        /// </summary>
        /// <param name="address">起始地址,示例:"100",如果是输入寄存器:"x=4;100"</param>
        /// <param name="high">高位数据</param>
        /// <param name="low">地位数据</param>
        public void Write(string address, byte high, byte low)
        {
            Write(address, new byte[] { high, low });
        }

        #endregion

        #region NetServer Override

        /// <summary>
        /// 当客户端登录后,进行Ip信息的过滤,然后触发本方法,也就是说之后的客户端需要
        /// </summary>
        /// <param name="socket">网络套接字</param>
        /// <param name="endPoint">终端节点</param>
        protected override void ThreadPoolLoginAfterClientCheck(Socket socket, System.Net.IPEndPoint endPoint)
        {
            // 开始接收数据信息
            AppSession appSession = new AppSession();
            appSession.IpEndPoint = endPoint;
            appSession.WorkSocket = socket;
            try
            {
                socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(SocketAsyncCallBack), appSession);
                AddClient(appSession);
            }
            catch
            {
                socket.Close();
                LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
            }
        }

        private void SocketAsyncCallBack(IAsyncResult ar)
        {
            if (ar.AsyncState is AppSession session)
            {
                try
                {
                    int receiveCount = session.WorkSocket.EndReceive(ar);

                    ModbusTcpMessage mdMessage = new ModbusTcpMessage();
                    OperateResult<byte[]> read1 = ReceiveByMessage(session.WorkSocket, 5000, mdMessage);
                    if (!read1.IsSuccess)
                    {
                        LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, session.IpEndPoint));
                        RemoveClient(session);
                        return;
                    };

                    ushort id = (ushort)(read1.Content[0] * 256 + read1.Content[1]);
                    byte[] back = ModbusInfo.PackCommandToTcp(ReadFromModbusCore(SoftBasic.BytesArrayRemoveBegin(read1.Content, 6)), id);
                    if (back != null)
                    {
                        session.WorkSocket.Send(back);
                    }
                    else
                    {
                        session.WorkSocket.Close();
                        RemoveClient(session);
                        return;
                    }

                    RaiseDataReceived(read1.Content);
                    session.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(SocketAsyncCallBack), session);
                }
                catch
                {
                    // 关闭连接,记录日志
                    session.WorkSocket?.Close();
                    LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, session.IpEndPoint));
                    RemoveClient(session);
                    return;
                }
            }
        }

        #endregion

        #region Function Process Center

        /// <summary>
        /// 创建特殊的功能标识,然后返回该信息
        /// </summary>
        /// <param name="modbusCore">modbus核心报文</param>
        /// <param name="error">错误码</param>
        /// <returns>携带错误码的modbus报文</returns>
        private byte[] CreateExceptionBack(byte[] modbusCore, byte error)
        {
            byte[] buffer = new byte[3];
            buffer[0] = modbusCore[0];
            buffer[1] = (byte)(modbusCore[1] + 0x80);
            buffer[2] = error;
            return buffer;
        }

        /// <summary>
        /// 创建返回消息
        /// </summary>
        /// <param name="modbusCore">modbus核心报文</param>
        /// <param name="content">返回的实际数据内容</param>
        /// <returns>携带内容的modbus报文</returns>
        private byte[] CreateReadBack(byte[] modbusCore, byte[] content)
        {
            byte[] buffer = new byte[3 + content.Length];
            buffer[0] = modbusCore[0];
            buffer[1] = modbusCore[1];
            buffer[2] = (byte)content.Length;
            Array.Copy(content, 0, buffer, 3, content.Length);
            return buffer;
        }

        /// <summary>
        /// 创建写入成功的反馈信号
        /// </summary>
        /// <param name="modbus">modbus核心报文</param>
        /// <returns>携带成功写入的信息</returns>
        private byte[] CreateWriteBack(byte[] modbus)
        {
            byte[] buffer = new byte[6];
            Array.Copy(modbus, 0, buffer, 0, 6);
            return buffer;
        }


        private byte[] ReadCoilBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                // 越界检测
                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                // 地址长度检测
                if (length > 2040)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                bool[] read = ReadCoil(address.ToString(), length);
                byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read);
                return CreateReadBack(modbus, buffer);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpReadCoilException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }

        private byte[] ReadDiscreteBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                // 越界检测
                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                // 地址长度检测
                if (length > 2040)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                bool[] read = ReadDiscrete(address.ToString(), length);
                byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read);
                return CreateReadBack(modbus, buffer);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpReadCoilException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }


        private byte[] ReadRegisterBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                // 越界检测
                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                // 地址长度检测
                if (length > 127)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                byte[] buffer = Read(address.ToString(), length).Content;
                return CreateReadBack(modbus, buffer);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpReadRegisterException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }

        private byte[] ReadInputRegisterBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                // 越界检测
                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                // 地址长度检测
                if (length > 127)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                byte[] buffer = Read("x=4;" + address.ToString(), length).Content;
                return CreateReadBack(modbus, buffer);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpReadRegisterException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }

        private byte[] WriteOneCoilBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);

                if (modbus[4] == 0xFF && modbus[5] == 0x00)
                {
                    WriteCoil(address.ToString(), true);
                }
                else if (modbus[4] == 0x00 && modbus[5] == 0x00)
                {
                    WriteCoil(address.ToString(), false);
                }
                return CreateWriteBack(modbus);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpWriteCoilException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }



        private byte[] WriteOneRegisterBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                short ValueOld = ReadInt16(address.ToString()).Content;
                // 写入到寄存器
                Write(address.ToString(), modbus[4], modbus[5]);
                short ValueNew = ReadInt16(address.ToString()).Content;
                // 触发写入请求
                OnRegisterBeforWrite(address, ValueOld, ValueNew);

                return CreateWriteBack(modbus);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpWriteRegisterException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }

        private byte[] WriteCoilsBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                if (length > 2040)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                byte[] buffer = new byte[modbus.Length - 7];
                Array.Copy(modbus, 7, buffer, 0, buffer.Length);
                bool[] value = BasicFramework.SoftBasic.ByteToBoolArray(buffer, length);
                WriteCoil(address.ToString(), value);
                return CreateWriteBack(modbus);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpWriteCoilException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }


        private byte[] WriteRegisterBack(byte[] modbus)
        {
            try
            {
                ushort address = ByteTransform.TransUInt16(modbus, 2);
                ushort length = ByteTransform.TransUInt16(modbus, 4);

                if ((address + length) > ushort.MaxValue + 1)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound);
                }

                if (length > 127)
                {
                    return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver);
                }

                byte[] buffer = new byte[modbus.Length - 7];

                // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47
                MonitorAddress[] addresses = new MonitorAddress[length];
                for (ushort i = 0; i < length; i++)
                {
                    short ValueOld = ReadInt16((address + i).ToString()).Content;
                    Write((address + i).ToString(), modbus[2 * i + 7], modbus[2 * i + 8]);
                    short ValueNew = ReadInt16((address + i).ToString()).Content;
                    // 触发写入请求
                    addresses[i] = new MonitorAddress()
                    {
                        Address = (ushort)(address + i),
                        ValueOrigin = ValueOld,
                        ValueNew = ValueNew
                    };
                }

                // 所有数据都更改完成后,再触发消息
                for (int i = 0; i < addresses.Length; i++)
                {
                    OnRegisterBeforWrite(addresses[i].Address, addresses[i].ValueOrigin, addresses[i].ValueNew);
                }

                return CreateWriteBack(modbus);
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), StringResources.Language.ModbusTcpWriteRegisterException, ex);
                return CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException);
            }
        }


        #endregion

        #region Subscription Support

        // 本服务器端支持指定地址的数据订阅器,目前仅支持寄存器操作

        private List<ModBusMonitorAddress> subscriptions;     // 数据订阅集合
        private SimpleHybirdLock subcriptionHybirdLock;       // 集合锁

        /// <summary>
        /// 新增一个数据监视的任务,针对的是寄存器
        /// </summary>
        /// <param name="monitor">监视地址对象</param>
        public void AddSubcription(ModBusMonitorAddress monitor)
        {
            subcriptionHybirdLock.Enter();
            subscriptions.Add(monitor);
            subcriptionHybirdLock.Leave();
        }

        /// <summary>
        /// 移除一个数据监视的任务
        /// </summary>
        /// <param name="monitor"></param>
        public void RemoveSubcrption(ModBusMonitorAddress monitor)
        {
            subcriptionHybirdLock.Enter();
            subscriptions.Remove(monitor);
            subcriptionHybirdLock.Leave();
        }

        /// <summary>
        /// 在数据变更后,进行触发是否产生订阅
        /// </summary>
        /// <param name="address">数据地址</param>
        /// <param name="before">修改之前的数</param>
        /// <param name="after">修改之后的数</param>
        private void OnRegisterBeforWrite(ushort address, short before, short after)
        {
            subcriptionHybirdLock.Enter();
            for (int i = 0; i < subscriptions.Count; i++)
            {
                if (subscriptions[i].Address == address)
                {
                    subscriptions[i].SetValue(after);
                    if (before != after)
                    {
                        subscriptions[i].SetChangeValue(before, after);
                    }
                }
            }
            subcriptionHybirdLock.Leave();
        }

        #endregion

        #region Modbus Core Logic

        /// <summary>
        /// 检测当前的Modbus接收的指定是否是合法的
        /// </summary>
        /// <param name="buffer">缓存数据</param>
        /// <returns>是否合格</returns>
        private bool CheckModbusMessageLegal(byte[] buffer)
        {
            try
            {
                if (buffer[1] == ModbusInfo.ReadCoil ||
                    buffer[1] == ModbusInfo.ReadDiscrete ||
                    buffer[1] == ModbusInfo.ReadRegister ||
                    buffer[1] == ModbusInfo.ReadInputRegister ||
                    buffer[1] == ModbusInfo.WriteOneCoil ||
                    buffer[1] == ModbusInfo.WriteOneRegister)
                {
                    if (buffer.Length != 0x06)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else if (
                    buffer[1] == ModbusInfo.WriteCoil ||
                    buffer[1] == ModbusInfo.WriteRegister)
                {
                    if (buffer.Length < 7)
                    {
                        return false;
                    }
                    else
                    {
                        if (buffer[6] == (buffer.Length - 7))
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                LogNet?.WriteException(ToString(), ex);
                return false;
            }
        }

        /// <summary>
        /// Modbus核心数据交互方法,允许重写自己来实现,报文只剩下核心的Modbus信息,去除了MPAB报头信息
        /// </summary>
        /// <param name="modbusCore">核心的Modbus报文</param>
        /// <returns>进行数据交互之后的结果</returns>
        protected virtual byte[] ReadFromModbusCore(byte[] modbusCore)
        {
            byte[] buffer = null;

            switch (modbusCore[1])
            {
                case ModbusInfo.ReadCoil:
                    {
                        buffer = ReadCoilBack(modbusCore); break;
                    }
                case ModbusInfo.ReadDiscrete:
                    {
                        buffer = ReadDiscreteBack(modbusCore); break;
                    }
                case ModbusInfo.ReadRegister:
                    {
                        buffer = ReadRegisterBack(modbusCore); break;
                    }
                case ModbusInfo.ReadInputRegister:
                    {
                        buffer = ReadInputRegisterBack(modbusCore); break;
                    }
                case ModbusInfo.WriteOneCoil:
                    {
                        buffer = WriteOneCoilBack(modbusCore); break;
                    }
                case ModbusInfo.WriteOneRegister:
                    {
                        buffer = WriteOneRegisterBack(modbusCore); break;
                    }
                case ModbusInfo.WriteCoil:
                    {
                        buffer = WriteCoilsBack(modbusCore); break;
                    }
                case ModbusInfo.WriteRegister:
                    {
                        buffer = WriteRegisterBack(modbusCore); break;
                    }
                default:
                    {
                        buffer = CreateExceptionBack(modbusCore, ModbusInfo.FunctionCodeNotSupport); break;
                    }
            }

            return buffer;
        }

        #endregion

        #region Serial Support

#if !NETSTANDARD2_0

        private SerialPort serialPort;            // 核心的串口对象

        /// <summary>
        /// 使用默认的参数进行初始化串口,9600波特率,8位数据位,无奇偶校验,1位停止位
        /// </summary>
        /// <param name="com">串口信息</param>
        public void StartSerialPort( string com )
        {
            StartSerialPort( com, 9600 );
        }

        /// <summary>
        /// 使用默认的参数进行初始化串口,8位数据位,无奇偶校验,1位停止位
        /// </summary>
        /// <param name="com">串口信息</param>
        /// <param name="baudRate">波特率</param>
        public void StartSerialPort( string com, int baudRate )
        {
            StartSerialPort( sp =>
            {
                sp.PortName = com;
                sp.BaudRate = baudRate;
                sp.DataBits = 8;
                sp.Parity = Parity.None;
                sp.StopBits = StopBits.One;
            } );
        }

        /// <summary>
        /// 使用自定义的初始化方法初始化串口的参数
        /// </summary>
        /// <param name="inni">初始化信息的委托</param>
        public void StartSerialPort( Action<SerialPort> inni )
        {
            if (!serialPort.IsOpen)
            {
                inni?.Invoke( serialPort );

                serialPort.ReadBufferSize = 1024;
                serialPort.ReceivedBytesThreshold = 1;
                serialPort.Open( );
                serialPort.DataReceived += SerialPort_DataReceived;
            }
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public void CloseSerialPort( )
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close( );
            }
        }

        /// <summary>
        /// 接收到串口数据的时候触发
        /// </summary>
        /// <param name="sender">串口对象</param>
        /// <param name="e">消息</param>
        private void SerialPort_DataReceived( object sender, SerialDataReceivedEventArgs e )
        {
            int rCount = 0;
            byte[] buffer = new byte[1024];
            byte[] receive = null;

            while(true)
            {
                System.Threading.Thread.Sleep( 20 );            // 此处做个微小的延时,等待数据接收完成
                int count = serialPort.Read( buffer, rCount, serialPort.BytesToRead );
                rCount += count;
                if(count == 0) break;

                receive = new byte[rCount];
                Array.Copy( buffer, 0, receive, 0, count );
            }

            if(receive == null) return;
            
            if (receive.Length < 3)
            {
                LogNet?.WriteError( ToString( ), $"Uknown Data:" + SoftBasic.ByteToHexString( receive, ' ' ) );
                return;
            }

            if (Serial.SoftCRC16.CheckCRC16( receive ))
            {
                byte[] modbusCore = SoftBasic.BytesArrayRemoveLast( receive, 2 );

                if (!CheckModbusMessageLegal( modbusCore ))
                {
                    // 指令长度验证错误,关闭网络连接
                    LogNet?.WriteError( ToString( ), $"Receive Nosense Modbus-rtu : " + SoftBasic.ByteToHexString( receive, ' ' ) );
                    return;
                }

                // 验证站号是否一致
                if(station >= 0 && station != modbusCore[0])
                {
                    LogNet?.WriteError( ToString( ), $"Station not match Modbus-rtu : " + SoftBasic.ByteToHexString( receive, ' ' ) );
                    return;
                }

                // LogNet?.WriteError( ToString( ), $"Success:" + BasicFramework.SoftBasic.ByteToHexString( receive, ' ' ) );
                // 需要回发消息
                byte[] copy = ModbusInfo.PackCommandToRtu( ReadFromModbusCore( modbusCore ) );

                serialPort.Write( copy, 0, copy.Length );

                if (IsStarted) RaiseDataReceived( receive );
            }
            else
            {
                LogNet?.WriteWarn( "CRC Check Failed : " + SoftBasic.ByteToHexString( receive, ' ' ) );
            }
        }

#endif

        #endregion

        #region IDisposable Support

        /// <summary>
        /// 释放当前的对象
        /// </summary>
        /// <param name="disposing">是否托管对象</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                subcriptionHybirdLock?.Dispose();
                subscriptions?.Clear();
                coilBuffer?.Dispose();
                inputBuffer?.Dispose();
                registerBuffer?.Dispose();
                inputRegisterBuffer?.Dispose();
#if !NETSTANDARD2_0
                serialPort?.Dispose( );
#endif
            }
            base.Dispose(disposing);
        }

        #endregion

        #region Private Member

        private SoftBuffer coilBuffer;                // 线圈的数据池
        private SoftBuffer inputBuffer;               // 离散输入的数据池
        private SoftBuffer registerBuffer;            // 寄存器的数据池
        private SoftBuffer inputRegisterBuffer;       // 输入寄存器的数据池

        private const int DataPoolLength = 65536;     // 数据的长度
        private int station = 1;                      // 服务器的站号数据,对于tcp无效,对于rtu来说,如果小于0,则忽略站号信息

        #endregion

        #region Object Override

        /// <summary>
        /// 返回表示当前对象的字符串
        /// </summary>
        /// <returns>字符串</returns>
        public override string ToString()
        {
            return $"ModbusTcpServer[{Port}]";
        }

        #endregion
    }
}