[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (09) 實作 RtuModbusResponse

[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (09) 實作 RtuModbusResponse

續上篇,接下來,我要實作 Modbus RTU 的 Response Protocol ,這個 RtuModbusResponse類別主要是驗証資料的正確性

如下圖紅框:

image

 

RtuModbusResponse 實作 AbsModbusResponse 抽像類別:

  1. 指派 FunctionCodePosition ,它表示 Function Code 的位置,由下圖得知,Function Code 的索引值是 1。
  2. CheckDataValidate 方法裡驗證了Response 的 CRC 是否符合期望結果。
  3. GetResultArray 則是取出結果,例如下圖取出 Coil Status 的結果。
    image

 

程式碼如下:


{
    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;
    }
}

建立單元測試,同樣的我們需要驗証資料處理的正確性,在這裡我用到了驅動測試

下圖為測試檔案。

image

驅動測試詳細作法請參考:[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

Image result for microsoft+mvp+logo