32 1 5 8 8 realise


http://www.verydemo.com/demo_c161_i272139.html

本文章基于stm32官方例程实现,详细代码可下载例程。

在RT-thread系统上实现1 5 8 8协议,网络驱动上需要做较多的修改。 


2.代码修改


2.1驱动分析


当Accumulator register,溢出之后,会增加subsecond register一个步长,这个步长为constant value;每个时钟周期 Accumulator register会加上 addend register的值,这样做的目的是调整 subsecond register 增加的周期。
为Accumulator register提供clock的位系统时钟 HCLK,一般为72MHz,而 subsecond register 增加的频率需要为50MHz。
subsecond register的最大值为2^31,把2^31作为1秒钟,那么每20ns subsecond register需要增加 20ns  * (2^31) / 10^9ns = 43 ,即constant value 为43.。
Accumulator register 溢出时间为 49 *10^9 / (2^31) ~= 20.023ns
 Addend / 2^32 = (1 / 20ns) /72mhz    换算单位之后 Addend = 2979125334.90

2.2驱动层的修改

原代码的DMA描述符如下:

  1.  static ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];  
  2.   
  3. //STM32的MAC加入时间戳时,会将描述符的地址覆盖,  
  4. //所以需要将地址提前保存起来,MAC的时间戳读出来之后,再将地址写回去。   
  5. //再创建两个描述符用于保存地址   
  6.   
  7.  ETH_DMADESCTypeDef DMAPTPRxDscrTab[ETH_RXBUFNB], DMAPTPTxDscrTab[ETH_TXBUFNB];/* Ethernet Rx & Tx PTP Helper Descriptors */  


2.3发送函数的更改

  1. rt_err_t rt_stm32_eth_tx( rt_device_t dev, struct pbuf* p)  
  2. {  
  3.     struct pbuf* q;  
  4.     rt_uint32_t offset = 0;  
  5.     unsigned char * buffer;  
  6.       
  7.       
  8.     /* get free tx buffer */  
  9.     {  
  10.         rt_err_t result;  
  11.         result = rt_sem_take(&tx_buf_free, 2);  
  12.         if (result != RT_EOK) return -RT_ERROR;  
  13.     }  
  14. #if LWIP_PTP  
  15.     unsigned int timeout = 0;  
  16.     struct ptptime_t timestamp;  
  17.       
  18.     DMATxDescToSet->Buffer1Addr = DMAPTPTxDescToSet->Buffer1Addr;   //保存地址  
  19.     DMATxDescToSet->Buffer2NextDescAddr = DMAPTPTxDescToSet->Buffer2NextDescAddr;  
  20. #endif  
  21.       
  22.     buffer = (unsigned char *)DMATxDescToSet->Buffer1Addr;  
  23.       
  24.     for (q = p; q != NULL; q = q->next)  
  25.     {  
  26.         rt_uint8_t* ptr;  
  27.         rt_uint32_t len;  
  28.           
  29.         len = q->len;  
  30.         ptr = q->payload;  
  31.           
  32.         /**Copy the frame to be sent into memory pointed by the current ETHERNET DMA Tx descriptor*/  
  33.         memcpy((void *)(&buffer[offset] ), ptr, len);  
  34.         offset += len;  
  35.     }  
  36.       
  37. #ifdef ETH_TX_DUMP  
  38. .......  
  39. #endif  
  40.       
  41.     /* Setting the Frame Length: bits[12:0] */  
  42.     DMATxDescToSet->ControlBufferSize = (p->tot_len & ETH_DMATxDesc_TBS1);  
  43.     /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */  
  44.     DMATxDescToSet->Status |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS;  
  45.     /* Enable TX Completion Interrupt */  
  46.     DMATxDescToSet->Status |= ETH_DMATxDesc_IC;  
  47. #ifdef CHECKSUM_BY_HARDWARE  
  48. ........  
  49. #endif  
  50.     /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */  
  51.     DMATxDescToSet->Status |= ETH_DMATxDesc_OWN;  
  52.     /* When Tx Buffer unavailable flag is set: clear it and resume transmission */  
  53.     if ((ETH->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET)  
  54.     {  
  55.         /* Clear TBUS ETHERNET DMA flag */  
  56.         ETH->DMASR = ETH_DMASR_TBUS;  
  57.         /* Transmit Poll Demand to resume DMA transmission*/  
  58.         ETH->DMATPDR = 0;  
  59.     }  
  60. #if LWIP_PTP  
  61.     /* Wait for ETH_DMATxDesc_TTSS flag to be set */  
  62.     do  
  63.     {  
  64.         timeout++;  
  65.     } while (!(DMATxDescToSet->Status & ETH_DMATxDesc_TTSS) && (timeout < PHY_READ_TO));  //等待加入时间戳  
  66.     /* Return ERROR in case of timeout */  
  67.     if(timeout == PHY_READ_TO)  
  68.     {  
  69.         return ETH_ERROR;  
  70.     }  
  71.       
  72.     timestamp.tv_nsec = ETH_PTPSubSecond2NanoSecond(DMATxDescToSet->Buffer1Addr);  
  73.     timestamp.tv_sec = DMATxDescToSet->Buffer2NextDescAddr;  
  74.       
  75.     /* Clear the DMATxDescToSet status register TTSS flag */  
  76.     DMATxDescToSet->Status &= ~ETH_DMATxDesc_TTSS;  
  77.       
  78.     DMATxDescToSet->Buffer1Addr = DMAPTPTxDescToSet->Buffer1Addr;  
  79.     DMATxDescToSet->Buffer2NextDescAddr = DMAPTPTxDescToSet->Buffer2NextDescAddr;   //还原地址  
  80.       
  81.     /* Update the ETHERNET DMA global Tx descriptor with next Tx decriptor */  
  82.     /* Chained Mode */  
  83.     /* Selects the next DMA Tx descriptor list for next buffer to send */  
  84.     DMATxDescToSet = (ETH_DMADESCTypeDef*) (DMATxDescToSet->Buffer2NextDescAddr);  
  85.       
  86.     if(DMAPTPTxDescToSet->Status != 0)  
  87.     {  
  88.         DMAPTPTxDescToSet = (ETH_DMADESCTypeDef*) (DMAPTPTxDescToSet->Status);  
  89.     }  
  90.     else  
  91.     {  
  92.         DMAPTPTxDescToSet++;  
  93.     }  
  94. #else  
  95.       
  96.     /* Update the ETHERNET DMA global Tx descriptor with next Tx decriptor */  
  97.     /* Chained Mode */  
  98.     /* Selects the next DMA Tx descriptor list for next buffer to send */  
  99.     DMATxDescToSet = (ETH_DMADESCTypeDef*) (DMATxDescToSet->Buffer2NextDescAddr);  
  100.       
  101. #endif  
  102.       
  103. #if LWIP_PTP  
  104.     p->time_sec = timestamp.tv_sec;  
  105.     p->time_nsec = timestamp.tv_nsec;  
  106. #endif  
  107.     /* Return SUCCESS */  
  108.     return RT_EOK;  
  109. }  

2.4其他

接收函数也做类似的更改,还有中断函数直接参照例程修改就可以。

3.协议分析

1588协议中,定义了两种报文,事件报文和通用报文;

事件报文时间概念报文,进出设备端口时打上精确的时间戳,PTP根据事件报文携带的时间戳,计算链路延迟。事件报文包含以下4种:Sync、Delay_Req、Pdelay_Req和Pdelay_Resp。

通用报文:非时间概念报文,进出设备不会产生时间戳,用于主从关系的建立、时间信息的请求和通告。通用报文包含以下6种:Announce、Follow_Up、Delay_Resp、Pdelay_Resp_Follow_Up、Management和Signaling,目前设备不支持Management、Signaling报文。


时钟同步的实现主要包括3个步骤:

  1. 建立主从关系,选取最优时钟、协商端口主从状态等。
  2. 频率同步,实现从节点频率与主节点同步。
  3. 时间同步,实现从节点时间与主节点同步。

协议初始化之后,开始监听网络,master会主动发送sync、Announce包,slave收到Announce后,添加主机(addForeign函数实现),并对其进行最佳主时钟算法(BMC)比较。

3.1建立主从关系

主从关系建立步骤

PTP是通过端口接收到和发送Announce报文,实现端口数据集和端口状态机信息的交互。BMC(Best Master Clock)算法通过比较端口数据集和端口状态机,实现时钟主从跟踪关系。一般按照下面几个步骤来建立:

  1. 接收和处理来自对端设备端口的Announce报文。

  2. 利用BMC算法决策出最优时钟和端口的推荐状态,包括Master、Slave或者Passive状态。

  3. 根据端口推荐状态,更新端口数据集合。

  4. 按照推荐状态和状态决策事件,根据端口状态机决定端口的实际状态,实现时钟同步网络的建立。状态决策事件包括Announce报文的接收事件和接收Announce报文的超时时间结束事件,当接口接收Announce报文的时间间隔大于超时时间间隔时,将此PTP接口状态置为Master。


BMC算法

(bmc函数实现),简单的来说就是依次比较每个主机的参数,这几个参数为:gPriority1clockClassclockAccuracyoffsetScaledLogVariancePriority2这里做一些比较,得出最佳主时钟。

  • Priority1:时钟优先级1,支持用户配置,取值范围是0~255,取值越小优先级越高。
  • ClockClass:时钟级别,定义时钟的时间或频率的国际原子时TAI(International Atomic Time)跟踪能力。
  • ClockAccuracy:时钟精度,取值越低精确度越高。
  • OffsetScaledLogVariance:时钟稳定性。
  • Priority2:时钟优先级2,支持用户配置,取值范围是0~255,取值越小优先级越高。

最优时钟可以通过手工配置静态指定,也可以通过最佳主时钟BMC(Best Master Clock)算法动态选举。

 3.2 PTP频率同步


在主从关系建立后,即可以进行频率同步和时间同步。PTP本来只是用户设备之间的高精度时间同步,但也可以被用来进行设备之间的频率同步。

PTP通过记录主从设备之间事件报文交换时产生的时间戳,计算出主从设备之间的路径延迟和时间偏移,实现主从设备之间的时间和频率同步,设备支持两种携带时间戳的模式,分别为:

  • 单步时钟模式(One step),指事件报文Sync和Pdelay_Resp带有本报文发送时刻的时间戳,报文发送和接收的同时也完成了时间信息的通告。
  • 两步时钟模式(Two step),指事件报文Sync和Pdelay_Resp不带有本报文发送时刻的时间戳,而分别由后续的通用报文Follow_Up和Pdelay_Resp_Follow_Up带上该Sync和PDelay_Resp报文的发送时间信息。两步时钟模式中,时间信息的产生和通告分两步完成,这样可以兼容一些不支持给事件报文打时间戳的设备。

 3.3  PTP时间同步

PTP时间同步有两种不同的同步方式:Delay方式和Pdelay方式,如此划分主要是由于PTP计算路径延时有两种机制。

  • 延时请求-请求响应机制E2E(End to End):根据主从时钟之间的整体路径延时时间计算时间差。
  • 对端延时机制P2P(Peer to Peer):根据主从时钟之间的每一条链路延时时间计算时间差。

fg

对端延时机制P2P(Peer to Peer)

    P2P机制是利用延时请求Pdelay_Req报文、延时回答Pdelay_Resp报文和可能的Pdelay_Resp_Follow_Up报文,计算两个支持P2P机制的通信端口之间测量端口到端口的传播时间,也就是路径延时。与延时请求-响应机制相比,路径延时测量原理并无不同,只是路径延时测量在每段链路之间进行,主从节点间每段链路的链路延时累计在Pdelay_Resp或Pdelay_Resp_Follow_Up报文中,向下游传递,同时传递信息还包括同步报文在透明时钟TC上的驻留时间。从节点每段链路的链路延时和在透明时钟TC上的驻留时间,计算主从节点的平均路径延时。

在对端延时机制中,延时测量和端口的主从属性无关,在支持Pdelay机制的两个相连端口之间进行。

 Pdelay机制原理 

时间戳t1和t2是Pdelay_Req消息发送时间戳和接收时间戳,时间戳t3和t4是Pdelay_Resp消息的发送时间戳和接收时间戳。计算单段链路延时的公式如下所示:

单段链路延时=[(t2-t1) + (t4-t3)]/2 = [(t2-t3) + (t4-t1)]/2。

4.协议代码分析

 4.1  handle(PtpClock *ptpClock)函数:


  1. /* check and handle received messages */  
  2. static void handle(PtpClock *ptpClock)  
  3. {  
  4.   
  5.     int ret;  
  6.     Boolean isFromSelf;  
  7.     TimeInternal time = { 0, 0 };  
  8. //**********************************************************************检查是否收到数据  
  9.     if (FALSE == ptpClock->messageActivity)  
  10.     {  
  11.         ret = netSelect(&ptpClock->netPath, 0);  
  12.   
  13.         if (ret < 0)<span>                           </span>//接收出错  
  14.         {  
  15.             ERROR("handle: failed to poll sockets\n");  
  16.             toState(ptpClock, PTP_FAULTY);  
  17.             return;  
  18.         }  
  19.         else if (!ret)<span>                            </span>//没有收到数据,直接返回  
  20.         {  
  21.           //  DBGVV("handle: nothing\n");  
  22.             return;  
  23.         }  
  24.     }  
  25. //**********************************************************************  
  26.   //  DBGVV("handle: something\n");  
  27.   
  28.     ptpClock->msgIbufLength = netRecvEvent(&ptpClock->netPath, ptpClock->msgIbuf, &time);  
  29.     /* local time is not UTC, we can calculate UTC on demand, otherwise UTC time is not used */  
  30.     /* time.seconds += ptpClock->timePropertiesDS.currentUtcOffset; */  
  31.   
  32.   
  33.     if (ptpClock->msgIbufLength < 0)  
  34.     {  
  35.         ERROR("handle: failed to receive on the event socket\n");  
  36.         toState(ptpClock, PTP_FAULTY);  
  37.         return;  
  38.     }  
  39.     else if (!ptpClock->msgIbufLength)  
  40.     {                                 <span>//读取数据,接收时MAC层加入的时间戳保存在time中;数据保存在msgIbuf中</span>  
  41.         ptpClock->msgIbufLength = netRecvGeneral(&ptpClock->netPath, ptpClock->msgIbuf, &time);   
  42.   
  43.         if (ptpClock->msgIbufLength < 0)  
  44.         {  
  45.             ERROR("handle: failed to receive on the general socket\n");  
  46.             toState(ptpClock, PTP_FAULTY);  
  47.             return;  
  48.         }  
  49.         else if (!ptpClock->msgIbufLength)  
  50.             return;  
  51.     }  
  52.   
  53.     ptpClock->messageActivity = TRUE;  
  54.   
  55.     if (ptpClock->msgIbufLength < HEADER_LENGTH)  
  56.     {  
  57.         ERROR("handle: message shorter than header length\n");  
  58.         toState(ptpClock, PTP_FAULTY);  
  59.         return;  
  60.     }  
  61.   
  62.     msgUnpackHeader(ptpClock->msgIbuf, &ptpClock->msgTmpHeader);//将数据包解析后放在<span>ptpClock-></span><span>msgTmpHeader中。</span>  
  63.   
  64.     if (ptpClock->msgTmpHeader.versionPTP != ptpClock->portDS.versionNumber)  
  65.     {  
  66.         DBGV("handle: ignore version %d message\n", ptpClock->msgTmpHeader.versionPTP);  
  67.         return;  
  68.     }  
  69.   
  70.     if (ptpClock->msgTmpHeader.domainNumber != ptpClock->defaultDS.domainNumber)  
  71.     {  
  72.         DBGV("handle: ignore message from domainNumber %d\n", ptpClock->msgTmpHeader.domainNumber);  
  73.         return;  
  74.     }  
  75.   
  76.     /*Spec 9.5.2.2*/  
  77.     isFromSelf = isSamePortIdentity(  
  78.         &ptpClock->portDS.portIdentity,  
  79.         &ptpClock->msgTmpHeader.sourcePortIdentity);  //判断是否是同一个主机  
  80.   
  81.     /* subtract the inbound latency adjustment if it is not a loop back and the 
  82.        time stamp seems reasonable */  
  83.     if (!isFromSelf && time.seconds > 0)  
  84.         subTime(&time, &time, &ptpClock->inboundLatency);  
  85.   
  86.     switch (ptpClock->msgTmpHeader.messageType)  
  87.     {  
  88.   
  89.     case ANNOUNCE:  
  90.         handleAnnounce(ptpClock, isFromSelf);  
  91.         break;  
  92.   
  93.     case SYNC:  
  94.         handleSync(ptpClock, &time, isFromSelf);  
  95.         break;  
  96.   
  97.     case FOLLOW_UP:  
  98.         handleFollowUp(ptpClock, isFromSelf);  
  99.         break;  
  100.   
  101.     case DELAY_REQ:  
  102.         handleDelayReq(ptpClock, &time, isFromSelf);  
  103.         break;  
  104.   
  105.     case PDELAY_REQ:  
  106.         handlePDelayReq(ptpClock, &time, isFromSelf);  
  107.         break;  
  108.   
  109.     case DELAY_RESP:  
  110.         handleDelayResp(ptpClock, isFromSelf);  
  111.         break;  
  112.   
  113.     case PDELAY_RESP:  
  114.         handlePDelayResp(ptpClock, &time, isFromSelf);  
  115.         break;  
  116.   
  117.     case PDELAY_RESP_FOLLOW_UP:  
  118.         handlePDelayRespFollowUp(ptpClock, isFromSelf);  
  119.         break;  
  120.   
  121.     case MANAGEMENT:  
  122.         handleManagement(ptpClock, isFromSelf);  
  123.         break;  
  124.   
  125.     case SIGNALING:  
  126.         handleSignaling(ptpClock, isFromSelf);  
  127.         break;  
  128.   
  129.     default:  
  130.         DBG("handle: unrecognized message %d\n", ptpClock->msgTmpHeader.messageType);  
  131.         break;  
  132.     }  
  133. }  
 

4.2 handleSync

  1. static void handleSync(PtpClock *ptpClock, TimeInternal *time, Boolean isFromSelf)  
  2. {  
  3.     TimeInternal originTimestamp;  
  4.     TimeInternal correctionField;  
  5.   
  6.     Boolean isFromCurrentParent = FALSE;  
  7.     DBGV("handleSync: received\n");  
  8.   
  9.     if (ptpClock->msgIbufLength < SYNC_LENGTH)  
  10.     {  
  11.         ERROR("handleSync: short message\n");  
  12.         toState(ptpClock, PTP_FAULTY);  
  13.         return;  
  14.     }  
  15.   
  16.     switch (ptpClock->portDS.portState)  
  17.     {  
  18.     case PTP_INITIALIZING:  
  19.     case PTP_FAULTY:  
  20.     case PTP_DISABLED:  
  21.   
  22.         DBGV("handleSync: disreguard\n");  
  23.         break;  
  24.   
  25.     case PTP_UNCALIBRATED:  
  26.     case PTP_SLAVE:  
  27.   
  28.         if (isFromSelf)  
  29.         {  
  30.             DBGV("handleSync: ignore from self\n");  
  31.             break;  
  32.         }  
  33.   
  34.         isFromCurrentParent = isSamePortIdentity(  
  35.             &ptpClock->parentDS.parentPortIdentity,  
  36.             &ptpClock->msgTmpHeader.sourcePortIdentity);  
  37.   
  38.         if (!isFromCurrentParent)  
  39.         {  
  40.             DBGV("handleSync: ignore from another master\n");  
  41.             break;  
  42.         }  
  43.   
  44.         ptpClock->timestamp_syncRecieve = *time;    //保存接收sync报文时,本机的时间戳  
  45.   
  46.         scaledNanosecondsToInternalTime(&ptpClock->msgTmpHeader.correctionfield, &correctionField); //保存sync报文的修正时间  
  47.   
  48.         if (getFlag(ptpClock->msgTmpHeader.flagField[0], FLAG0_TWO_STEP))  //采用TWO_STEP方式,也就是说发送sync报文主机的时间,通过follow_up报文发送过来而不是包含在sync报文中。  
  49.         {  
  50.             ptpClock->waitingForFollowUp = TRUE;    
  51.             ptpClock->recvSyncSequenceId = ptpClock->msgTmpHeader.sequenceId;  //用于识别  
  52.             /* Save correctionField of Sync message for future use */  
  53.             ptpClock->correctionField_sync = correctionField;  
  54.         }  
  55.         else  
  56.         {  
  57.             msgUnpackSync(ptpClock->msgIbuf, &ptpClock->msgTmp.sync);  
  58.             ptpClock->waitingForFollowUp = FALSE;  
  59.             /* Synchronize  local clock */  
  60.             toInternalTime(&originTimestamp, &ptpClock->msgTmp.sync.originTimestamp);  
  61.             /* use correctionField of Sync message for future use */  
  62.             updateOffset(ptpClock, &ptpClock->timestamp_syncRecieve, &originTimestamp, &correctionField);  
  63.             updateClock(ptpClock);  
  64.           
  65.             issueDelayReqTimerExpired(ptpClock);  
  66.         }  
  67.   
  68.         break;  
  69.   
  70.   
  71.     case PTP_MASTER: //如果本机是主机  
  72.   
  73.         if (!isFromSelf)  
  74.         {  
  75.             DBGV("handleSync: from another master\n");  
  76.             break;  
  77.         }  
  78.         else  
  79.         {  
  80.             DBGV("handleSync: ignore from self\n");  
  81.             break;  
  82.         }  
  83.   
  84. //      if waitingForLoopback && TWO_STEP_FLAG  
  85. //        {  
  86. //            /*Add latency*/  
  87. //            addTime(time, time, &rtOpts->outboundLatency);  
  88. //  
  89. //            issueFollowup(ptpClock, time);  
  90. //            break;  
  91. //        }  
  92.     case PTP_PASSIVE:  
  93.         issueDelayReqTimerExpired(ptpClock);  
  94.         DBGV("handleSync: disreguard\n");  
  95.         break;  
  96.   
  97.     default:  
  98.         DBGV("handleSync: disreguard\n");  
  99.   
  100.         break;  
  101.     }  
  102. }  

4.3 handleFollowUp


  1. static void handleFollowUp(PtpClock *ptpClock, Boolean isFromSelf)  
  2. {  
  3.     TimeInternal preciseOriginTimestamp;  
  4.     TimeInternal correctionField;  
  5.     Boolean isFromCurrentParent = FALSE;  
  6.   
  7.     DBGV("handleFollowup: received\n");  
  8.   
  9.   
  10.     if (ptpClock->msgIbufLength < FOLLOW_UP_LENGTH)  
  11.     {  
  12.         ERROR("handleFollowup: short message\n");  
  13.         toState(ptpClock, PTP_FAULTY);  
  14.         return;  
  15.     }  
  16.   
  17.     if (isFromSelf)  
  18.     {  
  19.         DBGV("handleFollowup: ignore from self\n");  
  20.         return;  
  21.     }  
  22.   
  23.     switch (ptpClock->portDS.portState)  
  24.     {  
  25.     case PTP_INITIALIZING:  
  26.     case PTP_FAULTY:  
  27.     case PTP_DISABLED:  
  28.     case PTP_LISTENING:  
  29.   
  30.         DBGV("handleFollowup: disreguard\n");  
  31.         break;  
  32.   
  33.     case PTP_UNCALIBRATED:  
  34.     case PTP_SLAVE:  
  35.   
  36.         isFromCurrentParent = isSamePortIdentity(  
  37.             &ptpClock->parentDS.parentPortIdentity,  
  38.             &ptpClock->msgTmpHeader.sourcePortIdentity);  
  39.   
  40.         if (!ptpClock->waitingForFollowUp)  
  41.         {  
  42.             DBGV("handleFollowup: not waiting a message\n");  
  43.             break;  
  44.         }  
  45.   
  46.         if (!isFromCurrentParent)  
  47.         {  
  48.             DBGV("handleFollowup: not from current parent\n");  
  49.             break;  
  50.         }  
  51.   
  52.   
  53.         if (ptpClock->recvSyncSequenceId !=  ptpClock->msgTmpHeader.sequenceId)  
  54.         {  
  55.             DBGV("handleFollowup: SequenceID doesn't match with last Sync message\n");  
  56.             break;  
  57.         }  
  58.   
  59.         msgUnpackFollowUp(ptpClock->msgIbuf, &ptpClock->msgTmp.follow); //从msgIbuf中 34 36 40位置,获取时间戳,也就是sync的master时间。参考<strong>协议</strong>  
  60.   
  61.         ptpClock->waitingForFollowUp = FALSE;  
  62.         /* synchronize local clock */  
  63.         toInternalTime(&preciseOriginTimestamp, &ptpClock->msgTmp.follow.preciseOriginTimestamp);//  
  64.         scaledNanosecondsToInternalTime(&ptpClock->msgTmpHeader.correctionfield, &correctionField);//handle中赋值msgTmpHeader.correctionfield。这里是follow_up  的修正值  
  65.         addTime(&correctionField, &correctionField, &ptpClock->correctionField_sync);//handleSync中赋值。这里是sync的修正值。两个修正值叠加  
  66.         updateOffset(ptpClock, &ptpClock->timestamp_syncRecieve, &preciseOriginTimestamp, &correctionField);//sync接收到时间timestamp_syncRecieve,主机发送sync时间preciseOriginTimestamp,修正时间correctionField  
  67.         updateClock(ptpClock);  
  68.           
  69.         issueDelayReqTimerExpired(ptpClock);  
  70.         break;  
  71.   
  72.     case PTP_MASTER:  
  73.         DBGV("handleFollowup: from another master\n");  
  74.   
  75.         break;  
  76.   
  77.     case PTP_PASSIVE:  
  78.         issueDelayReqTimerExpired(ptpClock);  
  79.         DBGV("handleFollowup: disreguard\n");  
  80.         break;  
  81.       
  82.     default:  
  83.         DBG("handleFollowup: unrecognized state\n");  
  84.   
  85.         break;  
  86.     }//Switch on (port_state)  
  87.   
  88. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值