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