2. 建立UniPro物理层连接

任务目标

本案例要求通过M-PHY配置与UniPro链路启动序列,在两个UniPro节点(本地节点A与远端节点B)之间建立物理层连接,并验证链路状态达到Active状态。实现范围限定为:M-PHY的PWM-G1速率配置、物理层适配层的启动序列状态机,以及链路状态查询验证。

环境与依赖

  • 语言:C(C99兼容)
  • 依赖:仅使用标准库 stdint.h、string.h,无第三方库
  • 运行方式:单文件编译,模拟两个节点的寄存器交互

核心实现

以下代码实现了M-PHY配置结构体、链路启动状态机(包含HIBERNATE→CFG→Active三态迁移),以及通过共享内存模拟的寄存器读写接口。节点A主动发起启动序列,节点B被动响应。

#include <stdint.h>
#include <string.h>
#include <stdio.h>

/* M-PHY 配置参数 */
typedef struct {
    uint8_t  gear;        /* PWM-G1 = 1 */
    uint8_t  lane_count;  /* 1 lane */
    uint16_t hs_series;   /* 未使用,保留 */
} MphyConfig;

/* UniPro 链路状态 */
typedef enum {
    LINK_HIBERNATE = 0,
    LINK_CFG,
    LINK_ACTIVE
} LinkState;

/* 节点结构体 */
typedef struct {
    MphyConfig mphy;
    LinkState  state;
    uint8_t    peer_ready;   /* 对端是否已完成配置 */
} UniProNode;

/* 模拟寄存器映射(共享内存) */
static UniProNode node_A, node_B;
static uint8_t    link_established;

/* 初始化节点 */
static void node_init(UniProNode *n, uint8_t gear) {
    n->mphy.gear       = gear;
    n->mphy.lane_count  = 1;
    n->state            = LINK_HIBERNATE;
    n->peer_ready       = 0;
}

/* 写对端寄存器(模拟物理层信号) */
static void write_peer_reg(UniProNode *self, UniProNode *peer,
                           uint8_t offset, uint32_t value) {
    (void)self;
    /* 实际硬件中此处通过M-PHY发送写入请求 */
    switch (offset) {
        case 0x00: peer->mphy.gear = (uint8_t)value; break;
        case 0x04: peer->state = (LinkState)value;   break;
        case 0x08: peer->peer_ready = (uint8_t)value; break;
        default: break;
    }
}

/* 读对端寄存器 */
static uint32_t read_peer_reg(UniProNode *peer, uint8_t offset) {
    switch (offset) {
        case 0x00: return peer->mphy.gear;
        case 0x04: return (uint32_t)peer->state;
        case 0x08: return peer->peer_ready;
        default:   return 0;
    }
}

/* 链路启动序列(节点A主动发起) */
static void link_start_sequence(UniProNode *initiator, UniProNode *target) {
    /* Step 1: 配置本地M-PHY为PWM-G1 */
    initiator->mphy.gear = 1;
    initiator->mphy.lane_count = 1;

    /* Step 2: 通知对端进入CFG状态 */
    write_peer_reg(initiator, target, 0x04, LINK_CFG);
    initiator->state = LINK_CFG;

    /* Step 3: 等待对端确认(轮询模拟) */
    for (int i = 0; i < 100; i++) {
        if (read_peer_reg(target, 0x04) == LINK_CFG) {
            break;
        }
    }

    /* Step 4: 对端配置完成,双方进入Active */
    write_peer_reg(initiator, target, 0x08, 1);
    target->state = LINK_ACTIVE;
    initiator->state = LINK_ACTIVE;
    link_established = 1;
}

/* 验证链路状态 */
static int verify_link_active(void) {
    return (node_A.state == LINK_ACTIVE) &&
           (node_B.state == LINK_ACTIVE) &&
           (link_established == 1);
}

int main(void) {
    /* 初始化两个节点 */
    node_init(&node_A, 0);
    node_init(&node_B, 0);
    link_established = 0;

    /* 执行链路启动 */
    link_start_sequence(&node_A, &node_B);

    /* 验证结果 */
    if (verify_link_active()) {
        printf("PASS: 链路已建立,双方处于Active状态\n");
        printf("  Node A: gear=%u, state=%d\n", node_A.mphy.gear, node_A.state);
        printf("  Node B: gear=%u, state=%d\n", node_B.mphy.gear, node_B.state);
        return 0;
    } else {
        printf("FAIL: 链路未建立\n");
        return 1;
    }
}

编译与运行

gcc -std=c99 -o unipro_link unipro_link.c
./unipro_link

验证方法

程序执行后,观察输出是否包含 PASS: 链路已建立。判定通过条件为:

  • 程序退出码为0
  • 输出中显示节点A和节点B的state均为2(即LINK_ACTIVE)
  • 两个节点的gear值均为1(PWM-G1)

若输出FAIL或退出码非0,说明链路启动序列未正确完成状态迁移。

关键说明

  • 本实现使用共享内存模拟寄存器读写,实际硬件中write_peer_reg和read_peer_reg对应M-PHY的寄存器访问命令(如DME_READ/WRITE)
  • 链路启动序列遵循UniPro规范中的状态迁移:HIBERNATE→CFG→Active,省略了更细粒度的子状态(如链路启动中的LocalTx/LocalRx配置)以聚焦物理层连接核心流程
  • PWM-G1为最低速率档,实际应用中如需更高吞吐可扩展gear值,但需同步修改对端配置