# API-libcomm — 通讯抽象层模块

> 版本: v1.0
> 日期: 2026-07-08
> 状态: 已实现（TCP/UDP 完整, UART 待实现）

---

## 1. 模块概述

libcomm 是 RTU 通讯装置的**通讯抽象层**，为上层协议栈（Modbus、IEC104 等）提供统一的 TCP/UDP/UART 通讯接口。

### 设计思想

- **类型统一**：同一套 API 操作 TCP 服务器/客户端、UDP、UART
- **异步事件驱动**：基于 epoll 单线程事件循环，非阻塞 I/O
- **回调解耦**：接收数据和状态变化通过回调通知上层
- **纯 C 接口**：`extern "C"` 包裹，C/C++ 均可调用

### 架构

```
┌──────────────────────────────────────────────┐
│           协议层（libmodbus / lib60870）       │
│   调用 comm_create / comm_send / recv_cb     │
├──────────────────────────────────────────────┤
│            libcomm（纯 C 接口层）              │
│  ┌──────────┬──────────┬──────────────────┐  │
│  │ TCP 服务 │ TCP 客户 │ UDP 服务 / 客户  │  │
│  │ 器端     │ 端       │                  │  │
│  └──────────┴──────────┴──────────────────┘  │
│  ┌──────────────────────────────────────────┐ │
│  │  epoll 事件循环 + fd 管理 + 状态机      │ │
│  └──────────────────────────────────────────┘ │
├──────────────────────────────────────────────┤
│    实现层（C++: map/mutex + POSIX socket）    │
└──────────────────────────────────────────────┘
```

### 源文件结构

```
libcomm/
├── inc/
│   └── myComm.h              # 对外 C 接口头文件
└── src/
    ├── comm_internal.h       # 内部共享类型/全局变量/函数声明
    ├── comm_core.cpp         # 核心: create/destroy/run/stop + epoll 事件循环
    ├── comm_tcp.cpp          # TCP 服务器/客户端
    ├── comm_udp.cpp          # UDP 通讯
    └── comm_uart.cpp         # UART 串口通讯
```

---

## 2. 数据结构

### 2.1 通讯类型

```c
typedef enum
{
    COMM_TYPE_TCP_SERVER = 0,   /** TCP 服务器（监听+accept） */
    COMM_TYPE_TCP_CLIENT,       /** TCP 客户端 */
    COMM_TYPE_UDP_SERVER,       /** UDP 服务器 */
    COMM_TYPE_UDP_CLIENT,       /** UDP 客户端 */
    COMM_TYPE_UART              /** UART 串口 */
} enum_comm_type;
```

### 2.2 通讯状态

```c
typedef enum
{
    COMM_STATE_DISCONNECTED = 0, /** 未连接 */
    COMM_STATE_CONNECTING,       /** 连接中 */
    COMM_STATE_CONNECTED,        /** 已连接 */
    COMM_STATE_ERROR             /** 错误状态 */
} enum_comm_state;
```

### 2.3 参数结构体

```c
/** TCP 参数 */
typedef struct
{
    char local_ip[64];       /** 本地 IP（服务器用） */
    int  local_port;         /** 本地端口（服务器用） */
    char remote_ip[64];      /** 远端 IP（客户端用） */
    int  remote_port;        /** 远端端口（客户端用） */
} stru_tcp_para;

/** UDP 参数 */
typedef struct
{
    char local_ip[64];       /** 本地 IP */
    int  local_port;         /** 本地端口 */
    char remote_ip[64];      /** 远端 IP（客户端用） */
    int  remote_port;        /** 远端端口（客户端用） */
} stru_udp_para;

/** UART 参数 */
typedef struct
{
    char device[128];        /** 串口设备路径（如 /dev/ttyS0） */
    int  baudrate;           /** 波特率 */
    int  data_bits;          /** 数据位（5/6/7/8） */
    int  stop_bits;          /** 停止位（1/2） */
    char parity;             /** 校验位（'N'/'E'/'O'） */
} stru_uart_para;

/** 通讯参数联合体 */
typedef union
{
    stru_tcp_para  tcp;
    stru_udp_para  udp;
    stru_uart_para uart;
} union_comm_para;
```

### 2.4 回调函数类型

```c
/** 接收数据回调 */
typedef void (*comm_recv_cb)(int id, int fd, const unsigned char *data, int len);

/** 状态变化回调 */
typedef void (*comm_state_cb)(int id, int fd, int state);
```

### 2.5 错误码

| 常量 | 值 | 说明 |
|------|-----|------|
| `COMM_OK` | 0 | 成功 |
| `COMM_ERR_PARAM` | -1 | 参数错误 |
| `COMM_ERR_MEM` | -2 | 内存不足 |
| `COMM_ERR_SOCKET` | -3 | Socket 创建失败 |
| `COMM_ERR_BIND` | -4 | 绑定失败 |
| `COMM_ERR_LISTEN` | -5 | 监听失败 |
| `COMM_ERR_CONNECT` | -6 | 连接失败 |
| `COMM_ERR_SEND` | -7 | 发送失败 |
| `COMM_ERR_NOT_FOUND` | -8 | 实例不存在 |
| `COMM_ERR_STATE` | -9 | 状态错误 |
| `COMM_ERR_INTERNAL` | -10 | 内部错误 |

---

## 3. 接口函数

### 3.1 comm_create — 创建通讯实例

```c
int comm_create(int type, int debug, const union_comm_para *para);
```

**参数**：
- `type`：通讯类型（enum_comm_type）
- `debug`：是否打印调试信息（1=打印, 0=静默）
- `para`：通讯参数（根据 type 选择对应成员）

**返回值**：`>=0` 实例 ID，`<0` 错误码

**使用场景**：协议栈初始化时创建对应的通讯通道

---

### 3.2 comm_connect — 建立连接

```c
int comm_connect(int id);
```

**行为**（按类型）：
- TCP 服务器：bind + listen，注册到 epoll
- TCP 客户端：非阻塞 connect，监听 EPOLLOUT 等待完成
- UDP：bind 本地端口
- UART：open 串口设备 + 配置波特率/数据位/停止位/校验

**返回值**：`COMM_OK` 成功，`<0` 错误码

---

### 3.3 comm_disconnect — 断开连接

```c
int comm_disconnect(int id);
```

关闭所有 fd（监听 + 客户端 + 本地），保留参数可重新 connect。

---

### 3.4 comm_send — 发送数据

```c
int comm_send(int id, int fd, const unsigned char *data, int len);
```

**参数**：
- `fd`：目标 fd（TCP 服务器需指定客户端 fd）
- `data`/`len`：数据与长度

**返回值**：`>=0` 实际发送字节数，`<0` 错误码

**注意**：UDP 客户端会自动 sendto 到创建时指定的远端地址

---

### 3.5 comm_recv_register — 注册接收回调

```c
int comm_recv_register(int id, comm_recv_cb cb);
```

epoll 检测到可读后，自动调用此回调，传入 `(id, fd, data, len)`。

---

### 3.6 comm_state_register — 注册状态回调

```c
int comm_state_register(int id, comm_state_cb cb);
```

连接建立/断开/错误时回调，传入 `(id, fd, state)`。

---

### 3.7 comm_destroy — 销毁实例

```c
int comm_destroy(int id);
```

关闭所有 fd、释放内存。

---

### 3.8 comm_run / comm_stop — 事件循环

```c
int  comm_run(void);    /** 阻塞运行 epoll 事件循环 */
void comm_stop(void);   /** 停止事件循环 */
```

**约定**：调用者在独立线程中调用 `comm_run()`。停止时调用 `comm_stop()`。

---

## 4. 使用示例

### 4.1 TCP 客户端

```c
#include "myComm.h"

static void on_recv(int id, int fd, const unsigned char *data, int len)
{
    printf("recv %d bytes on fd=%d\n", len, fd);
}

static void on_state(int id, int fd, int state)
{
    if (state == COMM_STATE_CONNECTED)
    {
        printf("connected!\n");
    }
}

void tcp_client_example(void)
{
    union_comm_para para;

    strcpy(para.tcp.remote_ip, "192.168.1.100");
    para.tcp.remote_port = 502;
    para.tcp.local_ip[0] = '\0';
    para.tcp.local_port = 0;

    int id = comm_create(COMM_TYPE_TCP_CLIENT, 1, &para);

    comm_recv_register(id, on_recv);
    comm_state_register(id, on_state);
    comm_connect(id);

    /* 在另一个线程启动事件循环 */
    comm_run();
}
```

### 4.2 TCP 服务器

```c
void tcp_server_example(void)
{
    union_comm_para para;

    strcpy(para.tcp.local_ip, "0.0.0.0");
    para.tcp.local_port = 502;

    int id = comm_create(COMM_TYPE_TCP_SERVER, 1, &para);

    comm_recv_register(id, on_recv);
    comm_state_register(id, on_state);
    comm_connect(id);

    comm_run();
}
```

### 4.3 UDP

```c
void udp_example(void)
{
    union_comm_para para;

    strcpy(para.udp.local_ip, "0.0.0.0");
    para.udp.local_port = 2404;

    int id = comm_create(COMM_TYPE_UDP_SERVER, 1, &para);

    comm_recv_register(id, on_recv);
    comm_connect(id);
    comm_run();
}
```

---

## 5. 依赖关系

```
myBase.h → libcomm
   (无其他模块依赖)
```

libcomm 是阶段 2 的第一个模块，被后续 `libmodbus`、`lib60870` 等协议栈依赖。

---

## 6. 程序运行流程

```
comm_create(type, para)
  → 分配 stru_comm_instance，拷贝参数，返回 id
  → 首次调用时初始化 epoll + eventfd

comm_connect(id)
  → TCP_SERVER: socket → bind → listen → epoll_add(listen_fd)
  → TCP_CLIENT: socket → nonblock-connect → epoll_add(fd, EPOLLOUT)
  → UDP: socket → bind → epoll_add(fd)
  → UART: open(device) → tcsetattr → epoll_add(fd)

comm_run() [阻塞，需在独立线程中调用]
  → epoll_wait 循环
  → EPOLLIN (listen_fd) → accept → epoll_add(client_fd) → state_cb
  → EPOLLIN (data_fd) → recv → recv_cb
  → EPOLLOUT → getsockopt(SO_ERROR) → connect 完成 → state_cb
  → EPOLLERR/HUP/RDHUP → close_fd → state_cb(DISCONNECTED)

comm_stop()
  → write(eventfd) → epoll 收到 → g_running = false → 退出循环
```
