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
Ankündigung
Einklappen
Keine Ankündigung bisher.
ESP8266 KNX mit ETS
Einklappen
X
-
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?
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?Code:<ApplicationProgram Id="M-00FA_A-..." [COLOR=#FF0000]ApplicationNumber="555" ApplicationVersion="11"[/COLOR] ProgramType="ApplicationProgram" ...>
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:
-
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:
-
Danke für die Aufklärung. Auf das & hab ich nicht geachtet. Das zeigt mal wieder meine C++-Lücken...Zitat von thesing Beitrag anzeigenDer Dpt ist im GroupObject derzeit nicht als Referenz (Dpt&) definiert
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 anzeigenEs würde schon Sinn machen jeden Dpt nur einmal zu instanzieren. Da hast du Recht.
Da bin ich auch für, das man das dann einfacher in .git einchecken und muss es mit einer "richtigen IDE" nicht anfassenZitat von thesing Beitrag anzeigenAllerdings mit #ifndefs damit man das bei einer "richtigen" IDE übersteuern kann.
.
Gruß, Waldemar
Einen Kommentar schreiben:
-
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:
-
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.
Ich würde die config.h jetzt nicht unnötig mit #ifndefs usw. zupflastern.Zitat von mumpf Beitrag anzeigenIch fände die Möglichkeit, beides zu nutzen, am schönsten (also Thomas #ifndef-Vorschlag).
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:
-
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
Ich fände die Möglichkeit, beides zu nutzen, am schönsten (also Thomas #ifndef-Vorschlag).Zitat von Nanosonde Beitrag anzeigeneinfacher ist vermutlich wirklich eine einfache globale config.h.
Gruß, Waldemar
Einen Kommentar schreiben:
-
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:
-
Hi Thomas,
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...Zitat von thesing Beitrag anzeigenIch denke da könnte man in der Tat etwas sparen:
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:
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 anzeigenZusätzlich macht man noch ein globales Callback auf der GroupObjectTable (für Leute die viele GroupObjects haben und auf jedem ein UpdateCallback haben)
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.Zitat von thesing Beitrag anzeigenDen 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.
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:
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?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
Gruß, Waldemar
P.S.: Wäre der globale _updateHandler nicht als Klassenmethode im GroupObject besser aufgehoben? Anstatt in der GroupObjectTable?
Einen Kommentar schreiben:
-
Hi Thomas,
das habe ich irgendwo auch mal gelesen, es aber bisher nicht verifiziert. Ich muss mir mal die Kommandozeile für den Linker ansehen.Zitat von thesing Beitrag anzeigenScheinbar sollte ein #ifdef MEDIUM_TYPE == FOO nicht nötig sein, das der Linker die nicht benutzen Objectdateien nicht linken sollte.
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:
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.Code:#ifndef MEDIUM_TYPE #define MEDIUM_TYPE 0 #endif
Jetzt, wo ich es versanden habe (korrigier mich, falls nicht):
Gruß, Waldemar
- Likes 1
Einen Kommentar schreiben:
-
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:
-
Ich denke da könnte man in der Tat etwas sparen:
(a)
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.Code:(4) GroupObjectUpdatedHandler _updateHandler;
(b)
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:(2) uint16_t _asap = 0;
Die wird man wohl nicht los werden.Code:(1) ComFlag _commFlag = Ok; (4) uint8_t* _data = 0;
(c)
Den könnte man wohl analog zu _asap jedes mal von der GroupObjectTable herauspulen lassen.Code:(1) uint8_t _dataLength = 0;
(d)
Der könnte wirklich zur Klassenvariable gemacht werden.Code:(4) GroupObjectTableObject* _table = 0;
(e)
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).Code:(4) Dpt _datapointType;
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:
-
Hi Thomas,
was meinst Du mit
Sicher nicht sowasZitat von thesing Beitrag anzeigenKann man bei Visual Studio Code eigentlich Defines for den Code angeben?
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?Code:#ifdef __linux__ #include <functional> typedef std::function<void(GroupObject&)> GroupObjectUpdatedHandler; #else typedef void (*GroupObjectUpdatedHandler)(GroupObject& go); #endif
Gruß, Waldemar
Einen Kommentar schreiben:
-
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:


Einen Kommentar schreiben: