为 C++ chrono 重定向 newlib
Retargeting newlib for c++ chrono
我正在使用带有 newlib 的 arm-none-eabi 工具链来针对带有 ARM Cortex-M0+ 的自定义板(特别是 MCU-on-eclipse 版本的工具链)。我是 compiling/linking,-nostartfiles
和 --specs=nano.specs
,并且分别将 stdout 和 stderr 重新定位到 USB 和串行端口。我已经为大多数 C 系统调用创建了实现。
我正在使用带有两个 custom clock 的 chrono 库,now() 函数获取 RTC 时间或我的系统计时器。这似乎反映了标准 steady_clock 和 system_clock 的目的,所以我可以尝试使用它们。
为此我必须实现我所做的 gettimeofday 系统调用
// returning a set time of one second just for testing
int _gettimeofday(struct timeval* tv, void* tz) {
tv->tv_sec = 1;
tv->tv_usec = 255;
return 0;
}
我的主要代码如下:
int main(void)
{
HWInit();
static std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
static std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
int64_t count1 = t1.time_since_epoch().count();
int64_t count2 = t2.time_since_epoch().count();
printf("Time 1: %lld\n Time 2: %lld\n", count1, count2);
for(;;){}
return 0;
}
使用调试器我可以看到 steady_clock::now()
和 sysytem_clock::now()
都调用了我的 _gettimeofday() 函数,并且都以完全相同的时间点结束。
当然,如果我尝试执行以下操作,我会遇到多个定义错误:
using SysClock = std::chrono::system_clock;
SysClock::time_point SysClock::now() noexcept {
return SysClock::time_point( SysClock::duration(1983) );
}
那么我能否以某种方式重载标准计时时钟的 now() 函数?或者也许整个时钟实现与我自己的持续时间和更匹配硬件的 rep typedef?我可以为我的嵌入式系统重载 new 和 delete(并且应该),所以为 chrono 这样做也很好。
system_clock::now()
使用 gettimeofday(&tv, 0);
或 clock_gettime(CLOCK_REALTIME, &tp);
或系统调用。如果 gettimeofday
适合你,那就意味着它会使用它。
steady_clock::now()
使用 clock_gettime(CLOCK_MONOTONIC, &tp);
。所以你应该重载 clock_gettime
并处理 CLOCK_MONOTONIC
参数。
- newlib 没有提供
_clock_gettime_r
函数,而 _gettimeofday_t
中的函数传递了 newlib 的 struct reent
。如果您想在 newlib 中处理多线程,最好编写您自己的类似包装器来处理 _reent->errno
值。但赌注是重载 _gettimeofday_r
函数,因为你只针对 newlib.
与其尝试更改 system_clock
和 steady_clock
的行为,我建议您只编写自己的自定义时钟并使用它们。这样您就可以更好地根据您的硬件和需求定制它们。如果你有办法获取当前时间,创建一个自定义 chrono
时钟来封装该函数是非常容易的。
class SysClock
{
public:
// 500MHz, or whatever you need
using period = std::ratio<1, 500'000'000>;
using rep = long long;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<SysClcok>;
static constexpr bool is_steady = true;
static time_point now() noexcept
{
return time_point{duration{
/*turn SysTick_getValue() into the number of ticks since epoch*/}};
}
};
现在在您的代码中使用 SysClock::now()
而不是 system_clock::now()
。这给你 SysClock::time_point
和 chrono::durations
减去两个 SysClock::time_point
的结果。
如果您可以将您的低级 "now" 转换为某个时期的滴答计数,并且您可以使用 period
将这些滴答描述为编译时秒的分数,然后你可以开始了。
我正在使用带有 newlib 的 arm-none-eabi 工具链来针对带有 ARM Cortex-M0+ 的自定义板(特别是 MCU-on-eclipse 版本的工具链)。我是 compiling/linking,-nostartfiles
和 --specs=nano.specs
,并且分别将 stdout 和 stderr 重新定位到 USB 和串行端口。我已经为大多数 C 系统调用创建了实现。
我正在使用带有两个 custom clock 的 chrono 库,now() 函数获取 RTC 时间或我的系统计时器。这似乎反映了标准 steady_clock 和 system_clock 的目的,所以我可以尝试使用它们。
为此我必须实现我所做的 gettimeofday 系统调用
// returning a set time of one second just for testing
int _gettimeofday(struct timeval* tv, void* tz) {
tv->tv_sec = 1;
tv->tv_usec = 255;
return 0;
}
我的主要代码如下:
int main(void)
{
HWInit();
static std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
static std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
int64_t count1 = t1.time_since_epoch().count();
int64_t count2 = t2.time_since_epoch().count();
printf("Time 1: %lld\n Time 2: %lld\n", count1, count2);
for(;;){}
return 0;
}
使用调试器我可以看到 steady_clock::now()
和 sysytem_clock::now()
都调用了我的 _gettimeofday() 函数,并且都以完全相同的时间点结束。
当然,如果我尝试执行以下操作,我会遇到多个定义错误:
using SysClock = std::chrono::system_clock;
SysClock::time_point SysClock::now() noexcept {
return SysClock::time_point( SysClock::duration(1983) );
}
那么我能否以某种方式重载标准计时时钟的 now() 函数?或者也许整个时钟实现与我自己的持续时间和更匹配硬件的 rep typedef?我可以为我的嵌入式系统重载 new 和 delete(并且应该),所以为 chrono 这样做也很好。
system_clock::now()
使用gettimeofday(&tv, 0);
或clock_gettime(CLOCK_REALTIME, &tp);
或系统调用。如果gettimeofday
适合你,那就意味着它会使用它。steady_clock::now()
使用clock_gettime(CLOCK_MONOTONIC, &tp);
。所以你应该重载clock_gettime
并处理CLOCK_MONOTONIC
参数。- newlib 没有提供
_clock_gettime_r
函数,而_gettimeofday_t
中的函数传递了 newlib 的struct reent
。如果您想在 newlib 中处理多线程,最好编写您自己的类似包装器来处理_reent->errno
值。但赌注是重载_gettimeofday_r
函数,因为你只针对 newlib.
与其尝试更改 system_clock
和 steady_clock
的行为,我建议您只编写自己的自定义时钟并使用它们。这样您就可以更好地根据您的硬件和需求定制它们。如果你有办法获取当前时间,创建一个自定义 chrono
时钟来封装该函数是非常容易的。
class SysClock
{
public:
// 500MHz, or whatever you need
using period = std::ratio<1, 500'000'000>;
using rep = long long;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<SysClcok>;
static constexpr bool is_steady = true;
static time_point now() noexcept
{
return time_point{duration{
/*turn SysTick_getValue() into the number of ticks since epoch*/}};
}
};
现在在您的代码中使用 SysClock::now()
而不是 system_clock::now()
。这给你 SysClock::time_point
和 chrono::durations
减去两个 SysClock::time_point
的结果。
如果您可以将您的低级 "now" 转换为某个时期的滴答计数,并且您可以使用 period
将这些滴答描述为编译时秒的分数,然后你可以开始了。