Ankündigung

Einklappen
Keine Ankündigung bisher.

ESP8266 KNX mit ETS

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • thesing
    antwortet
    Hi Waldemar,

    die Versionen, die ich meine habe nichts direkt mit der knxprod zu tun. Man kann im Sketch festlegen, welchen Hardwaretyp, welchen Hersteller, welche Firmwareversion usw. der Sketch hat. Ich würde nur prüfen, ob die Werte im Flash mit dehnen im Sketch übereinstimmen.

    Die ApplicationVersion in der knxprod wird (AFAIK) nur von ETS genutzt. Man könnte zusätzlich noch in der knxprod einstellen, dass beim Programmieren via ETS geprüft wird, ob der HardwareType des Sketches zum HardwareType der knxprod passt. Andere Prüfungen gehen sicher auch. Standartmäßig prüft ETS zumindest ob der Manufacturer der richtige ist.

    VG
    Thomas

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Hi Thomas,

    ich würde ja gern was davon halten, aber ich weiß nicht, worauf Du Dich beziehst. Um welche Attribute welcher Elemente im XML geht es? Geht es um diese beiden?
    Code:
            <ApplicationProgram Id="M-00FA_A-..." [COLOR=#FF0000]ApplicationNumber="555" ApplicationVersion="11"[/COLOR] ProgramType="ApplicationProgram" ...>
    Wenn ja, dann bitte nur auf ApplicationNumber prüfen, nicht auf die ApplicationVersion! Ich verlasse mich ja explizit drauf, dass man über ReplacesVersions die Version kompatibel erhöhen kann ohne die Firmware ändern zu müssen. Da könnte man höchstens eine MinVersion prüfen. Aber wahrscheinlich geht es um was anderes, oder?

    Grundsätzlich bin ich dafür, dass man prüft, ob die Firmware (also der Sketch) zu einer knxprod passt, aber die vorgesehenen Upgradepfade (neue knxprod für bestehende Firmware) sollen immer noch gehen.

    Ich hab das bisher selber geprüft, indem ich den ersten Paremter in der ETS unsichtbar, mit einer konstante (magic value) vorbelegt immer mitschicke und in der Firmware prüfe, ob der erste Parameter dieses magic value enthält.

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • thesing
    antwortet
    Aktuell schreibe ich beim Save am Anfang des Flashs ein paar Magic Numbers um beim Restore nach einem Restart zu erkennen ob der Speicher gültig ist. Zukünftig würde ich dort die PID_HARDWARE_TYPE und PID_VERSION vom DeviceObject schreiben wollen. Dann würde man zusätzlich prüfen, ober der Flash zum Sketch passt. Das setzt natürlich vorraus, dass man die Werte des DeviceObjects im Sketch entsprechend füllt. Was haltet ihr davon?

    VG
    Thomas

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Zitat von thesing Beitrag anzeigen
    Der Dpt ist im GroupObject derzeit nicht als Referenz (Dpt&) definiert
    Danke für die Aufklärung. Auf das & hab ich nicht geachtet. Das zeigt mal wieder meine C++-Lücken...

    Zitat von thesing Beitrag anzeigen
    Es würde schon Sinn machen jeden Dpt nur einmal zu instanzieren. Da hast du Recht.
    Wenn das nur 4 statt 6 Bytes bringt, ist das nicht so doll... da macht Dein Vorschlag mit dem weglassen des _datapointType und immer DPT mitgeben beim Aufruf der Value-Funktionen mehr Sinn.

    Zitat von thesing Beitrag anzeigen
    Allerdings mit #ifndefs damit man das bei einer "richtigen" IDE übersteuern kann.
    Da bin ich auch für, das man das dann einfacher in .git einchecken und muss es mit einer "richtigen IDE" nicht anfassen .

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Nanosonde:
    Ich kann Dir meine platformio.ini Datei hier mal zur Verfügung stellen, wenn Du magst.
    Das wäre toll, danke.

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • thesing
    antwortet
    mumpf
    Der Dpt ist im GroupObject derzeit nicht als Referenz (Dpt&) definiert. Damit entspricht die Größe der Summe der Instanzvariablen. In c++ ist eine struct eine Klasse nur public membern. Bei mir ist der Dpt ein Klasse mit nur public-Membern. Also praktisch das gleiche, aber nicht so deklariert.

    Es würde schon Sinn machen jeden Dpt nur einmal zu instanzieren. Da hast du Recht.

    Bei Punkt (a) müsste man in der GroupObjectTable schon eine Liste von (asap, callBack) haben um die richtigen Callbacks ermitteln zu können.

    Vielleicht sollten wir für Listen entweder die STL nutzen, oder ein eigenes Template hinzufügen.

    Da niemand ein Problem mit einer config.h hat, wird es dann darauf hinaus laufen. Allerdings mit #ifndefs damit man das bei einer "richtigen" IDE übersteuern kann.

    Einen Kommentar schreiben:


  • Nanosonde
    antwortet
    PlatformIO und J-Link war einfach einzurichten. Ich nutze das alles unter Windows 10 64-Bit.
    Ich kann Dir meine platformio.ini Datei hier mal zur Verfügung stellen, wenn Du magst.

    Zitat von mumpf Beitrag anzeigen
    Ich fände die Möglichkeit, beides zu nutzen, am schönsten (also Thomas #ifndef-Vorschlag).
    Ich würde die config.h jetzt nicht unnötig mit #ifndefs usw. zupflastern.
    Derjenige, der das vom Build Prozess aus steuerbar benötigt, kann sich das ja einfach selbst mit zwei Zeilen hinzufügen.
    Von daher würde ich dort wikrlich nur die #defines mit ein wenig Doku wozu das ist, da rein packen.

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Hi Nanosonde,

    ich bin von PlatformIO auch begeistert und habe mir gestern den Segger J-Link EDU bestellt. Falls ich das nicht vernünftig eingerichtet bekomme, würde ich mich nochmal an Dich wenden

    Zitat von Nanosonde Beitrag anzeigen
    einfacher ist vermutlich wirklich eine einfache globale config.h.
    Ich fände die Möglichkeit, beides zu nutzen, am schönsten (also Thomas #ifndef-Vorschlag).

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • Nanosonde
    antwortet
    Hi!
    Ich würde auch für eine globale config.h plädieren.
    Projekte wie FreeRTOS und BTstack nutzen sowas auch, um internes Feintuning usw. für den Stack einzustellen.

    (Die Arduino GUI ist für mich keine IDE ;-) )

    Ich habe PlatformIO mit VS Code zum ersten Mal für die KNX-RF Implementierung genutzt und bin begeistert.
    Auch das Debugging in VS Code mit einem Segger J-Link EDU klappt super und hat echt geholfen.
    Die #defines setzt man dort in der zentralen Datei "platformio.ini".

    Der Arduino Build Prozess ist beschrieben.

    Für die Linux-Plattform könnte man ja das CMakeFileLists.txt entsprechend anpassen, um #defines unterzubringen.


    ABER: einfacher ist vermutlich wirklich eine einfache globale config.h.
    Da könnte ich dann auch die PIN-Definitionen für RF unterbringen. Und welches SPI Device zu nutzen ist.

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Hi Thomas,

    Zitat von thesing Beitrag anzeigen
    Ich denke da könnte man in der Tat etwas sparen:
    danke für Deine ausführliche Antwort, ich muss nur mal ein paar Sachen mit meinen Worten formuliert nachfragen, um zu checken, ob ich Dich richtig verstanden habe...

    Erstmal um mein Unwissen auszuräumen und was zu lernen:
    Punkt (e): Dpt ist doch eine Klasse mit 3 short, also 6 Byte lang. Ich dachte, wenn man eine Instanz kreiert, dann wird die dynamisch in Speicher erzeugt (6 Bytes) und die Referenz darauf (also   _datapointType ) ist technisch ein Pointer, also weitere 4 Byte. Mit meinem Vorschlag wollte ich die Referenz belassen, aber die immer gleichen Instanzen (z.B. 120-mal DPT(1,1)) vermeiden. Ich ging davon aus, ich würde dann nur 6 statt 120*6=720 Bytes verbrauchen. Natürlich hätte man immer noch 120*4 Byte referenz auf diese Instanz. Um beim Beispiel zu bleiben: Vorher sind es 120*(4+6)=1200 Byte, hinterher 120*4+6=486 Byte. Du sprichst vom struct, den habe ich aber nirgendwo gesehen. Als struct wären es dann ja 120*6=720 Byte, da man sich die ganzen Pointer spart. Wie gesagt, diese Rückfrage ist nur, um mein Bild zurechtzurücken...

    Ansonsten habe ich Deine Antwort so verstanden, dass man komplett _datapointType weglassen könnte, wenn man alle Methoden, die darauf verweisen (eben die erwähnten value-Methoden) entfernt. Was bedeutet, dass man beim Aufruf immer den DPT mitgeben muss. Ich schau mir das an, aber ich könnte mir ein #define vorstellen, das den _datapointType und alle davon abhängigen Methoden ausblendet. Das wären dann (je nachdem, ob ich oben richtig liege) 6 oder 10 Bytes weniger, dafür weniger Komfort beim Aufruf.

    Punkt (d) sind wir uns ja einig, Punkt (c) würde ich nicht anfassen wollen (für nur 1 Byte). Punkt (b) müsste auch nicht sein, wenn man Punkt (a) hinbekommt.

    Zu Punkt (a) aber auch noch eine Verständnisfrage:
    Zitat von thesing Beitrag anzeigen
    Zusätzlich macht man noch ein globales Callback auf der GroupObjectTable (für Leute die viele GroupObjects haben und auf jedem ein UpdateCallback haben)
    Den Teil verstehe ich: Nur ein Callback, da das KO ja als Parameter mitgeschickt wird, muss man im callback sowieso anhand der asap dispatchen. Das wäre neu, keine Seiteneffekte.

    Zitat von thesing Beitrag anzeigen
    Den könnte man los werden wenn man die UpdateHandler in der GroupObjectable verwaltet. (etwa stumpf als Liste) Die würde man dann bei einem Update durchgehen und die Callbacks aufrufen.
    Hier habe ich ein Problem: Entweder man muss dann in der Liste das Pärchen (asap, callback) halten oder wieder ein Array von callbacks machen, was keinen Vorteil bringt. Und einfach stumpf alle callbacks aufzurufen würde eine Verhaltensänderung mit sich bringen, denn zur Zeit wird ja nur das KO aufgerufen, dass einen Callback zugewiesen hat. Die Liste (asap, callback) würde letztendlich mehr Speicher verbrauchen, sobald mehr als 2/3 aller KO einen callback haben.

    Mein Vorschlag: Über ein #define den callback aus dem GroupObject entfernen und dann nur noch den globalen callback zu lassen. Dispatching passiert dann auf Applikationsebene und alles ist gut. Das wären dann weitere 4 Bytes gespart.

    Ich würde dann auf sowas hin arbeiten:
    Code:
        size_t asapValueSize(uint8_t code);
    #ifndef SMALLER_GROUPOBJECTS
        GroupObjectUpdatedHandler _updateHandler;
        Dpt _datapointType;
    #endif
        size_t goSize();
        uint16_t _asap = 0;
        ComFlag _commFlag = Ok;
        uint8_t* _data = 0;
        uint8_t _dataLength = 0;
        // GroupObjectTableObject* _table = 0; //is now class variable
    natürlich mit #ifndef an allen weiteren abhängigen Stellen + ein globaler _updateHandler. Damit wäre ein KO nur noch 5 Byte (+Daten) groß, oder?

    Gruß, Waldemar

    P.S.: Wäre der globale _updateHandler nicht als Klassenmethode im GroupObject besser aufgehoben? Anstatt in der GroupObjectTable?

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Hi Thomas,

    Zitat von thesing Beitrag anzeigen
    Scheinbar sollte ein #ifdef MEDIUM_TYPE == FOO nicht nötig sein, das der Linker die nicht benutzen Objectdateien nicht linken sollte.
    das habe ich irgendwo auch mal gelesen, es aber bisher nicht verifiziert. Ich muss mir mal die Kommandozeile für den Linker ansehen.

    Aber selbst wenn der Linker nur die benötigten object files linkt, sollte man über #ifdef/#ifndef absichern, dass man nicht versehentlich oder aus Unwissenheit Codingteile referenziert, die nicht gebraucht werden. Die Idee einer config.h, die überall includiert ist, finde ich gut (wenn man bei Arduino wirklich keine defines von außen mitgeben kann - ich dachte, das kann jede C/C++ Entwicklungsumgebung). Allerdings hätte ich in dem config.h nur ein paar #defines gesehen, die #ifdef/#ifndef stehen doch dann im restlichen Stack, oder?

    Ahh, jetzt hab ich es gepeilt! Du würdest config.h folgendermaßen aufbauen:
    Code:
    #ifndef MEDIUM_TYPE 
    #define MEDIUM_TYPE 0
    #endif
    So könnte man sowohl von außen konfigurieren (über Kommandozeile) wie auch über die config.h in der Arduino-IDE. Wäre super für eine Konfigurierbarkeit, da könnte dann auch Dein Vorschlag von oben mit   #define SMALLER_GROUPOBJECTS  rein.

    Jetzt, wo ich es versanden habe (korrigier mich, falls nicht):

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • thesing
    antwortet
    mumpf Genau das meinte ich. Wahrscheinlich ist es am besten eine config.h in die lib zu packen mit lauter #ifndefs. Die muss dann halt der arduino-IDE User editieren wenn er z.B. eine anderen Medientyp nutzen will. Oder hat noch jemand eine bessere Idee?

    Edit:
    Hm. Scheinbar sollte ein #ifdef MEDIUM_TYPE == FOO nicht nötig sein, das der Linker die nicht benutzen Objectdateien nicht linken sollte. Muss ich bei Gelegenheit mal testen.
    Zuletzt geändert von thesing; 29.10.2019, 00:16.

    Einen Kommentar schreiben:


  • thesing
    antwortet
    Ich denke da könnte man in der Tat etwas sparen:

    (a)
    Code:
    (4) GroupObjectUpdatedHandler _updateHandler;
    Den könnte man los werden wenn man die UpdateHandler in der GroupObjectable verwaltet. (etwa stumpf als Liste) Die würde man dann bei einem Update durchgehen und die Callbacks aufrufen. Zusätzlich macht man noch ein globales Callback auf der GroupObjectTable (für Leute die viele GroupObjects haben und auf jedem ein UpdateCallback haben). Das registrCallback vom GroupObject wird dann gleich zur GroupObjectTable durchgereicht.

    (b)
    Code:
    (2) uint16_t _asap = 0;
    Der könnte auch weg. Dann müsste das GroupObject immer die GroupObjectTable nach dem Index von sich selbst fragen. Die müsste dann immer die Liste von allen GroupObjecten durchgehen und schauen wie der Index nun ist. Ich bin nicht sicher, ob man das will. Müsste man mal testen wie viel Performance das kostet. Wir haben ja immerhin kein 8bin MCUs.

    Code:
    (1) ComFlag _commFlag = Ok;
    (4) uint8_t* _data = 0;
    Die wird man wohl nicht los werden.

    (c)
    Code:
    (1) uint8_t _dataLength = 0;
    Den könnte man wohl analog zu _asap jedes mal von der GroupObjectTable herauspulen lassen.

    (d)
    Code:
    (4) GroupObjectTableObject* _table = 0;
    Der könnte wirklich zur Klassenvariable gemacht werden.

    (e)
    Code:
    (4) Dpt _datapointType;
    Hier wird es dir nichts Nützen nur eine Instanz pro Typ zu haben. Obwohl du die Größe dann von 6 auf 4 Byte drücken könntest. (ist ein struct aus drei shorts).
    Um den wirklich zu entfernen müsste man die value()-Methoden ohne Dpt entfernen.

    (a) und (d) finde ich gut.
    Für (b), (c) und (e) könnte man mit einem #define SAVE_SPACE oder SMALLER_GROUPOBJECTS o.ä. konfigurierbar machen. (Wenn das mit der Konfiguration per #define gescheit funktioniert.)

    VG
    Thomas

    Einen Kommentar schreiben:


  • mumpf
    antwortet
    Hi Thomas,

    was meinst Du mit
    Zitat von thesing Beitrag anzeigen
    Kann man bei Visual Studio Code eigentlich Defines for den Code angeben?
    Sicher nicht sowas
    Code:
    #ifdef __linux__
    #include <functional>
    typedef std::function<void(GroupObject&)> GroupObjectUpdatedHandler;
    #else
    typedef void (*GroupObjectUpdatedHandler)(GroupObject& go);
    #endif
    denn das hast Du ja schon häufig bei Dir drin. Ich kann bei VSCode dem Compiler aber sagen, dass __linux__ definiert ist (über compile-Flags). Meinst Du das?

    Gruß, Waldemar

    Einen Kommentar schreiben:


  • thesing
    antwortet
    Kann man bei Visual Studio Code eigentlich Defines for den Code angeben? Die Dateien für den RF werden z.B. nur bei MEDIUM_TYPE == 2 kompiliert. Ähnliches könnte man bei den Dateien für IP machen. Ich möchte ungern die Nutzer der Arduino-IDE aussperren. Mir ist aber nicht klar, wie man da derzeit für RF kompilieren kann. Wahrscheinlich gar nicht
    Hat da jemand eine zündende Idee?

    Einen Kommentar schreiben:

Lädt...
X