Skip to Content


Modbus (www.modbus.org) is de facto standard protocol used in manufacturing environment. NetWeaver 7.5 TCP/IP communication using ABAP channels can be used for example to query some device registers and optimize planning in SAP according to real situation.

How to set up demo of such scenario?

You need any Modbus TCP device emulator – from here http://sourceforge.net/projects/modbuspal/ or here http://sourceforge.net/projects/jamod/ … ModbusPal will be used in our case.

Add Modbus slave

/wp-content/uploads/2015/11/slave_827809.jpg

Run editor for this slave and add holding register 1

/wp-content/uploads/2015/11/register_827951.jpg

Edit value in the register, we will query this value later on

/wp-content/uploads/2015/11/value_827952.jpg

Finally, run the modbus device on port 502 using Run button

/wp-content/uploads/2015/11/run_827954.jpg

Now, we need to write ABAP TCP client to connect our device and display register value.

In addition, we need some proxy to modify outbound and inbound data. NetWeaver distinguishes between three TCP frame types – frames terminated by defined byte, fixed length frames and variable frame length defined at some position in the frame, i.e. some offset and the field length. Modbus protocol implements last variant with small difference – field with data length contains only variable data length without fixed header (i.e. without 6 bytes of the header). So we need to modify data packets to conform Modbus protocol. The easiest method how to achieve this consists in using of terminated frames at NetWeaver side and trimming/adding this byte from/to outgoing/incoming frames.

Small java proxy program (https://github.com/protomouse/synchronet/blob/master/web/root/telnet/tools/proxy.java) should be modified to achieve this in run method at the end:

public void run()

  {

    int count;

    try {

     while(companion != null) {

       if((count = from.read(buffer)) < 0)

          break;

      // Insert block – begin

      if (buffer[count-1] == 10) {

          buffer[count-1] = (byte) 0x00;

            count = count – 1;         

         } else {

        buffer[count] = (byte) 0x0A;

           count = count + 1;

       }

      // Insert block – end

     to.write(buffer, 0, count);

     }

   } catch(Exception e) {

System.err.println(“redirector: connection lost”);

   }

Now, we can create and modify ABAP TCP client example program from

http://help.sap.com/saphelp_nw75/helpdata/en/b8/c7a04b032542a6ad9ac01d3c9e50a0/content.htm?frameset=/en/4f/3f842b2e2447789c3a2ad1e5b67668/frameset.htm&current_toc=/en/f3/d99aa19ceb44c89907697382aa8726/plain.htm&node_id=24


REPORT ZMODBUS_CLIENT.
PARAMETERS: host    TYPE string LOWER CASE DEFAULT ‘localhost’,
             port    TYPE string DEFAULT ‘504’.

*            message TYPE string LOWER CASE DEFAULT ‘Say hello !’.

” implementing class for the event handler interface IF_APC_WSP_EVENT_HANDLER
CLASS lcl_apc_handler DEFINITION
   FINAL
   CREATE PUBLIC .

   PUBLIC SECTION.
     INTERFACES: if_apc_wsp_event_handler.
     DATA      : m_message TYPE xstring.
     data: mlen type i.
     data: regval type string.
ENDCLASS.

CLASS lcl_apc_handler IMPLEMENTATION.
   METHOD if_apc_wsp_event_handler~on_open.

    ENDMETHOD.

   METHOD if_apc_wsp_event_handler~on_message.
     “message handling
     TRY.
         m_message = i_message->get_binary( ).
         mlen = xstrlen( m_message ) 2.
         regval = m_message+mlen(1).
         m_message = regval.

       CATCH cx_apc_error INTO DATA(lx_apc_error).
         m_message = lx_apc_error->get_text( ).
     ENDTRY.
   ENDMETHOD.

   METHOD if_apc_wsp_event_handler~on_close.
     “close handling
     m_message = ‘Connection closed !’.
   ENDMETHOD.

   METHOD if_apc_wsp_event_handler~on_error.
     “error/close handling
   ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
   DATA: lo_client          TYPE REF TO if_apc_wsp_client.
   DATA: lo_event_handler   TYPE REF TO lcl_apc_handler.
   DATA: lo_message_manager TYPE REF TO if_apc_wsp_message_manager.
   DATA: lo_message         TYPE REF TO if_apc_wsp_message.
   DATA: lv_frame           TYPE apc_tcp_frame.
   DATA: lv_terminator TYPE xstring. ” frame termination bytes in hex
   data:       frame_t TYPE string value ‘0A’. “frame terminator bytes, e.g. line feed 0A
  data: regval type i.

* Modbus hex string to read data from register 1
  DATA: lv_binary_message type xstring value ‘000100000006010300000001’.

   TRY.
       ” create the event handler object,  the interface IF_APC_WSP_EVENT_HANDLER is implemented in local class lcl_apc_handler
       CREATE OBJECT lo_event_handler.

       ” specification of TCP frame
       lv_frameframe_type = if_apc_tcp_frame_types=>co_frame_type_terminator. “frames are terminated with specific bytes
*       lv_frame-frame_type = if_apc_tcp_frame_types=>CO_FRAME_TYPE_LENGTH_FIELD.
*       lv_frame-frame_type = if_apc_tcp_frame_types=>CO_FRAME_TYPE_FIXED_LENGTH.
*       lv_frame-FIXED_LENGTH = 12.
*       lv_frame-LENGTH_FIELD_LENGTH = 1.
*       lv_frame-LENGTH_FIELD_OFFSET = 5.

       lv_frameterminator = frame_t. “frame termination bytes
       lo_client = cl_apc_tcp_client_manager=>create( i_host = host
                                                      i_port = port
                                                      i_frame = lv_frame
                                                      i_event_handler = lo_event_handler ).

       ” initiate the connection setup, successful connect leads to execution of ON_OPEN
       lo_client->connect( ).

       ” save the terminator bytes as hex
       lv_terminator = frame_t.

       “create message manager and message object for sending the message
       lo_message_manager ?= lo_client->get_message_manager( ).
       lo_message         ?= lo_message_manager->create_message( ).

       ” convert the text into UTF-8 byte stream
*      DATA(lv_binary_message) = cl_abap_codepage=>convert_to( source = message ).
*      ” append the terminator byte, e.g. LF, to the message frame bevor sending
       CONCATENATE lv_binary_message lv_terminator INTO lv_binary_message IN BYTE MODE.
       lo_message->set_binary( lv_binary_message ).
       lo_message_manager->send( lo_message ).

       “wait for the a message from peer
       CLEAR: lo_event_handler->m_message.
       WAIT FOR PUSH CHANNELS UNTIL lo_event_handler->m_message IS NOT INITIAL UP TO 10 SECONDS.
       IF sysubrc = 8.
         WRITE: ‘Timeout occured !’.
       ELSE.
*       WRITE: ‘Received message: ‘, lo_event_handler->m_message.
         regval lo_event_handler->m_message.
         write: ‘Register value: ‘, regval.
       ENDIF.

       ” close connection
       lo_client->close( i_reason = ‘application closed connection !’ ).

     CATCH cx_apc_error INTO DATA(lx_apc_error).
       MESSAGE lx_apc_error->get_text( ) TYPE ‘E’.
   ENDTRY.

Finally, we run the proxy using java proxy 504 localhost 502

and the ABAP report.

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

  1. Klaus Steinbach

    Nice post. I have the same problem, having an external server which has a constant header of 16 bytes and a payload. The length of the payload is given in the 16 bytes. Why does SAP does not support such a common variant? 😥 🙁

    (0) 

Leave a Reply