最近在研究OpenAVB代码,主要分两个方面进行梳理:
目录
AVB应用(Talker/Listener)获取gPTP时间流程
主要文件说明
common:
ap_message.cpp
common_port.cpp
gptp_cfg.cpp: 处理解析gptp_cfg.ini配置文件
ieee1588clock.cpp
wireless_port.cpp
avbts_osnet.cpp
ether_port.cpp
gptp_log.cpp: 输出log相关信息
ptp_message.cpp
wireless_tstamper.cpp
几个时间的区别
OPENAVB_CLOCK_REALTIME: 系统时间
OPENAVB_CLOCK_MONOTONIC:系统启动上电到目前的时间
OPENAVB_TIMER_CLOCK:目前等同于OPENAVB_CLOCK_MONOTONIC
OPENAVB_CLOCK_WALLTIME:gPTP时间,也就是TSN网络对时之后的时间,其获取方式可参考如下代码:
bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
if (openavbClockId < OPENAVB_CLOCK_WALLTIME)
{
clockid_t clockId = CLOCK_MONOTONIC;
switch (openavbClockId) {
case OPENAVB_CLOCK_REALTIME:
clockId = CLOCK_REALTIME;
break;
case OPENAVB_CLOCK_MONOTONIC:
clockId = CLOCK_MONOTONIC;
break;
case OPENAVB_TIMER_CLOCK:
clockId = CLOCK_MONOTONIC;
break;
case OPENAVB_CLOCK_WALLTIME:
break;
}
struct timespec getTime;
if (!clock_gettime(clockId, &getTime)) {
*timeNsec = ((U64)getTime.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)getTime.tv_nsec;
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return TRUE;
}
}
else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return x_getPTPTime(timeNsec);
}
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return FALSE;
}
gptp相关时间解析
gptp的时间相关参数可以通过其提供的shm_test来查看,相关log输出如下:
Frequency 3537550000 Hz
ml phoffset 2065469072503
ml freq offset 1.000155
ls phoffset 1608168703330912468
ls freq offset 1.000005
local time 3428994432467
gptp grandmaster id 00:00:00:00:00:00:00:00
gptp domain number 0
clock identity a0:36:9f:ff:fe:72:8f:20
priority1 248
clock_class 248
offset_scaled_log_variance 17258
clock_accuracy 34
priority2 248
domain_number 0
log_sync_interval 0
log_announce_interval 0
log_pdelay_interval 0
port_number 1
sync count 226
pdelay count 88
asCapable True
Port State 9
process_id 2655
其中
local time: 是通过网卡取得的本地网卡时间,其调用流程如下:
port->getDeviceTime=>setMasterOffset=>ipc->update=>LinuxSharedMemoryIPC::update
这里port->getDeviceTime通过调用_hw_timestamper->HWTimestamper_gettime,最终进入到ptp内核驱动并获取了网卡时间。
ml phoffset: 是master到Local的时间延迟,是通过sync_arrival-preciseOriginTimestamp计算得来的
其中sync_arrival是sync数据包到达的设备时间,preciseOriginTimestamp为精准的原始时间戳。
AVB应用(Talker/Listener)获取gPTP时间流程
Talker 端:
Talker会通过配置项spin_wait的不同,获取不同的时间戳,
如果是0,则直接获取OPENAVB_TIMER_CLOCK->osalClockGettime->CLOCK_MONOTONIC->clock_gettime
如果是1,则:
1. talkerStartStream->CLOCK_GETTIME->osalClockGettime->x_getPTPTime
2. talkerDoStream->CLOCK_GETTIME->osalClockGettime->x_getPTPTime
x_getPTPTime代码如下:
static bool x_getPTPTime(U64 *timeNsec) {
AVB_TRACE_ENTRY(AVB_TRACE_TIME);
if (gptpgetdata(gPtpMmap, &gPtpTD) < 0) {
AVB_LOG_ERROR("GPTP data fetch failed");
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return FALSE;
}
uint64_t now_local;
uint64_t update_8021as;
int64_t delta_8021as;
int64_t delta_local;
if (gptplocaltime(&gPtpTD, &now_local)) {
update_8021as = gPtpTD.local_time - gPtpTD.ml_phoffset;
delta_local = now_local - gPtpTD.local_time;
delta_8021as = gPtpTD.ml_freqoffset * delta_local;
*timeNsec = update_8021as + delta_8021as;
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return TRUE;
}
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return FALSE;
}
其大体流程如下:
1. 获取gptp数据
2. 获取本地系统时间 (CLOCK_REALTIME)
3. 通过本地系统时间计算as的now_time,计算过程代码如下:
bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local)
{
struct timespec sys_time;
uint64_t now_system;
uint64_t system_time;
int64_t delta_local;
int64_t delta_system;
if (!td || !now_local)
return false;
if (clock_gettime(CLOCK_REALTIME, &sys_time) != 0)
return false;
now_system = (uint64_t)sys_time.tv_sec * 1000000000ULL + (uint64_t)sys_time.tv_nsec;
system_time = td->local_time + td->ls_phoffset;
delta_system = now_system - system_time;
delta_local = td->ls_freqoffset * delta_system;
*now_local = td->local_time + delta_local;
return true;
}
4. 通过本地上次的now_time时间和gptp时间的偏移计算当前now_local,即为目前的as wall time时间
5. 输出校准后的时间
Listener端:
1. listenerStartStream->CLOCK_GETTIME(OPENAVB_TIMER_CLOCK)->osalClockGettime->CLOCK_MONOTONIC->clock_gettime
2. listenerDoStream->CLOCK_GETTIME(OPENAVB_TIMER_CLOCK)->osalClockGettime->CLOCK_MONOTONIC->clock_gettime
Listener直接使用了系统单调时间作为时间戳
OpenAVB h264 gst流程(AVB 1722 协议)
Callback 接口:
intf_cfg_cb: 配置接口回调
intf_gen_init_cb:
intf_tx_init_cb: A call to this callback indicates that this interface module will be a talker. Any talker initialization can be done in this function.
intf_tx_cb: This callback will be called for each AVB transmit interval. Commonly this will be 4000 or 8000 times per second.
intf_rx_init_cb: A call to this callback indicates that this interface module will be a listener. Any listener initialization can be done in this function.
intf_rx_cb: This callback is called when acting as a listener
intf_end_cb: This callback will be called when the interface needs to be closed. All shutdown should occur in this function
intf_gen_end_cb:
intf_set_stream_uid_cb:
Talker端:
intf_tx_cb (openavbIntfH264RtpGstTxCB)流程:
=>openavbMediaQHeadLock(pMediaQ);
=>gst_al_pull_rtp_buffer
=>gst_al_rtp_buffer_get_marker
=>openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); //其中设置该包的walltime时间,该时间即为通过gptp对时后的网络时间
=>openavbMediaQHeadPush(pMediaQ);