libmodbus icon indicating copy to clipboard operation
libmodbus copied to clipboard

Invalid CRC

Open theprelior opened this issue 1 year ago • 3 comments

libmodbus version

3.1.10

OS and/or distribution

Ubuntu 22.04.4 Jammy release

Environment

Raspberry Pi 4B Arc

Description

Hello, I'm trying to connect and get datas from specific registers that is on a slave connected to raspbery pi from /dev/ttyUSB0 port. Connecting and opening port are okay but here is the problem whenever I tried to read registers which is starting 30001 and up to 30004 it says invalid crc. But if I start with 0 I got these different datas from expected

Actual behavior if applicable

int rc=modbus_read_registers(ctx,30001,3,tab_reg); Opening /dev/ttyUSB0 at 9600 bauds (O, 8, 1) [21][03][75][30][00][04][59][6A] Sending request using RTS signal Waiting for a confirmation... <21><00><00><00><00> ERROR CRC received 0x0 != CRC calculated 0x21CA Invalid CRC

int rc=modbus_read_registers(ctx,0,3,tab_reg); Opening /dev/ttyUSB0 at 9600 bauds (O, 8, 1) [21][03][00][00][00][03][02][AB] Sending request using RTS signal Waiting for a confirmation... <21><03><06><00><00><00><00><00><21><78><AC> reg[0]=0 (0x0) reg[1]=0 (0x0) reg[2]=33 (0x21) reg[3]=0 (0x0)

Expected behavior or suggestion

image image

Steps to reproduce the behavior (commands or source code)

#include <stdio.h>
#include <modbus.h>
#include <cerrno>
#include <iostream>
int main(){

	const int REMOTE_ID = 33;
	modbus_t *ctx;
	uint16_t tab_reg[4];

	ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'O', 8, 1);
	modbus_set_slave(ctx, 33);
	modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
	modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
	modbus_rtu_set_rts_delay(ctx, 3);
	modbus_set_debug(ctx, 1);
	if (ctx == NULL) {
	    fprintf(stderr, "Unable to create the libmodbus context\n");
	    return -1;
	}

	if (modbus_connect(ctx) == -1) {
	    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
	    modbus_free(ctx);
	    return -1;
	}
	
	int rc=modbus_read_registers(ctx,30001,3,tab_reg);
	if(rc==-1){
		fprintf(stderr,"%s\n",modbus_strerror(errno));
		std::cout<<"Reading register error";
		return -1;
	}
	for (int i=0;i<sizeof(tab_reg)/sizeof(tab_reg[0]);i++){
					printf("reg[%d]=%d (0x%X)\n",i,tab_reg[i],tab_reg[i]);
			    }
	
	modbus_close(ctx);
	modbus_free(ctx);
}

libmodbus output with debug mode enabled

<...>

theprelior avatar May 03 '24 13:05 theprelior

Correct. Welcome to the wonderful world of modbus. "30000" just means "registers" and 20000 and 40000 just mean "input registers" and "coils"

it's kinda like "modbus_opration(3000x)" will automatically do a read_registers(x) and "modbus_operation(4000x)" will automatically do a "read_holding_registers(x)"

libmodbus doesn't support the 30000 style, just the "full" style.

karlp avatar May 03 '24 14:05 karlp

How can I solve this problem and read these datas as I expected on top?Btw tried to start with 40001. I already wrote a code snippet which is working with termios but here too, the datas are not resolvable.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <cstdint>
#define DEVICE_PATH "/dev/ttyUSB0" // Update the serial port path appropriately
#define REMOTE_ID 33 // Device's slave ID
#define START_ADDRESS 30001 // Start register address
#define NUM_REGISTERS 4 // Number of registers to read

int main() {
    int fd;
    struct termios serial;
    uint16_t tab_reg[NUM_REGISTERS];

    // Open the serial port
    fd = open(DEVICE_PATH, O_RDWR | O_NOCTTY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // Configure the serial port settings
    tcgetattr(fd, &serial);
    cfsetispeed(&serial, B9600); // Set input baud rate
    cfsetospeed(&serial, B9600); // Set output baud rate
    serial.c_cflag |= (CLOCAL | CREAD); // Enable port for local and reading capabilities
    serial.c_cflag &= ~PARENB; // Disable parity
    serial.c_cflag |= PARODD;
    serial.c_cflag &= ~CSTOPB; // Use 1 stop bit
    serial.c_cflag &= ~CSIZE; // Clear data bits
    serial.c_cflag |= CS8; // Use 8 data bits
    serial.c_cc[VMIN] = 0; // Set minimum character count to 0
    serial.c_cc[VTIME] = 10; // Set timeout to 1 second

    // Apply the serial port settings
    tcsetattr(fd, TCSANOW, &serial);

    // Modbus read operation
    if (write(fd, "\x21\x03\x75\x31\x00\x04\x49\x68", 8) != 8) {
        perror("write");
        return -1;
    }

    sleep(3); // Wait for 0.5 seconds

    int rc = read(fd, tab_reg, sizeof(tab_reg));
    if (rc == -1) {
        perror("read");
        return -1;
    }

    // Print the read register values
    for (int i = 0; i < NUM_REGISTERS; i++) {
        printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
    }

    // Close the serial port
    close(fd);

    return 0;
}

output: reg[0]=45936 (0xB370) reg[1]=51248 (0xC830) reg[2]=65535 (0xFFFF) reg[3]=0 (0x0)

theprelior avatar May 03 '24 14:05 theprelior

You simply don't. libmodbus (much as many other tools) simply doens't use the 300xx / 400xx addressing. If you want to read 30013, you do a "read regs 13" if you want 40013, you do a "read holding regs 13" (or vice versa, I never remember which is holding and which is input)

karlp avatar May 03 '24 23:05 karlp

Thank you @karlp for your comments.

stephane avatar Jul 17 '24 12:07 stephane