Skip to main content
Home
for DLMS smart meters

Main navigation

  • Home
  • Products
  • About us
  • Open Source
  • Community
  • Forum
  • Downloads
User account menu
  • Log in

Breadcrumb

  1. Home
  2. Gurux.DLMS.Iec
Gurux DLMS Component for C#, .Net, Java, Delphi and ANSI C++ Getting started

Read basic information from Gurux.DLMS component before you start to create DLMS client.

Connection Initialization for IEC

The connection initialization depends on the connection type and the device. Some devices require IEC62056-21 protocol handshake when optical port (strobe) connecion is used before starting to communicate using DLMS protocol.

IEC62056-21 Handshake

If you are using IEC handshake with serial port you must first send identify command and move to mode E. If you are using TCP/IP connection you can skip this.

In serial port connection default IEC62056-21 settings are: Bitrate 300, 7E1.

"/?" + deviceSerialNumber + "!\r\n"

Send query to the device containing "/?!" and a new line (0x0D 0x0A) without the quotations. This requests the identity information from the device.

The device responds with serial number and the maximum connection speed. The reply data is formatted as follows:
/XXXZ Ident and a new line
XXX is the manufacturer name
Z is the maximum baud rate
Ident is the Identification info of the device.

Values of Z are:
0 - 300 Bd
1 - 600 Bd
2 - 1 200 Bd
3 - 2 400 Bd
4 - 4 800 Bd
5 - 9 600 Bd
6 - 19200Bd
7, 8, 9 - reserved for later extensions.

Send request to change to DLMS mode. Packet is formatted as follows:
0x06 "0" Z "2" 0x0D 0x0A without the quotations.
Z is the requested connection speed.

  • Java
  • C#
  • Delphi
  • ANSI C++
void InitSerial() throws Exception
{
    ReceiveParameters<byte[]> p = new ReceiveParameters<byte[]>(byte[].class);
    p.setAllData(false);
    p.setEop((byte) '\n');
    p.setWaitTime(WaitTime);
    String data;
    String replyStr;
    synchronized (Media.getSynchronous())
    {
        data = "/?!\r\n";        
        Media.send(data, null);
        if (!Media.receive(p))
        {
            throw new Exception("Invalid meter type.");                    
        }        
        //If echo is used.
        replyStr = new String(p.getReply());
        if (data.equals(replyStr))
        {
            if (!Media.receive(p))
            {
                throw new Exception("Invalid meter type.");                    
            }        
            replyStr = new String(p.getReply());
        }
    }
    if (replyStr.length() == 0 || replyStr.charAt(0) != '/')
    {
        throw new Exception("Invalid responce.");
    }
    String manufactureID = replyStr.substring(1, 3);
    if (manufacturer.getIdentification().compareToIgnoreCase(manufactureID) != 0)
    {
        throw new Exception("Manufacturer " + manufacturer.getIdentification() + " expected but " + manufactureID + " found.");
    }
    int bitrate = 0;
    char baudrate = replyStr.charAt(4);
    switch (baudrate)
    {
        case '0':
            bitrate = 300;
            break;
        case '1':
            bitrate = 600;
            break;
        case '2':
            bitrate = 1200;
            break;
        case '3':
            bitrate = 2400;
            break;
        case '4':
            bitrate = 4800;
            break;
        case '5':
            bitrate = 9600;
            break;
        case '6':
            bitrate = 19200;
            break;
        default:
            throw new Exception("Unknown baud rate.");
    }
    //Send ACK
    //Send Protocol control character
    byte controlCharacter = (byte)'2';// "2" HDLC protocol procedure (Mode E)
    //Send Baudrate character
    //Mode control character
    byte ModeControlCharacter = (byte)'2';//"2" //(HDLC protocol procedure) (Binary mode)
    //Set mode E.
    byte[] tmp = new byte[] { 0x06, controlCharacter, (byte)baudrate, ModeControlCharacter, 13, 10 };
    GXSerial serial = (GXSerial) Media;
    synchronized (Media.getSynchronous())
    {        
        serial.setBaudRate(bitrate);
        Media.send(tmp, null);        
    }
    serial.setDataBits(8);
    serial.setParity(Parity.NONE);
    serial.setStopBits(StopBits.ONE);    
}

void InitSerial()
{
    GXSerial serial = Media as GXSerial;
    byte Terminator = (byte)0x0A;
    if (serial != null && InitializeIEC)
    {
        serial.BaudRate = 300;
        serial.DataBits = 7;
        serial.Parity = Parity.Even;
        serial.StopBits = StopBits.One;
    }
    Media.Open();
    //Query device information.
    if (Media != null && InitializeIEC)
    {
        string data = "/?!\r\n";
        if (Trace)
        {
            Console.WriteLine("HDLC sending:" + data);
        }
        ReceiveParameters p = new ReceiveParameters()
        {
            Eop = Terminator,
            WaitTime = WaitTime
        };
        lock (Media.Synchronous)
        {
            Media.Send(data, null);
            if (!Media.Receive(p))
            {
                //Try to move away from mode E.                        
                throw new Exception("Failed to receive reply from the device in given time.");
            }
            //If echo is used.
            if (p.Reply == data)
            {
                p.Reply = null;
                if (!Media.Receive(p))
                {
                    //Try to move away from mode E.                            
                    throw new Exception("Failed to receive reply from the device in given time.");
                }
            }
        }                
        if (Trace)
        {
            Console.WriteLine("HDLC received: " + p.Reply);
        }
        if (p.Reply[0] != '/')
        {
            p.WaitTime = 100;
            Media.Receive(p);
            throw new Exception("Invalid responce.");
        }
        string manufactureID = p.Reply.Substring(1, 3);
        //UpdateManufactureSettings(manufactureID);
        char baudrate = p.Reply[4];
        int BaudRate = 0;
        switch (baudrate)
        {
            case '0':
                BaudRate = 300;
                break;
            case '1':
                BaudRate = 600;
                break;
            case '2':
                BaudRate = 1200;
                break;
            case '3':
                BaudRate = 2400;
                break;
            case '4':
                BaudRate = 4800;
                break;
            case '5':
                BaudRate = 9600;
                break;
            case '6':
                BaudRate = 19200;
                break;
            default:
                throw new Exception("Unknown baud rate.");
        }
        Console.WriteLine("BaudRate is :", BaudRate.ToString());
        //Send ACK
        //Send Protocol control character
        byte controlCharacter = (byte)'2';// "2" HDLC protocol procedure (Mode E)
        //Send Baudrate character
        //Mode control character 
        byte ModeControlCharacter = (byte)'2';//"2" //(HDLC protocol procedure) (Binary mode)
        //Set mode E.
        byte[] arr = new byte[] { 0x06, controlCharacter, (byte)baudrate, ModeControlCharacter, 13, 10 };
        if (Trace)
        {
            Console.WriteLine("Moving to mode E", BitConverter.ToString(arr));
        }
        lock (Media.Synchronous)
        {
            Media.Send(arr, null);
            p.Reply = null;
            p.WaitTime = 500;
            if (!Media.Receive(p))
            {
                //Try to move away from mode E.
                this.ReadDLMSPacket(m_Parser.DisconnectRequest());                        
                throw new Exception("Failed to receive reply from the device in given time.");
            }
        }
        if (serial != null)
        {
            serial.BaudRate = BaudRate;
            serial.DataBits = 8;
            serial.Parity = Parity.None;
            serial.StopBits = StopBits.One;
        }
    }
}
//Delphi do not support serial port at the moment.
void InitSerial()
{
#if _MSC_VER > 1000
	strcpy_s(buff, 10, "/?!\r\n");
#else
	strcpy(buff, "/?!\r\n");
#endif		
    cnt = strlen(buff);
    DWORD sendSize = 0;		
    BOOL bRes = ::WriteFile(m_hComPort, buff, cnt, &sendSize, &m_osWrite);
    if (!bRes)
    {				
	    DWORD err = GetLastError();
	    //If error occurs...
	    if (err != ERROR_IO_PENDING)
	    {				
		    return ERROR_CODES_SEND_FAILED;
	    }
	    //Wait until data is actually sent
	    ::WaitForSingleObject(m_osWrite.hEvent, INFINITE);			
    }
    //Read reply data.				
    DWORD bytesRead = 0;
    do
    {
	    cnt = 0;
	    do
	    {
		    //Read reply one byte at time.
		    if (!ReadFile(m_hComPort, m_Receivebuff + cnt, 1, &bytesRead, &m_osReader))
		    {
			    DWORD nErr = GetLastError();
			    if (nErr != ERROR_IO_PENDING)     
			    {
				    return ERROR_CODES_SEND_FAILED;
			    }			
			    //Wait until data is actually read
			    ::WaitForSingleObject(m_osReader.hEvent, INFINITE);
		    }
		    ++cnt;
	    }while(m_Receivebuff[cnt - 1] != 0x0A);
	    m_Receivebuff[cnt] = 0;			
    }
    while(memcmp(buff, m_Receivebuff, cnt) == 0);//Remove echo.
    if (m_Receivebuff[0] != '/')
    {
	    return ERROR_CODES_SEND_FAILED;
    }
    char baudrate = m_Receivebuff[4];
    if (baudrate == ' ')
    {
        baudrate = '5';
    }
    int bitrate = 0;
    switch (baudrate)
    {
        case '0':
            bitrate = 300;
            break;
        case '1':
            bitrate = 600;
            break;
        case '2':
            bitrate = 1200;
            break;
        case '3':
            bitrate = 2400;
            break;
        case '4':
            bitrate = 4800;
            break;
        case '5':                            
            bitrate = 9600;
            break;
        case '6':
            bitrate = 19200;
            break;
        default:
            return ERROR_CODES_INVALID_PARAMETER;
    }   
    //Send ACK
    buff[0] = 0x06;
    //Send Protocol control character
    buff[1] = '2';// "2" HDLC protocol procedure (Mode E)
    buff[2] = baudrate;
    buff[3] = '2';
    buff[4] = (char) 0x0D;
    buff[5] = 0x0A;  
    bRes = ::WriteFile(m_hComPort, buff, 6, &sendSize, &m_osWrite);
    if (!bRes)
    {
	    DWORD err = GetLastError();
	    //If error occurs...
	    if (err != ERROR_IO_PENDING)
	    {				
		    return ERROR_CODES_SEND_FAILED;
	    }
	    //Wait until data is actually sent
	    ::WaitForSingleObject(m_osWrite.hEvent, INFINITE);			
    }
    m_Receivebuff[cnt] = 0;					
    //Read reply data.				
    bytesRead = 0;
    cnt = 0;
    //This sleep is in standard. Do not remove.
    Sleep(500);
    //Change bit rate.
    conf.dcb.BaudRate = bitrate;
    SetCommState(m_hComPort, &conf.dcb);    
    do
    {
	    //Read reply one byte at time.
	    if (!ReadFile(m_hComPort, m_Receivebuff + cnt, 1, &bytesRead, &m_osReader))
	    {
		    DWORD nErr = GetLastError();
		    if (nErr != ERROR_IO_PENDING)     
		    {
			    return ERROR_CODES_SEND_FAILED;
		    }			
		    //Wait until data is actually read
		    ::WaitForSingleObject(m_osReader.hEvent, INFINITE);
	    }
	    ++cnt;
    }
    while(m_Receivebuff[cnt - 1] != 0x0A);				
    //Change bit rate.
    conf.dcb.ByteSize = 8; 
    conf.dcb.StopBits = ONESTOPBIT; 
    conf.dcb.Parity = NOPARITY; 		
    SetCommState(m_hComPort, &conf.dcb); 	
    //Some meters need this sleep. Do not remove.
    Sleep(300);
    return ERROR_CODES_OK;
}

Thats it. Now you can continue with DLMS protocol. If you have any questions or ideas how to improve Gurux.DLMS component let us know or ask question in a Forum
  • Create new account
  • Reset your password

Hire Us!

Latest Releases

  • Mon, 06/01/2026 - 10:15
    gurux.dlms.cpp 9.0.2606.0101
  • Thu, 05/28/2026 - 16:06
    gurux.dlms.java 4.0.94
  • Thu, 05/28/2026 - 13:16
    Gurux.DLMS.Net 9.0.2605.2801
  • Thu, 05/28/2026 - 13:14
    Gurux.DLMS.Python 1.0.198
  • Tue, 05/26/2026 - 11:37
    gurux.dlms.c 9.0.2605.2601

New forum topics

  • Error reading L&G Meter
  • Pass a TCP Client to GXNet
  • Australian EDMI Mk10D (Essential Energy area)
  • Strange mix of data notificiation vs get response
  • DLMS Connection
More
RSS feed
Privacy FAQ GXDN Issues Contact
Follow Gurux on Twitter Follow Gurux on Linkedin