[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (09) 實作 RtuModbusResponse
續上篇,接下來,我要實作 Modbus RTU 的 Response Protocol ,這個 RtuModbusResponse類別主要是驗証資料的正確性
如下圖紅框:
RtuModbusResponse 實作 AbsModbusResponse 抽像類別:
- 指派 FunctionCodePosition ,它表示 Function Code 的位置,由下圖得知,Function Code 的索引值是 1。
- CheckDataValidate 方法裡驗證了Response 的 CRC 是否符合期望結果。
- GetResultArray 則是取出結果,例如下圖取出 Coil Status 的結果。
程式碼如下:
{ private byte _functionCodePosition = 1; protected override byte FunctionCodePosition { get { return _functionCodePosition; } set { _functionCodePosition = value; } } protected override void CheckDataValidate(byte[] ResponseArray) { var sourceCrcArray = new byte[2]; Array.Copy(ResponseArray, ResponseArray.Length - 2, sourceCrcArray, 0, sourceCrcArray.Length); var sourceDataArray = new byte[ResponseArray.Length - 2]; Array.Copy(ResponseArray, 0, sourceDataArray, 0, sourceDataArray.Length); var destinationCrcArray = Utility.CalculateCRC(sourceDataArray); if (!sourceCrcArray.SequenceEqual(destinationCrcArray)) { throw new ModbusException("CRC Validate Fail"); } } protected override byte[] GetResultArray(byte[] ResponseArray) { var counterPosition = this.FunctionCodePosition + 1; var position = ResponseArray[counterPosition]; var resultArray = new byte[position]; Array.Copy(ResponseArray, counterPosition + 1, resultArray, 0, resultArray.Length); return resultArray; } }
建立單元測試,同樣的我們需要驗証資料處理的正確性,在這裡我用到了驅動測試
下圖為測試檔案。
驅動測試詳細作法請參考:[Visual Studio 2012 ] 建立資料驅動單元測試
測試程式碼如下:
[TestMethod()] [DeploymentItem("TestDoc\\RtuReadFunc1Test.csv")] [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\TestDoc\\RtuReadFunc1Test.csv", "RtuReadFunc1Test#csv", DataAccessMethod.Random)] public void ReadCoilsTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[0].ToString()); byte[] ResponseArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[1].ToString()); byte[] expected = _modbusUtility.HexStringToBytes(TestContext.DataRow[2].ToString()); byte[] actual; actual = target.ReadCoils(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] [DeploymentItem("TestDoc\\RtuReadFunc2Test.csv")] [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\TestDoc\\RtuReadFunc2Test.csv", "RtuReadFunc2Test#csv", DataAccessMethod.Sequential)] public void ReadDiscreteInputsTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[0].ToString()); byte[] ResponseArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[1].ToString()); byte[] expected = _modbusUtility.HexStringToBytes(TestContext.DataRow[2].ToString()); byte[] actual; actual = target.ReadDiscreteInputs(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] [DeploymentItem("TestDoc\\RtuReadFunc3Test.csv")] [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\TestDoc\\RtuReadFunc3Test.csv", "RtuReadFunc3Test#csv", DataAccessMethod.Sequential)] public void ReadHoldingRegistersTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[0].ToString()); byte[] ResponseArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[1].ToString()); byte[] expected = _modbusUtility.HexStringToBytes(TestContext.DataRow[2].ToString()); byte[] actual; actual = target.ReadHoldingRegisters(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] [DeploymentItem("TestDoc\\RtuReadFunc4Test.csv")] [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\TestDoc\\RtuReadFunc4Test.csv", "RtuReadFunc4Test#csv", DataAccessMethod.Sequential)] public void ReadInputRegistersTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[0].ToString()); byte[] ResponseArray = _modbusUtility.HexStringToBytes(TestContext.DataRow[1].ToString()); byte[] expected = _modbusUtility.HexStringToBytes(TestContext.DataRow[2].ToString()); byte[] actual; actual = target.ReadInputRegisters(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] public void WriteSingleCoilTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes("01 05 00 02 FF 00 2D FA"); byte[] ResponseArray = _modbusUtility.HexStringToBytes("01 05 00 02 FF 00 2D FA"); byte[] expected = ResponseArray; byte[] actual; actual = target.WriteSingleCoil(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] public void WriteSingleRegisterTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes("01 06 00 03 00 DF 38 52"); byte[] ResponseArray = _modbusUtility.HexStringToBytes("01 06 00 03 00 DF 38 52"); byte[] expected = ResponseArray; byte[] actual; actual = target.WriteSingleRegister(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] public void WriteMultipleCoilsTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes("01 0F 00 00 00 0A 02 3A 01 36 58"); byte[] ResponseArray = _modbusUtility.HexStringToBytes("01 0F 00 00 00 0A D5 CC"); byte[] expected = ResponseArray; byte[] actual; actual = target.WriteMultipleCoils(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); } [TestMethod()] public void WriteMultipleRegistersTest() { RtuModbusResponse target = new RtuModbusResponse(); byte[] RequestArray = _modbusUtility.HexStringToBytes("01 10 00 00 00 0A 14 03 15 00 00 00 0D 00 0C 00 00 FF E9 00 00 00 00 00 6D 00 00 E7 B1"); byte[] ResponseArray = _modbusUtility.HexStringToBytes("01 10 00 00 00 0A 40 0E"); byte[] expected = ResponseArray; byte[] actual; actual = target.WriteMultipleRegisters(RequestArray, ResponseArray); Assert.IsTrue(expected.SequenceEqual(actual)); }
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET