Example #1
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;

            switch (entity.Function)
            {
            case MBFunction.ReadHoldingRegisters:
                store = DataStore.HoldingRegisters;
                break;

            case MBFunction.ReadInputRegisters:
                store = DataStore.InputRegisters;
                break;

            default:
                break;
            }
            if (count > store.Count)
            {
                return(entity.SetError(Errors.Count));
            }
            // 起始地址+数量 不正确
            if (addr + count > 0xFFFF)
            {
                return(entity.SetError(Errors.Address));
            }
            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);
        }
Example #2
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
                NewLife.Log.XTrace.WriteLine(ex.ToString());
#endif

                // 执行错误
                return(entity.SetError(Errors.ProcessError));
            }
        }
Example #3
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;

            switch (entity.Function)
            {
            case MBFunction.ReadCoils:
                store = DataStore.Coils;
                break;

            case MBFunction.ReadInputs:
                store = DataStore.Inputs;
                break;

            default:
                break;
            }

            // 起始地址+数量 不正确
            if (addr + count >= store.Count)
            {
                return(entity.SetError(Errors.Address));
            }
            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);
        }
Example #4
0
        /// <summary>处理指令</summary>
        /// <param name="entity">指令实体</param>
        /// <param name="expect">预期返回数据长度</param>
        /// <returns></returns>
        ModbusEntity Process(ModbusEntity entity, Int32 expect)
        {
            if (Transport == null)
            {
                throw new NullReferenceException("Transport");
            }

            entity.Host = Host;

            // 发送
            var buf = entity.ToArray();

#if MF && DEBUG
            var str = "Request :";
            for (int i = 0; i < buf.Length; i++)
            {
                str += " " + buf[i].ToString("X2");
            }
            WriteLine(str);
#endif
#if !MF
            if (EnableDebug)
            {
                WriteLine(entity.Function + " :" + buf.ToHex());
            }
#endif

            // Modbus加锁,防止冲突
            lock (this)
            {
                // 预期返回指令长度,传入参数expect没有考虑头部和校验位
                var st = Transport as SerialTransport;
                //if (st != null) st.FrameSize = expect + ModbusEntity.NO_DATA_LENGTH;
                Transport.Send(buf);

                // lscy 2013-7-29
                // 发送后,休眠一段时间,避免设备数据未全部写到串口缓冲区中
                // 一般情况下,100ms 已足够
                if (Delay > 0)
                {
                    Thread.Sleep(Delay);
                }

                // 读取
                var count = Transport.Receive(buf_receive);
                if (count <= 0)
                {
                    return(null);
                }

#if MF && DEBUG
                str = "Response:";
                for (int i = 0; i < count; i++)
                {
                    str += " " + buf_receive[i].ToString("X2");
                }
                WriteLine(str);
                WriteLine("");
#endif
#if !MF
                if (EnableDebug)
                {
                    WriteLine(new String(' ', entity.Function.ToString().Length) + "=>" + buf_receive.ToHex(0, count));
                }
#endif

                var rs = new ModbusEntity().Parse(buf_receive, 0, count);
                if (rs == null)
                {
                    return(null);
                }
                if (rs.IsException)
                {
                    throw new ModbusException(rs.Data != null && rs.Data.Length > 0 ? (Errors)rs.Data[0] : (Errors)0);
                }
                return(rs);
            }
        }