Modbus RTU support in Typica has always been relatively weak, but there's enough other hardware support that I haven't considered improving that to be a high priority. Recently someone contacted me about paying to raise the priority on a specific improvement that would allow them to use Typica with hardware they already had on their roaster and since this is a project that can always use financial support I decided to spend an evening making that change and using it as an opportunity to do some related work that I've wanted in Typica for a while. I'll have another post about those changes and how to use the new build later.
When working on code that communicates with hardware, I like to have hardware set up to test that code against. For Modbus RTU hardware, a basic test rig consists of a power transformer, a panel display, a thermocouple simulator, and an RS485 to USB serial adapter along with all the wires needed to hook those things together. That works, but it's not very portable and it's easy to disturb. There were also a couple of different ways device manufacturers implement one of the features I would be adding so a hardware only test rig would require at least two different panel displays. Rather than expand the hardware test rig I decided to try something else: running a simulation of the bus and using that for the initial testing. I would still want to go back and make sure it works with physical hardware, but simulated hardware would make the initial work easier to do. Since I prefer to write software on my laptop computer that runs Linux, that is where I set this up. The hardware testing that came later was under Windows.
ModbusPal is a free Java application that can simulate a bus with devices communicating using Modbus, though it doesn't quite work for that out of the box. Serial port communications require additional software (RXTX, you want version 2.2pre2 if you're on amd64; earlier versions crash as soon as you try to read from the port) and it can take a bit of searching around to find where the various files should go, especially if you don't write software in Java on Linux often enough to be familiar with that.
tty0tty is a null modem emulator. It adds files like /dev/tnt0 and /dev/tnt1 and programs can connect to those like they would any other serial port, but if you have one program talking to /dev/tnt0 and another program talking to /dev/tnt1 those two programs can communicate with each other as if there were a null modem cable run between two real serial ports. This is handy because my laptop doesn't have old style serial ports, much less two of them. I could have gone with two USB serial adapters and a null modem cable instead, but that's not much better than just using real hardware. It probably would have taken me longer just to find a null modem cable than it would have to set this up. I haven't needed to use one of those in decades.
Recognizing the ports
Unfortunately, a lot of programs that use serial ports don't know that they can use the files created by tty0tty. Typica uses qextserialport for serial port communications which doesn't enumerate those /dev/tnt* files, but getting that to work was a tiny change to one line of code and rebuilding that library. No changes were needed in Typica.
For ModbusPal I needed to launch that on the command line as:
java -Dgnu.io.rxtx.SerialPorts=/dev/tnt0 -jar ModbusPal.jar
to get that port to show up.
Getting things talking
With ModbusPal configured to use /dev/tnt0 and Typica configured to use /dev/tnt1 it's now possible for Typica to use that simulated bus. The old code won't work very well with that as it seems that ModbusPal doesn't support Modbus function 4 (read input registers). It does, however, support function 3 (read holding registers) which has identical query and response structures. The only difference is that the 2nd byte contains a 3 instead of a 4.
Next, we can make things a little more interesting. The Automation section in ModbusPal allows you to set up generators that produce changing values. It's then possible to bind those generators to addresses on a simulated device. Configuring Typica to read from those registers allows you to see the values changing.
Earlier I wrote that a test involving physical hardware would require multiple devices. This is because different devices do not agree on how to represent numbers. The Modbus RTU protocol only knows about 1 bit values (coils) and 16 bit values (registers). With temperature measurements, it's often desirable to present those values with a fractional part. Some devices do this with a 16 bit value by presenting that as an integer and leaving it to software to divide that by a fixed power of 10 to shift the decimal point to the correct position. Another option is to use a floating point number. It's possible to fit a half precision floating point number in 16 bits, but half precision floating point numbers weren't standardized until a couple decades after Modbus was introduced and it's really not a good choice for this sort of thing. I hope nobody is making devices that use that. Many devices do, however, use single precision floating point numbers (aka binary32). As you might have guessed, these require 32 bits. Modbus doesn't have a concept of 32 bit values, but you could take two 16 bit values and just split the number in half. Since the protocol doesn't have a concept of 32 bit values or floating point numbers, it doesn't specify how that data should be ordered so manufacturers do what they want. That means Typica should support both options.
ModbusPal makes it easy to test that. You can take a generator and bind it to four registers. Use one order for two of them, use the other order for the other two. You can also set up registers to use an integer representation to make sure the fixed point stuff still works.