stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.44k stars 1.75k forks source link

Feature request - devices with non-standard 3-byte registers #648

Closed marekm72 closed 2 years ago

marekm72 commented 2 years ago

I have an unusual device which doesn't seem to be supported by libmodbus - MV3DL energy meter made by http://www.dossena.it/ . It is ~20 years old but still works for me. It can co-exist with other devices talking proper Modbus RTU on the same RS485 bus, but has an unusual response format to a standard "read registers" (function 3) request. When asked to read N registers, it returns N registers but each register is 3 (not 2) bytes long, in a non-standard floating point format: first two bytes are the usual big-endian 16-bit signed value, followed by decimal exponent in the third byte. So, multiply the value in the first two bytes (high, low) by 10^(third_byte - 3). Response length byte in the response header is correct, reading 32 registers by function 3 returns response of 101 bytes total: address, 3, 96, response[96], crc[2]. Write register (function 6) is still standard 16-bit (device has only one register, writing to it resets energy count, I do this once a day after reading the count, as higher counts lose precision when the exponent increases). I have rolled my own code to handle all this (it was written 20 years ago and still runs on the same Pentium Pro 200MHz box) but would like to convert my own app (home heating control system) to libmodbus so it can talk over Modbus TCP converted to RS485 by MikroTik KNOT - this will eliminate the separate physical machine, as the code talking Modbus TCP can run in a VM instead. Would it be possible to add support for such non-standard devices in libmodbus? Not sure how widespread they are today.

stephane commented 2 years ago

You can may be use the https://libmodbus.org/docs/v3.1.7/modbus_send_raw_request.html?

stephane commented 2 years ago

BTW the support of such not compliant devices will be very hard to maintain so I don't intend to support it. Let me know if you are able to communicate with your device with the low level functions.

marekm72 commented 1 year ago

I can confirm https://libmodbus.org/reference/modbus_send_raw_request/ works - actually the request format is standard, only the response format from the MV3DL is different (with 3-byte registers), the KNOT passes the RTU response back as TCP transparently, then it is received by modbus_receive_confirmation.

One caveat: raw response in the buffer filled by modbus_receive_confirmation is different depending on the mode (RTU or TCP): RTU: raw response starts at rsp[0] and includes CRC at the end TCP: raw response starts at rsp[6] without CRC at the end

Return value of modbus_receive_confirmation is the response length in bytes, reading 32 registers of 3 bytes each returns 101 for RTU (address, function=3, length=96, data[96], crc[2]) and 105 for TCP (tcp_header[6], address, function=3, length=96, data[96]).

For applications that should be able to talk to either RTU (local serial port) or TCP (over the network) slaves, a higher level function similar to modbus_receive_confirmation which returns the frame always in the same (RTU) format may be useful (in the same way as modbus_send_raw_request always expects the raw request in RTU format as well, even for TCP).