Как вы реализуете printf в GCC от Newlib? - PullRequest
0 голосов
/ 06 марта 2019

Я изо всех сил пытаюсь правильно реализовать printf из newlib в моем esp32, используя GCC.

Я просмотрел документацию по newlib, и она дает мне общую информацию о том, как вызывается printf, но не объясняет мне внутреннюю реализацию.

Исходя из моих текущих исследований, я определил, что printf выводит отформатированную строку в STDOUT. На ПК это было проще для понимания, потому что есть консольное окно, в котором отображался бы форматированный вывод printf, однако во встроенной системе я понимаю, что вы должны указать библиотеке, куда перенаправлять форматированный вывод printf, и вот что Я пытаюсь понять.

Опять же, основываясь на моих исследованиях, я понял, что для этого необходимы некоторые функции, в частности, функция _write.

Мне очень трудно понять, как сократить разрыв между printf и использованием функции _write. Я надеюсь, что кто-то здесь может помочь мне понять, как правильно реализовать printf.

И если я пропустил какую-то документацию, которая ясно объясняет это, тогда, пожалуйста, перенаправьте меня на это. Я попытался прочитать документацию newlib, а также документацию, связанную с GCC, но в действительности ничего не упоминает, как использовать printf, но есть много документации о том, как вызывать printf и форматировать строку, но эта часть проста. Мне нужно знать, как получить отформатированную строку из стандартного вывода MCU.

Спасибо всем!

1 Ответ

0 голосов
/ 06 марта 2019

В Newlib вы не реализуете printf(), который включен в библиотеку. Вы просто реализуете минимальный набор системных вызовов для поддержки библиотеки. API sycalls потокового устройства включает в себя open, close, read и write (или реентерабельные версии с суффиксом _r) - реентерабельность в этом полезна, если вы используете многопоточность и вам требуется на поток errno (среди любых требований повторного входа для конкретной реализации).

Если все, что вы реализуете, это stdout (поток, используемый printf(), putchar(), puts() и т. Д.) И поддерживает только одно устройство (обычно UART) и не беспокоится о возможности для перенаправления или повторного входа, тогда open, close и read могут быть пустыми, а write может просто вывести предоставленный буфер непосредственно в ваш низкоуровневый API последовательного ввода / вывода:

int _write(int handle, char *data, int size ) 
{
    int count ;

    handle = handle ; // unused

    for( count = 0; count < size; count++) 
    {
        outputByte( data[count] ) ;  // Your low-level output function here.
    }

    return count;
}

Обратите внимание, что handle здесь не используется. Для stdout это будет 1 (stdin = 0 и stderr = 2). Аргумент handle будет использоваться, если вам нужны отдельные устройства вывода для stdout и stderr или если вы поддерживаете дополнительные устройства или файловую систему и перенаправление fopen или stdout. Он используется для идентификации пара, открытого по open. Игнорируя все выходные данные потока (такие как fprintf(), будут обрабатываться одинаково и выводиться на одно и то же устройство); во многих случаях (где printf() - это просто средство получения отладочной информации, или у вашего приложения нет файловой системы, вам все равно.

Учитывая, что функция write, printf() будет "просто работать" (самым простым способом), потому что под капотом все функции вывода stdio вызывают write). Рекомендуется использовать низкоуровневую выходную функцию с буферизацией и неблокированием (например, драйвер UART с прерыванием).

Очевидно, что если вы хотите принять ввод на stdin, вы бы реализовали аналогичную функцию read.

Если вам нужна куча (malloc() и т. Д.), Вам также необходимо реализовать sbrk / sbrk_r. Я бы посоветовал вам, по крайней мере, реализовать это в системных вызовах Newlib.

Более сложный подход к реализации системных вызовов обсуждается Биллом Гейтлиффом в Портирование и использование Newlib во встроенных системах , в то время как базовая реализация обсуждается в здесь , в то время как пример минимальных заглушек реализации похож на все вышеперечисленное предусмотрено в самой документации Newlib .

...