stephane / libmodbus

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

Missing Modbus TCP Server Sample #530

Open napperley opened 4 years ago

napperley commented 4 years ago

Although there is a C source file showing how to do a Modbus server it covers far too much (it is too complex), and lacks focus on a specific area. To make matters worse the source file isn't extensively documented (especially on memory management, and how to send a response back to the client with register data set in the response), and lacks proper code structure (all logic is done in a enormous sized main function).

The libmodbus library would greatly benefit from having a small Modbus TCP server sample that only focuses on a single area, and shows the minimum required to get a Modbus TCP server implemented.

watsocd commented 4 years ago

I had the same issue recently.

Below is a Hello World Modbus TCP server.

Hope this helps.

I have the following in my main() function.

//Start Modbus slave/server thread pthread_t thread_id; pthread_create(&thread_id, NULL, modbus_main, NULL);

/*

Hello World: Modbus slave function. Address node 3, data in registers 40001, 40002, and 40003

/*

void modbus_main(void x) {

int i;
int server_socket = -1;
modbus_t *ctx;

ctx = modbus_new_tcp(NULL, 502);
//    modbus_set_debug(ctx, TRUE);

int header_length = modbus_get_header_length(ctx);

server_socket = modbus_tcp_listen(ctx, 2);  //Listen to max two connection

//This next line will block program execution until there is a connection made
modbus_tcp_accept(ctx, &server_socket);

modbus_mapping_t *mb_map, *mb_mapping[100];  //Array of pointers for each device

//this sets up 500 holding registers starting at 40001
mb_map = modbus_mapping_new(0, 0, 500, 0);
mb_mapping[1] = mb_map;

if (mb_mapping[1] == NULL) {
    fprintf(stderr, "Failed to allocate the mapping: %s\n",
            modbus_strerror(errno));
    modbus_free(ctx);
    return;
}

for (;;) {
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
    int rc;

    do {
        rc = modbus_receive(ctx, query);
        /* Filtered queries return 0 */
    } while (rc == 0);

    /* The connection is not closed on errors which require on reply such as
            bad CRC in RTU.
     */
    if (rc == -1 && errno != EMBBADCRC) {
        /* Quit */
        break;  //the loop
    }

    //Set up some dummy data
    mb_mapping[1]->tab_registers[0] = rand() % 1000;
    mb_mapping[1]->tab_registers[1] = rand() % 100;
    mb_mapping[1]->tab_registers[2] = 333;

    //See here for a description of the query
    //http://www.simplymodbus.ca/FC03.htm

    printf("Node=%d function=%d num registers=%d start addr=%d\n", query[header_length - 1], query[header_length], MODBUS_GET_INT16_FROM_INT8(query, header_length + 3), MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) + 40001);

    //query[6] = modbus node address
    //query[7] = modbus function

    if (query[6] != 3) { //If the node is NOT correct
        modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_GATEWAY_TARGET);
        continue;
    } else {
        /* Return data */
        /* rc is the query size */
        modbus_reply(ctx, query, rc, mb_mapping[1]);
    }
}

printf("Quit the loop: %s\n", modbus_strerror(errno));

if (server_socket != -1) {
     close(server_socket);
}

modbus_mapping_free(mb_mapping[1]);
modbus_close(ctx);
modbus_free(ctx);

}

From: Nick Apperley notifications@github.com Sent: Wednesday, April 8, 2020 10:42 PM To: stephane/libmodbus libmodbus@noreply.github.com Cc: Subscribed subscribed@noreply.github.com Subject: [stephane/libmodbus] Missing Modbus TCP Server Sample (#530)

Although there is a C source file https://github.com/stephane/libmodbus/blob/master/tests/unit-test-server.c showing how to do a Modbus server it covers far too much (it is too complex), and lacks focus on a specific area. To make matters worse the source file isn't extensively documented (especially on memory management, and how to send a response back to the client with register data set in the response), and lacks proper code structure (all logic is done in a enormous sized main function).

The libmodbus library would greatly benefit from having a small Modbus TCP server sample that only focuses on a single area, and shows the minimum required to get a Modbus TCP server implemented.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/stephane/libmodbus/issues/530 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFDSAKLM6IJW6CVTBQER43RLUYXLANCNFSM4MEMNACQ . https://github.com/notifications/beacon/AAFDSAJVOLP543N3PSR2XQDRLUYXLA5CNFSM4MEMNAC2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4I4VGNUQ.gif

napperley commented 4 years ago

That example doesn't work. An error message appears after sending the reply on the server side:

Illegal data address 0x9C44 in read_input_registers
karlp commented 4 years ago

0x9c44 is simply not in range of the registers setup in @watsocd 's example, so it's behaving exactly as expected. They setup 500 holding registers, and no input registers.

watsocd commented 4 years ago

Code comment at the top: Hello World: Modbus slave function. Address node 3, data in registers 40001, 40002, and 40003

Of course no/limited error checking. IT IS a Hello World minimal example for holding (40000) registers.

alongL commented 1 year ago

Caution: this demo server code only serve for one client.
If you want the server serving for multi clients at the same time.
You should see bandwidth-server-many-up.c in tests dir.
or you can try this https://github.com/alongL/modbusServer

sunasrariyaz commented 9 months ago

The code above gives me segmentation fault during runtime. So does the random-test-server when i access the mb_mapping->tab_registers[0] to print or to assign some value to it. Without accessing the mb_mapping->tab_registers[index] it runs fine. As a sever i want to assign some values in the tab_registers array. Any kind of help is greatly appreciated.

I am running it in rhel 7 with libmodbus-3.1.10 installed.