Forum: Projekte & Code Open Source Projekt TRICE - ein Software-Tracer & Logger für alle µC: PIC, AVR, ARM, TI, Infinion,..


von Thomas H. (rokath)


Angehängte Dateien:

Lesenswert?

Wenn Log-Ausgaben mit printf oder einfach puts nicht oder schwer 
möglich sind, etwa im Interrupt oder Scheduler, instrumentiere den Code 
mit **TRICE**. Dadurch sinkt der Gesamt-Flashspeicherbedarf da nur 
etwa 150 Bytes Code hinzukommen, aber man erhält dafür den ganzen Platz 
den bisher die Logstrings und der printf Library Code benötigten. Man 
kann damit auch wunderbar Zeitmessungen machen, da ein TRICE sehr 
schnell geht.

Siehe https://github.com/rokath/trice

Die maschinell in Deutsch übersetzte Version:
https://translate.google.com/translate?sl=en&tl=de&u=https://github.com/rokath/trice

Nicht von der Doku abschrecken lassen, es sollte ganz ganz einfach zu 
benutzen sein für alle Arten von Prozessoren.

Gerne hätte ich dazu Feedback und wenn jemand eine Portierung beisteuern 
möchte, wäre das toll.

von eeeeeee (Gast)


Lesenswert?

Die Firma heißt Infineon.  :-)

von Thomas H. (rokath)


Lesenswert?

Danke, kann es leider nicht mehr korrigieren...

von David M. (milo-d)


Lesenswert?

Hallo,

ich finde das Projekt sehr interessant. Gefällt mir ^^ Das Blockdiagramm 
ist auch sehr gelungen. Schade, dass sich hier nur so wenige gemeldet 
haben.

Ich hätte da eine Frage. Bei folgender Signatur:
1
 Trice8_2i( "sig:task %d -> %d: ", previousTaskID, nexTaskID );

Gibt es einen bestimmten Grund aus dem du keine variadischen Argumente 
akzeptierst ? Damit könnte man sich den Suffix _2i bzw. _ni sparen.

Ich kenne mich mit dem TRICE Quellcode nicht aus, deswegen gehe ich 
davon aus, dass dies schon seine Gründe hat ^^ Wollte diese hier nur mal 
kurz erfragen ^^

Wenn ich mal wieder was mit den stm32 boards mache, werde ich auf TRICE 
zurück kommen.

Danke für die Software :)

von Thomas H. (rokath)


Lesenswert?

Sorry David, habe Deine Frage eben erst gesehen.

Zunächst: Es ist **kein** STM32 spezifisches Projekt, sondern sollte auf 
jedem Mikrocontroller laufen.

Variadic Arguments habe ich aus zwei Gründen vermieden:

1. Laufzeit: So ein TRICE Makro soll schnellstmöglich ausgeführt werden. 
Jegliche variadischen Argumente würden dies verlangsamen. Initial kannst 
Du
einfach schreiben ```Trice8i( "sig:task %d -> %d: ", previousTaskID, 
nexTaskID );``` oder ```Trice8( "sig:task %d -> %d: ", previousTaskID, 
nexTaskID );``` und `trice u` wird `_2` automatisch einfügen zusammen 
mit der generierten Id(123).

2. CompileTime Check: Wenn Du z.B. im Code hast ```printf( "%d", a, b 
):``` oder ```printf( "%d%d", a);``` bemerkst Du das Problem 
normalerweise erst zur Laufzeit, also beim Debuggen/Testen. Ein 
```TRICE8( "%d%d", a);``` wird mit `trice u` zu ```TRICE8_2( Id(123), 
"%d%d", a);``` da ```trice u``` nur die Formatspezifier auswertet. Der 
Compiler wird aber einen Fehler melden, da die Parameterzahl nicht 
stimmt und Du kannst es korrigieren.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Thomas H. schrieb:
> Variadic Arguments habe ich aus zwei Gründen vermieden:

Beide Gründe treffen aber nicht zu. David meinte ein sog. Variadic 
Macro. Das wird zur Compilezeit vom Preprocessor umgesetzt.

Beispiele für ein Variadic Macro:
1
#define eprintf(...) fprintf (stderr, __VA_ARGS__)
Auch hier ist es ein Macro mit CompileTime-Check, d.h. Anzahl und Typen 
der Argumente werden at Compile Time überprüft.

Siehe auch https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

: Bearbeitet durch Moderator
von Thomas H. (rokath)


Lesenswert?

Vielleicht hast Du irgendwie recht, Frank, und es wäre toll einfach nur
1
TRICE8( Id(123), "%d%d", a, b);
final im Code zu haben.
Augenblicklich aber keine Idee wie das ohne Laufzeit 
Geschwindigkeitsverlust Compiler unabhängig umsetzbar wäre.
Wenn Du beispielsweise auf diese beiden Definitionen aus der FLEX 
Codierung schaust:
1
#define TRICE8_1i( id, pFmt, d0 ) do{ \
2
    TRICE_HTON_U32PUSH( id|0x0100|triceCycle ); \
3
    triceCycle++; \
4
    TRICE_HTON_U32PUSH( (uint8_t)(d0) ); \
5
} while(0)
6
7
#define TRICE8_2i( id, pFmt, d0, d1 ) do{ \
8
    TRICE_HTON_U32PUSH( id|0x0200|triceCycle ); \
9
    triceCycle++; \
10
    TRICE_HTON_U32PUSH( TRICE_U8_JOIN(d0,d1) ); \
11
} while(0)

Wie könnte dann TRICE8 als variadic Macro geschrieben werden? Wenn es 
dafür eine akzeptable Lösung gibt setze ich das gerne um.

(Mod: C-Formatierung korrigiert)

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Thomas H. schrieb:
> Wie könnte dann TRICE8 als variadic Macro geschrieben werden?

Hm, das wird wohl dann doch komplizierter, wenn nicht gar unmöglich. 
Dazu müsste ich mir mal in Ruhe die anderen Makros wie 
TRICE_HTON_U32PUSH und TRICE_U8_JOIN anschauen. Leider habe ich für den 
Rest des Abends keine Zeit, vielleicht morgen.

von Klaus H. (klummel69)


Lesenswert?

Hi Thomas,

schönes Projekt! Den Ressourcenverbrauch von printf auf kleinen µC hat 
mich auch immer gestört.
Und warum soll ein µC sich mit der Konvertierung rumschlagen, wenn ich 
das Ganze sowieso nur über die Schnittstelle am PC ausgebe. Ich habe 
etwas ähnliches gebastelt aber das ist nicht so ausgereift wie dein 
Projekt (Läuft immerhin auf STM32 und AVRs).
Hier ein bisschen Feedback von mir (wobei das eher persönlicher 
Geschmack ist, das Projekt ist gut umgesetzt. Sorry, falls ich was 
übersehen habe.)

* Die Idee mit der automatischen Instrumentierung und der Vergabe der 
IDs ist OK. Ich bin allerdings kein Freund davon Sourcecode zu 
überschreiben. Hatte mal Probleme mit einem Tool, das Code 
instrumentalisiert hat und dabei einen Fehler eingebaut hat. Aber mit 
ordentlichen Diff Tools ist sowas ja durchaus aufdeckbar.

* Fliesskomma Typen sind bisher nicht berücksichtigt, oder? Zumindest 
für ARM Controller sinnvoll.

* Ich würde in der Datei til.json noch Dateiname und Sourcecodezeile 
speichern. Dann kann diese gleich bei der Ausgabe mit angegeben werden. 
Ich liebe es, wenn man aus dem Log-Fenster mit Klick direkt in den Code 
springen kann. (Gefahr ist natürlich, dass die Zeilennummern bei 
vergessenem Update nicht mehr passen).

* Die Encrypt Idee ist Klasse. Für "einfachen" Schutz gut nutzbar.

* Ich hätte die Endianess Unterscheidung weggelassen. Sowas kann auch 
die Empfängerseite machen.

* Schön auch die Einbindung der RTT Schnittstelle. Deutlich performanter 
als vieles andere.

* Das Variadic Macro Problem hatte ich auch. Eine bessere Lösung hatte 
ich auch nicht.

* Das Makro ``#define Id(n) (n)`` halte ich für gefährlich. Den 
Bezeichner "Id" nutze ich immer mal wieder. Könnte zu Kollisionen mit 
anderen Modulen kommen. Besser wäre einen eigenen Namensraum per Makro 
Prefix zu nutzen, z.B. ``#define TRICE_ID(n) (n)``. Noch sicherer: einen 
eigenen Datei-Typ definieren. Dann meckert ggf der Compiler.

* Mir fehlt noch ein Wrapper für Logging, so dass je Modul und Loglevel 
Meldungen statisch/dynamisch ein/ausgeschaltet werden können. Aber das 
kann man natürlich auch selber drum herum bauen. Dafür würde sich aber 
natürlich auch die Id() anbieten. Statt dass das Id() Makro direkt den 
Wert ausgibt, mapt man die Zahl z.B. über eine enum. Dann kann man vor 
dem Compilieren die Ausgabe Konfigurieren.

Inzwischen schreibe ich Code nur noch in C++ und nutze printf nur in 
Notfällen. Die Ausgabe erfolgt per überladenem Stream operator. Dadurch 
entfallen die vielen Trace Macro-varianten und jede Überladung nutzt 
automatisch die richtige Implementierung. Ist aber ein komplett anderer 
Ansatz (und ich will jetzt um Gotteswillen nicht wieder diese 
Diskussionen um C/C++ anfachen.)

Ein tolles Projekt! Schönen Sonntag.

von Klaus H. (klummel69)


Lesenswert?

Jetzt ist mir doch eingefallen, wie man TRICE8 als variadic Macro 
schreiben kann. Ist sogar recht simpel. Intern brauchst Du allerdings 
weiterhin die Makros TRICE8_1, TRICE8_2...

Die Vorgehensweise wird in https://stackoverflow.com/a/11763277/2931984 
beschrieben.

Hier ein Beispiel das mit 1...4 Parametern umgehen kann.
1
#define TRICE8_GETNAME(_1,_2,_3,_4, NAME,...) NAME
2
#define TRICE8(id, ...) TRICE8_GETNAME(__VA_ARGS__,TRICE8_4,TRICE8_3,TRICE8_2,TRICE8_1)(id, __VA_ARGS__)

Dann müsste sowas funktionieren
1
TRICE8(Id(18031),"START");
2
TRICE8(Id(17033),"x=%d", 1);
3
TRICE8(Id(17243),"%d,%d", 1,2);
4
TRICE8(Id(17121),"%d,%d,%d", 1,2,3);

von Klaus H. (klummel69)


Lesenswert?

Update: Der Parameter frmt zählt nicht zu den variablen Daten.
1
#define TRICE8_GETNAME(_1,_2,_3,_4, NAME,...) NAME
2
#define TRICE8(id,frmt, ...) TRICE8_GETNAME(__VA_ARGS__,TRICE8_4,TRICE8_3,TRICE8_2,TRICE8_1)(id,frmt, __VA_ARGS__)

von Thomas H. (rokath)


Lesenswert?

Hi Klaus,

vielen Dank für Deine Nachricht - weiter unten ein paar Kommentare:

Klaus H. schrieb:
> Hi Thomas,
>
> schönes Projekt! Den Ressourcenverbrauch von printf auf kleinen µC hat
> mich auch immer gestört.
> Und warum soll ein µC sich mit der Konvertierung rumschlagen, wenn ich
> das Ganze sowieso nur über die Schnittstelle am PC ausgebe. Ich habe
> etwas ähnliches gebastelt aber das ist nicht so ausgereift wie dein
> Projekt (Läuft immerhin auf STM32 und AVRs).
> Hier ein bisschen Feedback von mir (wobei das eher persönlicher
> Geschmack ist, das Projekt ist gut umgesetzt. Sorry, falls ich was
> übersehen habe.)
>
> * Die Idee mit der automatischen Instrumentierung und der Vergabe der
> IDs ist OK. Ich bin allerdings kein Freund davon Sourcecode zu
> überschreiben. Hatte mal Probleme mit einem Tool, das Code
> instrumentalisiert hat und dabei einen Fehler eingebaut hat. Aber mit
> ordentlichen Diff Tools ist sowas ja durchaus aufdeckbar.

Da bin ich ganz bei Dir und ich habe lange darüber nachgedacht und keine
bessere Lösung gefunden. Durch die ID-Vergabepolitik (Default Random 1 
aus
ca. 1 Million) ist selbst bei größeren Projekten die Wahrscheinlichkeit
hinreichend klein für Kollisionen und eine einmal vergebene ID wird nor-
malerweise nicht mehr geändert. Problematisch kann es aber bei Library
Code sein, der in mehreren Projekten verwendet wird. Da aber durch den
-src Schalter mehrere Verzeichnisse ausgewählt und durch Nichtauswählen
ausgeschlossen werden können, lässt sich Library Code mit TRICE Makros
sicher schützen.

>
> * Fliesskomma Typen sind bisher nicht berücksichtigt, oder? Zumindest
> für ARM Controller sinnvoll.
>

Richtig. In Ermanglung passender Hardware erstmal nicht dabei, da ohne
HW nicht so easy testbar. Ist aber mit überschaubarem Aufwand 
nachrüstbar.

> * Ich würde in der Datei til.json noch Dateiname und Sourcecodezeile
> speichern. Dann kann diese gleich bei der Ausgabe mit angegeben werden.
> Ich liebe es, wenn man aus dem Log-Fenster mit Klick direkt in den Code
> springen kann. (Gefahr ist natürlich, dass die Zeilennummern bei
> vergessenem Update nicht mehr passen).
>

Ja und Nein. Derzeit bekommen mehrfache identische TRICEs auch alle die
gleiche ID (=same ID, was leicht änderbar ist =uniq ID) und damit ist 
der Ort
mehrdeutig. Auch ist til.json eher als Metafile für mehrere Projekte 
gedacht.
Man kann naürlich auch mit _LINE_ als Parameter arbeiten...auch der
Dateiname ist machbar.

Evenutell ist es sinnvoll eine zweite Datei namens location.json bei
jedem Compilerlauf projektspezifisch zu generieren mit den Zusatzdaten.
Zusammen mit unique IDs wäre es dann was Du willst.

> * Die Encrypt Idee ist Klasse. Für "einfachen" Schutz gut nutzbar.
>

An eine Banking APP hatte ich nicht gedacht :-)

> * Ich hätte die Endianess Unterscheidung weggelassen. Sowas kann auch
> die Empfängerseite machen.
>

Ist es per Default, aber es gibt wohl big-endian Targets und die
sollen es auch leicht haben können. Die Transfer-Endiannes lässt sich 
per
Compilerschalter an die Target-Endiannes anpassen.

> * Schön auch die Einbindung der RTT Schnittstelle. Deutlich performanter
> als vieles andere.
>

Und sehr hilfreich beim Debuggen und wenn kein anderes Interface da ist.

> * Das Variadic Macro Problem hatte ich auch. Eine bessere Lösung hatte
> ich auch nicht.
>
> * Das Makro ``#define Id(n) (n)`` halte ich für gefährlich. Den
> Bezeichner "Id" nutze ich immer mal wieder. Könnte zu Kollisionen mit
> anderen Modulen kommen. Besser wäre einen eigenen Namensraum per Makro
> Prefix zu nutzen, z.B. ``#define TRICE_ID(n) (n)``. Noch sicherer: einen
> eigenen Datei-Typ definieren. Dann meckert ggf der Compiler.
>

Das sind auch genau meine Bauchschmerzen, aber
1
TRICE64_1( TRICE_ID(103456), "%d", 7);
liest sich sehr holperig. im Vergleich zu
1
TRICE64_1( Id(103456), "%d", 7);
Wie meinst Du das mit dem "eigenen Datei-Typ definieren"?
Leider reicht mein Macro Programmierwissen nicht um so etwas zu machen:
1
TRICE##103456##_64_1( "%d", 7);

> * Mir fehlt noch ein Wrapper für Logging, so dass je Modul und Loglevel
> Meldungen statisch/dynamisch ein/ausgeschaltet werden können. Aber das
> kann man natürlich auch selber drum herum bauen. Dafür würde sich aber
> natürlich auch die Id() anbieten. Statt dass das Id() Makro direkt den
> Wert ausgibt, mapt man die Zahl z.B. über eine enum. Dann kann man vor
> dem Compilieren die Ausgabe Konfigurieren.
>

Derzeit kann man Datei-spezifisch zur Compile-Time die TRICEs 
wegschalten.
Da die TRICEs so wenig Strom brauchen kann man dynamisch auf dem Host 
machen was man will, also nur bestimmte ID-Räume anzeigen oder Kanäle in 
separate Fenster leiten. Das trice Tool hat noch viel Potential zur 
Verbesserung. Ich denke man sollte den Target Code einfach halten, auch 
in der Benutzung. Auch beinhaltet Id() einen Compile Time Shift zur 
Laufzeitoptimierung.

> Inzwischen schreibe ich Code nur noch in C++ und nutze printf nur in
> Notfällen. Die Ausgabe erfolgt per überladenem Stream operator. Dadurch
> entfallen die vielen Trace Macro-varianten und jede Überladung nutzt
> automatisch die richtige Implementierung. Ist aber ein komplett anderer
> Ansatz (und ich will jetzt um Gotteswillen nicht wieder diese
> Diskussionen um C/C++ anfachen.)
>

Ja, C++... habe den Stroustrup seinerzeit gelesen und bin nicht warm 
geworden mit C++. Man muss C++ schon sehr gut beherrschen um effektiven 
Code für embedded Devices zu schreiben. Auch ist mir C++ too rich.
In C arbeite ich gerne mit Functionpointer Tabellen und vermisse C++ 
nicht, vielleicht sind meine Projekte auch zu trivial.

> Ein tolles Projekt! Schönen Sonntag.

Und im übrigen bin ich nun ein Go Fan. Das trice Tool hatte ich in C++
angefangen und zum Glück hatte ich einen Tip bzgl. Go bekommen, sonst 
wäre
nicht das geworden was jetzt da ist.

Danke für Deine Kritik!

von Thomas H. (rokath)


Lesenswert?

Cool, Deine Macro Anregungen, Klaus, schaue ich mir demnächst genauer 
an!

von Thomas H. (rokath)


Lesenswert?

OK, variadic Macro würde funktionieren. Man büßt allerdings die 
implizite Verifizierung der Parameteranzahl ein. Das ist aber nicht 
schlimm, denn dem User bleibt die Wahl ob er
1
TRICE8( Id(0), "...%u...%b...", 1, 2);
 oder
1
TRICE8_2( Id(0), "...%u...%b...", 1, 2);
 schreibt. Diese Wahl hat er jetzt schon. Allerdings ändert das trice 
Tool ein TRICE8 um in ein TRICE8_2 wenn 2 Formatspezifier gefunden 
werden. Ich könnte eine zusätzliche Option für update einführen, die das 
unterbindet. Allerdings muss dann die Generierung der til.json auf etwas 
andere Weise geschehen. Merke ich mir als ein ToDo vor. Vielleicht gibt 
es noch eine gute Idee für die Id(n) Notation und dann mache ich das in 
einem Rutsch.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Wir hatten bei uns auchmal so etwas ähnliches in Verwendung. Die Trace 
Ids wurden dabei in einer externen Datei vorgegeben, daraus dann ein 
C-Header + C-Source mit den Trace Funktionen erzeugt die man dann 
einfach aufgerufen hat. War also nicht so ganz komfortabel zu benutzen.

Als Ausgabepfad aus dem System heraus gab es dann verschiedene Backends:
- Über DCC Register ( ich glaube das ist wie Segger RTT)
- Über UART oder USB
- Über Ethernet als "Syslog" Telegramme.[*]

[*] Dazu wurde dann aus den gesammelten Trace Ids eine c-Source erstellt 
der die ganzen printf Format-Strings wieder im Bauch hatte und mit in 
die Firmware eincompiliert war. Der hat das auf dem Chip (in einer Extra 
Task) dekodiert und auf das Netzwerk gesendet im Syslog Format gesendet. 
Syslog hat den Vorteil das der Wireshark das schön lesbar anzeigt und da 
unsere Anwendung immer Netzwerkanschlüsse hat war das sinnvoll. (Um so 
ein Syslog UDP Telegram zu erzeugen braucht man nicht mal einen IP 
Stack)

Inzwischen sind wir aber wieder auf ein Printf ähnliches system 
umgestiegen, wir haben einfach zu viele vorkompilierte Komponenten, da 
synchronisiert sich das mit fixen Ids  etwas schwierig. Da wir die 
Rechenpower haben ist das für uns so einfacher. Der Unterschied zum 
normalen printf ist jedoch, das unser "Printf" statt den String direkt 
zu formatieren, den Pointer auf den Formatstring und die va_args in eine 
FIFO wirft und diese Fifo dann in einer extra Task gelesen, formatiert 
und ausgegeben wird. (Mit Syslog und Webserver backend) Theoretisch 
könnte man auch die FIFO rauststreamen, sich am PC aus der ELF die 
Formatstrings fischen und dann extern formatieren.

Als Vorschlag würde ich bei deinen Traces noch einen "Message-Zähler" 
mitlaufen lassen. Das ist sehr hilfreich, wenn man erkennen will, dass 
die Trace FIFO übergelaufen ist. Man sieht dann auf der Ausgabe Sprünge 
in der Nummer.

von Hartmut (Gast)


Lesenswert?

Von der GitHub-Seite:
1
Or build trice from Go sources
2
3
    Install Go.

Hole ich mir damit die Schnüffler von Google auf den Hals?

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

Ich frage mich, warum da alle immer alles selber instrumentieren wollen.
Der GCC kann das doch automatisch... siehe "-finstrument-functions"

Du musst dann noch ein paar Funktionen definieren und schwupps, bekommst 
du von jedem functionscall einen entsprechenden callback (also für enter 
und exit).

Damit brauchst du eigentlich keine IDs mehr (das kann ja der entrypoint 
der Funktion sein) und du hast mehr Infos (nämlich die Funktion und den 
Caller!) wie z.B. mit den _LINE_ Makro.

In den FiFo schiebst du die enter und exit events und dazwischen deine 
outputs. Im postprocessing kannst du gemütlich das dann wieder 
zusammenführen.

Willst du ganz krass arbeiten, dann kann sich deine debug-print-routine 
auch vom stack die caller adresse holen.

Dein Visualisierungstool muss nur aus dem ELF die entsprechenden Debug 
Ausgaben raussuchen (was ja nicht das Thema ist, weil du die Symbole 
dafür ja kennst) und dann das filtern, was du willst.

BTDT...

Die paar zeitkritischen Funktionen, die diese Art von Instrumentierung 
nicht vertragen bekommen im Zweifelsfall das Attribut 
"no_instrument_function"...

73

von Andreas M. (amesser)


Lesenswert?

Hans W. schrieb:
> Ich frage mich, warum da alle immer alles selber instrumentieren wollen.
> Der GCC kann das doch automatisch... siehe "-finstrument-functions"

Hans W. schrieb:
> Die paar zeitkritischen Funktionen, die diese Art von Instrumentierung
> nicht vertragen bekommen im Zweifelsfall das Attribut
> "no_instrument_function"...

Wenn man genug FIFO Speicher hat, dann kann man das tun. Unser Power 
Trace 32 braucht "gerade mal" 512MB für 40 Sekunden Programablauf... Im 
übrigen gibt es Anwendungen wo es nicht nur "ein paar" zeitkritische 
Funktionen gibt, sondern die Aufgabe der gesamten Firmware darin besteht 
zeitkritsche Kommunikation zu machen...

von Marc (Gast)


Lesenswert?

Hans W. schrieb:
> Ich frage mich, warum da alle immer alles selber instrumentieren wollen.
> Der GCC kann das doch automatisch... siehe "-finstrument-functions"

Es geht hier um die Ausgabe von Daten nicht um Funktioncalls.
Ggf hat man in einer Funktion 10 Ausgaben, in anderen Funktion keine.

von Klaus H. (klummel69)


Lesenswert?

Thomas H. schrieb:
> Derzeit bekommen mehrfache identische TRICEs auch alle die
> gleiche ID (=same ID, was leicht änderbar ist =uniq ID) und damit ist
> der Ort mehrdeutig.
Ah, ok. Dachte Du sammelst einfach alle Ausgaben ein.
UniqueIDs hätten u.a. den Vorteil dass man bei der Ausgabe danach 
filtern könnte.


>> ...#define TRICE_ID(n) (n)
> Das sind auch genau meine Bauchschmerzen, aber
> TRICE64_1( TRICE_ID(103456), "%d", 7);
> liest sich sehr holperig. im Vergleich zu
> TRICE64_1( Id(103456), "%d", 7);
> Wie meinst Du das mit dem "eigenen Datei-Typ definieren"?

Statt eines Id() Makros hätte ich eher einen Datentyp Id erstellt und 
den Wert über einen Type Cast eingefügt.
Zum Beispiel
1
typedef uint16_t Id;
2
//...
3
TRICE8( (Id)103456, "%d", 7);
4
//Oder als Compound literal geschrieben
5
TRICE8( (Id){103456}, "%d", 7);
Vorteil: der Datentyp Id wird durch den Compiler geprüft. Nutzt 
irgendein Stück Code
den Bezeichner Id anders meckert der Compiler.
(Der Preprozessor meckert nicht, der ersetzt einfach nur stur.)
Nachteil: Dein Tool muss halt nach (Id)123 statt Id(123) suchen.

> Derzeit kann man Datei-spezifisch zur Compile-Time die TRICEs wegschalten.
Ich nutzte oft einen Aufbau in dem ich gezielt Ausgaben ein / auschalten 
kann
(Logglevel je Modul):
1
LOGG(MEAS_INFO,"Temp1:%d", Temp1);
2
LOGG(MEAS_INFO,"Temp2:%d", Temp2);
3
LOGG(MEAS_ERR, "ERR: No Data");
4
LOGG(COMM_INFO,"COM: %d", comport);
Die Ids MEAS_INFO... sind Konstanten. Innerhalb des LOGG Makros wird 
einfach geprüft
ob die Id !=0 ist. Ansonsten wird sie nicht ausgeführt.
Dadurch kann man sehr granular konfigurieren, was einen interessiert.
Zum Beispiel nur Errors und Warnings durchlassen.
Bei zeitkritischen Ausgaben wird einfach alles was nicht nötig ist auf 0 
gesetzt = abgeschaltet.

Könnte man theoretisch auch mit deinen Ids machen, aber die sind ja 
nicht unique.
Und ich vermute es wird dann zu unübersichtlich.

> Und im übrigen bin ich nun ein Go Fan. Das trice Tool hatte ich in C++
> angefangen und zum Glück hatte ich einen Tip bzgl. Go bekommen, sonst
> wäre nicht das geworden was jetzt da ist.
Ich gebe zu, dass ich auch damit liebgeäugelt habe. Nette Sprache.
Aber allein... es fehlt die Zeit...

> Danke für Deine Kritik!
Gerne, aber Kritik würde ich das nicht bezeichnen.

von Thomas H. (rokath)


Lesenswert?

Andreas M. schrieb:
>
> Als Vorschlag würde ich bei deinen Traces noch einen "Message-Zähler"
> mitlaufen lassen. Das ist sehr hilfreich, wenn man erkennen will, dass
> die Trace FIFO übergelaufen ist. Man sieht dann auf der Ausgabe Sprünge
> in der Nummer.

Einen Cycle Counter gibt es. Nur die short Trices verzichten ďarauf.

von Thomas H. (rokath)


Lesenswert?

Hartmut schrieb:
> Von der GitHub-Seite:
>
>
1
> 
2
> Or build trice from Go sources
3
> 
4
>     Install Go.
5
> 
6
>
>
> Hole ich mir damit die Schnüffler von Google auf den Hals?

Go ist komplett OPEN-SOURCE.

von Thomas H. (rokath)


Lesenswert?

Hans W. schrieb:
> Ich frage mich, warum da alle immer alles selber instrumentieren wollen.
> Der GCC kann das doch automatisch... siehe "-finstrument-functions"
>
Es gibt viele Kriterien und Wege. Compiler Unabhängigkeit, Speed, 
Minimainstrumentierung und Einfachheit in der Anwendung sind mir wichtig 
gewesen.

von Thomas H. (rokath)


Lesenswert?

Klaus H. schrieb:
> UniqueIDs hätten u.a. den Vorteil dass man bei der Ausgabe danach
> filtern könnte.
>
Ist ja eingebaut. Nur muss es explizit  eingeschaltet werden. Siehe 
Update switch -sharedIDs
>
> Nachteil: Dein Tool muss halt nach (Id)123 statt Id(123) suchen.
>
Gute Gedanken zum Nachdenken aber besser wird es anscheinend nicht, nur 
anders.

> Und ich vermute es wird dann zu unübersichtlich.
>
Ich nenne INFO, ERR und Co. Kanäle und sie sind Teil der Formatstrings. 
Das trice Tool könnte kanalspezifisch die IDs vergeben, etwa ERR 
10000-19999 und INFO 40000-49999. Wenn es ID Range abhängig möglich wäre 
die TRICE Makros Code generieren zu lassen oder nicht wäre das THEMA VOM 
TISCH.

>> Und im übrigen bin ich nun ein Go Fan. Das trice Tool hatte ich in C++
>> angefangen und zum Glück hatte ich einen Tip bzgl. Go bekommen, sonst
>> wäre nicht das geworden was jetzt da ist.
> Ich gebe zu, dass ich auch damit liebgeäugelt habe. Nette Sprache.
> Aber allein... es fehlt die Zeit...
>
Leicht erlernbar, hoch performant und produktiv.

>> Danke für Deine Kritik!
> Gerne, aber Kritik würde ich das nicht bezeichnen.

Doch, es ist konstruktive Kritik und genau die ist wichtig.

von Thomas H. (rokath)


Lesenswert?

Habe soeben v0.26.1 released. Da sind die variadic Macros als nutzbare 
Option umgesetzt, man kann also auf die Suffixe _1, _2, ... verzichten, 
wenn man möchte.
1
TRICE16( Id( 59976), "rd:%d, %d, %d, %d\n", 1, 2, 3, 4 );
2
TRICE32( Id( 64745), "rd:%d\n", 1 );
3
TRICE32( Id( 56533), "rd:%d, %d\n", 1, 2 );
Danke Klaus für den sehr hilfreichen Hinweis diesbezüglich!!!

Per default werden nun unique IDs generiert und shared IDs nur mit 
entsprechendem Schalter.

Eine Referenzliste von jeder ID in den Source Code lässt sich relativ 
einfach bauen nur habe ich noch keine klare Vorstellung wie man eine 
solche effektiv nutzen kann. Auch ist bei unterschiedlichen 
Firmwareversionen diese Info entsprechend zu verwalten.

Es wäre auch möglich die jeweils erste ID am Zeilenanfang optional 
auszugeben, was vielleicht ausreicht zur schnellen Lokalisierung im 
Code.

Falls jemand TRICE einsetzt freue ich mich über Rückmeldung. Es sollte 
weitgehend hardwareunabhängig nutzbar sein

von Thomas H. (rokath)


Angehängte Dateien:

Lesenswert?

Eine optionale Ausgabe der Trice IDs ist jetzt ab v0.29.3 möglich.
1
  -showID string
2
        Format string for displaying first trice ID at start of each line. Example: "debug:%7d ". Default is "". If several trices form a log line only the first trice ID is displayed.
Übrigens sind die Zahlen an den Zeilenenden des Screenshots der jeweils 
aktuelle Prozessorclock. Der Abstand 12 oder 13 bedeutet bei einer 48 
MHz Taktrate eine Zeitdifferenz von ca. 250ns. Licht schafft es in 
dieser Zeit etwa 80m weit.
Ja, und Trice hat nun ein Gesicht Dank meinem Töchterchen.
Hie nochmal der Link: https://github.com/rokath/trice

: Bearbeitet durch User
von Thomas H. (rokath)


Lesenswert?

Habe die Schalter -pick und -ban eingeführt um einzele oder Gruppen von 
Kanälen zu selektieren oder auszusperren. Etwa
1
trice l -port COM7 -ban "debug,diag"
 unterdrückt die Ausgabe aller Debug- und Diagnose- Trices.

von funky (Gast)


Lesenswert?

Bin gerade durch den Beitrag bei Interrupt drauf gestoßen. Sieht sehr 
interessant aus. Werde ich mal ausprobieren

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.