/// <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); }
/// <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)); } }
/// <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); }
/// <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); } }