当前位置: 首页 > news >正文

新乡营销网站建设公司哪家好/百度后台登陆入口

新乡营销网站建设公司哪家好,百度后台登陆入口,字节跳动员工人数多少,营销网站的建设欢迎交流~ 个人 Gitter 交流平台,点击直达: 偶然注意到PX4日志中老是出现类似于2000.01.01 00:00:00这种日期(有兴趣的可以搜索一下千年虫问题),于是结合代码进行了一波分析。 最后定位到gmtime_r(FAR const time_t *timer, FAR struct tm *…

欢迎交流~ 个人 Gitter 交流平台,点击直达:Gitter


偶然注意到PX4日志中老是出现类似于2000.01.01 00:00:00这种日期(有兴趣的可以搜索一下千年虫问题),于是结合代码进行了一波分析。

最后定位到gmtime_r(FAR const time_t *timer, FAR struct tm *result)这个函数以及struct tm这个结构体。

/** time.h* /
...
struct tm
{int tm_sec;     /* second (0-61, allows for leap seconds) */int tm_min;     /* minute (0-59) */int tm_hour;    /* hour (0-23) */int tm_mday;    /* day of the month (1-31) */int tm_mon;     /* month (0-11) */int tm_year;    /* years since 1900 */int tm_wday;    /* day of the week (0-6) */                         /*not supported by NuttX*/int tm_yday;    /* day of the year (0-365) */                       /*not supported by NuttX*/int tm_isdst;   /* non-0 if daylight savings time is in effect */   /*not supported by NuttX*/
};

PX4中所有输出的函数都是由tm这个结构体给出的。

这里需要注意到的是tm_year是从1900.01.01 00:00:00年开始计的。称为系统时间System Time。

gmtime_r()是根据从1970.01.01 00:00:00后的秒数换算过来的。称为格林威治时间/Unix time。

这实在是一件有意思的事情啊。

下面给出gmtime_r()函数的换算过程吧,有趣

/***************************************************************************** libc/time/lib_gmtimer.c* * Function:  gmtime_r** Description:*  Time conversion (based on the POSIX API)*****************************************************************************/FAR struct tm *gmtime_r(FAR const time_t *timer, FAR struct tm *result)
{time_t epoch;time_t jdn;int    year;int    month;int    day;int    hour;int    min;int    sec;/* Get the seconds since the EPOCH *//* 纪元开始 1970.01.01 00:00:00*/epoch = *timer;sdbg("timer=%d\n", (int)epoch);/* Convert to days, hours, minutes, and seconds since the EPOCH */jdn    = epoch / SEC_PER_DAY; // 天数epoch -= SEC_PER_DAY * jdn; // 减去 天数 * 一天的秒数hour   = epoch / SEC_PER_HOUR; // 小时数epoch -= SEC_PER_HOUR * hour; // 减去 小时数 * 一小时的秒数min    = epoch / SEC_PER_MIN; // 分钟数epoch -= SEC_PER_MIN * min; // 减去 分钟数 * 一分钟的秒数sec    = epoch; // 最终秒数sdbg("hour=%d min=%d sec=%d\n",(int)hour, (int)min, (int)sec);/* Convert the days since the EPOCH to calendar day */clock_utc2calendar(jdn, &year, &month, &day); // 确定日期,自1970.1.1之后的sdbg("jdn=%d year=%d month=%d day=%d\n",(int)jdn, (int)year, (int)month, (int)day);/* Then return the struct tm contents */result->tm_year = (int)year - 1900; /* Relative to 1900 */result->tm_mon  = (int)month - 1;   /* zero-based */result->tm_mday = (int)day;         /* one-based */result->tm_hour = (int)hour;result->tm_min  = (int)min;result->tm_sec  = (int)sec;return result;
}

上面调用了clock_utc2calendar函数,将UTC确定的天数转换成年月日。

#ifdef CONFIG_GREGORIAN_TIME // 公历时间/* Only handles dates since Jan 1, 1970 */
/* 处理1970.1.1之后的日期  */
static void clock_utc2calendar(time_t days, int *year, int *month, int *day)
{int  value;int  min;int  max;int  tmp;bool leapyear;/* There is one leap year every four years, so we can get close with the* following:*/value   = days  / (4*365 + 1);  /* Number of 4-years periods since the epoch 多少个四年 */days   -= value * (4*365 + 1);  /* Remaining days 剩余天数 */value <<= 2;                    /* Years since the epoch 左移两位,乘以4,得到从EPOCH后的年数 *//* Then we will brute force the next 0-3 years */// 简单匹配接下来的0到3年// 将剩下的天数分配到接下来的3年for (;;){/* Is this year a leap year (we'll need this later too) */leapyear = clock_isleapyear(value + 1970);/* Get the number of days in the year */tmp = (leapyear ? 366 : 365);/* Do we have that many days? */if (days >= tmp){/* Yes.. bump up the year */value++;days -= tmp;}else{/* Nope... then go handle months */break;}}/* At this point, value has the year and days has number days into this year */*year = 1970 + value;/* Handle the month (zero based) */min = 0;max = 11;do{/* Get the midpoint */value = (min + max) >> 1; // value = (min + max)/2/* Get the number of days that occurred before the beginning of the month* following the midpoint.*/tmp = clock_daysbeforemonth(value + 1, leapyear); // (value + 1)月开始前过了多少天了/* Does the number of days before this month that equal or exceed the* number of days we have remaining?*/if (tmp > days){/* Yes.. then the month we want is somewhere from 'min' and to the* midpoint, 'value'.  Could it be the midpoint?*/tmp = clock_daysbeforemonth(value, leapyear);if (tmp > days){/* No... The one we want is somewhere between min and value-1 */max = value - 1;}else{/* Yes.. 'value' contains the month that we want */break;}}else{/* No... The one we want is somwhere between value+1 and max */min = value + 1;}/* If we break out of the loop because min == max, then we want value* to be equal to min == max.*/value = min;}while (min < max);/* The selected month number is in value. Subtract the number of days in the* selected month*/days -= clock_daysbeforemonth(value, leapyear);/* At this point, value has the month into this year (zero based) and days has* number of days into this month (zero based)*/*month = value + 1; /* 1-based */*day   = days + 1;  /* 1-based */
}#endif /* CONFIG_GREGORIAN_TIME */

然后返回到gmtime_r()函数可以确定,struct tm结构体的赋值源头所在。

闲人看来是历史遗留问题,懒得改了。

最后的结论是,在使用tm的结构体时,要把年数加1900,月数加1,才能得到正确的UTC时间。

关于北京东八区的问题这里不再论述,之前在log日志正确显示的博文中已经有介绍,笔者觉得结合这篇博客看才是真。

然后回到2000.01.01这个日期上来,没有接收GPS的授时信息的情况下,默认时间会是它。而不是1970.01.01!显然这30年的差距得有代码站出来认了。

关于这个,系统默认时间

一个猜测是CLOCK_REALTIME与CLOCK_ACTIVETIME两个clk_id的选取

/* CLOCK_REALTIME refers to the standard time source.  For most implementations,* the standard time source is the system timer interrupt.  However, if the* platform supports an RTC, then the standard time source will be the RTC* for the clock_gettime() and clock_settime() interfaces (the system timer* is still the time source for all of the interfaces).*/#define CLOCK_REALTIME     0/* If an RTC is supported, then the non-standard CLOCK_ACTIVETIME is also* supported to manage time based on the system timer interrupt separately from* the RTC.  This may be necessary, for example, in certain cases where the* system timer interrupt has been stopped in low power modes.** CLOCK_ACTIVETIME is only recognized by clock_gettime() and clock_settime().*/#ifdef CONFIG_RTC
#  define CLOCK_ACTIVETIME 1
#else
#  define CLOCK_ACTIVETIME CLOCK_REALTIME
#endif

因为系统在确定当前时间时调用了这个函数

/** sdlog2.c*/
bool get_log_time_tt(struct tm *tt, bool boot_time) {struct timespec ts;px4_clock_gettime(CLOCK_REALTIME, &ts); // 请注意,时间由我定/* use RTC time for log file naming, e.g. /fs/microsd/2014-01-19/19_37_52.px4log */time_t utc_time_sec = 0;if (_gpstime_only && has_gps_3d_fix) {utc_time_sec = gps_time_sec;} else {utc_time_sec = ts.tv_sec + (ts.tv_nsec / 1e9);}if (utc_time_sec > PX4_EPOCH_SECS) {/* strip the time elapsed since boot */if (boot_time) {utc_time_sec -= hrt_absolute_time() / 1e6;}/* apply utc offset (min, not hour) */utc_time_sec += _utc_offset*60;struct tm *ttp = gmtime_r(&utc_time_sec, tt);return (ttp != NULL);} else {return false;}
}

px4_clock_gettime()的时间由clk_id决定,最后链接到clock_gettime()

/** px4_time.h*/
#elif defined(__PX4_LINUX) || defined(__PX4_NUTTX) || defined(__PX4_DARWIN)#define px4_clock_gettime clock_gettime
#define px4_clock_settime clock_settime

这里提一点:目前还是没有能够找到一个合适的编辑器查看PX4代码,时常会跳转错误。特别是涉及到NuttX后,非常多相同名称的函数,针对posix、qurt、NuttX的,还望细心。

/************************************************************************* Name: clock_gettime** Description:*   Clock Functions based on POSIX APIs*************************************************************************/int clock_gettime(clockid_t clock_id, struct timespec *tp)
{
#ifdef CONFIG_SYSTEM_TIME64uint64_t msecs;uint64_t secs;uint64_t nsecs;
#elseuint32_t msecs;uint32_t secs;uint32_t nsecs;
#endifint ret = OK;sdbg("clock_id=%d\n", clock_id);DEBUGASSERT(tp != NULL);/* CLOCK_REALTIME - POSIX demands this to be present. This is the wall* time clock.*/#ifdef CONFIG_RTCif (clock_id == CLOCK_REALTIME || clock_id == CLOCK_ACTIVETIME)
#elseif (clock_id == CLOCK_REALTIME)
#endif{/* Do we have a high-resolution RTC that can provie us with the time? */#ifdef CONFIG_RTC_HIRESif (g_rtc_enabled && clock_id != CLOCK_ACTIVETIME){/* Yes.. Get the hi-resolution time from the RTC */
/////////// 使用RTC //////ret = up_rtc_gettime(tp);}else
#endif{/* Get the elapsed time since power up (in milliseconds) biased* as appropriate.*//* 获取从系统上电后的时间 不上电不走数 */msecs = MSEC_PER_TICK * (g_system_timer - g_tickbias);sdbg("msecs = %d g_tickbias=%d\n",(int)msecs, (int)g_tickbias);/* Get the elapsed time in seconds and nanoseconds. */secs  = msecs / MSEC_PER_SEC;nsecs = (msecs - (secs * MSEC_PER_SEC)) * NSEC_PER_MSEC;sdbg("secs = %d + %d nsecs = %d + %d\n",(int)msecs, (int)g_basetime.tv_sec,(int)nsecs, (int)g_basetime.tv_nsec);/* Add the base time to this. */secs  += (uint32_t)g_basetime.tv_sec;nsecs += (uint32_t)g_basetime.tv_nsec;/* Handle carry to seconds. */if (nsecs > NSEC_PER_SEC){uint32_t dwCarrySecs = nsecs / NSEC_PER_SEC;secs  += dwCarrySecs;nsecs -= (dwCarrySecs * NSEC_PER_SEC);}/* And return the result to the caller. */tp->tv_sec  = (time_t)secs;tp->tv_nsec = (long)nsecs;}sdbg("Returning tp=(%d,%d)\n", (int)tp->tv_sec, (int)tp->tv_nsec);}else{sdbg("Returning ERROR\n");errno = EINVAL;ret = ERROR;}return ret;
}

其中RTC的几个宏定义如下

/** rtc.h*/
/***************************************************************************** Pre-processor Definitions****************************************************************************/
/* Configuration ************************************************************/
/* CONFIG_RTC - Enables general support for a hardware RTC.  Specific*   architectures may require other specific settings.** CONFIG_RTC_DATETIME - There are two general types of RTC:  (1) A simple*   battery backed counter that keeps the time when power is down, and (2)*   A full date / time RTC the provides the date and time information, often*   in BCD format.  If CONFIG_RTC_DATETIME is selected, it specifies this*   second kind of RTC. In this case, the RTC is used to "seed" the normal*   NuttX timer and the NuttX system timer provides for higher resoution*   time.** CONFIG_RTC_HIRES - If CONFIG_RTC_DATETIME not selected, then the simple,*   battery backed counter is used.  There are two different implementations*   of such simple counters based on the time resolution of the counter:*   The typical RTC keeps time to resolution of 1 second, usually*   supporting a 32-bit time_t value.  In this case, the RTC is used to*   "seed" the normal NuttX timer and the NuttX timer provides for higher*   resoution time.**   If CONFIG_RTC_HIRES is enabled in the NuttX configuration, then the*   RTC provides higher resolution time and completely replaces the system*   timer for purpose of date and time.** CONFIG_RTC_FREQUENCY - If CONFIG_RTC_HIRES is defined, then the frequency*   of the high resolution RTC must be provided.  If CONFIG_RTC_HIRES is*   not defined, CONFIG_RTC_FREQUENCY is assumed to be one.** CONFIG_RTC_ALARM - Enable if the RTC hardware supports setting of an*   alarm.  A callback function will be executed when the alarm goes off*/

CONFIG_RTC_HIRES的说明可以看出,定义了此项后,有飞控板上的纽扣电池支持断电情况下的计时器工作,并且精度也是高高的。

那么问题来了。
经过实际测试,编写时间获取程序,发现,时间是在系统上电时才增加。

int fantasy_test_main(int argc, char *argv[])
{PX4_INFO("Hello Sky!");time_t timeSec = time(NULL);//1970.01.01struct tm tt;struct tm *timeinfo = gmtime_r(&timeSec, &tt);PX4_INFO("The time is %d-%d-%d  %d:%d:%d  \n",\timeinfo->tm_year+1900,\timeinfo->tm_mon+1,\timeinfo->tm_mday,\timeinfo->tm_hour,\timeinfo->tm_min,\timeinfo->tm_sec);return 0;
}

时间一直是从2000.01.01 00:00:00开始的,并且只有USB上电时间才增加,难道电池没电?


而GPS给出的UTC秒数,由下列代码可以看出

#
# vehicle_gps_position.msg
#
uint64 time_utc_usec        # Timestamp (microseconds, UTC), this is the timestamp which comes from the gps module. It might be unavailable right after cold start, indicated by a value of 0 

最后的总结,确定当前系统时间时,先获取已经经过的秒数,再调用struct tm *timeinfo = gmtime_r(&timeSec, &tt);就能获取tm的时间了。

先接受一次GPS卫星授时吧,需要3d fix。

关于RTC时间,再看。


             
                            By Fantasy

http://www.lbrq.cn/news/2089.html

相关文章:

  • 网站做分布式部署/今日最新的新闻
  • 温州网站设计案例/网络营销实训总结报告
  • wordpress里验证谷歌站长/2345手机浏览器
  • 惠州网站建设哪家好/com域名
  • 上海千樱网站建设/拉新推广怎么找渠道
  • 政府网站一般用什么做/外贸企业网站推广
  • jsp网站怎么做的好看/ip域名查询地址
  • 朝阳做网站/seo研究中心超逸seo
  • 小团队兼职做网站/自动点击竞价广告软件
  • 网站服务器有什么用/seo搜索引擎
  • 网站建设 财务归类/爱站长尾词挖掘工具
  • 全国企业查询网上查询/dz论坛seo
  • 建设工程个人信息采集哪个网站/长春网站建设方案报价
  • 微信公众号 手机网站开发/免费拓客软件排行榜
  • 自己网站建设问题/网上教育培训机构
  • 企业网站前期建设方案案例/百度指数有什么作用
  • 济南建设官方网站/排名优化哪家专业
  • 阿里云里做网站能上百度首页么/手机百度识图网页版入口
  • 成都工信部网站/山东搜索引擎优化
  • 做网站建设的联系电话/的网站建设
  • 网站建设 响应式/徐州百度seo排名
  • 网站备案号超链接怎么做/脚上起小水泡还很痒是怎么回事
  • 网站 用户体验 考虑/成人职业技能培训有哪些项目
  • 物流公司做网站注重什么/360搜索指数
  • 查看wordpress插件/移动端排名优化软件
  • 旅游响应式网站建设/站长之家源码
  • 网站建设公司的服务公司/百度搜索引擎怎么弄
  • 做安全宣传的是什么网站/怎么在百度上打广告
  • 网站建设公司哪个好呀金融网站建设/精准粉丝引流推广
  • seo网站建设/万网域名交易
  • C语言指针完全指南:从入门到精通
  • 神经网络-local minima and saddle point
  • 数模个人笔记
  • 学习Java的Day28
  • 从 AI 到实时视频通道:基于模块化架构的低延迟直播全链路实践
  • 【传奇开心果系列】Flet框架实现的功能丰富设计现代化的管理仪表盘组件自定义模板