Qcom平台 Sensor时间戳timestamp 简概

Sensor时间戳作用

同sensor数据一起上报,记录下sensor数据所处的时间,例如如camera时间戳搭配,结合相关算法计算设备姿态,优化拍照效果;

DDF中获取时间戳

DDF中,Timestamps来自频率为32 kHz clock ticks,这里获取的Timestamps 是ticks的具体次数;

获取Timestamps 的API 为:

sns_ddf_get_timestamp

HAL中处理时间戳

Sensor HAL中 TimeSyncService实现对Sensor时间戳的转换函数如下:

Timestamp Conversion in HAL
int64_t TimeSyncService::timestampCalc(uint64_t dsps_timestamp, int sensor_handle)
int64_t rv = timestamp_offset_apps_dsps +
((dsps_timestamp * NSEC_PER_SEC)/DSPS_HZ);
…
/* If a roll-over has likely occurred */
if( (dsps_timestamp < TS_ROLLOVER_THRESH) &&
(UINT32_MAX -g_time_control->dsps_ts_last < TS_ROLLOVER_THRESH) )
…
// If the # of rollovers determined by the HAL is different than in the
// last message received from the time service, adjust the timestamp
rv += (rollover_diff * UINT32_MAX) * NSEC_PER_SEC / DSPS_HZ;
…
/* Ensure sensor samples are sent to LA with increasing timestamps */
rv = timestamp_last_sent[ sensor_handle ] + 1;

timestampCalc 将Timestamps 根据 ticks clock转换成具体时间,再加上timestamp_offset_apps_dsps(adsp中时间戳的差值与系统启动时间的差值),来得到当前的时间;

其中TimeSyncService 会让timestamp_offset_apps_dsps 不断的更新和校准;

TimeSyncService

TimeSyncService类的定义:

class TimeSyncService {
private:
    /* time_service enabled status */
    int               enabled;
    /*timesync_sensor1_cb_t to be used for Daemon restart cases as well*/
    hal_sensor1_cb_t *sensor1_cb;
    /* Offset (in ns) between apps and dsps timestamps */
    int64_t           timestamp_offset_apps_dsps; /*应用程序和DSP时间戳之间的偏移量(单位:ns)*/
    /* Last DSPS timestamp received */
    uint32_t          dsps_ts_last[MAX_NUM_SENSORS]; /*接收到的最后一个DSPS时间戳*/
    /* # of times the DSPS clock has "rolled over" and restarted at 0 */
    uint32_t          dsps_rollover_cnt[MAX_NUM_SENSORS]; /*#DSPS时钟在0时“翻转”并重新启动的次数*/
    /* Rollover count as received in last time service report */
    uint32_t          dsps_rollover_cnt_rcv[MAX_NUM_SENSORS]; /*上次服务报告中接收的滚动计数*/
    /* Boottime timestamp of the last predicted rollover event */
    int64_t           boot_ts_last_rollover[MAX_NUM_SENSORS]; /*上次预测的滚动更新事件的引导时时间戳*/
    /* The timestamp on the last sample sent to Android (per sensor) */
    int64_t           timestamp_last_sent[MAX_NUM_SENSORS]; /*发送到Android的最后一个样本的时间戳(每个传感器)*/
    /* we only allow time_service class has one object */
    static TimeSyncService *self;
    /*Sensor type*/
    int sns_type;
    //......
     static TimeSyncService* getTimeSyncService();
     static int64_t getElapsedRealtimeNanoOffset(void);
     void processTimeResp(sensor1_msg_header_s const *msg_hdr,
                         sns_time_timestamp_resp_msg_v02 const *msg_ptr);
     void processTimeInd(sensor1_msg_header_s const *msg_hdr,
                         sns_time_timestamp_ind_msg_v02 const *msg_ptr);
    //......

通过前面对sensorHAL的了解,可知管理sensor维系了一个SensorsContext; SensorsContext中会获取具体的TimeSyncService;

SensorsContext::SensorsContext(){
  sensor1_init(); 
 //......
    /* Time Service */
  time_service = TimeSyncService::getTimeSyncService();
  getSensorList();
  updateSensorList();
}
TimeSyncService* TimeSyncService::getTimeSyncService()
{
    if (NULL == self)
        self = new TimeSyncService;
    return self;
}

注册回调

sensor1_error_e sensor1_open( sensor1_handle_s **hndl, sensor1_notify_data_cb_t data_cbf,
    intptr_t cb_data )
{
//......
  sensor1_init();
  print_group_info();
    client->cb_data = cb_data;
    client->sns_svc_num = SNS_SMGR_SVC_ID_V01;
    client->notify_cb = data_cbf;  //注册回调
//.....
  } else {

响应回调

void time_service_sensor1_cb(intptr_t cb_data, sensor1_msg_header_s *msg_hdr,
        sensor1_msg_type_e msg_type, void *msg_ptr)
{
    TimeSyncService *time_service = (TimeSyncService *)cb_data;
    hal_sensor1_cb_t  *timesync_sensor1_cb = time_service->getCb();
//......
    if (SENSOR1_MSG_TYPE_RESP == msg_type &&
        SNS_TIME_TIMESTAMP_RESP_V02 == msg_hdr->msg_id) {
        time_service->processTimeResp(msg_hdr, (sns_time_timestamp_resp_msg_v02*)msg_ptr);
    }
    else if (SENSOR1_MSG_TYPE_RESP == msg_type &&
        SNS_TIME_CANCEL_RESP_V02 == msg_hdr->msg_id) {
        time_service->processCancelResp();
    }
    else if (SENSOR1_MSG_TYPE_IND == msg_type) {
        time_service->processTimeInd(msg_hdr, (sns_time_timestamp_ind_msg_v02*)msg_ptr);
    }
//响应回调

offset同步更新 tsOffsetIs

void TimeSyncService::tsOffsetIs(uint32_t timestamp_ssc, uint64_t timestamp_ap)
{
    uint64_t ssc_ns;
    uint64_t elapsed_realtime_ns, elapsed_realtime_ns_best;
    struct timespec ts_start, ts_end;
    uint64_t boottime_ns, boottime_start, boottime_end;
    int attempts = MAX_CLOCK_DIFF_ATTEMPTS;
    uint64_t boottime_diff;
    uint64_t boottime_diff_best = MAX_CLOCK_DIFF_NS;
    uint64_t boottime_start_best = 0, boottime_end_best =0;
    /* Figure out the difference between the CLOCK_BOOTTIME time and
     * elapsedRealtimeNano */
    do {
        clock_gettime( CLOCK_BOOTTIME, &ts_start );
        elapsed_realtime_ns = android::elapsedRealtimeNano();
        clock_gettime( CLOCK_BOOTTIME, &ts_end );
        boottime_start = ts_start.tv_sec * NSEC_PER_SEC + ts_start.tv_nsec;
        boottime_end = ts_end.tv_sec * NSEC_PER_SEC + ts_end.tv_nsec;
        boottime_diff = boottime_end - boottime_start;
        if ((attempts == (int)MAX_CLOCK_DIFF_ATTEMPTS && boottime_diff >= boottime_diff_best) ||
            ( boottime_diff < boottime_diff_best )) {
            boottime_start_best = boottime_start;
            boottime_end_best = boottime_end;
            boottime_diff_best = boottime_diff;
            elapsed_realtime_ns_best = elapsed_realtime_ns;
        }
        HAL_LOG_DEBUG("%s: boottime_diff: %" PRId64 " boottime_diff_best: %" PRId64 " boottime_start_best: %" PRId64 " boottime_end_best: %" PRId64 "",
                      __FUNCTION__, boottime_diff, boottime_diff_best, boottime_start_best, boottime_end_best);
    } while ((boottime_diff > MAX_CLOCK_DIFF_NS) && (--attempts > 0));
    boottime_ns = (boottime_start_best + boottime_end_best) / 2;
    ssc_ns = (uint64_t)(((uint64_t)timestamp_ssc * NSEC_PER_SEC) / DSPS_HZ);
    timestamp_offset_apps_dsps = timestamp_ap - ssc_ns - boottime_ns + elapsed_realtime_ns_best;
    HAL_LOG_DEBUG("%s: Apps: %" PRIu64"; DSPS: %u; Offset : %" PRId64 " (diff %" PRId64 "; elapsed %" PRId64 " @%d)",
                  __FUNCTION__,  timestamp_ap, timestamp_ssc, timestamp_offset_apps_dsps,
                  boottime_diff_best, elapsed_realtime_ns_best, attempts);
}

uint64_t timestamp_apps_boottime;

/**< Timestamp from the Apps processor in nanoseconds since boot */

uint32_t timestamp_dsps;

/**< Timestamp from the DSPS in clock ticks */ ssc_ns (uint64_t)(((uint64_t)timestamp_ssc * NSEC_PER_SEC) / DSPS_HZ);

ssc_ns 是转为纳秒的 DSPS 时间戳;

timestamp_offset_apps_dsps = timestamp_ap - ssc_ns - boottime_ns + elapsed_realtime_ns_best;

timestamp_offset_apps_dsps 不断的被校准;

Qcom平台 Sensor时间戳timestamp 简概

SMGRSensor::processReportInd

路径:C:\work\sensors\sensors\msm8953_sensor_prj\VendorHalSensors\dsps\libhalsensors\src\SMGRSensor.cpp
 void SMGRSensor::processReportInd(Sensor** mSensors, sns_smgr_periodic_report_ind_msg_v01* smgr_ind)
{
    //......   
	sensor_data.timestamp = time_service->timestampCalc((uint64_t)smgr_data->TimeStamp, sensor_data.sensor);
    HAL_LOG_DEBUG("%s: handle:%d SMGR TS:%d HAL TS:%" PRId64 " elapsedRealtimeNano:%" PRId64 "",
                  __FUNCTION__, handle, smgr_data->TimeStamp,
                  sensor_data.timestamp, android::elapsedRealtimeNano());
    //......
}

Debug log

#define HAL_LOG_DEBUG(...) LOGD_IF((g_hal_log_level <= HAL_LOG_LEVEL_DEBUG), VA_ARGS )

log能否输出 取决于 g_hal_log_level

C:\work\sensors\sensors\msm8953_sensor_prj\VendorHalSensors\dsps\libhalsensors\src\SensorsContext.cpp

void SensorsContext::enableLogging()
{
//......
    /* Get the debug level from the property */
    debug_prop_len = property_get(HAL_PROP_DEBUG, debug_prop, "");
    if (debug_prop_len == 1) {
        switch (debug_prop[0]) {
            case ‘0‘:
                g_hal_log_level = HAL_LOG_LEVEL_DISABLED;
                break;
            case ‘1‘:
                g_hal_log_level = HAL_LOG_LEVEL_ALL;
                break;
            case ‘v‘:
            case ‘V‘:
                g_hal_log_level = HAL_LOG_LEVEL_VERBOSE;
                break;
            case ‘d‘:
            case ‘D‘:
                g_hal_log_level = HAL_LOG_LEVEL_DEBUG;
                break;
            case ‘i‘:
    //......
        }
        LOGI("%s: Setting log level to %d", __FUNCTION__, g_hal_log_level);
    }
    //......
}
C:\work\sensors\sensors\msm8953_sensor_prj\VendorHalSensors\dsps\libhalsensors\src\SensorsContext.cpp
SensorsContext::SensorsContext()
    : device(),
{   //......
     enableLogging();
    //......
}  

SensorsContext 在创建实例化对象时,会 enableLogging 可以通过adb 设置prop,重启;

07-20 13:06:29.703   540   654 D qti_sensors_hal: getHandleFromInd: handle =1       
07-20 13:06:29.703   540   654 D qti_sensors_hal: processReportInd: handle:1 SMGR TS:4230600 HAL TS:125002539356 elapsedRealtimeNano:125025682191  
07-20 13:06:29.703   540   829 D qti_sensors_hal: poll:polldata:1, sensor:1, type:1, x:-1.155472 y:-2.164871 z:8.922607
07-20 13:06:29.703   540   829 D qti_sensors_hal: poll: count: 16                         
07-20 13:06:29.703   540   829 D qti_sensors_hal: waitForResponse: timeout=0                
07-20 13:06:29.762   540   654 D qti_sensors_hal: processBufferingInd: Samples_len=1 Items=1 max_reports_per_index=1  
07-20 13:06:29.762   540   654 D qti_sensors_hal: getHandleFromInd: handle =1                
07-20 13:06:29.762   540   654 D qti_sensors_hal: processBufferingInd: Handle=1 mSensors[handle]->isBatchingEnable()=1  
07-20 13:06:29.762   540   654 D qti_sensors_hal: processBufferingInd: Handle=1 mSensors[handle]->getFlags()=0 smgr_ind->IndType=0                            
07-20 13:06:29.762   540   654 D qti_sensors_hal: getHandleFromInd: handle =1                                
07-20 13:06:29.762   540   654 D qti_sensors_hal: processReportInd: handle:1 SMGR TS:4232800 HAL TS:125069678028 elapsedRealtimeNano:125085008233             
//....

elapsedRealtimeNano 是android的API;

类似获取time的函数的有:

时间函数 api elapsedRealtimeNanos () :
1、public static long currentThreadTimeMillis ()   返在当前线程运行的毫秒数。
2、public static long elapsedRealtime ()   返回系统启动到现在的毫秒数,包含休眠时间。
3、public static long elapsedRealtimeNanos ()   返回系统启动到现在的纳秒数,包含休眠时间。
4、public static boolean setCurrentTimeMillis (long millis)    设置当前的"墙"时间,要求调用进程有许可权限。返回是否成功。
5、public static void sleep (long ms)    等待给定的时间。和Thread.sleep(millis)类似,但是它不会抛出InterruptedException异常。事件被推迟到下一个中断操作。该方法直到指定的时间过去才返回。
6、public static long uptimeMillis ()   返回系统启动到现在的毫秒数,不包含休眠时间。就是说统计系统启动到现在的非休眠期时间

Qcom平台 Sensor时间戳timestamp 简概

上一篇:[Celery分布式的异步任务框架]


下一篇:vue 简单版复制功能