Write Port/Socket Failure

Asked by jcarroll

I nearly have a complete system that uses shared memory and preforms as both a slave and a server, as well as logging data to a MYSQL database. I ran into a problem which I am hoping to get help with.

The error is a "Write Port/Socket Failure" error and it only occurs when requesting 6 or more registers at a time. It appears to only show up during a 03, 04 read command.

I have not altered any of the libmodbus code, what I did do is build a function that sets up the mb_mapping structure with pointers to the shared memory with the proper offsets.

The error is coming from the write() call to the serial port in the modbus_send() function. What I don't know is if the error is caused by a the data that is sent to the write() function or from inside the write() function.

I realize the data is sparce but as I gather more I will update.

Any help would be appreciated.

Question information

Language:
English Edit question
Status:
Solved
For:
libmodbus Edit question
Assignee:
No assignee Edit question
Solved by:
jcarroll
Solved:
Last query:
Last reply:
Revision history for this message
jcarrr (jcarroll-collinscom) said :
#1

Justin and I have been discussing this problem and agree that the description of the circumstances is pretty sparse. More detail.

Our application acts as an aggregator of data from multiple sources. 485, usb and serial and TCP devices contribute. A socket connection to a mysql data base engine is part of the show. The application remaps data from the various sources into the register format a legacy control system expects.

We are becoming pretty good at shuffling data about. Every thing works very well except for the multiple port read transactions with the simulated legacy master control system. We became concerned that all of our development devices are the product of the same library and used the 'Simply Modbus' tool on an XP box to fetch data from the aggregator in order to test that function. A query for five registers from Simply Modbus works, a query for six brings back five and errors. The query arrives at the slave intact and properly formed. I realize now that I do not know what the the non_data part of the reply says, only that the system squawks about the"Write Port/Socket Failure" error.

On the other side of the device there appears to be no problem reading multiple registers. Some of the instruments are real. Multiple data reads comes screaming back from them. One of the devices is simulated. The simulated machine is a box running software developed with the common source. Right now the machine is being queried with single register reads because the registers of interest are all over the map. As each data arrives it is mapped individually so it makes sense to do it this way. Tomorrow I will add some multiple register reads from the machine, get all the boxes going and report on the results. I just realized we can test our simulated machine with simply modbus as well.

'simply modbus' multiple reads to a usb serial port seem to fail when the number of registers is > 5
Certainly some one knows what happens when a libmodbus device asks another libmodbus machine for multiple registers across a 485 / usb link. As long as we are simulating in the office it could go 232 or TCP. We will try them all.

I am reminded that the writes to mysql sometimes miss some data, but I think that can be solved by spacing the queries a few milliseconds.

Any Bets about the results of the experiments to come?

Thanks for paying attention. I think we can make a contribution to the development in a couple of weeks after this project is off the ground.

John Carroll

Revision history for this message
Stéphane Raimbault (sra) said :
#2

in modbus.c:

        if ((ret == -1) || (ret != query_length)) {
                ret = PORT_SOCKET_FAILURE;
                error_treat(mb_param, ret, "Write port/socket failure");
        }

Could you add a printf like that?
      if ((ret == -1) || (ret != query_length)) {
                printf("RET %d\n", ret);
                ret = PORT_SOCKET_FAILURE;
                error_treat(mb_param, ret, "Write port/socket failure");
        }

may be the device supports only very short request.

Revision history for this message
jcarrr (jcarroll-collinscom) said :
#3

If this is a duplicate reply, I apologize

Good idea, we will try to get more data. It will be a few days, Justin is
installing the system containing the code in Chicago. The security of the
western world is hanging on sucessful operation. Not really, just one
turbine generator will shut down if it fails, and it has shut down many
times in the past.

The slave code that faults is a simple application uitlizing code from the
library. The slave is our bogus turbine used for testing communication
and control. I cannot find anything in the application code that would
make much difference. It may be solved by toying with some communication
parameters. ver 0.1 is going into action with single register reads. The
turbine software is so slow that it takes a second or so to read all of
the interesting registers. It will work fine for now but not if a number
of slow slaves are on one chain.

Thank you for the fine code.

John Carroll

> Question #65157 on libmodbus changed:
> https://answers.launchpad.net/libmodbus/+question/65157
>
> Status: Needs information => Answered
>
> Stéphane Raimbault proposed the following answer:
> in modbus.c:
>
> if ((ret == -1) || (ret != query_length)) {
> ret = PORT_SOCKET_FAILURE;
> error_treat(mb_param, ret, "Write port/socket failure");
> }
>
> Could you add a printf like that?
> if ((ret == -1) || (ret != query_length)) {
> printf("RET %d\n", ret);
> ret = PORT_SOCKET_FAILURE;
> error_treat(mb_param, ret, "Write port/socket failure");
> }
>
> may be the device supports only very short request.
>
> --
> You received this question notification because you are a direct
> subscriber of the question.
>

Revision history for this message
jcarroll (justcarroll) said :
#4

I researched the problem and found a solution, at least for my application. The problem is that the port was trying to be opened before it was all the way closed from the previous use.

I added these lines:

        int on;
        on = 1;
        ret = setsockopt( new_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

in the function that listens for a query from a modbus master using TCP. It basically keeps the port open and as long as the same machine request to use the port it will work. It will limit other machines from working on that port.

Here is on page that describes the use:
http://beej.us/guide/bgnet/output/html/multipage/setsockoptman.html

I am submitting a patch but, like I said, I don't think this a solution for everyone. A port handler needs to be written.

Revision history for this message
Stéphane Raimbault (sra) said :
#5

I've just committed that last week (TCP reuse and a slave able to handle many connections):
http://bazaar.launchpad.net/~sra/libmodbus/trunk/revision/147