J1939 系列 05|J1939-22 的 FD Transport Protocol 与 J1939-21/22 选型对比
如果说 Multi-PG 是 J1939-22 在“小消息高效聚合”方向上的代表设计,那么 FD Transport Protocol,也就是 FD.TP,就是 J1939-22 在“大消息传输”方向上的核心升级。上一页更像在讲怎么拼车,这一页则是在讲:拼不下了,别硬塞,老老实实走物流通道。
在 J1939-21 里,经典 TP 的逻辑大家都比较熟:
- BAM
- RTS/CTS
- TP.CM
- TP.DT
- 每包 7 字节
到了 J1939-22,这些思想没有消失,但实现方式已经明显升级了:
- 数据段从 7 字节提升到 60 字节
- 引入 Session Number
- 结束阶段拆成 EOMS 和 EOMA
- Assurance Data 可以在会话结束阶段承载
- 并发能力大幅增强
这一篇就专门把 FD.TP 讲透。
一、先回答一个根本问题:什么时候必须进入 FD.TP
很多人会下意识觉得:
- J1939-22 不是都到 64 字节了吗
- 那是不是只有“超过 64 字节”才需要传输协议
这个理解不对。64 这个数字很醒目,但它不是万能通行证,更不是“只要没超过 64 就肯定能单帧搞定”的免死金牌。
FD.TP 的判定边界不是单纯看 PG data 长度,而是看:
- PG data + assurance data 的组合长度
只要这个组合长度 超过 60 字节,就已经不能再做成一个 C-PG,必须进入 FD.TP。
这也是为什么标准里会出现一种看起来有点反直觉的情况:
- 某个 PG 的业务数据本身只有 53 bytes
- 但如果再加上 8 bytes assurance data,总共 61 bytes
- 这时虽然 PG data 没超过 60,仍然必须走 FD.TP
- 最终只会有 1 个 FD.TP.DT 段,而 assurance data 则放在 EOMS 里
把这个发送决策画成图,会非常清楚:
#mermaid-svg-94sVtZ61wZ9vnbs6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-94sVtZ61wZ9vnbs6 .error-icon{fill:#552222;}#mermaid-svg-94sVtZ61wZ9vnbs6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-94sVtZ61wZ9vnbs6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .marker.cross{stroke:#333333;}#mermaid-svg-94sVtZ61wZ9vnbs6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-94sVtZ61wZ9vnbs6 p{margin:0;}#mermaid-svg-94sVtZ61wZ9vnbs6 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster-label text{fill:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster-label span{color:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster-label span p{background-color:transparent;}#mermaid-svg-94sVtZ61wZ9vnbs6 .label text,#mermaid-svg-94sVtZ61wZ9vnbs6 span{fill:#333;color:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .node rect,#mermaid-svg-94sVtZ61wZ9vnbs6 .node circle,#mermaid-svg-94sVtZ61wZ9vnbs6 .node ellipse,#mermaid-svg-94sVtZ61wZ9vnbs6 .node polygon,#mermaid-svg-94sVtZ61wZ9vnbs6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .rough-node .label text,#mermaid-svg-94sVtZ61wZ9vnbs6 .node .label text,#mermaid-svg-94sVtZ61wZ9vnbs6 .image-shape .label,#mermaid-svg-94sVtZ61wZ9vnbs6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-94sVtZ61wZ9vnbs6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .rough-node .label,#mermaid-svg-94sVtZ61wZ9vnbs6 .node .label,#mermaid-svg-94sVtZ61wZ9vnbs6 .image-shape .label,#mermaid-svg-94sVtZ61wZ9vnbs6 .icon-shape .label{text-align:center;}#mermaid-svg-94sVtZ61wZ9vnbs6 .node.clickable{cursor:pointer;}#mermaid-svg-94sVtZ61wZ9vnbs6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .arrowheadPath{fill:#333333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-94sVtZ61wZ9vnbs6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-94sVtZ61wZ9vnbs6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-94sVtZ61wZ9vnbs6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster text{fill:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 .cluster span{color:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-94sVtZ61wZ9vnbs6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-94sVtZ61wZ9vnbs6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-94sVtZ61wZ9vnbs6 .icon-shape,#mermaid-svg-94sVtZ61wZ9vnbs6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-94sVtZ61wZ9vnbs6 .icon-shape p,#mermaid-svg-94sVtZ61wZ9vnbs6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-94sVtZ61wZ9vnbs6 .icon-shape rect,#mermaid-svg-94sVtZ61wZ9vnbs6 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-94sVtZ61wZ9vnbs6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-94sVtZ61wZ9vnbs6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-94sVtZ61wZ9vnbs6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
是
否
否
是
否
A_PDU
PG data + assurance data <= 60
构造成 C-PG
地址语义和打包规则允许吗
进入 Multi-PG
进入 FD.TP
PDU1 且发往特定 DA
RTS/CTS
BAM
所以,FD.TP 的本质不是“超过 64 字节才用”,而是“一旦超出 C-PG 能力边界,就由 FD.TP 接管”。别被那个 64 字节表面数字骗了,真正卡你的往往是 C-PG 那条 60 字节红线。

二、FD.TP 由哪两个 PG 组成
J1939-22 定义了新的两个核心 PG:
- FD.TP.CM:PGN = 0x004D00
- FD.TP.DT:PGN = 0x004E00
它们的职责划分非常明确:
- FD.TP.CM 负责建连、流控、结束、Abort
- FD.TP.DT 负责真正的数据段传输
2.1 FD.TP.CM 的公共框架
FD.TP.CM 的标准长度是 12 bytes,只有 EOMS 在带 assurance data 时可以扩展到最多 64 bytes。
它的公共字段可以先记成这样:
| Control Type | Byte1 低 4 bit | 当前是哪种控制消息 |
| Session Number | Byte1 高 4 bit | 会话编号 |
| Bytes 2..4 | 3 bytes | 总字节数或保留 |
| Bytes 5..7 | 3 bytes | 总段数、下一段号或保留 |
| Byte 8 | 1 byte | 最大段数、允许段数、AD size 或 role |
| Byte 9 | 1 byte | AD type、request code 或 abort reason |
| Bytes 10..12 | 3 bytes | 目标 PGN |
| Bytes 13..64 | 可选 | Assurance Data,仅 EOMS 使用 |
也就是说,FD.TP.CM 虽然有很多消息类型,但骨架其实是一致的。
2.2 FD.TP.DT 的公共框架
FD.TP.DT 的数据场结构更直接:
| DTFI | Byte1 低 4 bit | Data Transfer Format Indicator,目前标准值为 0 |
| Session Number | Byte1 高 4 bit | 会话编号 |
| Segment Number | Bytes2…4 | 3 字节段号 |
| Segment Data | Bytes5…64 | 最多 60 字节 PG data |
这和 J1939-21 的 TP.DT 对比很强烈:
- -21:1 字节包号 + 7 字节数据
- -22:4 字节控制头 + 60 字节数据
三、FD.TP.CM 里有哪些控制消息
FD.TP.CM 主要有六类控制消息:
| RTS | 0 | 发送方 | 发起 destination-specific 会话 |
| CTS | 1 | 接收方 | 控制流量、暂停、请求重发 |
| EOMS | 2 | 发送方 | 告知所有段已发完,并带可选 assurance data |
| EOMA | 3 | 接收方 | 确认整条消息已正确接收 |
| BAM | 4 | 发送方 | 发起广播式 FD.TP 会话 |
| Abort | 15 | 任一方 | 关闭或拒绝会话 |
如果只想先抓主线,可以这么记:
- RTS/CTS 负责“开始并控制会话”
- DT 负责“搬运分段数据”
- EOMS/EOMA 负责“完成和闭环”
- Abort 负责“中止”
四、Session Number 为什么是 FD.TP 的关键
4.1 它让会话不再只能靠隐式上下文去猜
在 J1939-21 里,TP.DT 没有显式会话号,因此接收方通常要靠:
- SA
- DA
- 当前上下文
去推断一串 TP.DT 属于哪个会话。
在 J1939-22 里,标准明确要求用:
- SA
- DA
- Session Number
来唯一关联一条 FD.TP 会话。你也可以把它理解成:每条长报文终于有了自己的号码牌,不用再靠“我大概记得刚才是谁在说话”这种模糊印象去猜。
可以直接把连接键写成:
FD.TP Session Key = (Source Address, Destination Address, Session Number)
4.2 它带来的能力提升是什么
这件事会直接带来几种改观:
- 同一对节点之间可以并发多条长报文会话
- 同一个发送方可以同时跑多个 BAM 会话
- Abort 也能更明确地指向某一个会话
标准允许的上限是:
- 每个源地址到同一目标地址,最多 8 个 RTS/CTS 会话
- 每个源地址最多 4 个 BAM 会话
同时还有会话号使用范围约束:
- BAM 只用 0..3
- RTS/CTS 只用 0..7
- 8..15 预留
五、FD.TP 的段为什么是 60 字节
FD.TP.DT 的数据场最多 64 字节,但前 4 字节要拿来放:
- DTFI
- Session
- Segment Number
所以真正能装 PG data 的就是:
- 60 bytes
这就形成了 FD.TP 最核心的传输单位:
- 一个 FD.TP.DT = 最多 60 bytes PG data
段号范围也明显大得多:
- BAM:最多 255 段
- RTS/CTS:最多 279621 段
相比 J1939-21 的 255 x 7 = 1785 bytes,J1939-22 的容量和效率都已经是另一档了。
六、RTS/CTS:FD.TP 的点对点传输长什么样
6.1 一条正常会话的主流程
FD.TP 的 RTS/CTS 主流程可以先看成这样:
接收方发送方接收方发送方#mermaid-svg-kd6UNGxCj2AomY6p{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kd6UNGxCj2AomY6p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kd6UNGxCj2AomY6p .error-icon{fill:#552222;}#mermaid-svg-kd6UNGxCj2AomY6p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kd6UNGxCj2AomY6p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kd6UNGxCj2AomY6p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kd6UNGxCj2AomY6p .marker.cross{stroke:#333333;}#mermaid-svg-kd6UNGxCj2AomY6p svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kd6UNGxCj2AomY6p p{margin:0;}#mermaid-svg-kd6UNGxCj2AomY6p .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kd6UNGxCj2AomY6p text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-kd6UNGxCj2AomY6p .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-kd6UNGxCj2AomY6p .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-kd6UNGxCj2AomY6p .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-kd6UNGxCj2AomY6p .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-kd6UNGxCj2AomY6p #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-kd6UNGxCj2AomY6p .sequenceNumber{fill:white;}#mermaid-svg-kd6UNGxCj2AomY6p #sequencenumber{fill:#333;}#mermaid-svg-kd6UNGxCj2AomY6p #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-kd6UNGxCj2AomY6p .messageText{fill:#333;stroke:none;}#mermaid-svg-kd6UNGxCj2AomY6p .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kd6UNGxCj2AomY6p .labelText,#mermaid-svg-kd6UNGxCj2AomY6p .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-kd6UNGxCj2AomY6p .loopText,#mermaid-svg-kd6UNGxCj2AomY6p .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-kd6UNGxCj2AomY6p .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-kd6UNGxCj2AomY6p .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-kd6UNGxCj2AomY6p .noteText,#mermaid-svg-kd6UNGxCj2AomY6p .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-kd6UNGxCj2AomY6p .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kd6UNGxCj2AomY6p .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kd6UNGxCj2AomY6p .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kd6UNGxCj2AomY6p .actorPopupMenu{position:absolute;}#mermaid-svg-kd6UNGxCj2AomY6p .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-kd6UNGxCj2AomY6p .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kd6UNGxCj2AomY6p .actor-man circle,#mermaid-svg-kd6UNGxCj2AomY6p line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-kd6UNGxCj2AomY6p :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}loop[当前窗口内的 segments]loop[下一窗口内的 segments]FD.TP.CM_RTS(session, total bytes, total segs, max segs, ADT, PGN)FD.TP.CM_CTS(session, next seg, xfr segs, rqst=0)FD.TP.DT(session, segment number, 60-byte data)FD.TP.CM_CTS(session, next seg, xfr segs, rqst=0)FD.TP.DT(session, segment number, 60-byte data)FD.TP.CM_EOMS(session, total bytes, total segs, AD size, AD type, PGN)FD.TP.CM_EOMA(session, total bytes received, total segs received, PGN)
这和 J1939-21 的主流程很像,但有三个明显不同:
- 会话里有 Session Number
- 数据段单位变成 60 字节
- 结束阶段拆成 EOMS -> EOMA
6.2 RTS 的关键字段
RTS 至少会告诉接收方:
- 这条大消息的总字节数
- 总共会分成多少段
- 每条 CTS 最多允许请求多少段
- assurance data 将来会按什么类型提供
- 当前使用哪个 Session
- 被传输的目标 PGN
其中最容易被忽略的是 Maximum Number of Segments:
- 它是发送方给接收方设的上限
- 接收方后面所有 CTS 的 xfr segs 都不能超过这个值
6.3 CTS 在 FD.TP 里更像一个控制面板
CTS 在 FD.TP 里不只是“继续发”,它至少同时承担四个角色:
- 流控:本轮允许发多少段
- 续传:下一段从哪一个段号开始
- 暂停:用 xfr segs = 0 保持连接但先别发
- 请求重发 EOMS:用 rqst = 1
把 CTS 的关键字段拆开看,会更清楚:
| Session | 指明属于哪个会话 |
| Next Segment Number | 本轮从哪一段开始发 |
| Number of Segments to Send | 本轮最多发多少段 |
| Request Code | 是否要求重发 EOMS |
| PGN | 当前被传输的是哪个 PG |
6.4 Request Code 是 FD.TP 比 J1939-21 多出来的一个细节
在 FD.TP 里,CTS 还多了一个 Request Code 字段。
最重要的标准用法是:
- rqst = 0:普通 CTS
- rqst = 1:请求发送方重发 EOMS
当接收方已经收到了所有 FD.TP.DT 段,但没正确收到 EOMS 时,它可以这样做。这个细节很有意思,因为它说明 FD.TP 连“最后那张签收单没收到”都单独留了补救动作:
- 发一条 CTS
- rqst = 1
- next segment number = FFFFFFh
- xfr segs 这个字段此时会被发送方忽略
这件事很有代表性,因为它说明 FD.TP 的控制面比 J1939-21 更细。
6.5 发送方在窗口之间怎么走
FD.TP 的发送方逻辑其实和你前面问到的 J1939-21 CTS=10 那个问题是一脉相承的,只是现在从“包”变成了“段”。
#mermaid-svg-FcZP4w3SHxlChSEb{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FcZP4w3SHxlChSEb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FcZP4w3SHxlChSEb .error-icon{fill:#552222;}#mermaid-svg-FcZP4w3SHxlChSEb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FcZP4w3SHxlChSEb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FcZP4w3SHxlChSEb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FcZP4w3SHxlChSEb .marker.cross{stroke:#333333;}#mermaid-svg-FcZP4w3SHxlChSEb svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FcZP4w3SHxlChSEb p{margin:0;}#mermaid-svg-FcZP4w3SHxlChSEb .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-FcZP4w3SHxlChSEb .cluster-label text{fill:#333;}#mermaid-svg-FcZP4w3SHxlChSEb .cluster-label span{color:#333;}#mermaid-svg-FcZP4w3SHxlChSEb .cluster-label span p{background-color:transparent;}#mermaid-svg-FcZP4w3SHxlChSEb .label text,#mermaid-svg-FcZP4w3SHxlChSEb span{fill:#333;color:#333;}#mermaid-svg-FcZP4w3SHxlChSEb .node rect,#mermaid-svg-FcZP4w3SHxlChSEb .node circle,#mermaid-svg-FcZP4w3SHxlChSEb .node ellipse,#mermaid-svg-FcZP4w3SHxlChSEb .node polygon,#mermaid-svg-FcZP4w3SHxlChSEb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FcZP4w3SHxlChSEb .rough-node .label text,#mermaid-svg-FcZP4w3SHxlChSEb .node .label text,#mermaid-svg-FcZP4w3SHxlChSEb .image-shape .label,#mermaid-svg-FcZP4w3SHxlChSEb .icon-shape .label{text-anchor:middle;}#mermaid-svg-FcZP4w3SHxlChSEb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FcZP4w3SHxlChSEb .rough-node .label,#mermaid-svg-FcZP4w3SHxlChSEb .node .label,#mermaid-svg-FcZP4w3SHxlChSEb .image-shape .label,#mermaid-svg-FcZP4w3SHxlChSEb .icon-shape .label{text-align:center;}#mermaid-svg-FcZP4w3SHxlChSEb .node.clickable{cursor:pointer;}#mermaid-svg-FcZP4w3SHxlChSEb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FcZP4w3SHxlChSEb .arrowheadPath{fill:#333333;}#mermaid-svg-FcZP4w3SHxlChSEb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FcZP4w3SHxlChSEb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FcZP4w3SHxlChSEb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FcZP4w3SHxlChSEb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FcZP4w3SHxlChSEb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FcZP4w3SHxlChSEb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FcZP4w3SHxlChSEb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FcZP4w3SHxlChSEb .cluster text{fill:#333;}#mermaid-svg-FcZP4w3SHxlChSEb .cluster span{color:#333;}#mermaid-svg-FcZP4w3SHxlChSEb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FcZP4w3SHxlChSEb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FcZP4w3SHxlChSEb rect.text{fill:none;stroke-width:0;}#mermaid-svg-FcZP4w3SHxlChSEb .icon-shape,#mermaid-svg-FcZP4w3SHxlChSEb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FcZP4w3SHxlChSEb .icon-shape p,#mermaid-svg-FcZP4w3SHxlChSEb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FcZP4w3SHxlChSEb .icon-shape rect,#mermaid-svg-FcZP4w3SHxlChSEb .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FcZP4w3SHxlChSEb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FcZP4w3SHxlChSEb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FcZP4w3SHxlChSEb :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
是
否
否
是
是
否
是
否且超时
收到 CTS
rqst 是否为 1
重发 EOMS
等待 CTS 或 EOMA
xfr segs 是否为 0
暂停发送并保持连接
等待下一条 CTS
按 next segment 和 xfr segs 发送本轮 FD.TP.DT
是否已发完最后一段
发送 EOMS
等待 EOMA 或新的 CTS
等待是否超时
发送 Abort
是否收到 EOMA
连接正常结束
这张图里最关键的判断有两个:
- 一次 CTS 只授权一轮段发送
- 发完最后一段并不代表连接结束,发送方还必须进入 EOMS -> EOMA 闭环
七、BAM:FD.TP 的广播大报文路径
FD.TP 的 BAM 和 RTS/CTS 在“发段”这件事上相似,但在连接控制上差别很大。
7.1 BAM 主流程
接收节点发送方接收节点发送方#mermaid-svg-YIf7VAmKkPw9EzlU{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YIf7VAmKkPw9EzlU .error-icon{fill:#552222;}#mermaid-svg-YIf7VAmKkPw9EzlU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YIf7VAmKkPw9EzlU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YIf7VAmKkPw9EzlU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YIf7VAmKkPw9EzlU .marker.cross{stroke:#333333;}#mermaid-svg-YIf7VAmKkPw9EzlU svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YIf7VAmKkPw9EzlU p{margin:0;}#mermaid-svg-YIf7VAmKkPw9EzlU .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YIf7VAmKkPw9EzlU text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-YIf7VAmKkPw9EzlU .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-YIf7VAmKkPw9EzlU .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-YIf7VAmKkPw9EzlU #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-YIf7VAmKkPw9EzlU .sequenceNumber{fill:white;}#mermaid-svg-YIf7VAmKkPw9EzlU #sequencenumber{fill:#333;}#mermaid-svg-YIf7VAmKkPw9EzlU #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-YIf7VAmKkPw9EzlU .messageText{fill:#333;stroke:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YIf7VAmKkPw9EzlU .labelText,#mermaid-svg-YIf7VAmKkPw9EzlU .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .loopText,#mermaid-svg-YIf7VAmKkPw9EzlU .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-YIf7VAmKkPw9EzlU .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-YIf7VAmKkPw9EzlU .noteText,#mermaid-svg-YIf7VAmKkPw9EzlU .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-YIf7VAmKkPw9EzlU .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YIf7VAmKkPw9EzlU .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YIf7VAmKkPw9EzlU .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YIf7VAmKkPw9EzlU .actorPopupMenu{position:absolute;}#mermaid-svg-YIf7VAmKkPw9EzlU .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-YIf7VAmKkPw9EzlU .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YIf7VAmKkPw9EzlU .actor-man circle,#mermaid-svg-YIf7VAmKkPw9EzlU line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-YIf7VAmKkPw9EzlU :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}loop[每 10..200 ms]无 CTS,无 EOMA,节点自行完成校验和重组FD.TP.CM_BAM(session, total bytes, total segs, ADT, PGN)FD.TP.DT(session, segment number, data)FD.TP.CM_EOMS(session, total bytes, total segs, AD size, AD type, PGN)
7.2 BAM 的几个核心特点
- 只能发给全局地址
- 适用于 PDU2,以及发往全局地址的 PDU1
- 没有接收方流控
- 接收方不能对 BAM 主动 Abort
- 发送方在结束时仍然要发 EOMS
这一点和 J1939-21 BAM 有点像,但 -22 把结束阶段也明确化了:
- 不是“最后一段发完就算结束”
- 而是“最后一段发完,再发 EOMS 才算会话结束”
八、EOMS 和 EOMA:为什么结束阶段被重新设计
8.1 EOMS 不是一句“我发完了”
EOMS 至少带这些内容:
- 总字节数
- 总段数
- AD Size
- AD Type
- 目标 PGN
- 可选 assurance data
所以它的真实含义更接近:
- “我这条长消息已经全部发完了”
- “这是这次完整消息对应的结束状态”
- “如果有 end-to-end assurance data,也一并在这里给你”
8.2 EOMA 是接收方的正式闭环
EOMA 则是接收方对整条消息的最终确认。一个负责说“我发完了”,另一个负责说“我核完了,确实都收到了”:
- 已经收到并重组成功
- 收到的总字节数和总段数是多少
- 这个会话可以明确关闭了
8.3 它和 J1939-21 的差别
对比经典 EndOfMsgACK,FD.TP 把结束逻辑拆得更清楚:
- 发送方:EOMS
- 接收方:EOMA
这样做有两个好处:
- 把 assurance data 放到完整消息结束状态里统一处理
- 让“数据发完”和“接收方确认整个会话结束”这两件事分开表达
九、超时、约束和边界值需要单独记一下
9.1 默认超时
| Tr | 200 ms | 最大响应时间 |
| Th | 500 ms | hold 状态下连续 CTS(0,…) 的最大发送间隔 |
| T1 | 750 ms | Transport Segment Interval |
| T2 | 1250 ms | 接收方在发出 CTS 后等待下一个 DT 的超时 |
| T3 | 1250 ms | 发送方等待下一条 CTS 的超时 |
| T4 | 1050 ms | 发送方在 hold 状态下等待下一条 CTS 的超时 |
| T5 | 3000 ms | 发送方在发出 EOMS 后等待 EOMA 的超时 |
9.2 容量上限
| 最大 PG data 字节数 | 15300 | 16777215 |
| 最大段号 | 255 | 279621 |
| 每段数据长度 | 60 bytes | 60 bytes |
| 段间隔 | 10..200 ms | 0..200 ms |
9.3 一些容易漏掉的边界
- DTFI 目前标准值应为 0
- Segment Number 不能为 0
- EOMA 如果在最后一个 DT 发完之前就到达,发送方应忽略
- Abort 收到后,发送方停止继续发该会话的数据和控制消息
- 同一 PG 可能有时走 Multi-PG,有时走 FD.TP,系统设计上要避免旧数据晚到新数据之后
十、J1939-21 与 J1939-22,工程上怎么选
10.1 继续用 J1939-21 的典型场景
如果你的网络:
- 大量设备仍是传统 J1939 设备
- 单帧消息占主流
- 大报文并不多
- 更看重兼容性和复杂度可控
那么 -21 依然是非常合理的选择。
10.2 适合转向 J1939-22 的典型场景
如果你的系统:
- 硬件已经支持 CAN FD
- 有很多大对象或高频数据
- 想通过 Multi-PG 提高总线利用率
- 需要更多并发长报文会话
- 未来要接功能安全或网络安全机制
那么 -22 的长期价值会明显更高。

10.3 把差异压成一张对照表
| 单帧有效数据能力 | <= 8 bytes | <= 64 bytes |
| 聚合机制 | 无 | Multi-PG |
| 大报文段大小 | 7 bytes | 60 bytes |
| 会话标识 | 无显式 session | Session Number |
| 结束阶段 | EndOfMsgACK | EOMS + EOMA |
| 并发能力 | 很有限 | 明显增强 |
| assurance data | 无标准入口 | 标准已预留承载位置 |
十一、小结
如果用一句话概括 FD.TP 的意义,那就是:
它把 J1939 的大消息传输,从经典 CAN 时代的“补丁式能力”,提升成了 CAN FD 时代的“正式连接管理服务”。
而把 J1939-21 和 J1939-22 放在一起看,最重要的结论也很清楚:
- -21 是经典 CAN 时代的成熟工程化方案
- -22 是面向 CAN FD、并发、多消息聚合和 assurance 扩展的数据链路重构版
如果前一篇的 Multi-PG 解决的是“怎样把小消息更高效地装进一个 FD 帧”,那么这一篇的 FD.TP 解决的就是“当消息已经大到无法再靠 C-PG 承载时,怎样把整条大消息稳妥地送到对端”。一个负责拼车省路费,一个负责走正规物流别把货弄丢。

