/*
 * Copyright © Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#ifndef MODBUS_TCP_PRIVATE_H
#define MODBUS_TCP_PRIVATE_H

/*
 * Modbus TCP 协议的帧格式定义：
 *
 * TCP ADU 帧结构（基于 MBAP 头 + PDU）：
 * ┌──────────────────────────┬───────────────┬──────────┐
 * │     MBAP 头部(7字节)      │  PDU(变长)     │    ...   │
 * └──────────────────────────┴───────────────┴──────────┘
 *
 * MBAP 头部分解：
 * ┌──────────────┬──────────────┬──────────────┬──────────┐
 * │  事务标识符   │  协议标识符   │   长度字段    │ 单元标识符 │
 * │  (2字节)     │  (2字节,=0)  │  (2字节)     │ (1字节)  │
 * └──────────────┴──────────────┴──────────────┴──────────┘
 */

/* TCP MBAP 头长度：事务ID(2) + 协议ID(2) + 长度(2) + 单元ID(1) = 7 字节 */
#define _MODBUS_TCP_HEADER_LENGTH     7
/* TCP 预设请求帧的总长度：MBAP头(7) + PDU(5) = 12 字节 */
#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
/* TCP 预设响应帧的总长度：MBAP头(7) + PDU(1) = 8 字节 */
#define _MODBUS_TCP_PRESET_RSP_LENGTH 8

/*
 * TCP 模式下没有独立的校验和字段。
 * TCP 协议本身通过底层 TCP/IP 栈的校验和机制保证数据完整性，
 * 因此 Modbus TCP 的 checksum 长度为 0。
 */
#define _MODBUS_TCP_CHECKSUM_LENGTH 0

/*
 * modbus_tcp_t — Modbus TCP 后端的私有数据结构体。
 * 在两个结构体中，事务标识符(t_id)都必须放在第一个字段位置，
 * 这样无论使用哪个 TCP 后端变体，都可以通过相同的内存偏移量快速访问事务ID。
 */
typedef struct _modbus_tcp {
    /*
     * 事务标识符。
     * 摘录自《MODBUS Messaging on TCP/IP Implementation Guide V1.0b》
     * （第 23/46 页）：
     * 事务标识符用于将未来的响应与对应的请求关联起来。
     * 在每个 TCP 连接上，此标识符是唯一的。
     * 客户端生成一个事务ID，服务器在响应中原样返回，
     * 从而允许客户端匹配请求和响应。
     */
    uint16_t t_id;
    /* TCP 端口号（标准 Modbus TCP 端口为 502） */
    int port;
    /* IP 地址字符串（如 "192.168.1.100"），最大 15 字符 + '\0' 结尾 */
    char ip[16];
} modbus_tcp_t;

/*
 * modbus_tcp_pi_t — Modbus TCP PI（协议独立）后端的私有数据结构体。
 * "PI" 表示 Protocol Independent（协议独立），即使用 getaddrinfo()
 * 解析的主机名和服务名，而非仅限 IPv4 地址。
 * 这使得该结构体同时支持 IPv4 和 IPv6 地址。
 */
typedef struct _modbus_tcp_pi {
    /* 事务标识符（放在首位，便于快速访问） */
    uint16_t t_id;
    /* TCP 端口号 */
    int port;
    /* 主机节点名（如 "modbus-server.local" 或 IPv4/IPv6 地址字符串） */
    char *node;
    /* 服务名（如 "502" 或 "/etc/services 中定义的服务名"） */
    char *service;
} modbus_tcp_pi_t;

#endif /* MODBUS_TCP_PRIVATE_H */
