Documentation
FieldTalk Modbus Slave Library for .NET
Examples |
This topic contains the following sections:
The following example tinyslave.cpp shows how to implement a small Modbus RTU slave:
// // @file tinyslave.cs // // A simple Modbus RTU slave program. // // @if NOTICE // // Copyright (c) proconX Pty Ltd. All rights reserved. // // The following source file constitutes example program code and is // intended merely to illustrate useful programming techniques. The user // is responsible for applying the code correctly. // // THIS SOFTWARE IS PROVIDED BY PROCONX AND CONTRIBUTORS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PROCONX OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // @endif // using System; using FieldTalk.Modbus.Slave; class MyDatatable: MbusDataTableInterface { private short[] localRegisters = new short[1000]; private bool[] localCoils = new bool[1000]; protected override bool readHoldingRegistersTable(Int32 startRef, Int16[] regArr) { Console.WriteLine("readHoldingRegisters from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + regArr.Length > localRegisters.Length) { return false; } // Copy registers from local data array to Modbus for (int i = 0; i < regArr.Length; i++) { regArr[i] = localRegisters[startRef + i]; } return true; } protected override bool writeHoldingRegistersTable(Int32 startRef, Int16[] regArr) { Console.WriteLine("writeHoldingRegisters from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + regArr.Length > localRegisters.Length) { return false; } // Copy registers from Modbus to local data block for (int i = 0; i < regArr.Length; i++) { localRegisters[startRef + i] = regArr[i]; } return true; } } class TcpSlaveApp { private MbusRtuSlaveProtocol mbusServer = new MbusRtuSlaveProtocol(); private MyDatatable dataTable = new MyDatatable(); private void startupServer() { int result; result = mbusServer.addDataTable(1, dataTable); // Unit ID is 1 if (result == BusProtocolErrors.FTALK_SUCCESS) { result = mbusServer.startupServer("COM1", 19200, // Baudrate MbusSerialServerBase.SER_DATABITS_8, MbusSerialServerBase.SER_STOPBITS_1, MbusSerialServerBase.SER_PARITY_EVEN); } if (result != BusProtocolErrors.FTALK_SUCCESS) { Console.WriteLine(BusProtocolErrors.getBusProtocolErrorText(result)); Environment.Exit(result); } Console.WriteLine("Modbus server started on serial interface " + mbusServer.portName); } private void shutdownServer() { mbusServer.shutdownServer(); } private void runServer() { int result; do { result = mbusServer.serverLoop(); } while (!(result != BusProtocolErrors.FTALK_SUCCESS)); if (result != BusProtocolErrors.FTALK_SUCCESS) { Console.WriteLine(BusProtocolErrors.getBusProtocolErrorText(result)); } } public static void Main() { TcpSlaveApp app = new TcpSlaveApp(); app.startupServer(); app.runServer(); app.shutdownServer(); } }
The following example tcpslave.cpp shows how to implement a small Modbus/TCP slave:
// // @file tcpslave.cs // // A simple console based example using FieldTalk in Modbus/TCP slave mode // @if NOTICE // // Copyright (c) proconX Pty Ltd. All rights reserved. // // The following source file constitutes example program code and is // intended merely to illustrate useful programming techniques. The user // is responsible for applying the code correctly. // // THIS SOFTWARE IS PROVIDED BY PROCONX AND CONTRIBUTORS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PROCONX OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // @endif // using System; using FieldTalk.Modbus.Slave; class MyDatatable: MbusDataTableInterface { private short[] localRegisters = new short[1000]; private bool[] localCoils = new bool[1000]; protected override bool readHoldingRegistersTable(Int32 startRef, Int16[] regArr) { MasterInfo? masterInfo = getMasterInfo(); // Retrieve optionally master meta data Console.WriteLine("readHoldingRegisters from {0}, {1} references using {2} by slave {3} via {4}", startRef, regArr.Length, masterInfo?.protocol, masterInfo?.slaveAddr, masterInfo?.connection); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + regArr.Length > localRegisters.Length) { return false; } // Copy registers from local data array to Modbus for (int i = 0; i < regArr.Length; i++) { regArr[i] = localRegisters[startRef + i]; } return true; } #if ENABLE_INPUT_REGS // Set to true if input registers shall be supported protected override bool readInputRegistersTable(Int32 startRef, Int16[] regArr) { Console.WriteLine("readInputRegistersTable from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + regArr.Length > localRegisters.Length) { return false; } // Copy registers from local data array to Modbus for (int i = 0; i < regArr.Length; i++) { regArr[i] = localRegisters[startRef + i]; } return true; } #endif protected override bool writeHoldingRegistersTable(Int32 startRef, Int16[] regArr) { Console.WriteLine("writeHoldingRegisters from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + regArr.Length > localRegisters.Length) { return false; } // Copy registers from Modbus to local data block for (int i = 0; i < regArr.Length; i++) { localRegisters[startRef + i] = regArr[i]; } return true; } protected override bool readCoilsTable(Int32 startRef, bool[] bitArr) { Console.WriteLine("readCoilsTable from " + startRef + ", " + bitArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + bitArr.Length > localCoils.Length) { return false; } // Copy registers from local data array to Modbus for (int i = 0; i < bitArr.Length; i++) { bitArr[i] = localCoils[startRef + i]; } return true; } protected override bool writeCoilsTable(Int32 startRef, bool[] bitArr) { Console.WriteLine("writeCoilsTable from " + startRef + ", " + bitArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // Validate range if (startRef + bitArr.Length > localCoils.Length) { return false; } // Copy registers from Modbus to local data block for (int i = 0; i < bitArr.Length; i++) { localCoils[startRef + i] = bitArr[i]; } return true; } #if ENABLE_ENRON_REGS // Set to true if Enron mode is required private Int32[] enronData = new Int32[4000]; protected override bool readEnronRegistersTable(int startRef, Int32[] regArr) { Console.WriteLine("readEnronRegistersTable from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // // Validate start address range // Note: In this example, we have 2000 references at 5000 and 2000 references at 7000. // if ((startRef < 5000) || (startRef >= 9000)) return false; else startRef -=5000; if (startRef + regArr.Length > enronData.Length) { return false; } // Copy registers from local data array to Modbus for (int i = 0; i < regArr.Length; i++) { regArr[i] = enronData[startRef + i]; } return true; } protected override bool writeEnronRegistersTable(Int32 startRef, Int32[] regArr) { Console.WriteLine("writeEnronRegistersTable from " + startRef + ", " + regArr.Length + " references"); // Adjust Modbus reference counting from 1-based to 0-based startRef--; // // Validate start address range // Note: In this example, we have 2000 references at 5000 and 2000 references at 7000. // if ((startRef < 5000) || (startRef >= 9000)) return false; else startRef -= 5000; if (startRef + regArr.Length > enronData.Length) { return false; } // Copy registers from Modbus to local data block for (int i = 0; i < regArr.Length; i++) { enronData[startRef + i] = regArr[i]; } return true; } #endif } class TcpSlaveApp { private MbusTcpSlaveProtocol mbusServer = new MbusTcpSlaveProtocol(); private MyDatatable dataTable = new MyDatatable(); private void startupServer() { int result; result = mbusServer.addDataTable(1, dataTable); // Unit ID is 1 if (result == BusProtocolErrors.FTALK_SUCCESS) { result = mbusServer.startupServer(); } if (result != BusProtocolErrors.FTALK_SUCCESS) { Console.WriteLine(BusProtocolErrors.getBusProtocolErrorText(result)); Environment.Exit(result); } Console.WriteLine("Modbus server started on TCP interface."); } private void shutdownServer() { mbusServer.shutdownServer(); } private void runServer() { int result; do { result = mbusServer.serverLoop(); } while (!(result != BusProtocolErrors.FTALK_SUCCESS)); if (result != BusProtocolErrors.FTALK_SUCCESS) { Console.WriteLine(BusProtocolErrors.getBusProtocolErrorText(result)); } } public static void Main() { TcpSlaveApp app = new TcpSlaveApp(); app.startupServer(); app.runServer(); app.shutdownServer(); } }