Ankündigung

Einklappen
Keine Ankündigung bisher.

Wie kommuniziert die ETS mit KNX-Geräten (z.B. beim partiellen Programmieren)

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

    #16
    Sehr gut
    Aber nicht zu früh freuen. Mein Code schafft zwar das Beispiel, aber wenn ich etwas anderes Vergleiche kommt was anderes als auf der Webseite raus...
    Muss die Tage mal schauen, was an meinem Code nicht passt.

    Aber freut mich, dass ich soweit schon mal helfen konnte ^^
    Und 6 Sekunden sind echt wenig!
    Werde dass dann auch bei Gelegenheit bei der Kaenx implementieren.
    Eine Frage allerdings noch: Die Funktion gibt es nur bei MaskenVersionen nach SystemB?

    Gruß Mike
    OpenKNX www.openknx.de | Kaenx-Creator | Dali-GW

    Kommentar


      #17
      Und bei 0705.

      Gruß Waldemar
      OpenKNX www.openknx.de

      Kommentar


        #18
        Super Fortschritte ihr beiden, sehr gut!

        Waldemar, kannst Du mal sagen wo genau Du den Stack gehackt hast? Ich habe in table_object.cpp eine CallBackProperty eingebaut die PID_MCB_TABLE mit einer Konstanten als CRC zurückliefert. Die wird beim partiellen Programmieren aber nicht aufgerufen, nur beim kompletten Upload. In welche cpp hast Du das eingebaut, ich bin da scheinbar an der falschen Stelle unterwegs...

        Und was hast Du in der knxprod geändert, hast Du den MergeId 7 dringelassen oder rausgelöscht? Das hatte ich im dem Beitrag am Anfang nicht genau verstanden. Ich hatte das bei mir eingebaut, evtl. liegt da aber gerade das Problem...
        Code:
        <LoadProcedure MergeId="7">
          <LdCtrlLoadImageProp ObjIdx="1" PropId="27" />
          <LdCtrlLoadImageProp ObjIdx="2" PropId="27" />
          <LdCtrlLoadImageProp ObjIdx="3" PropId="27" />
          <LdCtrlLoadImageProp ObjIdx="4" PropId="27" />
        </LoadProcedure>
        Vielen Dank!

        Gruß, Julius

        Kommentar


          #19
          Hi Julius,

          das ist aber ungeduldig . Aber schön, wenn das noch jemand testet. Wie gesagt, ich arbeite zwar auf einem Fork, aber diese Teile dürften noch so ziemlich gleich sein.

          Ich habe in TableObject folgendes ergänzt:
          Code:
          void TableObject::readProperty(PropertyID id, uint32_t start, uint32_t& count, uint8_t* data)
          {
              switch (id)
              {
                  case PID_LOAD_STATE_CONTROL:
                      data[0] = _state;
                      break;
                  case PID_TABLE_REFERENCE:
                      if (_state == LS_UNLOADED)
                          pushInt(0, data);
                      else
                          pushInt(tableReference(), data);
                      break;
          [MARKIEREN]        case PID_MCB_TABLE:
                      data = pushInt(_size, data); // segment size
                      data = pushByte(0x00, data);  // CRC Control Byte
                      data = pushByte(0xFF, data);  // ReadAccess/WrtiteAccess
                      pushWord(Crc16Citt(_data, _size), data);
                      // pushWord(tableReference() & 0xFFFF, data);
                      break;
          [/MARKIEREN]        case PID_ERROR_CODE:
                      data[0] = _errorCode;
                      break;
                  default:
                      InterfaceObject::readProperty(id, start, count, data);
              }
          }
          [MARKIEREN]uint16_t TableObject::Crc16Citt(uint8_t* data, uint16_t length)
          {
              uint16_t initialValue = 0x1D0F;
              uint16_t Table[] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
              if (data == nullptr)
                  return 0;
              if (length == 0)
                  return 0;
              uint16_t crc = initialValue;
              for (int i = 0; i <= length; i++)
              {
                  crc = (uint16_t)((crc << 8) ^ Table[((crc >> 8) ^ (0xff & data[i]))]);
              }
              return crc;
          }
          [/MARKIEREN]
          
          uint8_t TableObject::propertySize(PropertyID id)
          {
              switch (id)
              {
                  case PID_LOAD_STATE_CONTROL:
                      return 1;
                  case PID_TABLE_REFERENCE:
                      return 4;
                  case PID_ERROR_CODE:
                      return 1;
                  case PID_OBJECT_TYPE:
                      return 2;
          [MARKIEREN]        case PID_MCB_TABLE:
                      return 8;
          [/MARKIEREN]        default:
                      return InterfaceObject::propertySize(id);
              }
          }
          Das Headerfile angepasst:
          Code:
          [MARKIEREN]public:
              static uint16_t Crc16Citt(uint8_t* data, uint16_t length);
          [/MARKIEREN]
          und in der knxprod folgende Einträge bei den LoadProcedures:
          Code:
                      <LoadProcedures>
                        <LoadProcedure MergeId="2">
          [MARKIEREN]                <LdCtrlRelSegment LsmIdx="4" Size="0" Mode="0" Fill="0" AppliesTo="full" />
                          <LdCtrlRelSegment LsmIdx="4" Size="0" Mode="1" Fill="0" AppliesTo="par" />
          [/MARKIEREN]              </LoadProcedure>
                        <LoadProcedure MergeId="4">
          [MARKIEREN]                <LdCtrlWriteRelMem ObjIdx="4" Offset="0" Size="0" Verify="true" AppliesTo="full,par" />
          [/MARKIEREN]              </LoadProcedure>
          [MARKIEREN]              <LoadProcedure MergeId="7">
                            <LdCtrlLoadImageProp ObjIdx="1" PropId="27" />
                            <LdCtrlLoadImageProp ObjIdx="2" PropId="27" />
                            <LdCtrlLoadImageProp ObjIdx="3" PropId="27" />
                            <LdCtrlLoadImageProp ObjIdx="4" PropId="27" />
                        </LoadProcedure>
                      </LoadProcedures>
          [/MARKIEREN]
          Damit funktioniert das. Ist nicht wirklich viel, hat nur gedauert, es rauszufinden Ist aber noch nicht wirklich gut getestet, das wollte ich jetzt die nächsten Tage machen.

          Gruß, Waldemar
          OpenKNX www.openknx.de

          Kommentar


            #20
            Hi Waldemar,

            stimmt da war ich etwas ungeduldig - Danke dass Du trotzdem geantwortet hast . Leider sieht das in der aktuellen Version alles anders aus, da muss noch mehr geändert und getestet werden. Das nur als kurze Rückmeldung...

            Viele Grüße, Julius

            Kommentar


              #21
              Du hast recht, das ist im neuen Stack anders, ich bin nicht so gut mit Templates und schon gar nicht mit Lambdas...

              Aber es hat mir gezeigt, dass ich die PropertyDescription vergessen habe (obwohl es trotzdem funktioniert hat). Gib mir noch bis Ostern, damit ich sicher sagen kann, dass es läuft, dann versuche ich es auf den neuen Stack zu portieren und dann wäre es toll, wenn Du es ausprobieren würdest, denn ich kann (aus verschiedenen Gründen) nicht von meinem Fork weg. Insofern ist testen mit dem aktuellen Stack immer schwer für mich...

              Gruß, Waldemar
              OpenKNX www.openknx.de

              Kommentar


                #22
                Hi Waldemar und Mike,

                ich habe die CRC Funktion und die fehlende CallBackProperty für PID_MCB_TABLE in den neuen Stack eingebaut. Es gab aber immer einen Fehler bei PID_PROG_VERSION was beim partiellen Programmieren nicht gelesen werden konnte (Zugriff auf geschützten Speicherbereich). Dann habe ich gesehen dass _programVersion seit einiger Zeit nicht mehr im EEPROM gespeichert wird, daher war der Wert nicht lesbar. Also habe ich das eben zurückportiert und jetzt funktioniert es soweit ich sehen kann. Der commit ist im Fork: https://github.com/OutOfSync1/knx. Tester sind sehr willkommen!

                Credit für die Funktion geht natürlich an Waldemar und Mike!

                Gruß, Julius

                Kommentar


                  #23
                  Hi Julius,

                  ich hab mal rein geschaut, das sieht gut aus. Ein Glück, dass ich auf dem älteren Stack arbeite, ich hätte das mit dem fehlenden Property wohl nicht hinbekommen.
                  Insofern solltest Du Deinen Verdienst nicht herabwürdigen. Ist ein Community-Erfolg. Ich hab was ausprobiert, Maik hat Input gegeben, Du hast es portiert.
                  Wenn es klappt, nützt es allen.

                  Ich kann leider nicht testen! Sorry, aber der aktuelle Stack hat nicht die passende Flash Implementierung für meine Anwendung...

                  Gruß, Waldemar
                  OpenKNX www.openknx.de

                  Kommentar


                    #24
                    Hi allerseits,

                    nach ein paar weiteren Tests muss ich sagen, dass das mit dem partiellen Programmieren zu funktionieren scheint. Aber das beste ist: Ich hab jetzt verifizieren können, dass die komplette Programmierung der Applikation wesentlich schneller laufen kann, zumindest wenn (wie bei mir) das meiste, was initial übertragen wird, nur Nullen (0x00) sind. Ich verstehe jetzt endlich diese Einträge:

                    Code:
                                  <LoadProcedure MergeId="2">
                                    <LdCtrlRelSegment LsmIdx="4" Size="0" Mode="1" Fill="0" AppliesTo="full" />
                                    <LdCtrlRelSegment LsmIdx="4" Size="0" Mode="0" Fill="0" AppliesTo="par" />
                                  </LoadProcedure>
                    Mode=0 bedeutet nämlich, das Device soll beim Programmieren den Parameterspeicher so lassen, Mode=1 heißt aber, das Gerät soll selbständig vor dem Programmieren den Speicher mit dem Wert von Fill füllen (im obigen Fall also mit 0).

                    Somit ist die 2. Zeile klar: Für partielles Programmieren wäre es schwachsinnig, vorher den Speicher mit Nullen zu überschreiben, also bleibt nur Mode=0.
                    Aber bei der 1. Zeile hat man die Freiheit: Wenn man da Mode=0 macht, dann verlässt man sich nicht darauf, dass das Gerät wirklich das Löschen implementiert hat und lässt die ETS die ganzen Nullen übertragen (bei mir knapp 2 Minuten, und das schon mit long frames). Ich hatte das zuerst mit Mode=0, weil ich mir nicht sicher war, ob das Füllen im Stack implementiert ist.
                    Jetzt habe ich mal Mode=1 Fill=0 ausprobiert und was soll ich sagen: 21 Sekunden! Man sieht schön im Protokoll, dass die ETS dann nur noch Werte ungleich 0x00 überträgt. Klasse!
                    Und um auszuprobieren, ob der Speicher wirklich gelöscht wird, habe ich mal Mode=1 Fill=0 beim partiellen Programmieren gemacht. Die ETS hat dann nur ein paar Bytes übertragen, im Debugger habe ich dann geprüft, alle nicht übertragenen Parameter waren 0 und das Gerät hat sich dann auch aufgehängt.

                    Langer Rede kurzer Sinn: Mit der obigen Einstellung wird sowohl partielles wie auch komplettes Programmieren der Applikation beschleunigt, und das wesentlich!

                    Ich frage mich immer, warum die Hersteller nicht mehr in solche Delta-Übertragungen investieren. Die haben doch alle Informationen und müssen sie sich nicht mühsam wie wir über Try&Error zusammensuchen.

                    Gruß, Waldemar
                    OpenKNX www.openknx.de

                    Kommentar


                      #25
                      Hallo Waldemar,

                      das sind ja echt gute Neuigkeiten!
                      Hab mich schon lange gefragt was diese Mode macht xD

                      So ganz muss ich sagen hab ich das aber immer noch nicht verstanden.
                      Mode=0 heißt also ich übertrage alles egal ob es wie das Fill Attribut ist.
                      Mode=1 heißt ich übertrage nur, was nicht wie das Fill Attribut ist.

                      Muss ich dann iwas spezielles im MemoryWrite Telegramm machen, damit das Gerät weiß welcher Modus gerade aktiv ist?
                      Oder passiert das vll sogar schon früher beim AllocAbsSegment?

                      Ich kann ja auch bei einem MemoryWrite von 12 Bytes nicht einfach in der Mitte Bytes auslassen. Könnte dann also beim vollen Programmieren nur Blöcke weg lassen die komplett aus 0en besteht.

                      Oder hab ich da jetzt iwo nen großen Denkfehler?


                      Gruß Mike

                      P.s.: Da hast du natürlich recht. Bei denen geht es meist aber auch um Geld. Und Zeit ist nun mal Geld :/
                      Klar wäre das nur das erste mal ein kleiner Aufwand und danach könnte man es kopieren, aber wer kennt nicht den Chef der keine 50€ ausgeben will um nachher deutlich mehr zu sparen^^
                      OpenKNX www.openknx.de | Kaenx-Creator | Dali-GW

                      Kommentar


                        #26
                        Kleiner Nachschub:
                        Ich hab den Teil nun endlich in der KNX Spec gefunden.
                        3/5/2 Managment Procedures (Seite 116)

                        Wenn Mode=1 ist, kann ich also sicher sein (solange es im Stack auch so implementiert ist), dass der Speicher schon den Wert von Fill hat und ich ihn nicht übertragen muss.
                        Hab ich damals sogar auch schon eingebaut ohne zu wissen was es genau macht xD
                        Angehängte Dateien
                        OpenKNX www.openknx.de | Kaenx-Creator | Dali-GW

                        Kommentar


                          #27
                          Hi Mike,

                          Zitat von proggerKA Beitrag anzeigen
                          Oder passiert das vll sogar schon früher beim AllocAbsSegment?
                          wo es genau auf Telegramm-Ebene passiert, weiß ich gar nicht, aber es muss beim allozieren des Speichers passieren. Ich habe folgendes im Stack gefunden:
                          Code:
                          bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
                          {
                              if (_data)
                              {
                                  _platform.freeNVMemory(_ID);
                                  _data = 0;
                                  _size = 0;
                              }
                              if (size == 0)
                                  return true;
                              
                              _data = _platform.allocNVMemory(size+this->size(), _ID);
                              _data = _data + this->size();  //skip metadata
                              _size = size;
                          [MARKIEREN]    if (doFill){
                                  uint8_t* addr = _data;
                                  for(size_t i=0; i<_size;i++)
                                      _platform.writeNVMemory(addr++, fillByte);
                              }
                          [/MARKIEREN]    return true;
                          }
                          Also muss der Mode schon beim allozieren vom Speicher bekannt sein.

                          Aber da Du Dich ja damit auskennst: Sagt denn die ETS, wie viel Speicher sie haben will? Also gibt sie die Größe mit? Den Teil hab ich noch nicht analysiert...

                          Gruß, Waldemar
                          OpenKNX www.openknx.de

                          Kommentar


                            #28
                            Hallo Waldemar,

                            habs zwischenzeitlich in der Spec gefunden gehabt. Es passiert während dem Alloc.
                            In der Ladeprozedur in der Applikation wird immer die Größe des Speichers mit angegeben:
                            Code:
                            <LdCtrlRelSegment LsmIdx="4" Size="1740" Mode="1" Fill="0" AppliesTo="full" />
                            Beim partiellen Programmieren mit Mode=0 bin ich mir da aber nicht sicher.
                            Wenn ich nen Parameter auf 5 stelle und partiell übertrage. Und ihn danach wieder zurück auf 0 stelle, dann muss er doch übertragen werden oder? Ansonsten steht im Speicher ja noch 5, da er nicht mit 0er aufgefüllt wurde. Das war also nur für dich zum Testen?

                            Gruß Mike
                            OpenKNX www.openknx.de | Kaenx-Creator | Dali-GW

                            Kommentar


                              #29
                              Hi,

                              partielles Programmieren braucht Mode=0. Dann wird nämlich der Speicher so belassen, wie er ist. Die ETS weiß das ja und schickt auch eine 0, weil 0 anders ist als 5 .

                              Im Prinzip läuft die Delta-Ermittlung unterschiedlich:
                              • full mit Mode=0: alles schicken, da der Speicher "irgendeinen" Zustand hat.
                              • full mit Mode=1 und Fill=0: Der Speicher ist voller 0x00, also schicke nur die Bytes, die ungleich 0x00 sind. Wenn der Fill anders gewählt wird, dann natürlich das Delta passend zum Fill ermitteln.
                              • par mit Mode=0: Die ETS weiß den vorherigen Speicherzustand und verifiziert diesen über PID_MCB_TABLE. Wenn der noch stimmt, wird das Delta zum bekannten vorherigen Zustand gebildet und nur das geschickt. In Deinem Beispiel würde die ETS wissen, dass an der Stelle eine 5 im Speicher steht, und deswegen eine 0 schicken.
                              • par mit Mode=1 und Fill=0 geht nicht. Mein Device überschreibt alle Daten mit 0x00, die ETS schickt aber trotzdem nur das Delta zum vorherigen Wert. Ergibt Müll...
                              Gruß, Waldemar
                              OpenKNX www.openknx.de

                              Kommentar


                                #30
                                Hmmm, ich habe jetzt bei etwa jedem 5. partiellen programmieren doch eine full-programmierung, aber mit mode 0, also alle Daten übertragen, sprich die langsamste Variante. Weißt Du, was die Kriterien sind, dass sich die ETS dafür entscheidet? Wenn sie dann wenigstens die Settings für full (Mode 1, Fill 0) nehmen würde... Ich habe aber noch nicht die Kommunikation analysiert, das muss ich noch machen, vielleicht sieht man da was.

                                Gruß, Waldemar
                                OpenKNX www.openknx.de

                                Kommentar

                                Lädt...
                                X