Hallo zusammen,
ich sitze an einem BareMetall-Programm für den (CortexM4 des i.MX8MM)
und möchte der PRINTF-Funktion von NXP einen Loglevel hinzufügen. Die
PRINTF-Funktion unterstützt eine variable Anzahl an Argumenten.
Dazu möchte ich ebenfalls eine Log-Funktion mit Variabler Anzahl von
Argumenten implementieren, die nach dem Loglevel schaut und - sofern er
paßt - einfach die Argumente 1:1 an die PRINTF-Funktion von NXP
weitergibt.
Weiß jemand wie das geht? Eine Anzahl variabler Argumente einfach an
einen Call weitergeben?
Vielen Dank für Eure Hilfe,
Christoph
Jörg W. schrieb:> vprintf bzw. vfprintf is your friend
Danke Dir. Freunde schon, die Nützlichkeit sehe ich gerade nicht so.
vprintf will auch printen, das muss jedoch die PRINTF-Funktion von nxp,
welche es auf dem UART ausgibt und vfprintf möchte einen FILE-Pointer
als Ziel beglücken.
Ich bewege mich bare-metall auf dem CortexM4. Programmiersprache ist C.
Christoph F. schrieb:> Ich bewege mich bare-metall auf dem CortexM4. Programmiersprache ist C.
Ja, und? Habe ich auch oft genug gemacht. Die Standardbibliothek bei
ARM-GCC ist typischerweise ja eine newlib, und die hat die komplette
printf-Familie an Bord. Man muss dann halt nur das Backend
implementieren (_write in diesem Falle).
Heißt die Funktion wirklich PRINTF (in Großbuchstaben)? Dann hast du so
keine Chance. Wenn sie kein "v"-Pendant dazu liefern, dem man eine
va_list als Argument überreichen kann, ist deine Aufgabe so schlicht
nicht lösbar.
Jörg W. schrieb ...:
> vprintf bzw. vfprintf is your friend
So grundsätzlich war das mit dem v und printf schon gut. Mit vsnprintf()
aus dem Hause "stdio.h" bin ich nun glücklich geworden.
> Heißt die Funktion wirklich PRINTF (in Großbuchstaben)?
Ja. Ist leider so.
Herzlichen Dank für die schnellen und guten Tipps.
-Christoph
Christoph F. schrieb:> So grundsätzlich war das mit dem v und printf schon gut. Mit vsnprintf()> aus dem Hause "stdio.h" bin ich nun glücklich geworden.
Naja gut, musst du halt erst einen Puffer bereitstellen und dann hoffen,
dass er immer groß genug ist.
>> Heißt die Funktion wirklich PRINTF (in Großbuchstaben)?> Ja. Ist leider so.
Würde ich wegwerfen und durch Standard-printf ersetzen bzw. habe dies
auch so getan.
Das PRINTF von NXP ist ein Macro, das wahlweise in DbgConsole_Printf
oder das gewöhnliche printf expandiert wird. Natürlich kann man das
printf auch direkt aufrufen.
Man könnte auch das Macro printf (also gleich wie die zugrundeliegende
Bibliotheksfunktion) nennen, nur ist dann nicht mehr direkt ersichtlich,
dass es sich um ein Macro handelt.
Man könnte aber auch das Backend so umbauen, dass es die Funktion dieses
DbgConsole_Printf abstrahiert. Dann braucht man den Makro-Kram nicht,
und kann sogar zur Laufzeit umschalten, wenn man will.
Bei uns sieht das dann ungefähr so aus:
1
freopen(":uart0","r",stdin);
2
freopen(":uart0","w",stdout);
3
#ifdef DEBUG
4
freopen(":uart1","w",stderr);
5
#else
6
freopen(":null","w",stderr);
7
#endif
_open durchläuft dann für all Gerätedateinamen (mit Doppelpunkt
beginnend) eine Liste von vorher registrierten Treibern. Alle anderen
Namen gehen auf die SD-Karte, sofern eine solche in der Konfiguration
vorhanden ist.
Jetzt könnte man da statt des : ein ∕dev∕ davor stellen und davon auch
ein Directory-Listing anbieten, dann ist es schon fast wie auf einem
Unix-System.
Jörg W. schrieb:> Naja gut, musst du halt erst einen Puffer bereitstellen und dann hoffen,> dass er immer groß genug ist.
So ein Tipp in dieser Zeit... hoffentlich kein IoT-Device. ;-))
Rolf M. schrieb:> Jetzt könnte man da statt des : ein ∕dev∕ davor stellen und davon auch> ein Directory-Listing anbieten, dann ist es schon fast wie auf einem> Unix-System.
Ja, fand ich nur nicht weiter nützlich. Der einzelne Doppelpunkt tut's
auch (und ist insbesondere viel einfacher zu analysieren als ein
abschließender Doppelpunkt wie in "LPT1:" oder "NUL:"). Klar ist die
newlib Posix-zentrisch aufgebaut, das sieht man an den
Backend-Funktionen, auf denen sie aufsetzen möchte (die letztlich
Posix-Syscalls sind), aber für eine simple MCU muss man das auch nicht
übertreiben.
(prx) A. K. schrieb:>> Naja gut, musst du halt erst einen Puffer bereitstellen und dann hoffen,>> dass er immer groß genug ist.>> So ein Tipp in dieser Zeit... hoffentlich kein IoT-Device. ;-))
Er schrieb ja was von vsnprintf(), also wird er wohl hoffentlich die
passende Länge übergeben. Ist dann trotzdem doof, wenn von "Diese
Meldung ist superla" die letzten Buchstaben abgeschnitten werden …
Jörg W. schrieb:> Christoph F. schrieb:>>> Mit vsnprintf() aus dem Hause "stdio.h" bin ich nun glücklich geworden.>> Naja gut, musst du halt erst einen Puffer bereitstellen und dann hoffen,> dass er immer groß genug ist.
Das tut die Funktion von NXP auch. Die vsnprintf() hat die Pufferlänge
als Argument, sollte also - oberflächlich betrachtet - sicher sein und
die Ausgaben kürzen.
Das SDK von NXP soll in dem Projekt unangetastet bleiben, damit es
einfacher getauscht werden kann.
Es geht auch nur um ein paar eigene Hilfs-Ausgaben (debug/info/error) in
der Geräteinternen i.MX8MM/CM4-Console, wo nur Entwickler dran kommen.
Für eine saubere Schnittstelle an die der Endkunde ebenfalls ran kommt,
ist so etwas indiskutabel. Da würde ich direkt auf dem UART-Modul
aufsetzen, sofern eine UART-Schnittstelle dafür wiederum überhaupt in
Frage käme. Der i.MX8 hat da geschickteres im Bauch.
Danke euch, für mich passt es erst mal.
Christoph F. schrieb:> Das tut die Funktion von NXP auch. Die vsnprintf() hat die Pufferlänge> als Argument, sollte also - oberflächlich betrachtet - sicher sein und> die Ausgaben kürzen.
Ich wollte auch keine Pufferüberläufe unterstellen sondern eben eher den
oben beschriebenen Fall ("640 Kilobyte genügen für jeden" :), bei dem
dann vielleicht der interessante Teil der Ausgabe wegfällt, weil er
nicht mehr gepasst hat.
Die normale printf-Familie hat das Problem nicht, weil sie nicht
zwingend alles puffern muss, sondern dann ans Gerät rausschreibt.
Christoph F. schrieb:> Dazu möchte ich ebenfalls eine Log-Funktion mit Variabler Anzahl von> Argumenten implementieren
Es ist einfacher, wenn du ein log-Makro implementierst. Dann brauchst du
auch keine "v" Variante der NXP Funktion.
Christoph F. schrieb:> Hallo zusammen,>> ich sitze an einem BareMetall-Programm für den (CortexM4 des i.MX8MM)> und möchte der PRINTF-Funktion von NXP einen Loglevel hinzufügen. Die> PRINTF-Funktion unterstützt eine variable Anzahl an Argumenten.>> Dazu möchte ich ebenfalls eine Log-Funktion mit Variabler Anzahl von> Argumenten implementieren, die nach dem Loglevel schaut und - sofern er> paßt - einfach die Argumente 1:1 an die PRINTF-Funktion von NXP> weitergibt.>> Weiß jemand wie das geht? Eine Anzahl variabler Argumente einfach an> einen Call weitergeben?>> Vielen Dank für Eure Hilfe,> Christoph
1
externintlog_level
2
3
constchar*level_strings[]{
4
"[DEBUG]: ",
5
"[INFO ]: ",
6
"[WARN ]: ",
7
"[ERROR]: "
8
};
9
10
// kleiner Trick, damit die Funktion auch ohne Formatier-Parameter funktioniert.