一、libmodbus重要数据结构讲解

这两个结构体是 libmodbus 的核心,定义了 Modbus 通信上下文 (_modbus) 和通信后端 (_modbus_backend) 的详细信息,直接决定了 Modbus 的通信行为。


1. 结构体 _modbus

定义

这个结构体描述了 Modbus 通信的上下文 (modbus_t 类型的实际定义),包含了通信所需的参数和状态信息。

成员解析
struct _modbus {
    /* Slave address */
    int slave;
  • slave:当前上下文的从站地址。对于 Modbus 主站,表示要访问的从站地址;对于 Modbus 从站,表示设备自身的地址。
    /* Socket or file descriptor */
    int s;
  • s:文件描述符,用于标识当前连接。对于 Modbus TCP,表示一个套接字 (socket);对于 Modbus RTU,表示一个串口文件描述符。
    int debug;
  • debug:调试标志。设置为 1 时,启用调试模式,打印发送和接收的详细信息。
    int error_recovery;
  • error_recovery:错误恢复模式。启用后,通信发生错误时会自动尝试恢复连接(如重新连接或重发请求)。
    int quirks;
  • quirks:表示协议的特殊处理标志,用于处理不同 Modbus 实现的兼容性问题。
    struct timeval response_timeout;
    struct timeval byte_timeout;
    struct timeval indication_timeout;
  • response_timeout:等待从站响应的最大时间。
  • byte_timeout:等待每个字节接收的超时时间。
  • indication_timeout:Modbus 从站在无通信时的等待时间(仅在从站模式下使用)。
    const modbus_backend_t *backend;
  • backend:指向 Modbus 后端结构的指针,定义了具体的通信实现(如 Modbus TCP 或 RTU)。
    void *backend_data;
  • backend_data:与后端相关的私有数据指针。TCP 和 RTU 后端可能需要不同的附加信息(如 TCP 套接字地址或串口配置)。
小结
  • _modbus 是 Modbus 通信的抽象封装,结合 backend 提供具体的通信行为。
  • 它统一管理通信参数和状态信息,为主站和从站操作提供支持。

2. 结构体 _modbus_backend

定义

modbus_backend_t 定义了 Modbus 的通信后端接口,抽象了具体的通信实现(如 TCP 或 RTU)。通过这个结构体,libmodbus 能够适配不同的传输协议。

成员解析
    unsigned int backend_type;
  • backend_type:后端类型标志,用于区分 Modbus RTU、ASCII 或 TCP。
    unsigned int header_length;
    unsigned int checksum_length;
    unsigned int max_adu_length;
  • header_length:报文头长度,Modbus RTU 和 TCP 的头长度不同。
  • checksum_length:校验码长度。Modbus RTU 使用 CRC 校验,Modbus TCP 不需要校验。
  • max_adu_length:最大 ADU(Application Data Unit)长度,限制一次传输的数据量。
    int (*set_slave)(modbus_t *ctx, int slave);
  • set_slave:设置 Modbus 从站地址的函数指针。
    int (*build_request_basis)(modbus_t *ctx, int function, int addr, int nb, uint8_t *req);
  • build_request_basis:构建 Modbus 请求帧的函数,定义了如何封装功能码、寄存器地址和数据。
    int (*build_response_basis)(sft_t *sft, uint8_t *rsp);
  • build_response_basis:构建 Modbus 响应帧的函数,用于从站模式。
    int (*prepare_response_tid)(const uint8_t *req, int *req_length);
  • prepare_response_tid:准备响应时处理事务 ID 的函数(通常用于 TCP)。
    int (*send_msg_pre)(uint8_t *req, int req_length);
    ssize_t (*send)(modbus_t *ctx, const uint8_t *req, int req_length);
    ssize_t (*recv)(modbus_t *ctx, uint8_t *rsp, int rsp_length);
  • send_msg_pre:在发送请求前进行预处理(如添加校验)。
  • send:发送数据帧的底层实现。
  • recv:接收数据帧的底层实现。
    int (*check_integrity)(modbus_t *ctx, uint8_t *msg, const int msg_length);
  • check_integrity:校验数据帧完整性的函数(如 CRC 校验)。
    int (*pre_check_confirmation)(modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length);
  • pre_check_confirmation:检查从站响应是否与主站请求匹配。
    int (*connect)(modbus_t *ctx);
    unsigned int (*is_connected)(modbus_t *ctx);
    void (*close)(modbus_t *ctx);
  • connect:建立连接的函数。
  • is_connected:检查连接状态的函数。
  • close:关闭连接的函数。
    int (*flush)(modbus_t *ctx);
  • flush:清空接收缓冲区的函数。
    int (*select)(modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
  • select:实现 select 调用,等待特定时间以接收数据。
    void (*free)(modbus_t *ctx);
  • free:释放上下文相关资源的函数。
小结
  • modbus_backend_t 是 Modbus 的后端抽象,封装了不同通信协议的操作。
  • 每个通信协议(TCP 或 RTU)需要实现一套符合接口的具体函数。

3. 两者关系和工作流程

关系
  • _modbus 是 Modbus 通信的具体上下文,它通过指针 backend 关联到 _modbus_backend
  • _modbus_backend 提供了通信操作的实现,_modbus 负责调用这些接口。
工作流程
  1. 初始化

    • 创建 _modbus 实例,设置从站地址和通信参数。
    • 初始化对应的 _modbus_backend 实现(TCP 或 RTU)。
  2. 通信

    • 调用 backendbuild_request_basis 构建请求帧。
    • 使用 sendrecv 函数发送和接收数据。
    • 检查数据完整性并解析响应。
  3. 关闭连接

    • 调用 closefree 函数,释放资源。

这两个结构体共同构成了 libmodbus 的核心设计,通过分离上下文和后端逻辑,实现

12-30 06:47