using System; using System.Collections.Generic; using System.Text; using System.IO.Ports; using Modbus; using Modbus.Device; using Modbus.Utility; using System.Net.Sockets; using System.Net; namespace MTCPPowerMeterDemoCode { /// /// The "Program" Class will teach you that how to read/write power meter's holding registers, read power meter's Input Registers and so on. /// The "ConnectToPowerMeter" function show how to connect to power meter. /// The "DisconnectPowerMeter" function show how to disconnect power meter. /// The "ReadValueFromPowerMeter" function will show how to read input registers from power meter. /// The "WriteDefaultParameterValueToPowerMeter" function show how to write holding registers to power meter. /// class Program { private static ExampleSetting mySetting; private static TcpClient tcpClient; private static ModbusIpMaster tcpMaster; private static int channelNumber; /// /// "ExampleSetting" Structure contains connection parameters of power meter.The parameters are set by user interface or console inpute. /// In this programm, ExampleSetting member's values are either index or amount of units to set power meter parameters. /// They are not actually the real values of Modbus Holding Registers which specified in hardware manual. /// public struct ExampleSetting { //public string PortName; //public int BaudRate; //public int StopBit; public byte Modbus_slave_ID; public int Timeout; public int PT; public int CT; public const int Meter_Ratio = 500; // Truly value: 500 public int Port; public IPAddress IPAddr; } static void Main(string[] args) { // Get a list of available serial port names,then select a port number to communicate. //string[] ports = SerialPort.GetPortNames(); //if (ports.Length == 0) //{ // Console.WriteLine("No available COM port."); // Console.ReadLine(); // return; //} //string portnums = string.Empty; //for (int i = 0; i < ports.Length; i++) //{ // portnums += string.Format("[{0}]: {1}, ",i,ports[i]); // if ((i + 1) % 4 == 0 || (i+1) == ports.Length) // { portnums += "\n"; } //} //Console.WriteLine("Available COM port number: \n" + portnums ); //Console.Write(string.Format("Selected index ( 0 ~ {0} ): ",ports.Length-1)); // Get port's index which user input //int selectedPortIndex = 0; //bool isright = false; //while (!isright) //{ // int cursorleft = Console.CursorLeft; // int cursortop = Console.CursorTop; // if (int.TryParse(Console.ReadLine(), out selectedPortIndex)) // { // if (selectedPortIndex < ports.Length) // { // isright = true; // } // } // if (!isright) // Console.SetCursorPosition(cursorleft, cursortop); //} Console.WriteLine("Device IPv4 Address: "); int cursorleft = Console.CursorLeft; int cursortop = Console.CursorTop; IPAddress ipAddr; while(!IPAddress.TryParse(Console.ReadLine(), out ipAddr)) { Console.SetCursorPosition(cursorleft, cursortop); } Console.WriteLine(""); Console.WriteLine("Select Device: "); Console.WriteLine("[1]: PM-213x / PM3114"); Console.WriteLine("[2]: PM3112"); while(true) { string ans = Console.ReadLine(); int ansindex = 0; if (int.TryParse(ans, out ansindex)) { if (ansindex == 1 || ansindex == 2) { if (ansindex == 1) { channelNumber = 4; } else { channelNumber = 2; } break; } } } // Connect to power meter. If connecting is successful, then // read or write the data of power meter. if ( ConnectToPowerMeter(ipAddr) ) { string actionString = @"********************************************************************** Execute: [0] : Programe Exit. [1] : Read value from power meter [2] : Write default parameter value to power meter Input index number: "; // Get index number which user input bool isloop = true; while (isloop) { Console.WriteLine(); Console.Write(actionString); // Get index number which user input int actionIndex = 0; bool isOK= false; while (!isOK) { if (int.TryParse(Console.ReadLine(), out actionIndex)) { if (actionIndex < 3) { isOK = true; } } if (!isOK) { Console.SetCursorPosition(cursorleft, cursortop); } } Console.WriteLine(); // Execute function by selected index switch (actionIndex) { case 0: DisconnectPowerMeter(); isloop = false; break; case 1: ReadValueFromPowerMeter(); break; case 2: WriteDefaultParameterValueToPowerMeter(); break; } } } } /// /// This function show how to connect to power meter. /// /// /// private static bool ConnectToPowerMeter(IPAddress ipAddr) { // Before connecting, // we should initialize power meter's connection parameters first. // You can change parameter value by yourself. mySetting = new ExampleSetting(); mySetting.Modbus_slave_ID = 1; mySetting.PT = 1; mySetting.CT = 1; mySetting.Port = 502; mySetting.Timeout = 1500; mySetting.IPAddr = ipAddr; Console.WriteLine("Start to connect PM213x / PM-311x Modbus TCP Meter."); // new an TCP Client, and to create an instance for modbus communication. try { // Create a client instance for TCP communication tcpClient = new TcpClient(mySetting.IPAddr.ToString(), mySetting.Port); // After COM opened, // to create modbus master instance which is used to communicate a power meter. // Bind modbus master instance to the TCPClient instance. tcpMaster = ModbusIpMaster.CreateIp(tcpClient); tcpMaster.Transport.ReadTimeout = mySetting.Timeout; tcpMaster.Transport.WriteTimeout = mySetting.Timeout; } catch (Exception err) { Console.WriteLine(err.Message); //Console.WriteLine(err.StackTrace); Console.Read(); return false; } Console.WriteLine("Open PM213x / PM-311x Modbus TCP Meter Success!!"); return true; } /// /// This function show how to disconnect power meter. /// private static void DisconnectPowerMeter() { if (tcpClient != null) { tcpClient.Close(); tcpClient = null; tcpMaster.Dispose(); } } /// /// This function show how to read input registers from power meter. /// private static void ReadValueFromPowerMeter() { // Read Input Registers (Fun04). // Power meter will return 36 Power Parameters (Voltage, Current, Power, Energy...etc) ushort startAddress = 0x1100; // 4352; ushort numRegister =(ushort)( channelNumber * 18);//72; // 36*2 ushort[] PowerParameters = new ushort[72]; if (tcpClient.Connected) { try { // Set parameters of function to get all input register values in power meter. Console.WriteLine("Modbus_slave_ID: {0}, startAddress: {1}, numRegister: {2}", mySetting.Modbus_slave_ID, startAddress, numRegister); PowerParameters = tcpMaster.ReadInputRegisters(mySetting.Modbus_slave_ID, startAddress, numRegister); // Convert two UInt16 values into a IEEE 32 floating point format value. float[] fvalue = new float[36]; for (int i = 0; i < (numRegister / 2); i++) { fvalue[i] = ModbusUtility.GetSingle(PowerParameters[2 * i + 1], PowerParameters[2 * i]); } //Output the result. string titleformate = "{0,13} {1,13} {2,13} {3,13} {4,13}"; string dataformate = "{0,13} {1,13:f3} {2,13:f3} {3,13:f3} {4,13:f3}"; Console.WriteLine(string.Format(titleformate, "", "<>", "<>", "<>", "<>")); Console.WriteLine(string.Format(dataformate, "[Voltage]", fvalue[0], fvalue[9], fvalue[18], fvalue[27])); Console.WriteLine(string.Format(dataformate, "[Current]", fvalue[1], fvalue[10], fvalue[19], fvalue[28])); Console.WriteLine(string.Format(dataformate, "[kW]", fvalue[2], fvalue[11], fvalue[20], fvalue[29])); Console.WriteLine(string.Format(dataformate, "[kVar]", fvalue[3], fvalue[12], fvalue[21], fvalue[30])); Console.WriteLine(string.Format(dataformate, "[kVA]", fvalue[4], fvalue[13], fvalue[22], fvalue[31])); Console.WriteLine(string.Format(dataformate, "[PF]", fvalue[5], fvalue[14], fvalue[23], fvalue[32])); Console.WriteLine(string.Format(dataformate, "[kWh]", fvalue[6], fvalue[15], fvalue[24], fvalue[33])); Console.WriteLine(string.Format(dataformate, "[kvarh]", fvalue[7], fvalue[16], fvalue[25], fvalue[34])); Console.WriteLine(string.Format(dataformate, "[kVah]", fvalue[8], fvalue[17], fvalue[26], fvalue[35])); } catch (Exception err) { Console.WriteLine(err.Message); //Console.WriteLine(err.StackTrace); } } } /// /// This function show how to write and read holding registers /// which store power meter's connection parameters and meter parameters. /// In this function, you will know how to convert modbus holding regester /// values to UI value. /// private static void WriteDefaultParameterValueToPowerMeter() { ushort startAddress = 0x1003; // 4096 ushort numRegister = 2; // only PT, CT ushort[] PowerParameters = new ushort[2]; ushort[] feedbackParams = new ushort[2]; if (tcpClient.Connected) { try { // Default power meter parameters. // User must realize that how to convert the UI value to Modbus register value. // Modbus register value ===> UI value PowerParameters[0] = 1 * 100; // PT ratio: 1 PowerParameters[1] = 1; // CT ratio: 1 // Write data to power meter's holding registers by modbus protocol. tcpMaster.WriteMultipleRegisters(mySetting.Modbus_slave_ID, startAddress, PowerParameters); // After write new baudrate data to holding registers, // it must reassign serialport's baudrate value for next connection. // Read data from power meter's holding registers by modbus protocol. // User must realize how to convert modbus register value to UI value. feedbackParams = tcpMaster.ReadHoldingRegisters(mySetting.Modbus_slave_ID, startAddress, numRegister); Console.WriteLine("The parameter values read back after writing: "); Console.WriteLine(string.Format(" [PT ratio]: {0}", PowerParameters[0] * 0.01)); Console.WriteLine(string.Format(" [CT ratio]: {0}", PowerParameters[1])); } catch (Exception err) { Console.WriteLine(err.Message); //Console.WriteLine(err.StackTrace); } } } } }