INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Hardwareserial/Softserial: Problem mit Superklasse
13.05.2016, 09:55 (Dieser Beitrag wurde zuletzt bearbeitet: 13.05.2016 09:56 von tuxedo0801.)
Beitrag #1
Hardwareserial/Softserial: Problem mit Superklasse
Hi,

für ein mittelgroßes Projekt bastel ich gerade an einer "DebugUtil" Klasse.

Ziel:

Im Sketch definiert/konfiguriert man sich sein "Serial-Objekt" (Hardwareserial, Softserial, ....) und gib dieses der DebugUtil-Klasse bekannt. Diese ist als Singleton ausgelegt und kann somit von beliebigen Libs und dem Sketch benutzt werden.
Das mag für viele Szenarien nicht unbedingt sinnvoll sein, aber für meinen Anwendungsfall ist es das. Ich möchte also weniger über den Sinn und Unsinn diskutieren, sondern über das Verständnis-Problem das ich nicht gelöst bekomme.

Nun, wie dem auch sei: Ich krieg's nicht gebacken einen gemeinsamen Nenner für Hardwarserial und Softwareserial zu finden und zu nutzen.

Soweit ich in Erfahrung gebracht habe, ist die Klasse "Print" der gemeinsame Nenner.

Also hab ich mein DebugUtil darauf ausgelegt:

DebugUtil.h
Code:
#ifndef DEBUGUTIL_H
#define DEBUGUTIL_H

#include <Arduino.h>

class DebugUtil {
    
   // Constructor, Destructor
    DebugUtil(); // private constructor (singleton design pattern)

    ~DebugUtil() {
    } // private destructor (singleton design pattern)
    DebugUtil(DebugUtil&); // private copy constructor (singleton design pattern)
    
private:    
    Print* _out;

public:
    static DebugUtil Debug;
    
    void setPrint(Print* out);
    
    int freeRam();
    
    void print(char *fmt, ...);
    void print(const __FlashStringHelper *fmt, ...);
    void println(char *fmt, ...);
    void println(const __FlashStringHelper *fmt, ...);
};

// Reference to the KnxDevice unique instance
extern DebugUtil& Debug;

#endif // DEBUGUTIL_H


DebugUtil.cpp
Code:
#include "DebugUtil.h"

// DebugUtil unique instance creation
DebugUtil DebugUtil::Debug;
DebugUtil& Debug = DebugUtil::Debug;

DebugUtil::DebugUtil() {
}

void DebugUtil::setPrint(Print* out) {
    _out = out;
}

int DebugUtil::freeRam() {
    extern int __heap_start, *__brkval;
    int v;
    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void DebugUtil::print(char *fmt, ...) {
    if (_out) {
        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, fmt);
        vsnprintf(buf, 128, fmt, args);
        va_end(args);
        //Serial.print(buf);)
        _out->print(buf);
    }
}

void DebugUtil::print(const __FlashStringHelper *fmt, ...) {
    if (_out) {
        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, fmt);

#ifdef __AVR__    
        vsnprintf_P(buf, sizeof (buf), (const char *) fmt, args); // progmem for AVR
#else
        vsnprintf(buf, sizeof (buf), (const char *) fmt, args); // fpr rest of the world
#endif    
        va_end(args);
        //Serial.print(buf);)    
        _out->print(buf);
    }
}

Das compiliert schon soweit fehlerfrei. Problem ist dann das setzen des Streams im Sketch:

Code:
Debug.setPrint(Serial);

Da meckert der Compiler dass mein "Serial" eigentlich ein "Serial_" ist und sich nicht in "Print" quetschen lässt.

Kann mir jemand unter die Arme greifen und helfen den passenden Typ zu finden, bzw. erklären wie ich aus einem Serial (das ja Print auch kann/benutzt) ein Print mache?!
Ich bin nicht auf die Klasse Print festgelegt. Aber ziel soll es sein, in die DebugUtil-Klasse wahlweise ein vorkonfiguriertes Softserial oder HardwareSerial zu stecken und die in DebugUtil enthaltenen print...-Funktionen damit nutzen zu können.

Gruß
Alex
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
16.05.2016, 11:06 (Dieser Beitrag wurde zuletzt bearbeitet: 16.05.2016 11:29 von tuxedo0801.)
Beitrag #2
RE: Hardwareserial/Softserial: Problem mit Superklasse
So viele Viewer, aber keine Antwort Sad Ist das Problem etwa zu exotisch?

Aus lauter Frust auf "Print" wollte ich das ganze nun auf "Stream" umbauen und hab dabei "aus versehen" die Lösung gefunden:

in der Heaer-File kann die Instanzvariable "_out" vom Typ "Print*" bleiben. Man muss lediglich die Signatur der "setPrint()" Funktion anpassen. Statt "Print*" muss ein "Stream*" genutzt werden.

Im Sketch kann man dann die Funktion "Debug.setPrint(&Serial)" verwenden. Intern checkt der Compiler das dann irgendwie dass da zwar ein "Serial" rein kommt, aber intern dann in ein "Print" gespeichert wird.

Problem gelöst...
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
16.05.2016, 15:47
Beitrag #3
RE: Hardwareserial/Softserial: Problem mit Superklasse
(16.05.2016 11:06)tuxedo0801 schrieb:  So viele Viewer, aber keine Antwort Sad Ist das Problem etwa zu exotisch?

Aus lauter Frust auf "Print" wollte ich das ganze nun auf "Stream" umbauen und hab dabei "aus versehen" die Lösung gefunden:

in der Heaer-File kann die Instanzvariable "_out" vom Typ "Print*" bleiben. Man muss lediglich die Signatur der "setPrint()" Funktion anpassen. Statt "Print*" muss ein "Stream*" genutzt werden.

Im Sketch kann man dann die Funktion "Debug.setPrint(&Serial)" verwenden. Intern checkt der Compiler das dann irgendwie dass da zwar ein "Serial" rein kommt, aber intern dann in ein "Print" gespeichert wird.

Problem gelöst...

Vielleicht liegt's daran, dass keiner richtig kapiert hat was Du überhaupt genau für einen Effekt erzielen willst.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
17.05.2016, 07:36
Beitrag #4
RE: Hardwareserial/Softserial: Problem mit Superklasse
Zitat:Vielleicht liegt's daran, dass keiner richtig kapiert hat was Du überhaupt genau für einen Effekt erzielen willst.

Mag sein. Aber ich kann ja nicht riechen dass meine Frage zu missverständlich war, und mehr als den problematischen Source und dessen Fehlermeldung posten geht ja fast nicht.

Nun ja, Problem durch Zufall gelöst.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
17.05.2016, 08:59
Beitrag #5
RE: Hardwareserial/Softserial: Problem mit Superklasse
Hallo,

(17.05.2016 07:36)tuxedo0801 schrieb:  Nun ja, Problem durch Zufall gelöst.

bei Deinem Problem hätte ich Dir nicht helfen können, dazu sind meine C++ Kenntnisse zu bescheiden.
Ich hätte aber eine Frage zu Deinem Vorhaben: was soll DebugUtil leisten?
Man legt den Ausgabekanal fest und gibt dann Texte/Variableninhalte/Heapspace usw. usw. aus?

Ich spiele viel mit den ESP8266 rum und wenn Dein DebugUtil als Ausgabe nciht nur Serial/SoftSerial sondern auch einen Telnet-Server könnte, wäre es ein echter Gewinn. OTA-Update beim ESP ist sehr praktisch, evtl. Debugausgabe machen dann aber nur per Telnet Sinn, da habe ich aber noch keinen (für mich) gangbaren Weg gefunden, eine Umschaltung zwischen Serial und Telnet sauber hinzubekommen.

Ich schalte normalerweise debug mit #define DEBUG oder #define DEBUG_HTM usw. ein/aus.
#ifdef DEBUG
Serial.print("ausgabe");
#endif

Das jetzt so zu kapseln, daß ich nur oben festlege, ob eben Serial/SoftSerial oder eben telnetServer das "Print-Meduim" ist, wäre ideal.

Ich würde da selbstverständlich auch mittesten und helfen, soweit ich kann.

Gruß aus Berlin
Michael
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
17.05.2016, 09:15 (Dieser Beitrag wurde zuletzt bearbeitet: 17.05.2016 09:26 von tuxedo0801.)
Beitrag #6
RE: Hardwareserial/Softserial: Problem mit Superklasse
Zitat:Ich hätte aber eine Frage zu Deinem Vorhaben: was soll DebugUtil leisten?

DebugUtil soll Teil meiner Libraray werden. Es gibt hier mehrere Eckpunkte die die Verwendung dieser DebugUtil-Klasse notwendig werden lassen:

1) Der Sketch-Schreiber braucht selbst ein Logging für seinen Sketch
2) Die Lib ist leider recht komplex, so dass man, während man seinen Sketch aufbauend auf der Lib schreibt, auch in der Lib logging braucht
3) Die verwendete Hardware ist sehr vielfältig. Mal gibt es einen zweiten UART, mal keinen, mal gibt es nur die Möglichkeit des SoftSerials
4) Die Pin-Nutzung variert sehr stark, so dass ich nicht einfach hart auf SoftSerial setzen kann
5) Die Lib wird typischerweise in mehreren Projekten mit unterschiedlicher Hardware/Pin-Belegung gleichzeitig genutzt, so dass es für den User lästig wäre bei jedem umschalten des Projekts in der Lib die passende Pin/Serial-Konstellation für's Logging einzustellen


Ergo:

Logging muss im Sketch definiert werden und sowohl Sketch als auch Lib nutzen das eingestellte Logging gemeinsam.
Meine Lösung hat eigentlich einen gewaltigen Haken: Der Debug-Code ist auch im Produktiv-Code enthalten... Man kann zwar einfach im Sketch kein Stream-Objekt setzen, womit die Debug-Aufrufe dann ins leere laufen, aber die Debug-Strings und Aufrufe sind prinzipiell da.
Wer das dennoch nicht in seinem Code haben mag, der kann in DebugUtil.h "#define DEBUG" auskommentieren, neu bauen und ist den Debug-Code los. Aber das beisst sich evtl. mit anderen Projekten die noch nicht abgeschlossen sind und dieselbe Lib nutzen.


Natürlich könnte man DebugUtil noch um ein Telnet-Logging erweitern. Macht für den ESP ggf. auch Sinn. Aber wusstest du dass der ESP einen zweiten UART hat? Hier ist jedoch lediglich der TX-Pin herausgeführt, was aber für's Debug-Logging vollkommen ausreicht.
Da der ESP bei mir auch eine Rolle spielt, WLAN aber eher weniger, setze ich auf den zweiten UART. Das ist auch ein weniger Problematisch wenn es vom WLAN-Code-Abschnitt mal ein Problem gibt :-)

Für meine Schaltung habe ich eine Debug-Programmier-Pinleiste entworfen die beide UARTs beinhaltet. Ein spezieller Programmieradapter (ein USB Anschluss, aber zwei RS232 Schnittstellen) ist gerade in Arbeit. Damit kann ich dann mit einem Stecker auf der Hardware programmieren und "Debuggen".

Wenn es speziell nach OTA Updates etwas zu debuggen gibt, dann ist natürlich Telnet von Vorteil. Allerdings würde ich mir, statt das Gerät über's Netzwerk zu loggen, das Ding lieber auf den Schreibtisch stellen und direkt anschließen, statt auf das Netzwerk zu vertrauen.

Die Erweiterung von DebugUtil mit Telnet dürfte nicht allzuschwer sein.

Einfach eine passender set-Funktion einbauen die die Telnet-Schnittstelle bekannt gibt. Und in der Implementierung dann als alternative zu "_out" schauen ob diese Telnet-Schnittstelle gesetzt wurde und dann die Log-Meldung über die Telnet-Schnittstelle senden.

Wenn meine Hardwareentwicklung mal soweit gediehen ist dass sie funktioniert (warte noch auf die Platinen aus Fernost), dann kann ich mir das auch mal anschauen. Bis dahin hab ich aber noch wichtigere Dinge auf der ToDo Liste.

Hier die aktuelle Version von DebugUtil:

DebugUtil.h
Code:
#ifndef DEBUGUTIL_H
#define DEBUGUTIL_H


#include <Arduino.h>

#define DEBUG

#ifdef DEBUG
    #define DEBUG_PRINT(...) Debug.print(__VA_ARGS__);
    #define DEBUG_PRINTLN(...) Debug.println(__VA_ARGS__);
#else
    #define DEBUG_PRINT(...)
    #define DEBUG_PRINTLN(...)
#endif

#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
  (byte & 0x80 ? 1 : 0), \
  (byte & 0x40 ? 1 : 0), \
  (byte & 0x20 ? 1 : 0), \
  (byte & 0x10 ? 1 : 0), \
  (byte & 0x08 ? 1 : 0), \
  (byte & 0x04 ? 1 : 0), \
  (byte & 0x02 ? 1 : 0), \
  (byte & 0x01 ? 1 : 0)


class DebugUtil {
    
   // Constructor, Destructor
    DebugUtil(); // private constructor (singleton design pattern)

    ~DebugUtil() {
    } // private destructor (singleton design pattern)
    DebugUtil(DebugUtil&); // private copy constructor (singleton design pattern)
    
private:    
    Print* _printstream;

public:
    static DebugUtil Debug;
    
    void setPrintStream(Stream* printstream);
    
    int freeRam();
    
    void print(char *format, ...);
    void print(const __FlashStringHelper *format, ...);
    void println(char *format, ...);
    void println(const __FlashStringHelper *format, ...);
};

// Reference to the KnxDevice unique instance
extern DebugUtil& Debug;

#endif // DEBUGUTIL_H

DebugUtil.cpp
Code:
#include "DebugUtil.h"

// DebugUtil unique instance creation
DebugUtil DebugUtil::Debug;
DebugUtil& Debug = DebugUtil::Debug;

DebugUtil::DebugUtil() {
}

void DebugUtil::setPrintStream(Stream* printstream) {
    _printstream = printstream;
    print(F("DEBUG! free ram: %d\n"), freeRam());
}

int DebugUtil::freeRam() {
    extern int __heap_start, *__brkval;
    int v;
    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void DebugUtil::print(char *format, ...) {
    if (_printstream) {
        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, format);
        vsnprintf(buf, 128, format, args);
        va_end(args);
        //Serial.print(buf);)
        _printstream->print(buf);
    }

}

void DebugUtil::print(const __FlashStringHelper *format, ...) {
    if (_printstream) {
        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, format);

#ifdef __AVR__    
        vsnprintf_P(buf, sizeof (buf), (const char *) format, args); // progmem for AVR
#else
        vsnprintf(buf, sizeof (buf), (const char *) format, args); // fpr rest of the world
#endif    
        va_end(args);
        //Serial.print(buf);)    
        _printstream->print(buf);
    }
}

void DebugUtil::println(char *format, ...) {
    if (_printstream) {

        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, format);
        vsnprintf(buf, 128, format, args);
        va_end(args);
        //Serial.println(buf);)
        _printstream->println(buf);
    }
}

void DebugUtil::println(const __FlashStringHelper *format, ...) {
    if (_printstream) {

        char buf[128]; // limit to 128chars
        va_list args;
        va_start(args, format);

#ifdef __AVR__    
        vsnprintf_P(buf, sizeof (buf), (const char *) format, args); // progmem for AVR
#else
        vsnprintf(buf, sizeof (buf), (const char *) format, args); // fpr rest of the world
#endif    

        va_end(args);
        //Serial.println(buf);)    
        _printstream->println(buf);
    }
}
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
17.05.2016, 11:31
Beitrag #7
RE: Hardwareserial/Softserial: Problem mit Superklasse
Hallo tuxedo0801,

erstmal vielen Dank für die ausführliche Antwort, ich habe das mal nicht Zitat dringelassen.

Ich merke mir das auf jeden Fall mal.
Bei mir ist es nur Hobby, im Moment eben die ESP mit MQTT, OTA, Webserver usw.

Ich habe die ESP über Pfingsten mal mit geäenderten Webserver versehen, basierend auf ESP8266Webserver und SPIFFS. Ich mußte keinen zum Rechner tragen obwohl ich das meist schaffe. Wenn man 6 ESP in der OTA-Liste hat (mehr zeigt die dummerweise nicht an...) erwischt man manchmal auch mal den falschen...

Debug beschränkt sich da meist auf Zwischenausgaben von Sensorwerte-Berechnungen o.ä., dazu reicht mir dann Telnet oder auch ein Mißbrauch von MQTT (wird eben mal test/ subscribt).

Ich kann mich über die ESP eigentlich nicht beklagen, die Software (sowhl SDK als auch die Arduino-IDE-Einbindung) ist aber immer für Überraschungen gut.

WLAN-Reconncets gibt es selten, dann ist das WLAN hier selbst schuld. Ich habe fast 20 WLANS im Umfeld mit teilweise recht hohen Feldstärken. Wenn die LEute am Wochenende im Internet kramen sind eben die Kanäle zu.
Ich ahbe hier als Spielerei einen Icecast-Streamclient auf einem ESP laufen (VS1011 als MP3-Decoder am ESP). Bis 320kBit keine Probleme außer am Wochenende. Da läuftder Buffer dann schnell gegen leer und er hat Probleme, das aufzuholen. Mehr als 20k Buffer geht aber nicht sinnvoll. Normalerweise nur eine Spielerei, läuft jetzt mit 128kBit stabil, ein RasPi als Icecast-Server streamt einfach einen Ordner endlos.

Unmotiviert hängengeblieben oder abgestürzt ist noch keiner der ESP in den letzten Wochen.
Im Webbrowser waren die Transferraten teilweise jenseits von gut und böse (5-6k/s). Ursache ist dss verzögerte ACK, das Windows per default an hat (hier Win7). Firefox, Chrom usw. schliefen da manchmal fast ein.
IE seltsamerweise nicht, da muß MS ziemlich an den Registry-Einstellungen vorbeigreifen.

Beim Test des File-Upload zum ESP-SPIFFS mit einem 600k jpg-Bild fiel mir auf, daß er zum Upload rund 2s brauchte und zum Anzeigen im Firefox 50s.
Im IE nur knapp 2s.
Jetzt sind es auch im Firefox nur knapp 2s, ca. 500kB Datenrate aus dem SPIFFS sind mit dem ESP also durchaus möglich.

Gruß aus Berlin
Michael
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
17.05.2016, 12:09
Beitrag #8
RE: Hardwareserial/Softserial: Problem mit Superklasse
Hey Michael,

MQTT statt Telnet klingt nach einem adäquaten Ersatz. Gerade wenn es nicht im tiefgreifendes Debugging geht.

Der ESP ist aktuell auch mein favorisierter µC. Er könnte aber ein paar Pins mehr haben. Greife hier z.B. auf den MCP23008 zurück.

Und besten Dank für deinen WLAN Bericht. Das wird mir in Zukunft sicher hilfreich sein.

Die Idee mit dem Icecast klingt toll. Muss ich mir mal merken.

OTA Updates habe ich langfristig auch im Visier. Aber der Strombedarf des ESP ist hier noch eine bremse (entwickle aktuell hobbymäßig KNX Geräte, und vom KNX Bus kann man nicht so ohne weiteres ausreichend Strom ziehen um den ESP mit WLAN laufen zu lassen). Für einzelne Lösungen könnte das aber praktisch sein. Mal schauen.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  Problem mit SD Card Library BennIY 4 192 06.10.2016 18:38
Letzter Beitrag: Bitklopfer
  Problem mit SD.remove Eichner 6 212 22.08.2016 19:42
Letzter Beitrag: Eichner
  4x16 Tastermatrix Problem Michel 16 846 14.07.2016 10:02
Letzter Beitrag: StephanBuerger
  Problem mit Delay und Millis funnyzocker 1 458 26.06.2016 09:54
Letzter Beitrag: hotsystems
  Problem mit ESP8266 und EMail senden torsten_156 1 601 13.06.2016 21:14
Letzter Beitrag: torsten_156
  ESP8266_01 flashen - Problem torsten_156 12 1.051 30.05.2016 20:12
Letzter Beitrag: torsten_156
  ESP8266 HTML Problem arduino_weatherstation 1 497 25.04.2016 21:52
Letzter Beitrag: rkuehle
  Problem mit OLED 0.96" Display torsten_156 3 541 03.04.2016 15:10
Letzter Beitrag: hotsystems
  Problem: SDFat - Das Ende einer Datei finden und Schleife beenden MartinK 4 490 01.04.2016 05:49
Letzter Beitrag: MartinK
  Problem: RFID code mit Inhalt einer Textdatei auf einer SD Karte vergleichen MartinK 6 512 29.03.2016 16:45
Letzter Beitrag: MartinK

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste