Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

4.1 轻量PTP项目概述:从零开始的时间同步之旅

项目目标

学习了前面三章的理论和源码分析,现在让我们亲手实现一个完整的PTP程序!

项目定位:

教学导向:
- 代码简洁清晰
- 注释详细
- 突出核心流程

技术选型:
- E2E延迟测量(最常见)
- UDP/IPv4传输(最简单)
- 软件时间戳(普适性强)
- 默认域(domain 0)

功能范围:
- 主时钟程序
- 从时钟程序
- 完整同步流程
- 基本监控输出

不包含:
- BMCA(简化为静态配置)
- 透明时钟、边界时钟
- 管理协议
- 安全扩展

系统架构

整体架构:

┌─────────────────────────────────────┐
│主时钟(ptp_master)                  │
│                                     │
│  ┌──────────┐        ┌──────────┐  │
│  │ 时间源    │───────→│ PHC/系统 │  │
│  │ (本地)   │        │ 时钟     │  │
│  └──────────┘        └──────────┘  │
│                           │         │
│                           ▼         │
│  ┌──────────────────────────────┐  │
│  │ 消息发送模块                 │  │
│  │ - Announce                   │  │
│  │ - Sync + Follow_Up           │  │
│  │ - Delay_Resp                 │  │
│  └──────────────────────────────┘  │
└───────────────┬─────────────────────┘
                │
                │ UDP组播
                │ 224.0.1.129:319/320
                │
                ▼
┌─────────────────────────────────────┐
│从时钟(ptp_slave)                   │
│                                     │
│  ┌──────────────────────────────┐  │
│  │ 消息接收模块                 │  │
│  │ - Announce                   │  │
│  │ - Sync + Follow_Up           │  │
│  │ - Delay_Req                  │  │
│  └──────────────────────────────┘  │
│                           │         │
│                           ▼         │
│  ┌──────────┐        ┌──────────┐  │
│  │ 伺服算法  │───────→│ 时钟调整 │  │
│  │ (PI控制) │        │ 模块     │  │
│  └──────────┘        └──────────┘  │
│                           │         │
│                           ▼         │
│                     系统时钟同步     │
└─────────────────────────────────────┘

文件结构

ptp_lite/
├── README.md           # 项目说明
├── Makefile            # 编译脚本
├── ptp_common.h        # 公共定义
├── ptp_message.h       # 消息结构定义
├── ptp_message.c       # 消息编码解码
├── ptp_master.c        # 主时钟程序
├── ptp_slave.c         # 从时钟程序
├── ptp_servo.h         # 伺服算法头文件
├── ptp_servo.c         # 伺服算法实现

核心数据结构

时间戳结构

/* ptp_common.h */

/* PTP时间戳:48位秒 + 32位纳秒 */
typedef struct {
    uint16_t seconds_msb;/* 秒的高16位 */
    uint32_t seconds_lsb;/* 秒的低32位 */
    uint32_t nanoseconds;/* 纳秒部分 */
} __attribute__((packed)) ptp_timestamp_t;

/* 时间间隔:64位纳秒 */
typedef int64_t ptp_timeinterval_t;

/* 时钟ID:8字节 */
typedef uint8_t ptp_clock_identity_t[8];

消息头

/* ptp_message.h */

/* PTP消息头 - IEEE 1588-2019 (34 bytes) */
typedef struct {
    uint8_t  message_type;              /* 消息类型 */
    uint8_t  version_ptp;               /* PTP版本 */
    uint16_t message_length;            /* 消息长度 */
    uint8_t  domain_number;             /* 域号 */
    uint8_t  reserved1;                 /* 保留 */
    uint16_t flag_field;                /* 标志字段 */
    uint64_t correction_field;          /* 校正字段 */
    uint32_t reserved2;                 /* 保留 */
    ptp_port_identity_t source_port_identity;  /* 源端口ID */
    uint16_t sequence_id;               /* 序列号 */
    uint8_t  control_field;             /* 控制字段 */
    int8_t   log_message_interval;      /* 消息间隔 */
} __attribute__((packed)) ptp_header_t;

/* 消息类型 */
#define PTP_MSG_SYNC           0x0
#define PTP_MSG_DELAY_REQ      0x1
#define PTP_MSG_FOLLOW_UP      0x8
#define PTP_MSG_DELAY_RESP     0x9
#define PTP_MSG_ANNOUNCE       0xB

/* PTP版本 */
#define PTP_VERSION 2

配置参数

/* ptp_common.h */

/* 组播地址 */
#define PTP_PRIMARY_MCAST      "224.0.1.129"
#define PTP_EVENT_PORT         319
#define PTP_GENERAL_PORT       320

/* 默认间隔(log2秒) */
#define PTP_DEFAULT_ANNOUNCE_INT  1   /* 2秒 */
#define PTP_DEFAULT_SYNC_INT      0   /* 1秒 */

/* 默认参数 */
#define PTP_DEFAULT_DOMAIN     0
#define PTP_DEFAULT_PRIORITY1  128
#define PTP_DEFAULT_PRIORITY2  128

/* 伺服参数 */
#define SERVO_KP               0.7
#define SERVO_KI               0.3
#define SERVO_STEP_THRESHOLD   10000000LL  /* 10ms */

编译环境

# Makefile

CC = gcc
CFLAGS = -Wall -Wextra -O2 -std=gnu11
LDFLAGS = -lrt -lm

all: ptp_master ptp_slave

ptp_master: ptp_master.c ptp_message.c ptp_servo.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

ptp_slave: ptp_slave.c ptp_message.c ptp_servo.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

clean:
rm -f ptp_master ptp_slave *.o

.PHONY: all clean

运行要求

# 系统要求
# - Linux操作系统
# - GCC编译器
# - root权限(调整系统时钟)

# 编译
make

# 运行主时钟
sudo ./ptp_master eth0

# 运行从时钟
sudo ./ptp_slave eth0

# 测试
# 两台机器分别运行主从时钟
# 观察同步效果

项目特点

教学优势:

1. 代码量小
   - 主时钟:~220行
   - 从时钟:~325行
   - 便于理解全貌

2. 注释详细
   - 每个函数都有说明
   - 关键步骤有注释
   - 易于学习

3. 突出核心
   - 聚焦同步机制
   - 省略复杂功能
   - 抓住本质

4. 可运行
   - 完整可编译
   - 实际可运行
   - 真正能同步

局限性:

1. 精度有限
   - 软件时间戳
   - 微秒级精度
   - 适合教学

2. 功能简化
   - 无BMCA
   - 无安全
   - 无管理

3. 场景单一
   - 仅E2E
   - 仅UDP
   - 仅默认域

学习路径

第四章内容安排:

4.1 项目概述(本节)
- 了解项目目标
- 理解系统架构
- 准备开发环境

4.2 消息结构与编码
- PTP消息格式
- 编码解码函数
- 字节序处理

4.3 主时钟程序实现
- Announce发送
- Sync+Follow_Up发送
- Delay_Resp处理

4.4 从时钟程序实现
- 消息接收
- 时间戳记录
- 伺服算法
- 时钟调整

4.5 编译运行与测试
- 编译步骤
- 运行方法
- 测试验证

4.6 问题排查与优化
- 常见问题
- 调试技巧
- 性能优化

小结

我们为轻量级PTP项目做好了准备:

  • 明确了项目目标
  • 设计了系统架构
  • 定义了核心结构
  • 准备了开发环境

下一节,我们将实现消息结构与编码——这是PTP通信的基础。

【悬念留给4.2】

PTP消息有严格的二进制格式。

如何用C语言定义消息结构?

如何处理大小端字节序?

如何编码和解码时间戳?

下一节,深入消息格式。