Перенацеливание новой библиотеки для c chrono

#c #chrono #cortex-m #newlib

#c #c -chrono #cortex-m #новая библиотека

Вопрос:

Я использую набор инструментов arm-none-eabi с newlib для нацеливания на пользовательскую плату с ARM Cortex-M0 (в частности, на версию набора инструментов MCU-on-eclipse). Я компилирую / связываю с -nostartfiles и --specs=nano.specs и перенастроил stdout и stderr на USB и последовательный порт соответственно. Я создал реализации для большинства системных вызовов C.

Я использую библиотеку 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: %lldn Time 2: %lldn", 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 () стандартных часов chrono? или, может быть, вся реализация clock с моими собственными параметрами типа duration и rep, которые лучше соответствуют аппаратному обеспечению? Я могу перегрузить new и delete для своей встроенной системы (и должен), поэтому сделать это для chrono также было бы неплохо.

Ответ №1:

Из gccs libstdc chrono.cc :

  • system_clock::now() использует gettimeofday(amp;tv, 0); или clock_gettime(CLOCK_REALTIME, amp;tp); или системный вызов. Если gettimeofday у вас работает, это означает, что он его использует.
  • steady_clock::now() использует clock_gettime(CLOCK_MONOTONIC, amp;tp); . Таким образом, вы должны перегрузить clock_gettime и обработать CLOCK_MONOTONIC аргумент.
  • В newlib нет такой _clock_gettime_r функции, как в _gettimeofday_t , которая передает newlib struct reent по кругу. Если вы хотите обрабатывать многопоточность внутри newlib, неплохо написать свою собственную аналогичную оболочку, которая обрабатывает _reent->errno значение. Но ставка была бы на перегрузку _gettimeofday_r функции, поскольку вы нацелены только на newlib.

Комментарии:

1. похоже, что работает только gettimeofday, что означает, что моя копия была скомпилирована с _GLIBCXX_USE_GETTIMEOFDAY вместо _GLIBCXX_USE_CLOCK_REALTIME . В структуре возврата нет никаких указаний на тип запрашиваемых часов, поэтому мне, вероятно, пришлось бы перекомпилировать libstdc , чтобы заставить clock_gettime () работать. спасибо за ссылки на код.

2. _GLIBCXX_USE_GETTIMEOFDAY влияет system_clock::now() . Поскольку libstdc for arm-none-eabi-gcc компилируется без _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL необходимости предоставления определения extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp); . clk_id Точно используется для указания часов…

Ответ №2:

Вместо того, чтобы пытаться изменить поведение 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 секунд.

Если вы можете превратить ваше низкоуровневое «сейчас» в количество тактов по отношению к некоторой эпохе, и вы можете описать эти такты как доли секунды во время компиляции с помощью period , тогда все в порядке.

Комментарии:

1. Это то, что я делаю сейчас, с моими пользовательскими часами в заголовке sealChrono.h (это фреймворк на основе ластоногих), который затем включает chrono и date.h (кстати, потрясающая библиотека!). Я просто надеялся / экспериментировал с тем, чтобы сделать фреймворк более прозрачным для пользователя. Однако перекомпиляция стандартной библиотеки немного выходит за рамки, поэтому я, вероятно, буду придерживаться этого решения.