Library konfigurierbar machen

Hey, ich brauch mal etwas Starthilfe bei einem Design-Ansatz...

Ich hab eine Library, die ich etwas umgestalten will/muss um folgende Probleme zu lösen:

1) Die Lib hat mehrere Klassen und Header-Files. Ich will von außen der Lib sagen können welches Serial-Device für die Debug-Meldungen genutzt wird (HardwareSerial oder beliebiges SoftwareSerial, ...)

Hierfür könnte ich wohl einen "setter" einbauen mit dem der Benutzer eine Serial-Instanz in die Lib reinreichen kann, welche diese Instanz dann für Debug-Meldungen nutzt. Bessere Ideen?

2) Eigentlich soll die Lib im produktiven Einsatz kein Debug mehr enthalten. Bisher hab ich das immer mit einem "#define" in einem lib eigenen Header-File erledigt. Aber dazu müsste der Benutzer die Lib anfassen?!

3) Wenn ich die Lib in den Arduino Library Manager eintragen lasse (https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ), und die Benutzer die Lib darüber beziehen, dann ist das "anfassen" der Lib (bzw. deren Header-File für etwaige #define Einstellungen) zwar noch möglich (wenn man weiß wo die Lib nach dem Auto-Download landet), aber das ist immer "global" und nicht für jedes Projekt/Sketch separat.

Was ich nun Suche ist ein Ansatz mit dem ich * möglichst einfach für jedes Projekt das die Lib verwendet, die Lib einstellen kann * nach Möglichkeit Debug-Code im produktiven Release-Code weitgehend nicht-existent ist

Gibt's hier Lib-Bastler die schon vor einem ähnlichen Problem standen? 1+2 lässt sich durch eine geschickte Header-File in der Lib wohl lösen und der User reicht sein debug-serial Instanz einfach rein. Aber Punkt 3 stört mich aktuell noch am meisten, gerade in Hinsicht auf Projekt-verschiedene Anforderungen an die Lib und deren Debug-Einstellung ...

Any ideas?

Ein Ansatz wäre: Wem das Anfassen einer Library die über den Library-Manager rein kam, zu komplex ist, der soll halt die Finger davon lassen.

Eine andere Möglichkeit wäre, ein generelles #define über den-Dgcc Parameter vor alle .cpp zu stellen

-DDEBUG_OUT=Serial

und im Code dann

#ifdef DEBUG_OUT
   DEBUG_OUT.println(F(" Eine Test-Ausgabe"));
#endif

Ich weiß nicht, ob das zu weit führt, ich komm aus der Hochsprachen-Ecke, aber ich erwähne es mal: Dependency Injection.

Da die diversen Serial-Devices ja ne gemeinsame Basisklasse haben, kannst du bei der Erstellung einer Instanz deiner Klasse im Konstruktor die gewünschte Serial-Instanz angeben.

Ich glaube die leiten auch alle von Print ab, somit könntest du - falls du keine Logs möchtest - einfach ne Klasse von Print ableiten, die genau nichts tut. Die gibst du dann deiner Instanz mit.

Und in deiner Instanz loggst du einfach in das Print-Objekt das dir der Consumer im Konstruktor mitgibt.

Printable ist was anderes. Printable ist ein Interface mit dem man beliebige Objekte per Print drucken kann.

Wenn man eine beliebige Serial Instanz übergeben will, nimmt man eine Referenz oder einen Zeiger auf Print als Parameter. Für reines Lesen würde Stream reichen.

Das kann man gleich im Konstruktor machen. Dann wird der Benutzer gezwungen es zu tun.