乐于分享
好东西不私藏

AUTOSAR-CanNm源码分析 :NM 报文收发与状态机流转

AUTOSAR-CanNm源码分析 :NM 报文收发与状态机流转

导言

前一篇主要看的是 CanNm 的目录结构和模块边界。真正理解 CanNm,不能只看它有哪些 API,还要顺着一帧 NM 报文在源码里的生命周期往下走:

  1. 1. NM 报文是如何被接收的?
  2. 2. 收到的 NM 报文如何参与 CanNm_MainFunction 中的状态切换?
  3. 3. NM 报文又是如何被发出去的?

这三个问题串起来,其实就是 CanNm 的主干逻辑:下层 CanIf 把收到的 NM PDU 通知给 CanNm;CanNm 把接收结果先存入 RAM;周期调度函数 CanNm_MainFunction 再统一消费这些标志和缓存,驱动定时器、状态机和发送逻辑。

本文基于当前工程中的 NM/NM/CanNm 源码分析,重点文件包括:

CanNm_RxIndication.cCanNm.cCanNm_Inl.hCanNm_StartTransmission.cCanNm_TxConfirmation.cCanNm_Transmit.cCanNm_Init.cCanNm_Prv.hCanNm_PBcfg.c

1. 先看 CanNm 的运行模型

在这套源码中,CanNm 并不是“收到一帧报文就立刻切状态”的写法。

它采用的是典型 AUTOSAR BSW 周期调度模型:

CanNm 运行模型流程图

这种设计的好处是:中断或下层回调路径尽量短,只做数据搬运和事件置位;复杂的状态机逻辑放到周期任务里处理,便于控制运行时间和并发一致性。

在 CanNm_RamType 中可以看到 CanNm 维护的关键运行时变量:

PduInfoType            Pdu_s;CanNm_TimerType        MsgCyclePeriod;CanNm_TimerType        PrevMsgCycleTimestamp;CanNm_TimerType        PrevMsgTimeoutTimestamp;CanNm_TimerType        ctRepeatMessageTimer;CanNm_TimerType        ctNMTimeoutTimer;CanNm_TimerType        ctWaitBusSleepTimer;CanNm_TimerType        ctRemoteSleepIndTimer;uint8                  RxBuffer_au8[CANNM_PDU_LENGTH_MAX];uint8                  TxBuffer_au8[CANNM_PDU_LENGTH_MAX];Nm_StateType           State_en;CanNm_NetworkStateType NetworkReqState_en;Nm_ModeType            Mode_en;uint8                  RxNodeId_u8;uint8                  RxCtrlBitVector_u8;uint8                  TxCtrlBitVector_u8;boolean                MsgTxStatus_b;boolean                RxIndication_b;boolean                TxConfirmation_b;boolean                RxStatus_b;

这里需要先记住几个变量:

  • • RxBuffer_au8:最近收到的一帧 NM PDU 数据。
  • • RxNodeId_u8:从 NM 报文里解析出来的 Node ID。
  • • RxCtrlBitVector_u8:从 NM 报文里解析出来的 Control Bit Vector,也就是 CBV。
  • • RxIndication_b:本周期是否收到 NM 报文的事件标志。
  • • RxStatus_b:当前 NM sleep cycle 中是否已经收到过 NM 报文,供 GetUserDataGetPduDataGetNodeIdentifier 等 API 判断数据是否有效。
  • • MsgTxStatus_b:是否允许周期发送 NM PDU。
  • • TxConfirmation_b:是否收到过发送确认。

2. NM 报文是如何被接收的

NM 报文的接收入口是:

void CanNm_RxIndication(PduIdType RxPduId, const PduInfoType * PduInfoPtr)

这个函数是 CanNm 暴露给下层 CanIf 的回调。当 CAN NM I-PDU 被接收后,CanIf 会调用它,把 RxPduId 和 PduInfoPtr 传进来。

2.1 接收入口先做防御性检查

CanNm_RxIndication 前半段先做几类检查:

  • • 如果是 Post-Build Selectable 配置,会先通过 Channel_Mapping_Table 把 RxPduId 映射成内部 channel。
  • • 检查 RxPduId 是否越界。
  • • 检查 CanNm 是否初始化。
  • • 检查 PduInfoPtr 和 SduDataPtr 是否为空。

这些检查完成后,函数拿到两个核心指针:

RamPtr_ps = &CanNm_RamData_s[RxPduId];ConfigPtr_pcs = CANNM_GET_CHANNEL_CONFIG(RxPduId);

也就是说,后面的处理都是围绕“当前收到报文所属 channel 的配置”和“当前 channel 的 RAM 状态”进行。

2.2 如果开启 PN,会先做 PN 过滤

当前源码支持 Partial Network 相关逻辑。如果 CANNM_GLOBAL_PN_SUPPORT 打开,CanNm_RxIndication 不会无条件处理所有 NM 报文,而是先看 PN 信息。

它主要做三件事:

  1. 1. 从 CBV 中读取 PNI bit。
  2. 2. 用 PnFilterMask_pcu8 对收到的 PN info 做掩码过滤。
  3. 3. 根据 AllNmMessagesKeepAwake、PN message filtering 状态、PNI bit 和过滤结果决定 ProcessPdu_b 是否为 TRUE

如果过滤后发现这帧 NM PDU 与本 ECU 无关,CanNm_ProcessRxPdu() 就不会被调用。换句话说,报文虽然物理上收到了,但不会参与后续状态机的接收事件处理。

如果 PN 没开启,源码会直接走:

CanNm_ProcessRxPdu(ConfigPtr_pcs, RamPtr_ps, PduInfoPtr);

2.3 真正保存报文的是 CanNm_ProcessRxPdu

CanNm_ProcessRxPdu() 是接收路径最核心的函数。

它做的事情很明确:

第一步,如果配置了 Node ID 位置,就从报文中取出 Node ID:

RamPtr_ps->RxNodeId_u8 = PduInfoPtr->SduDataPtr[ConfigPtr_pcs->NodeIdPos_u8];

第二步,如果配置了 Control Bit Vector 位置,就从报文中取出 CBV:

RamPtr_ps->RxCtrlBitVector_u8 = PduInfoPtr->SduDataPtr[ConfigPtr_pcs->ControlBitVectorPos_u8];

第三步,把整帧 NM PDU 复制到 RxBuffer_au8

CanNm_CopyBuffer(SduPtr, RamPtr_ps->RxBuffer_au8, ConfigPtr_pcs->PduLength_u8);

这个复制动作被 SchM_Enter_CanNm_RxIndicationNoNest() 和 SchM_Exit_CanNm_RxIndicationNoNest() 包住,说明源码考虑了接收回调和周期任务之间的数据一致性,一般可以加入Rx中断屏蔽(别去屏蔽所有中断,影响实时性)。

第四步,置位两个关键标志:

RamPtr_ps->RxIndication_b = TRUE;RamPtr_ps->RxStatus_b = TRUE;

这两个变量很容易混淆:

  • • RxIndication_b 是给下一次 CanNm_MainFunction 消费的一次性事件标志。MainFunction 读取后会清掉。
  • • RxStatus_b 表示当前 sleep cycle 中已经收过 NM 报文。它不会在 MainFunction 中立刻清掉,而是在进入 Bus Sleep 时清掉。

最后,如果开启 CANNM_PDU_RX_INDICATION_ENABLED,CanNm 会继续通知 Nm Interface:

Nm_PduRxIndication(ConfigPtr_pcs->NetworkHandle);

所以,接收路径可以总结成一句话:

CanNm_RxIndication 不直接推动状态机,它只负责过滤、解析、缓存和置位。真正的状态处理留给 CanNm_MainFunction

3. NM 报文如何参与 CanNm_MainFunction 状态切换

CanNm_MainFunction() 是 CanNm 的周期调度入口。

它先判断模块是否初始化,然后遍历所有配置的 channel:

for(CanNm_NetworkHandle = 0;    CanNm_NetworkHandle < CANNM_NUMBER_OF_CHANNELS_CONFIGURED();    CanNm_NetworkHandle++){    CanNm_InternalMainProcess(CanNm_NetworkHandle);}

真正的状态机处理在 CanNm_InternalMainProcess()

3.1 MainFunction 先消费 RxIndication_b

进入 CanNm_InternalMainProcess() 后,源码先取配置和 RAM:

ConfigPtr_pcs = CANNM_GET_CHANNEL_CONFIG(CanNm_NetworkHandle);RamPtr_ps = &CanNm_RamData_s[CanNm_NetworkHandle];

然后更新软件自由运行计时器:

CanNm_ComputeSwFrTimer(RamPtr_ps);

接着进入临界区,读取并清除事件标志:

PduRxInd_b = RamPtr_ps->RxIndication_b;RamPtr_ps->RxIndication_b = FALSE;PduTxConfirmation_b = RamPtr_ps->TxConfirmation_b;RamPtr_ps->TxConfirmation_b = FALSE;CtrlBitVector_u8 = RamPtr_ps->RxCtrlBitVector_u8;RamPtr_ps->RxCtrlBitVector_u8 =    (RamPtr_ps->RxCtrlBitVector_u8 & CANNM_RESET_CONTROL_BIT_VECTOR_MASK);

这里有一个关键点:RxIndication_b 被读取后马上清掉,所以它是典型的 edge/event 语义。一次接收,只影响一次 MainFunction 调度周期。

而 CtrlBitVector_u8 会被保存成本地变量,后面 Ready Sleep、Normal Operation 等状态会用它判断对端是否请求 Repeat Message、Coordinator Sleep Ready 等。

3.2 Network Mode 下,收到报文先刷新定时器

如果当前 mode 是 NM_MODE_NETWORK,MainFunction 会先调用:

StateCopy_e = CanNm_NetworkModeProcessing(..., RamPtr_ps, PduRxInd_b, PduTxConfirmation_b);

这个函数是“Network Mode 公共处理”。只要本周期有 NM 报文接收,即 PduRxInd_b != FALSE,就会做几件重要的事。

第一,重启 NM Timeout Timer:

CanNm_StartTimer(RamPtr_ps->ctNMTimeoutTimer);

这就是 NM 报文维持网络活跃的核心机制。只要周期性收到 NM 报文,ctNMTimeoutTimer 就会不断被刷新,节点不会因为 NM Timeout 进入睡眠流程。

第二,如果开启 Remote Sleep Indication,会重启 Remote Sleep 定时器:

CanNm_StartTimer(RamPtr_ps->ctRemoteSleepIndTimer);

如果当前状态是 NORMAL_OPERATION 或 READY_SLEEP,还会取消之前已经上报的 Remote Sleep:

CanNm_CancelRemoteSleepInd(ConfigPtr_pcs, RamPtr_ps);

第三,如果开启 Bus Load Reduction,并且当前处于 Normal Operation,收到 NM 报文会把发送周期切到 MsgReducedTime

RamPtr_ps->MsgCyclePeriod = ConfigPtr_pcs->MsgReducedTime;CanNm_StartTimer(RamPtr_ps->PrevMsgCycleTimestamp);CanNm_StartTimer(RamPtr_ps->PrevMsgTimeoutTimestamp);

这说明接收报文不仅影响“是否睡眠”,还可能影响本节点自己的发送节奏。

3.3 Bus Sleep 状态收到 NM 报文

状态机 switch 中,NM_STATE_BUS_SLEEP 对应:

CanNm_CaseBusSleep(..., PduRxInd_b);

如果主动网络请求已经存在,节点会进入 Network Mode;如果没有主动请求,但在 Bus Sleep 中收到了 NM 报文,则源码会通知上层网络启动:

Nm_NetworkStartIndication(nmChannelHandle);Det_ReportRuntimeError(..., CANNM_E_NET_START_IND);

这里的语义是:本节点还在 Bus Sleep,却看到网络上出现 NM 报文,说明网络被其他节点唤醒了。CanNm 不在这里直接切到 Network Mode,而是把 network start 事件报给 Nm。

3.4 Prepare Bus Sleep 状态收到 NM 报文

NM_STATE_PREPARE_BUS_SLEEP 对应:

CanNm_CasePrepareBusSleep(CanNm_NetworkHandle, ConfigPtr_pcs, RamPtr_ps, PduRxInd_b);

这个状态本来是从 Network Mode 退向 Bus Sleep 的中间态。如果在这个阶段又收到了 NM 报文:

if (PduRxInd_b != FALSE){    CanNm_GotoNetworkMode(CanNm_NetworkHandle,                          NM_STATE_PREPARE_BUS_SLEEP,                          ConfigPtr_pcs,                          RamPtr_ps);}

也就是说,只要总线上还有 NM 报文活动,节点就不会继续睡下去,而是重新回到 Network Mode。

CanNm_GotoNetworkMode() 会做几件固定动作:

  • • 调用 CanNm_ChangeState() 切到 NM_STATE_REPEAT_MESSAGE 和 NM_MODE_NETWORK
  • • 通知 Nm:Nm_NetworkMode()
  • • 启动 Repeat Message Timer。
  • • 启动 NM Timeout Timer。
  • • 主动节点下调用 CanNm_StartTransmission() 开始发送 NM 报文。

3.5 Ready Sleep 状态如何使用收到的 CBV

NM_STATE_READY_SLEEP 对应:

CanNm_CaseReadySleep(..., CtrlBitVector_u8);

这里不直接看 PduRxInd_b,而是看刚才从接收报文里取出来的 CtrlBitVector_u8

源码会读取 Repeat Message bit:

stRepeatMessage_u8 = (CtrlBitVector_u8 & CANNM_READ_RPTMSG_MASK);

如果配置开启 Node Detection,并且收到的 CBV 中 Repeat Message bit 为 1,或者本地有 TxRptMsgStatus_b 请求,就进入 Repeat Message:

CanNm_GotoRepeatMessage(CanNm_NetworkHandle,                        NM_STATE_READY_SLEEP,                        ConfigPtr_pcs,                        RamPtr_ps);

如果没有 Repeat Message 请求,则检查 NM Timeout:

if (CanNm_TimerExpired(tiNMTimeoutTimer, ConfigPtr_pcs->NMTimeoutTime) != FALSE){    CanNm_GotoPrepareBusSleep(ConfigPtr_pcs, RamPtr_ps);}

这里就能看出收到 NM 报文对 Ready Sleep 的影响:

  • • 收到普通 NM 报文时,前面的 CanNm_NetworkModeProcessing() 会刷新 ctNMTimeoutTimer,所以 Ready Sleep 不会超时进入 Prepare Bus Sleep。
  • • 如果收到带 Repeat Message bit 的 NM 报文,则 Ready Sleep 会被拉回 Repeat Message。

3.6 Normal Operation 状态如何使用收到的 CBV

NM_STATE_NORMAL_OPERATION 对应:

CanNm_CaseNormalOperation(..., CtrlBitVector_u8);

Normal Operation 也会读取 CBV 中的 Repeat Message bit:

stRepeatMessage_u8 = (CtrlBitVector_u8 & CANNM_READ_RPTMSG_MASK);

如果对端请求 Repeat Message,或者本地请求 Repeat Message,状态机会进入 Repeat Message:

CanNm_GotoRepeatMessage(CanNm_NetworkHandle,                        NM_STATE_NORMAL_OPERATION,                        ConfigPtr_pcs,                        RamPtr_ps);

如果没有 Repeat Message 请求,但本地网络已经 release:

if (stNetworkState_e == CANNM_NETWORK_RELEASED_E){    CanNm_NormalOperationToRS(ConfigPtr_pcs, RamPtr_ps);    CanNm_StartTimer(RamPtr_ps->ctNMTimeoutTimer);}

则从 Normal Operation 进入 Ready Sleep,并停止发送:

RamPtr_ps->MsgTxStatus_b = FALSE;

所以在 Normal Operation 中,收到的 NM 报文主要通过两个路径影响状态机:

  1. 1. 通过 PduRxInd_b 刷新 NM Timeout Timer,维持网络模式。
  2. 2. 通过 CBV 中的 Repeat Message bit,把状态拉回 Repeat Message。

3.7 Repeat Message 状态里的报文影响

NM_STATE_REPEAT_MESSAGE 对应:

CanNm_CaseRepeatMessage(ConfigPtr_pcs, RamPtr_ps);

这个状态本身不直接读取 CtrlBitVector_u8,但收到 NM 报文仍然会在前面的 CanNm_NetworkModeProcessing() 中刷新 NM Timeout Timer。

Repeat Message 状态主要看 ctRepeatMessageTimer 是否到期:

if (CanNm_TimerExpired(RamPtr_ps->ctRepeatMessageTimer, RepeatMsgTime) != FALSE){    if (stNetworkState_e == CANNM_NETWORK_RELEASED_E)    {        CanNm_RepeatMessageToRS(ConfigPtr_pcs, RamPtr_ps);    }    else    {        CanNm_RepeatMessageToNO(ConfigPtr_pcs, RamPtr_ps);    }}

也就是说,Repeat Message 是一个由定时器控制的暂态:

  • • 如果本地网络已释放,超时后进入 Ready Sleep。
  • • 如果本地网络仍请求,超时后进入 Normal Operation。

4. NM 报文是如何发出的

接收路径讲完后,再看发送路径。

发送路径可以分成三类:

  1. 1. 状态机驱动的周期发送。
  2. 2. 上层触发的额外发送。
  3. 3. 特殊 API 触发的立即发送,例如 Bus Synchronization、Sleep Ready Bit 等。

本文重点看主路径:状态机驱动的周期发送。

4.1 初始化时准备 Tx PDU

在 CanNm_Init() 中,每个 active channel 初始化时会把 Pdu_s 指向 RAM 里的发送缓冲区:

RamPtr_ps->Pdu_s.SduDataPtr = &(RamPtr_ps->TxBuffer_au8[0]);RamPtr_ps->Pdu_s.SduLength = ConfigPtr_pcs->PduLength_u8;

后面 CanIf_Transmit() 发送的就是这个 Pdu_s

初始化时还会预填 Node ID:

RamPtr_ps->TxBuffer_au8[ConfigPtr_pcs->NodeIdPos_u8] = ConfigPtr_pcs->NodeId_u8;

并初始化 CBV 和 User Data:

RamPtr_ps->TxBuffer_au8[ConfigPtr_pcs->ControlBitVectorPos_u8] = 0x00;RamPtr_ps->UserDataBuffer_au8[Index_ui] = CANNM_DEFAULT_USER_BYTE;

CanNm_PBcfg.c 中的 channel 配置会决定发送周期、超时阈值、PDU 映射、报文长度、Node ID 位置、CBV 位置和 UserData 长度。

MsgCycleTime              = <周期 NM 报文发送周期>MsgCycleOffset            = <首次发送偏移>MsgTimeoutTime            = <发送确认超时>ImmediateNmCycleTime      = <Immediate NM 发送周期>NMTimeoutTime             = <NM Timeout 时间>RepeatMessageTime         = <Repeat Message 状态保持时间>WaitBusSleepTime          = <Prepare Bus Sleep 等待时间>TxPduId                   = <CanIf Tx PDU 映射>PduLength                 = <NM PDU 长度>NodeIdPos                 = <Node ID 字节位置>ControlBitVectorPos       = <CBV 字节位置>NodeId                    = <本节点 NM Node ID>UserDataLength            = <UserData 长度>ImmediateNmTransmissions  = <Immediate NM 发送次数>

所以,一帧 NM 报文的布局不是在发送逻辑里写死的,而是由配置决定。典型结构可以抽象为:

<Node ID 字段,位置由 NodeIdPos 决定><Control Bit Vector 字段,位置由 ControlBitVectorPos 决定><User Data 字段,长度由 UserDataLength 决定>

4.2 进入 Network Mode 时启动发送

发送不是一直打开的。状态机进入 Network Mode 或 Repeat Message 时,会调用:

CanNm_StartTransmission(CanNm_NetworkHandle);

这个函数并不立刻发送报文,而是设置发送状态和周期参数:

RamPtr_ps->MsgTxStatus_b = TRUE;RamPtr_ps->TxConfirmation_b = FALSE;if(RamPtr_ps->ImmediateNmTx_u8 == 0){    RamPtr_ps->MsgCyclePeriod = ConfigPtr_pcs->MsgCycleOffset;}else{    RamPtr_ps->MsgCyclePeriod = 0;}RamPtr_ps->PrevMsgCycleTimestamp = RamPtr_ps->ctSwFrTimer;

这里的 MsgTxStatus_b = TRUE 是周期发送的开关。

如果没有 Immediate NM PDU,第一次发送会等 MsgCycleOffset。这个偏移值来自项目配置;不同工程可能选择立即发送,也可能通过 offset 错开各节点的 NM 报文。

4.3 MainFunctionTx 周期检查是否该发送

CanNm_InternalMainProcess() 在状态机处理结束后,会调用:

CanNm_MainFunctionTx(CanNm_NetworkHandle);

CanNm_MainFunctionTx() 中,周期发送条件是:

if((RamPtr_ps->stCanNmComm != FALSE) &&   (RamPtr_ps->MsgTxStatus_b != FALSE) &&   (CanNm_TimerExpired(RamPtr_ps->PrevMsgCycleTimestamp,                       RamPtr_ps->MsgCyclePeriod) != FALSE)){    CanNm_UpdateTxPdu(ConfigPtr_pcs, RamPtr_ps);    RetValOfFuncs_ui = CanNm_MessageTransmit(ConfigPtr_pcs, RamPtr_ps);}

也就是说,CanNm 发一帧 NM PDU 需要三个条件:

  • • 通信允许:stCanNmComm != FALSE
  • • 发送开关打开:MsgTxStatus_b != FALSE
  • • 当前发送周期到期:MsgCyclePeriod 到期。

4.4 CanNm_UpdateTxPdu 组装发送报文

真正发之前,源码会先调用:

CanNm_UpdateTxPdu(ConfigPtr_pcs, RamPtr_ps);

这个函数负责把最新的 CBV 和 User Data 更新到 TxBuffer_au8

如果支持 COM User Data,并且不是 TriggerTransmit 模式,会先从 PduR 拉取最新用户数据:

PduR_CanNmTriggerTransmit(ConfigPtr_pcs->PduRId, &PduInfo_s);

然后更新 CBV:

TxBufferPtr[ConfigPtr_pcs->ControlBitVectorPos_u8] =    RamPtr_ps->TxCtrlBitVector_u8;

再把 User Data 拷贝到发送缓冲区:

CanNm_CopyBuffer(UserDataPtr, TxBufferPtr, ConfigPtr_pcs->UserDataLength_u8);

所以对普通周期 NM PDU 来说,发送前的报文内容来自:

  • • Node ID:初始化时写入 TxBuffer_au8
  • • CBV:每次发送前由 TxCtrlBitVector_u8 刷新。
  • • User Data:来自 UserDataBuffer_au8,或者通过 PduR 从 COM 获取。

4.5 CanNm_MessageTransmit 调 CanIf_Transmit

底层发送出口是:

RetValOfFuncs_ui = CanIf_Transmit(ConfigPtr_pcs->TxPduId, &(RamPtr_ps->Pdu_s));

调用前,CanNm 会打开发送超时监控:

RamPtr_ps->TxTimeoutMonitoringActive_b = TRUE;

如果 CanIf_Transmit() 返回 E_OK,说明发送请求被 CanIf 接受,CanNm 启动 message timeout timer:

CanNm_StartTimer(RamPtr_ps->PrevMsgTimeoutTimestamp);

如果返回 E_NOT_OK,说明发送请求没有被接受,CanNm 关闭本次超时监控:

RamPtr_ps->TxTimeoutMonitoringActive_b = FALSE;

发送成功提交后,CanNm_MainFunctionTx() 还会更新下一次发送周期:

if(RamPtr_ps->ImmediateNmTx_u8 == 0){    RamPtr_ps->MsgCyclePeriod = ConfigPtr_pcs->MsgCycleTime;}else{    RamPtr_ps->MsgCyclePeriod = ConfigPtr_pcs->ImmediateNmCycleTime;    RamPtr_ps->ImmediateNmTx_u8--;}CanNm_StartTimer(RamPtr_ps->PrevMsgCycleTimestamp);

如果配置了 Immediate NM 发送次数,源码会先使用 ImmediateNmCycleTime 快速发送若干帧;Immediate 发送耗尽后,再回到常规 MsgCycleTime。如果未配置 Immediate 发送,则发送周期直接按常规周期运行。

4.6 TxConfirmation 结束一次发送闭环

当下层确认一帧 NM PDU 已经发送完成后,CanIf 会回调:

void CanNm_TxConfirmation(PduIdType TxPduId, Std_ReturnType result)

这个函数会:

RamPtr_ps->TxConfirmation_b = TRUE;RamPtr_ps->TxTimeoutMonitoringActive_b = FALSE;

如果 MsgTxStatus_b 仍然为 TRUE,还会更新 PrevMsgTimeoutTimestamp

后续 CanNm_MainFunction() 会读取 TxConfirmation_b。如果当前没有接收事件,但有发送确认事件,CanNm_NetworkModeProcessing() 会刷新 NM Timeout Timer:

if (PduTxConfirmation_b != FALSE){    CanNm_StartTimer(RamPtr_ps->ctNMTimeoutTimer);}

这说明 CanNm 不仅靠“收到别人的 NM 报文”维持网络,也会通过“自己成功发出 NM 报文”刷新 NM Timeout。

5. 上层触发的额外发送

除了周期发送,源码里还有 CanNm_Transmit()

它用于 PduR 触发一次带指定 User Data 的 NM PDU 发送:

Std_ReturnType CanNm_Transmit(PduIdType CanNmTxPduId,                              const PduInfoType * PduInfoPtr)

这个 API 只有在状态是 NM_STATE_REPEAT_MESSAGE 或 NM_STATE_NORMAL_OPERATION 时才会真正发送:

if ((RamPtr_ps->State_en == NM_STATE_REPEAT_MESSAGE) ||    (RamPtr_ps->State_en == NM_STATE_NORMAL_OPERATION)){    CanNm_CopyBuffer(PduInfoPtr->SduDataPtr,                     UserDataPtr,                     (uint8)PduInfoPtr->SduLength);    RetVal_en = CanNm_MessageTransmit(ConfigPtr_pcs, RamPtr_ps);}

因此,CanNm_Transmit() 不是状态机周期发送的替代品,而是上层在合法网络状态下请求额外发送 NM PDU 的入口。

6. 把收发和状态机合在一起看

最后用一条完整链路总结。

6.1 接收链路

CanNm NM 报文接收链路流程图

6.2 状态机消费链路

CanNm_MainFunction 状态机消费链路流程图

6.3 发送链路

CanNm NM 报文发送链路流程图

7. 这套源码的核心理解

这套 CanNm 源码最核心的设计可以概括为三句话。

第一,接收回调只负责“记账”。

CanNm_RxIndication() 不直接做复杂状态机,它把收到的 NM PDU 解析到 RAM,置位 RxIndication_b,然后退出。

第二,状态机只在 CanNm_MainFunction() 中集中运行。

CanNm_MainFunction() 消费接收事件、发送确认事件、CBV、网络请求状态和多个软件定时器,再决定状态如何流转。

第三,发送由状态机打开,由 MainFunctionTx 周期执行。

进入 Network Mode 或 Repeat Message 时,CanNm_StartTransmission() 打开发送开关;后续 CanNm_MainFunctionTx() 按周期调用 CanNm_UpdateTxPdu() 和 CanNm_MessageTransmit(),最终通过 CanIf_Transmit() 发到 CAN 总线。

理解这三点后,再看 CanNm 的各个 API 就会清晰很多:NetworkRequestNetworkRelease 改的是网络请求状态;RxIndication 改的是接收事件;TxConfirmation 改的是发送确认事件;真正把这些事件编排成网络管理行为的,是周期运行的 CanNm_MainFunction()

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-06 08:31:52 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/718806.html
  2. 运行时间 : 0.130520s [ 吞吐率:7.66req/s ] 内存消耗:4,765.09kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=02aa02036d8d279a5568d41f68b7e159
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000647s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000847s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000417s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000376s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000780s ]
  6. SELECT * FROM `set` [ RunTime:0.000336s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000830s ]
  8. SELECT * FROM `article` WHERE `id` = 718806 LIMIT 1 [ RunTime:0.000604s ]
  9. UPDATE `article` SET `lasttime` = 1780705912 WHERE `id` = 718806 [ RunTime:0.002988s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000368s ]
  11. SELECT * FROM `article` WHERE `id` < 718806 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000639s ]
  12. SELECT * FROM `article` WHERE `id` > 718806 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000555s ]
  13. SELECT * FROM `article` WHERE `id` < 718806 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000994s ]
  14. SELECT * FROM `article` WHERE `id` < 718806 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002131s ]
  15. SELECT * FROM `article` WHERE `id` < 718806 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.004929s ]
0.132874s