Search code examples
clibmodbus

Separate connect function for libmodbus


I am trying to group the operation under libmodbus for Mod-bus connection and get-value into two simpler function as below.
However, it always cause Segmentation fault (core dumped) when I try to get value from the device.(get_float, modbus_read_registers)
Can anyone tell me how to fix it?

int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx){
    int fail = 0;
    ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
    
    modbus_set_slave(ctx, MODBUS_DEVICE_ID);
    modbus_set_debug(ctx, MODBUS_DEBUG);

    timeout.tv_sec = MODBUS_TIMEOUT_SEC;
    timeout.tv_usec = MODBUS_TIMEOUT_USEC;
    modbus_get_byte_timeout(ctx, &timeout.tv_sec, &timeout.tv_usec);
    timeout.tv_sec = MODBUS_TIMEOUT_SEC;
    timeout.tv_usec = MODBUS_TIMEOUT_USEC;
    modbus_set_response_timeout(ctx, timeout.tv_sec, timeout.tv_usec);
    
    fail = modbus_connect(ctx);
    if (fail == -1) {
        fprintf(stderr, "Connection failed: %s\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        fail = -1;
    }
    return fail;
}
int get_float(modbus_t *ctx, uint16_t addr, float *val){
    int fail = 0;
    __uint16_t value[2];
    printf("1\n");
    fail = modbus_read_registers(ctx, (addr-1), 2, value);
    printf("2\n");
    if(fail <= 0) {
        fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
    } else {
        *val = modbus_get_float_abcd(value);
    }
    return fail;
}

Besides, I can successfully run the similar code when I put them in same function as below:

int connect_n_getFloat(char *ip_addr, uint16_t addr, float *val){
    int fail = 0;
    modbus_t *ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
    ctxConfig(ctx);
    if (modbus_connect(ctx) == 0) {
        __uint16_t value[2];
        if(modbus_read_registers(ctx, (addr-1), 2, value) > 0) {
            *val = modbus_get_float_abcd(value);
        } else {
            fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
            fail = -1;
        }
    } else {
        fprintf(stderr, "Connection failed: %s\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        fail = -1;
    }
    return fail;
}

Solution

  • You're passing a context pointer to the connect function, but should be passing a pointer to a pointer, so you can return the allocated context and continue using it in further calls.

    Change the function signature, and ctx usage, from

    int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx) {
        int fail = 0;
        ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
    

    to

    int connect(char *ip_addr, struct timeval timeout, modbus_t **ctx) {
        int fail = 0;
        *ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
    

    This also explains why it works when you put them in the same function.