Closed ccatterina closed 6 years ago
From what I understand you have a Modbus RTU Master that needs to send requests to Modbus TCP slave. Is that correct?
No, i have a Modbus TCP master (my raspberrypi) that needs to send requests to a Modbus RTU slave, in the middle there is a rs485/ethernet converter that receives the requests from the raspberry and sends them to the slave through the serial line.
In short, i need to send a Modbus RTU packet wrapped in a TCP/IP packet.
This is no problem. I've build one myself using the building blocks that uModbus provides.
As you may know Modbus RTU and Modbus TCP have a few bytes in common, the PDU. As shown in this image.
To convert a Modbus TCP request into a Modbus RTU request you need to strip the MBAP header and add a CRC. After you receive the RTU response you need remove the CRC and prepend the message with the MBAP header and return that.
Here some code I wrote a while ago that did the job.
class ModbusRTUProxyHandler(RequestHandler):
def rewrite_request_adu(self, tcp_request_adu):
""" Rewrite a TCP request ADU to a RTU request ADU. """
slave_id = struct.unpack('>B', tcp_request_adu[6:7])[0]
return rtu._create_request_adu(slave_id, tcp_request_adu[7:])
def rewrite_response_adu(self, tcp_request_adu, rtu_response_adu):
""" Rewrite a RTU repsonse ADU to a TCP response ADU. """
response_pdu = rtu_response_adu[1:-2]
# Byte 6 of the MBAP is the length field. This number depends on the
# length of the adu and must be calculated. All other bytes of the
# request MBAP can be copied to the response MBAP.
mbap = tcp_request_adu[:4] +\
struct.pack('>H', len(response_pdu) + 1) + tcp_request_adu[6:7]
return mbap + response_pdu
def call_slave(self, rtu_request_adu):
self.server.rtu_lock.acquire()
self.server.serial_port.write(rtu_request_adu)
try:
rtu_response_adu = self.server.serial_port.read(256)
except SerialTimeoutException:
pass
finally:
self.server.rtu_lock.release()
return rtu_response_adu
def process(self, tcp_request_adu):
slave_id = struct.unpack('>B', tcp_request_adu[6:7])[0]
log.info('<-- {0} - {1}.'.format(self.client_address[0],
hexlify(tcp_request_adu)))
rtu_request_adu = self.rewrite_request_adu(tcp_request_adu)
rtu_response_adu = self.call_slave(rtu_request_adu)
return self.rewrite_response_adu(tcp_request_adu, rtu_response_adu)
Thank you very much. That's all I needed.
I close the issue.
Does
D'après ce que j'ai compris, vous avez un maître Modbus RTU qui doit envoyer des requêtes à l'esclave Modbus TCP. Est-ce exacte ? In this case what we do exactly ! And does the code work?
Hi, Is there a way to send RTU messages through TCP? I need this functionality because we usually convert all the serial devices with rs485/ethernet converter.