title: How do you implement Modbus Function 20 using C#?
body: <p>I've just been working on a project using this Modbus TCP library (<a href="https://github.com/stephanstricker/modbusTCP/tree/master/ModbusTCP/ModbusTCP" rel="nofollow">https://github.com/stephanstricker/modbusTCP/tree/master/ModbusTCP/ModbusTCP</a>) and this documentation for a reference to Function 20 (<a href="http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf" rel="nofollow">http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf</a>). The problem is that it does not support function code 20 (read general reference/file). Right now I am just trying to create my own function that can handle it however the response I get is a two byte array of 10 and 1.</p>
  
  <p>Here is the request header I've tried using:</p>
  
  <pre><code>private byte[] CreateReadFileHeader(ushort id, byte unit, byte count, ushort fileNumber, ushort recordNumber, ushort recordLength)
  {
      byte[] data = new byte[13];
  
      byte[] _id = BitConverter.GetBytes((short)id);
      data[0] = _id[1];               // Transaction ID high byte
      data[1] = _id[0];               // Transaction ID low byte
      data[2] = 11;                   // Packet Length
      data[3] = unit;                 // Slave address
      data[4] = fctReadFile;              // Function code = 20
      //byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
      data[5] = 7;                // Byte Count 0x07 to 0xF5 bytes 
      data[6] = 6;                // Reference Type 
      byte[] _FileNum = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)fileNumber));
      data[7] = 0;        // File Number Hi
      data[8] = 1;            // File Number Lo
      byte[] _RecordNum = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder(10000));
      data[9] = _RecordNum[0];            // Record Number Hi
      data[10] = _RecordNum[1];           // Record Number Lo
      byte[] _RecordLength = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)recordLength));
      data[11] = 0;           // Record Length Hi
      data[12] = 6;           // Record Length Lo
      return data;
  }
  </code></pre>
  
  <p>And here is the code that calls the request:
  </p>
  
  <pre><code>private byte[] WriteSyncData(byte[] write_data, ushort id)
  {
  
      if (tcpSynCl.Connected)
      {
          try
          {
              tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);
              int result = tcpSynCl.Receive(tcpSynClBuffer, 0, tcpSynClBuffer.Length, SocketFlags.None);
  
              byte unit = tcpSynClBuffer[6];
              byte function = tcpSynClBuffer[7];
              byte[] data;
  
              if (result == 0) CallException(id, unit, write_data[7], excExceptionConnectionLost);
  
              // ------------------------------------------------------------
              // Response data is slave exception
              if (function &gt; excExceptionOffset)
              {
                  function -= excExceptionOffset;
                  CallException(id, unit, function, tcpSynClBuffer[8]);
                  return null;
              }
              // ------------------------------------------------------------
              // Write response data
              else if ((function &gt;= fctWriteSingleCoil) &amp;&amp; (function != fctReadWriteMultipleRegister)&amp;&amp;(function!=fctReadFile))
              {
                  data = new byte[2];
                  Array.Copy(tcpSynClBuffer, 10, data, 0, 2);
              }
              // ------------------------------------------------------------
              // Read response data
              else
              {
                  data = new byte[tcpSynClBuffer[8]];
                  Array.Copy(tcpSynClBuffer, 9, data, 0, tcpSynClBuffer[8]);
              }
              return data;
          }
          catch (SystemException)
          {
              CallException(id, write_data[6], write_data[7], excExceptionConnectionLost);
          }
      }
      else CallException(id, write_data[6], write_data[7], excExceptionConnectionLost);
      return null;
  }
  </code></pre>
  
  <p>the TCP sync buffer returns [0,0,11,1,0,3,6,128,1,0,10,1,0,0,0,...]</p>
  
  <p><strong>Update:</strong></p>
  
  <p>I modified my request header to this.</p>
  
  <pre><code>private byte[] CreateReadFileHeader(ushort id, byte unit, byte count, ushort fileNumber, ushort recordNumber, ushort recordLength)
  {
      byte[] data = new byte[17];
  
      byte[] _id = BitConverter.GetBytes((short)id);
      data[0] = 0;//_id[1];               // Transaction ID high byte
      data[1] = 0;//_id[0];               // Transaction ID low byte
      byte[] _size = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)(11)));
      data[2] = 0;                //Protocol identifier
      data[3] = 0;                //Protocol identifier
      data[4] = 0;                // Packet Length
      data[5] = 11;                   // Packet Length
      data[6] = unit;                 //Unit Identifier
      data[7] = fctReadFile;              // Function code
      //byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
      data[8] = 0;                // Byte Count 0x07 to 0xF5 bytes 
      data[9] = 7;                // Byte Count 0x07 to 0xF5 bytes 
      data[10] = 6;               // Reference Type 
      byte[] _FileNum = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)fileNumber));
      data[11] = 0;       // File Number Hi
      data[12] = 1;           // File Number Lo
      byte[] _RecordNum = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder(10000));
      data[13] = _RecordNum[0];           // Record Number Hi
      data[14] = _RecordNum[1];           // Record Number Lo
      byte[] _RecordLength = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)recordLength));
      data[15] =0;            // Record Length Hi
      data[16] =1;            // Record Length Lo
      return data;
  }
  
  //I use this function to call the request
      public void ReadFile(ushort id, byte unit, ref byte[] values)
      {
          byte[] write_data = CreateReadFileHeader(id, unit, 7, 1, 10000, 6);
          tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);
          int result = tcpSynCl.Receive(tcpSynClBuffer, 0, tcpSynClBuffer.Length, SocketFlags.None);
          values = tcpSynClBuffer;
      }
  </code></pre>
  
  <p>and it now returns:</p>
  
  <p>[0,0,0,0,0,5,1,20,4,0,0,0,..]</p>