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
Run editor for this slave and add holding register 1
Edit value in the register, we will query this value later on
Finally, run the modbus device on port 502 using Run button
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
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_frame-frame_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_frame-terminator = 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 sy-subrc = 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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
9 | |
9 | |
7 | |
6 | |
5 | |
4 | |
4 | |
3 | |
3 | |
3 |