modbus slave calling master

258 views
Skip to first unread message

Jean-Denis Girard

unread,
Nov 29, 2013, 9:26:01 PM11/29/13
to modb...@googlegroups.com
Hi list,

I've been using modbus_tk successfully for a few years, for communicating with various systems in power generation and distribution sector. Usually the PC contacts the equipment to fetch data or send commands; the equipment acts as a normal modbus slave, it works fine.

Recently, I've been asked to develop software for some modbus slave devices that can call the Scada on alarm condition. When the device calls, the PC is supposed to send a bogus modbus request, then the device sends his slave address; then a normal modbus dialog can proceed. I've been able to implement a working script for modbus_rtu by reusing the rs232 object. Here is some test code:

rs232 = serial.Serial(port='/dev/ttyS0', baudrate=9600, bytesize=8,
      parity='N', stopbits=1, xonxoff=False, timeout=30)
 ...
# Réponse à une alarme : superviseur envoie en diffusion (adresse 0) un message
# invalide (code de fonction 0). Les 2 derniers octets sont le CRC 16 bits.
# modbus_tk ne permet pas d'envoyer cette trame, écriture directe sur le port.
rs232.write('\x00\x00\x01\xB0')

# Lecture réponse (5 octets), par exemple :
# 01 80 00 41 C0
#  \  \  \  CRC 16 bits
#   \  \  code exception -> sous-adresse
#    \  fonction reçue (0) avec bit de poids for à 1
#     adresse modbus
x = rs232.read(size=5)
esclave = ord(x[0])
sous_adr = ord(x[2])

# Dialogue modbus normal : lecture évènements en un seul bloc
# (mot échange + 4 évènements, chacun sur 8 mots)
print u'Lecture évènements...'
res = None
try:
   mb = modbus_rtu.RtuMaster(rs232)
   mb.open()
   res = mb.execute(esclave, cst.READ_INPUT_REGISTERS, 0x000F, 33)

...

This is working fine.

Now I need to do something similar for modbus_tcp... but that seems much more difficult, and this is where I'm looking for help. The idea I had was to use SocketServer.TCPServer or socket.socket to create a server waiting for incoming connections, then reuse that connection for modbus_tcp (like above for modbus_rtu). I have naively tried to modify modbus_tcp.TcpMaster so that it can take an existing socket as argument, but then modbus_tk fails (in hooks if I remember correctly). Is it possible to make it work with minimal changes to modbus_tk?


Thanks,
 --
Jean-Denis Girard

SysNux                  Systèmes  Linux  en Polynésie française
http://www.sysnux.pf/   Tél: +689 50 10 40 / GSM: +689 79 75 27

Luc JEAN

unread,
Dec 6, 2013, 9:05:21 AM12/6/13
to modb...@googlegroups.com
Hello Jean-Denis,

Sorry for long delay for answering. I think than sharing the socket may cause troubles. Did you look at the possibility to use a kind of proxy between master and slave. The TCP Server would receive connection from the SCADA and then would transfer mod bus packet to the oner side?

I hope it helps

Best
luc

PS: sounds nice to know that modbus_tk is used in french polynesia :)



2013/11/30 Jean-Denis Girard <jeandeni...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "modbus-tk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to modbus-tk+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jean-Denis Girard

unread,
Dec 18, 2013, 12:55:31 PM12/18/13
to modb...@googlegroups.com
Hi Luc,

Thanks for your reply.

The project had to move on, so I took a look at pymodbus, and could easily achieve what I wanted, by creating a server socket in my program, then reusing it for modbus communication, see example code below.

My preference would have been to stay with modbus_tk, as I'm used to it, and I didn't want to install another python lib.

import socket
from pymodbus.client.sync import ModbusTcpClient

class G200(ModbusTcpClient):
    def __init__(self, host, port, sock):
        super(G200, self).__init__(host, port)
        self.socket = sock

def handle(s, addr):
        host, port = addr
        print u'Connexion depuis %s:%s' %(host, port)
 
        # Envoi requête identification
        print u'Envoi requête d\'identification...',
        req_id = '\x00\x00\x00\x00\x00\x02\x00\x11'
        s.sendall(req_id)

        # Lecture et affichage identification
        # 00 00 00 00 00 06 FF 11 03 00 xx FF : xx = numéro esclave
        # XXX Vérifier valeur lue par rapport à trame ci-dessus
        r = s.recv(1024).strip()
        e = ord(r[10])
        print u'esclave %d' % e

        # Création client Modbus TCP
        g200 = G200(host, port, s)
        ...

# Main
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(5)
while True:
    print u'\nServeur en attente sur ', server.getsockname()
    conn, addr = server.accept()
    handle(conn, addr)
    conn.close()


Thanks anyway for modbus_tk.

Best regards,
--
Jean-Denis Girard

SysNux                      Systèmes  Linux  en  Polynésie française
http://www.sysnux.pf/   Tél: +689 50 10 40 / GSM: +689 79 75 27

Reply all
Reply to author
Forward
0 new messages