コード例 #1
0
        /// <summary>写多个线圈</summary>
        /// <remarks>
        /// 请求:0x0F|2字节起始地址|2字节输出数量(1~1698)|1字节字节计数|n字节输出值(n=输出数量/8,如果余数不为0,n=n+1)
        /// 响应:0x0F|2字节起始地址|2字节输出数量
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity WriteMultipleCoils(ModbusEntity entity)
        {
            var data = entity.Data;

            // 2字节地址,2字节数量,1字节计数,至少1字节的数据字节
            if (data == null || data.Length < 2 + 2 + 1 + 1)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr  = data.ReadUInt16(0);
            var size  = data.ReadUInt16(2);
            var count = data[4];

            // 输出数量
            if (size > 0x07B0 || count + 5 != data.Length)
            {
                return(entity.SetError(Errors.Count));
            }

            var store = DataStore.Coils;

            // 起始地址+输出数量
            if (addr + size >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }

#if DEBUG
            WriteLine("WriteMultipleCoils(0x" + addr.ToString("X2") + ", 0x" + size.ToString("X2") + ")");
#endif

            // 元素存放于m字节n位
            Int32 m = 0, n = 0;
            for (var i = 0; i < size; i++)
            {
                // 数据位于5+m字节的n位
                var flag = ((data[5 + m] >> n) & 0x01) == 0x01;

                store.Write(addr + i, flag);

                if (++n >= 8)
                {
                    m++;
                    n = 0;
                }
            }

            if (OnWriteCoil != null)
            {
                OnWriteCoil(entity, addr, size);
            }

            // 响应只要这么一点点
            entity.Data = data.ReadBytes(0, 4);

            return(entity);
        }
コード例 #2
0
        /// <summary>写单个线圈</summary>
        /// <remarks>
        /// 请求:0x05|2字节输出地址|2字节输出值(0x0000/0xFF00)
        /// 响应:0x05|2字节输出地址|2字节输出值(0x0000/0xFF00)
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity WriteSingleCoil(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令
            if (data == null || data.Length < 4)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr = data.ReadUInt16(0);
            var val  = data.ReadUInt16(2);

            // 输出值 False=0 True=0xFF00
            if (val != 0 && val != 0xFF00)
            {
                return(entity.SetError(Errors.Value));
            }

            var store = DataStore.Coils;

            // 输出地址
            if (addr >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }

            var flag = val != 0;

#if DEBUG
            WriteLine("WriteSingleCoil(0x" + addr.ToString("X2") + ", " + flag + ")");
#endif

            //store.Write(addr, flag);

            var count = 0;
            // 支持一下连续写入
            for (var i = 2; i + 1 < data.Length; i += 2, count++)
            {
                store.Write(addr + count, data.ReadUInt16(i) != 0);
            }

            if (OnWriteCoil != null)
            {
                OnWriteCoil(entity, addr, count);
            }

            // 读出来
            for (var i = 2; i + 1 < data.Length; i += 2)
            {
                data.WriteUInt16(i, (UInt16)(store.Read(addr + i - 2) ? 0xFF00 : 0));
            }

            //// 读出来
            //data.WriteUInt16(2, (UInt16)(store.Read(addr) ? 0xFF00 : 0));

            return(entity);
        }
コード例 #3
0
        /// <summary>写多个寄存器</summary>
        /// <remarks>
        /// 请求:0x10|2字节起始地址|2字节寄存器数量(1~123)|1字节字节计数|n*2寄存器值
        /// 响应:0x10|2字节起始地址|2字节寄存器数量
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity WriteMultipleRegisters(ModbusEntity entity)
        {
            var data = entity.Data;

            // 2字节地址,2字节数量,1字节计数,至少1字节的数据字节
            if (data == null || data.Length < 2 + 2 + 1 + 2)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr  = data.ReadUInt16(0);
            var size  = data.ReadUInt16(2);
            var count = data[4];

            // 输出数量
            if (size > 0x07B0 || data.Length - 5 != count)
            {
                return(entity.SetError(Errors.Count));
            }

            var store = DataStore.HoldingRegisters;

            // 起始地址+输出数量
            if (addr + size >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }

#if DEBUG
            WriteLine("WriteMultipleRegisters(0x" + addr.ToString("X2") + ", 0x" + size.ToString("X2") + ")");
#endif

            for (var i = 0; i < size; i++)
            {
                store.Write(addr + i, data.ReadUInt16(5 + i * 2));
            }

            if (OnWriteRegister != null)
            {
                OnWriteRegister(entity, addr, size);
            }

            // 响应只要这么一点点
            entity.Data = data.ReadBytes(0, 4);

            return(entity);
        }
コード例 #4
0
        /// <summary>写单个寄存器</summary>
        /// <remarks>
        /// 请求:0x06|2字节寄存器地址|2字节寄存器值
        /// 响应:0x06|2字节寄存器地址|2字节寄存器值
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity WriteSingleRegister(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令
            if (data == null || data.Length < 4)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr = data.ReadUInt16(0);
            var val  = data.ReadUInt16(2);
            // 寄存器值 0<<val<<0xFFFF
            //if (val != 0 && val != 0xFF00) return entity.SetError(3);

            var store = DataStore.HoldingRegisters;

            // 寄存器地址
            if (addr >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }

#if DEBUG
            WriteLine("WriteSingleRegister(0x" + addr.ToString("X2") + ", 0x" + val.ToString("X2") + ")");
#endif

            //store.Write(addr, val);
            var count = 0;
            // 支持多字连续写入
            for (var i = 2; i + 1 < data.Length; i += 2, count++)
            {
                store.Write(addr + count, data.ReadUInt16(i));
            }

            if (OnWriteRegister != null)
            {
                OnWriteRegister(entity, addr, count);
            }

            return(entity);
        }
コード例 #5
0
        /// <summary>诊断</summary>
        /// <remarks>
        /// 请求:0x08|2字节子功能|n*2字节数据
        /// 响应:0x08|2字节子功能|n*2字节数据
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity Diagnostics(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令。2字节子功能码,多字节的数据
            if (data == null || data.Length < 2)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var sub = data.ReadUInt16(0);

#if DEBUG
            WriteLine("Diagnostics(0x" + sub.ToString("X2") + ")");
#endif

            // 默认原样返回,暂时没有什么有用的子功能码需要处理
            return(entity);
        }
コード例 #6
0
        /// <summary>处理Modbus消息</summary>
        /// <param name="pk"></param>
        /// <returns></returns>
        public virtual Packet Process(Packet pk)
        {
#if DEBUG
            var buf = pk.Data;
            var str = "Request :";
            for (var i = 0; i < buf.Length; i++)
            {
                str += " " + buf[i].ToString("X2");
            }
            WriteLine(str);
#endif

            // 处理
            var entity = new ModbusEntity().Parse(pk.ReadBytes());
            // 检查主机
            if (entity.Host != 0 && entity.Host != Host)
            {
                return(null);
            }
            // 检查Crc校验
            var crc = pk.Data.Crc(pk.Offset, pk.Total - 2);
            if (crc != entity.Crc)
            {
                entity.SetError(Errors.CrcError);
            }
            else
            {
                entity = Process(entity);
            }
            pk = entity.ToArray();

#if DEBUG
            str = "Response:";
            for (var i = 0; i < buf.Length; i++)
            {
                str += " " + buf[i].ToString("X2");
            }
            WriteLine(str);
            WriteLine("");
#endif
            return(pk);
        }
コード例 #7
0
        /// <summary>报告从站ID</summary>
        /// <remarks>
        /// 请求:0x11
        /// 响应:0x11|1字节字节计数|从站ID|运行指示状态(0x00=OFF,0xFF=ON)|附加数据
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity ReportIdentity(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令。
            if (data != null && data.Length > 0)
            {
                return(entity.SetError(Errors.MessageLength));
            }

#if DEBUG
            WriteLine("ReportIdentity()");
#endif

            var hid = new Byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, };

            var buf = new Byte[1 + hid.Length];
            buf[0] = (Byte)hid.Length;
            Array.Copy(hid, 0, buf, 1, hid.Length);
            entity.Data = buf;

            return(entity);
        }
コード例 #8
0
        /// <summary>读取寄存器 输入寄存器/保持寄存器</summary>
        /// <remarks>
        /// 保持寄存器
        /// 请求:0x03|2字节起始地址|2字节寄存器数量(1~2000)
        /// 响应:0x03|1字节字节数|n*2字节寄存器值
        ///
        /// 输入寄存器
        /// 请求:0x04|2字节起始地址|2字节输入寄存器数量(1~2000)
        /// 响应:0x04|1字节字节数|n*2字节输入寄存器
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity ReadRegisters(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令
            if (data == null || data.Length != 4)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr  = data.ReadUInt16(0);
            var count = data.ReadUInt16(2);

            // 输出数量不正确 count <= 0x07D0=2000
            //if (count == 0 || count > 0x07D0) return entity.SetError(3);
            if (count == 0)
            {
                return(entity.SetError(Errors.Count));
            }

            IWordStore store = null;

#if DEBUG
            var func = "";
#endif
            switch (entity.Function)
            {
            case MBFunction.ReadHoldingRegisters:
                store = DataStore.HoldingRegisters;
#if DEBUG
                func = "ReadHoldingRegisters";
#endif
                break;

            case MBFunction.ReadInputRegisters:
                store = DataStore.InputRegisters;
#if DEBUG
                func = "ReadInputRegisters";
#endif
                break;

            default:
                break;
            }
            if (count > store.Count)
            {
                return(entity.SetError(Errors.Count));
            }
            // 起始地址+数量 不正确
            if (addr + count > 0xFFFF)
            {
                return(entity.SetError(Errors.Address));
            }

#if DEBUG
            WriteLine(func + "(0x" + addr.ToString("X2") + ", 0x" + count.ToString("X2") + ")");
#endif
            if (OnReadRegister != null)
            {
                OnReadRegister(entity, addr, count);
            }

            var buf = new Byte[1 + count * 2];
            buf[0] = (Byte)(count * 2);

            for (var i = 0; i < count; i++)
            {
                buf.WriteUInt16(1 + i * 2, store.Read(addr + i));
            }

            // 读出来
            entity.Data = buf;

            return(entity);
        }
コード例 #9
0
        /// <summary>读状态 离散量输入/线圈</summary>
        /// <remarks>
        /// 线圈
        /// 请求:0x01|2字节起始地址|2字节线圈数量(1~2000)
        /// 响应:0x01|1字节字节计数|n字节线圈状态(n=输出数量/8,如果余数不为0,n=n+1)
        ///
        /// 离散量输入
        /// 请求:0x02|2字节起始地址|2字节输入数量(1~2000)
        /// 响应:0x02|1字节字节计数|n字节输入状态(n=输入数量/8,如果余数不为0,n=n+1)
        /// </remarks>
        /// <param name="entity"></param>
        /// <returns></returns>
        ModbusEntity ReadCoils(ModbusEntity entity)
        {
            var data = entity.Data;

            // 无效功能指令
            if (data == null || data.Length != 4)
            {
                return(entity.SetError(Errors.MessageLength));
            }

            var addr  = data.ReadUInt16(0);
            var count = data.ReadUInt16(2);

            // 输出数量不正确 count <= 0x07D0=2000
            if (count == 0 || count > 0x07D0)
            {
                return(entity.SetError(Errors.Count));
            }

            IBitStore store = null;

#if DEBUG
            var func = "";
#endif
            switch (entity.Function)
            {
            case MBFunction.ReadCoils:
                store = DataStore.Coils;
#if DEBUG
                func = "ReadCoils";
#endif
                break;

            case MBFunction.ReadInputs:
                store = DataStore.Inputs;
#if DEBUG
                func = "ReadInputs";
#endif
                break;

            default:
                break;
            }

            // 起始地址+数量 不正确
            if (addr + count >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }
#if DEBUG
            WriteLine(func + "(0x" + addr.ToString("X2") + ", 0x" + count.ToString("X2") + ")");
#endif
            if (OnReadCoil != null)
            {
                OnReadCoil(entity, addr, count);
            }

            // 返回的时候,用字节存储每一个线圈的状态
            var n = count >> 3;
            if ((count & 0x07) != 0)
            {
                n++;
            }
            var buf = new Byte[1 + n];
            // 字节数
            buf[0] = (Byte)n;
            // 元素存放于m字节n位
            var m = n = 0;
            for (var i = 0; i < count; i++)
            {
                var p = store.Read(addr + i);

                // 存放在m个字节的n位,注意前面预留一个字节
                if (p)
                {
                    buf[1 + m] |= (Byte)(1 << n);
                }
                if (++n >= 8)
                {
                    m++;
                    n = 0;
                }
            }

            entity.Data = buf;

            return(entity);
        }
コード例 #10
0
        /// <summary>处理Modbus消息</summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected virtual ModbusEntity Process(ModbusEntity entity)
        {
            // 如果是广播消息,则设置主站ID,便于其他人知道我的主站ID
            if (entity.Host == 0)
            {
                entity.Host = Host;
            }
            try
            {
                switch (entity.Function)
                {
                case MBFunction.ReadCoils:
                case MBFunction.ReadInputs:
                    entity = ReadCoils(entity);
                    break;

                case MBFunction.ReadHoldingRegisters:
                case MBFunction.ReadInputRegisters:
                    entity = ReadRegisters(entity);
                    break;

                case MBFunction.WriteSingleCoil:
                    entity = WriteSingleCoil(entity);
                    break;

                case MBFunction.WriteSingleRegister:
                    entity = WriteSingleRegister(entity);
                    break;

                case MBFunction.WriteMultipleCoils:
                    entity = WriteMultipleCoils(entity);
                    break;

                case MBFunction.WriteMultipleRegisters:
                    entity = WriteMultipleRegisters(entity);
                    break;

                case MBFunction.Diagnostics:
                    entity = Diagnostics(entity);
                    break;

                case MBFunction.ReportIdentity:
                    entity = ReportIdentity(entity);
                    break;

                default:
                    // 不支持的功能码
                    return(entity.SetError(Errors.FunctionCode));
                }

                return(entity);
            }
            catch (Exception ex)
            {
                //WriteLine(ex.Message);
#if MF
                Microsoft.SPOT.Debug.Print(ex.Message);
#else
                Ding.Log.XTrace.WriteLine(ex.ToString());
#endif

                // 执行错误
                return(entity.SetError(Errors.ProcessError));
            }
        }