예제 #1
0
        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));
            }
        }
예제 #2
0
        private void ModbusDataReveiveCallback(IAsyncResult ar)
        {
            if (ar.AsyncState is ModBusState state)
            {
                try
                {
                    state.ContentReceivedLength += state.WorkSocket.EndReceive(ar);
                }
                catch (Exception ex)
                {
                    // 关闭连接,记录日志
                    state.WorkSocket?.Close();
                    state = null;
                    LogNet?.WriteException(LogHeaderText, "内容数据接收失败!", ex);
                    return;
                }

                if (state.ContentReceivedLength < state.Content.Length)
                {
                    // 数据不够,继续接收
                    state.WorkSocket.BeginReceive(state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength,
                                                  SocketFlags.None, new AsyncCallback(ModbusDataReveiveCallback), state);
                    return;
                }


                // 数据接收完成
                // 内容接收完成,所有的数据接收结束
                byte[] data = new byte[state.HeadByte.Length + state.Content.Length];
                state.HeadByte.CopyTo(data, 0);
                state.Content.CopyTo(data, state.HeadByte.Length);

                state.Clear();



                if (data[7] == 0x01 ||
                    data[7] == 0x02 ||
                    data[7] == 0x03)
                {
                    if (data.Length != 0x0C)
                    {
                        // 指令长度验证错误,关闭网络连接
                        state.WorkSocket?.Close();
                        state = null;
                        LogNet?.WriteWarn(LogHeaderText, "Command length check failed!");
                        return;
                    }
                }



                // 需要回发消息
                byte[] copy = null;
                try
                {
                    switch (data[7])
                    {
                    case 0x01:
                    {
                        // 线圈读取
                        int address = data[8] * 256 + data[9];
                        int length  = data[10] * 256 + data[11];
                        if (length > 2048)
                        {
                            length = 2048;                                // 线圈读取应该小于2048个
                        }
                        bool[] read   = ReadCoil((ushort)address, (ushort)length);
                        byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read);
                        copy = new byte[9 + buffer.Length];
                        Array.Copy(data, 0, copy, 0, 8);
                        copy[4] = (byte)((copy.Length - 6) / 256);
                        copy[5] = (byte)((copy.Length - 6) % 256);
                        copy[8] = (byte)buffer.Length;
                        Array.Copy(buffer, 0, copy, 9, buffer.Length);
                        break;
                    }

                    case 0x03:
                    {
                        // 寄存器读取
                        int address = data[8] * 256 + data[9];
                        int length  = data[10] * 256 + data[11];
                        if (length > 127)
                        {
                            length = 127;                                // 寄存器最大读取范围为127个
                        }
                        byte[] buffer = ReadRegister((ushort)address, (ushort)length);
                        copy = new byte[9 + buffer.Length];
                        Array.Copy(data, 0, copy, 0, 8);
                        copy[4] = (byte)((copy.Length - 6) / 256);
                        copy[5] = (byte)((copy.Length - 6) % 256);
                        copy[8] = (byte)buffer.Length;
                        Array.Copy(buffer, 0, copy, 9, buffer.Length);
                        break;
                    }

                    case 0x05:
                    {
                        // 写单个线圈
                        int address = data[8] * 256 + data[9];
                        if (data[10] == 0xFF && data[11] == 0x00)
                        {
                            WriteCoil((ushort)address, true);
                        }
                        else if (data[10] == 0x00 && data[11] == 0x00)
                        {
                            WriteCoil((ushort)address, false);
                        }
                        copy = new byte[12];
                        Array.Copy(data, 0, copy, 0, 12);
                        copy[4] = 0x00;
                        copy[5] = 0x06;
                        break;
                    }

                    case 0x06:
                    {
                        // 写单个寄存器
                        ushort address  = (ushort)(data[8] * 256 + data[9]);
                        short  ValueOld = ReadShortRegister(address);
                        // 写入到寄存器
                        WriteRegister(address, data[10], data[11]);
                        short ValueNew = ReadShortRegister(address);
                        // 触发写入请求
                        OnRegisterBeforWrite(address, ValueOld, ValueNew);

                        copy = new byte[12];
                        Array.Copy(data, 0, copy, 0, 12);
                        copy[4] = 0x00;
                        copy[5] = 0x06;
                        break;
                    }

                    case 0x0F:
                    {
                        // 写多个线圈
                        int    address = data[8] * 256 + data[9];
                        int    length  = data[10] * 256 + data[11];
                        byte[] buffer  = new byte[data.Length - 13];
                        Array.Copy(data, 13, buffer, 0, buffer.Length);
                        bool[] value = BasicFramework.SoftBasic.ByteToBoolArray(buffer, length);
                        WriteCoil((ushort)address, value);
                        copy = new byte[12];
                        Array.Copy(data, 0, copy, 0, 12);
                        copy[4] = 0x00;
                        copy[5] = 0x06;
                        break;
                    }

                    case 0x10:
                    {
                        // 写多个寄存器
                        int    address = data[8] * 256 + data[9];
                        int    length  = data[10] * 256 + data[11];
                        byte[] buffer  = new byte[data.Length - 13];

                        // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47
                        MonitorAddress[] addresses = new MonitorAddress[length];
                        for (int i = 0; i < length; i++)
                        {
                            if ((2 * i + 14) < data.Length)
                            {
                                short ValueOld = ReadShortRegister((ushort)(address + i));
                                WriteRegister((ushort)(address + i), data[2 * i + 13], data[2 * i + 14]);
                                short ValueNew = ReadShortRegister((ushort)(address + i));
                                // 触发写入请求
                                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);
                        }

                        copy = new byte[12];
                        Array.Copy(data, 0, copy, 0, 12);
                        copy[4] = 0x00;
                        copy[5] = 0x06;
                        break;
                    }

                    default:
                    {
                        copy = new byte[9];
                        Array.Copy(data, 0, copy, 0, 8);
                        copy[4] = 0x00;
                        copy[5] = 0x03;
                        copy[7] = (byte)(data[7] + 0x80);
                        copy[8] = 0x01;          // 不支持的功能码
                        break;
                    }
                    }
                }
                catch (Exception ex)
                {
                    state.WorkSocket?.Close( );
                    state = null;
                    LogNet?.WriteException(LogHeaderText, ex);
                    return;
                }



                try
                {
                    // 管他是什么,先开始数据接收
                    // state.WorkSocket?.Close();
                    state.WorkSocket.BeginReceive(state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback(ModbusHeadReveiveCallback), state);
                }
                catch (Exception ex)
                {
                    state.WorkSocket?.Close();
                    state = null;
                    LogNet?.WriteException(LogHeaderText, "Send exception:", ex);
                    return;
                }


                // 回发数据,先获取发送锁
                state.hybirdLock.Enter();
                state.WorkSocket.BeginSend(copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback(DataSendCallBack), state: state);


                // 通知处理消息
                if (IsStarted)
                {
                    OnDataReceived?.Invoke(data);
                }
            }
        }