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.
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); } ReceiveParametersp = 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; }