A free GPL’d IEC 60870-5-104 Protocol Tester

IEC 60870-5-104 is an internationally standardized protocol for data acquisition and control of power substations. This protocol is supported by most vendors, available in RTU’s, substation data concentrators and HMI’s.

I was in need of an implementation of the 104 protocol to use in 3 projects:

  • A historical data recorder that get all data from the SAGE system used in a control center (50.000 points).
  • A standalone IEC 104 protocol tester.
  • A protocol converter from IEC 104 to a custom format used to push data onto a HMI of my creation.

A quick Google search can show two free software implementations:

If you know of another one, please leave a comment below.

My intention was to have a GUI that can show point values and also issue commands. I considered both not well suited to my needs and decided to implement the protocol in C++ with a QT GUI. QT is a modern multi-platform GUI toolkit (http://qt-project.org). The code was compiled and tested with Linux and Windows operating systems.

Project link: https://sourceforge.net/projects/qtester104/

The base protocol class (iec140_class.cpp) was created in pure C++ without any platform or non-standard library dependencies, can be used to develop software with other compiler/library/sdk.

The iec104_class.h presents some pure virtual function that need to be user defined on a derived class.

// make a tcp connection, user provided
virtual void connectTCP() = 0;
// tcp disconnect, user provided
virtual void disconnectTCP() = 0;
// read tcp data, user provided
virtual int readTCP( char * buf, int szmax ) = 0;
// send tcp data, user provided
virtual void sendTCP( char * data, int sz ) = 0;

There are some other non-mandatory virtual functions that the user can re-implement:

// user point processing, user provided. (on each call there are only objects of the same type)
virtual void dataIndication( iec_obj * /*obj*/, int /*numpoints*/ ){};
// inform user that ACTCONFIRM of Interrogation was received from slave
virtual void interrogationActConfIndication(){};
// inform user that ACTTERM of Interrogation was received from slave
virtual void interrogationActTermIndication(){};
// inform user of command activation
virtual void commandActConfIndication( iec_obj * /*obj*/ ){};
// inform user of command termination
virtual void commandActTermIndication( iec_obj * /*obj*/ ){};
// user process APDU
virtual void userprocAPDU(iec_apdu * /* papdu */, int /* sz */){};

The qiec104.cpp and qiec104.h files inherits the iec104_class and re-implements those functions using the QT TCP/IP libraries. The mainwindow.cpp uses the qiec104.cpp data and provides a GUI.

The GUI consists of some input fields and buttons to configure the remote system (secondary, also called slave), plus bellow other fields and buttons to issue commands, a text box with protocol log messages and a grid with point addresses, values and types.

The same binary executable serve as a protocol tester and a protocol converter to the HMI.

The base class iec104_class.cpp was also used to create the historic data recorder module. This software process 50.000 points of real time data, feeding MySQL tables with SOE and current values and a daily binary file with minute to minute snapshots of the power system state.

You can use it as a standalone IEC60870-5-104 protocol tester, it works as a master and can scan and send commands to slave devices, or as part of my other project OSHMI-Open Substation HMI.


Ricardo Olsen in-2c-14px, MEng. :: https://dscsys.com

Copyright © 2013 Ricardo L. Olsen. All rights reserved.


25 thoughts on “A free GPL’d IEC 60870-5-104 Protocol Tester

  1. Hello Ricardo!

    I tried your qtester software with a SICAM CMIC, but it always says: “ASDU WITH UNECPECTED ORIGIN! Ignoring…” and then “sequence error” and “TCP disconnect”.

    As I could figure it out (using WireShark) your program doesn’t count the N(R) N(S) numbers, that’s why I get always Sequence error.

    Once I had some information in the right hand side panel, but most of the time it is blank.

    Could you please help me a bit?

    Thank you in advance!

    1. Please verify the IEC104 protocol link address of the RTU. It must match the parameter SECONDARY_ADDRESS of the RTU1 section in the file qtester104.ini.
      When the link address does not match then will occur the sequence errors you describe.

      1. Hello Ricardo!

        Thanks for the reply! My Local Link Address (originator address) is 0 (zero), the Remote Link Address is 01 (2 octets CASDU), but still have SEQUENCE ERROR! and TCP DISCONNECT! messages.

        What else could be the problem?

      2. The message “ASDU WITH UNEXPECTED ORIGIN! Ignoring…” can only happen when the configured parameter SECONDARY_ADDRESS (remote link address) is different from the common address of the received message comming from the RTU. This is clear in the code iec104_class.cpp, iec104_class::parseAPDU method: “if ( papdu->asduh.ca != slaveAddress && sz>6) … “.
        Please use Wireshark to watch for the response messages, look for the originator address (10th byte) and the common address (11th and 12th bytes). I think Wireshark can understand the IEC 104 messages and show these fields.
        Re-check the configuration of the RTU and QTester104.
        If the problem persist, I recommend that you use another scan tool like ASE2000 to test the RTU.
        Good luck.

      3. Dear Ricardo!

        Thank you for your patience and reply!
        I have reviewed all the options that could go wrong, and found (based on your suggestions) that during data transmission start the CMIC RTU sends some messages with CA=65535 and CA=508, despite its address is CA=1. When this happens, your program says “ASDU with unexpected origin” and then of course “Sequence error” since the Send Sequence numbers aren’t correct.

        By the way thank you for your big help!


  2. Dear Ricardo!

    Thank you for this great simulation tool. It works perfect. I have a question about the IEC 104 communication procedure (algorithm) that is used in your simulator. Would you be so kind and tell me where in the source code the actually IEC 104 communication (procedure) is carried out because I am not very skilled in C++.

    1. Dear Mitja,

      The protocol code is located in the module iec104_class.cpp, this code is platform and framework independent.
      The other files contains UI and network code that depends on the QT framework.

  3. Dear Ricardo!

    Thank you for your previous answer. The IEC 60870-5-104 Protocol Tester is realized only for only one RTU device right? Do you have any idea or suggestions how and where in your IEC 104 communication class code would be possible to upgrade algorithm to support data pooling from multiple RTUs?

    Thank you for your answer, help and kindness.

    With best regards,

    1. Yes, you are right MK, the system now works with only one RTU. To allow more it will be needed to create more instances of the base class and setup networking handlers for each one. It would be an nice addition, I may eventually code it, but it’s not now in my schedule.
      Best regards.

      1. Dear Ricardo!

        Thank you again for your answer. Would you be so kind and explain me a little bit the IEC 104 algorithm that is implemented in the iec104_class.cpp? I can’t figure it out how it works in whole. Especially I can’t figure out how the connection procedure starts after the TCP connection is establish. Can you tell me the sequence of functions/code execution.
        This would be very helpful for me. Thank you for your help and kindness.

        With best regards,

  4. Hi MK,
    When TCP successfully connects (onConnectTCP) you must sent a STARTDTACT (sendStartDTACT) message to enable the secondary station to send data. Then you must keep interpreting incoming data messages (packetReadyTCP, parseAPDU) and sending SUPERVISORY (sendSupervisory) messages to confirm packet sequence numbers. If a packet is lost (*** SEQUENCE ERROR! ***), the connection must be closed and reopened. If the secondary station is quiet for some time, you send a TESTFRACT message to keep the connection alive. Also send a General Interrogation after each connection and periodically (solicitGI).
    The IEC 60870-5-104 and 60870-5-101 documents contains the binary messages format description and useful protocol time diagrams.
    Look in http://manuals.lian98.biz/doc.en/html/u_iec104_struct.htm and also google the “norwegian iec 60870-5-101 user conventions” pdf to find more useful information.
    Wish this can help you.

  5. Hi, thank you for this great tool. I have a question about field “Command address” and “Command value”. Can you write some examples command address and value? Can I send clock synchronization command?

  6. Hi FF,

    Thank you for you appreciation.

    Command Address is the protocol “INFORMATION OBJECT ADDRESS”, a 24 bit integer that identifies the command in a RTU.

    Command value is an integer that is converted by QTester104 to the protocol specific value for the “Command Type” selected.
    In the current version there are the following possibilities:
    Types 45 or 58-Single Command- Enter value “0” for OFF and “1” for ON.
    Types 46 or 59-Double Command- Enter value “1” OFF and “2” for ON.
    Types 47 or 60-Reg.Step- Enter “2” for higher and “1” for lower.

    The clock synchronization command was not yet implemented in both directions. Maybe in the next version.

    Best regards.

  7. Dear Ricardo!

    When I send a single point information with timestamp I got this error message:
    –> 019: 68 11 0c 00 02 00 02 01 03 00 01 00 01 00 00 01 3e e9 2a
    CA 1 TYPE 2 CAUSE 3 SQ 0 NUM 1

    Thank you for the information and your feedback.

    Best regards,
    Dávid Józsa

    1. Sorry but the ASDU types with short time tag are not allowed by the IEC60870-5-104 specification, that is the case of the type 2 (Single-point information with time tag M_SP_TA_1). You should use the Single-point information with time tag CP56Time2a M_SP_TB_1, type 30 instead.
      Best regards,
      Ricardo Olsen

  8. How can i get work it with ASDU adresses like “12899”. This because i want calculate my ASDU with the last 2 octets of ip. Now i can only use it up to 255. I changed the masterAddress and slaveAddress to “short” instead of “char” and QIntValidator to 32767. But this is done by the error msg “ASDU WITH UNEXPECTED ORIGIN!…”

    Best regards

    1. Hi Marco,
      You are right about the validator, it should allow 2 byte addresses. Changing the validator should correct the problem. The slaveAddress is already of type “short”. You can debug setting a breakpoint to see what is the address that is coming in the message, maybe it is not arriving as you expect, perhaps the byte order is inverted. Make sure to capture messages with Wireshark to check the addresses.

  9. Hello, using the program qtester104, equipment Controne SP-305 readings gave out. But come the next day there was an error socketError 0. What does it mean?

  10. Dear Ricardo, thank you for making a good protocol simulator tool. It has helped me a lot. I am looking for a secure authentication version based on IEC 62351. I saw many DNP3 implementations but never come across any IEC 104 ones. Do you consider upgrading?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s