LibnoDave -> LastDataUnit in GetPlcBlocks

Jochen Kühner

Level-3
Beiträge
4.291
Reaktionspunkte
525
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo, Ich hab grad von einem Nutzer meiner Bibliothek einen Wireshark Auszug erhalten, in dem er von der SPS die Liste der DBs laden will. Da bekomme Ich von der CPU eine Antwaort, aber in der ersten Antwort steht LastDataUnit auf 1. Im folgetelegramm ist es dann null, aber der Fehlercode 0x0a! LibNoDave gibt dann aber nicht den richtigen Wert zurück! Ist das denn normal das im 2ten telegramm gar keine Namen mehr enthalten sind?
 

Anhänge

  • abzug.zip
    716 Bytes · Aufrufe: 5
Das kann bei manchen Steuerungen passieren, dass sie sagen "ich habe noch weitere Daten" und wenn diese dann angefragt werden die Antwort schicken "ich habe keine Daten". In diesem Fall den Fehler ab dem zweiten Paket einfach ignorieren und die Funktion ordentlich beenden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielleicht ist da in der CPU Firmware ein Fehler, denn wenn nur ein einziger Block mehr vorhanden wäre würde dieser nicht mehr in die PDU passen, die wäre dann um 2 Bytes zu groß.

Btw:
Wertest du eigentlich die Block flags aus? Ich habe noch nicht rausgefunden was die bedeuten, ich habe bisher nur gesehen dass diese bei 300er und 400ern unterschiedlich sind, zumindest in einem Bit.
 
Ist den der Fehler in der neusten libnodave behoben? Da wurde doch was wegen größeren Telegrammen eingebaut! Meiner Meinung nach hab Ich aber alle nötigen Änderungen in meine modifizierte Dll übernommen!
 
Also nach dem was in der 0.8.5.1 steht wird das nicht funktionieren.

snip
Code:
while (p2.param[9]!=0) {
	if (buffer!=NULL) memcpy(buffer+len,p2.udata,p2.udlen);
        dc->resultPointer=p2.udata;
        dc->_resultPointer=p2.udata;
        len+=p2.udlen;
	printf("more data\n");
	res=daveBuildAndSendPDU(dc, &p2,pam, sizeof(pam), NULL, 1);
	if (res!=daveResOK) return res; 	// bugfix from Natalie Kather
}
Man müsste vor dem Abbruch prüfen ob zumindest eine gültige Antwort eingetroffen ist.

Edit:
sehe grad dass der Bugfix mit der 0.8.5 eingetrudelt ist, vorher fehlte die Zeile.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Das hat nichts mit den größeren Telegrammen zu tun. Vielleicht prüft die CPU ja auch beim Pufferfüllen und stellt fest, dass nichts mehr reinpasst bzw. der nächste Eintrag über den Puffer hinaus gehen würde und schickt diesen dann ab mit dem Hinweis, dass weitere Daten vorhanden sind. Werden diese jetzt angefragt, stellt sie fest, dass doch nichts mehr zum Senden da ist. Ich würde an dieser Stelle nicht gleich von einem Firmwarefehler reden sondern von einer Unschönheit (Reihenfolge der Prüfungen), die nur in bestimmten Konstellationen auftritt. Ein Baustein mehr in die CPU einspielen und der Spuk ist vorbei. Dies sind nur Vermutungen über die Ursache, was wirklich dahinter steckt kann nur Siemens sagen. Ach ja, bei Vipa kann dieses Verhalten übrigens auch auftreten.
 
Sowas in der Art wird es sein. Zumindest könnte man durch einspielen einer passenden Anzahl an Bausteinen das Verhalten evtl. nachstellen und daran testen.

Ähnlichen Spuk generiert auch eine WinAC-RTX mit dem ständigen Verschicken von ISO-Paketen ohne Dateninhalt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, bei Iso on TCP. Es kommt vor jedem Paket mit den S7-Comm Daten ein ISO Paket mit den Flag "Last data unit" auf No, direkt danach kommt dann nochmal ein ISO Paket mit Last data unit = Yes und den eigentlichen Daten. Da aber nur für das erste ein TCP Ack geschickt wird, bzw, beide im TCP die gleiche Acknowledgement number besitzen, vermute ich mal dass beide Daten direkt mit einem TCP Sendebefehl auf die Leitung gehen.
Ich habe mal so ein Telegrammverkehr angehängt (hat mit dem Problem von Jochen nichts zu tun).
 

Anhänge

  • WinCC7_mit_WinAC_ZyklischeLesedienste_komplett.zip
    2,2 KB · Aufrufe: 3
Dabei handelt es sich um sogenannte FastAcknowledge-Pakete. Diese wurden vor langer Zeit eingeführt, da die CPs in der Regel nach dem Senden ca. 200-300 ms warteten bis sie das nächste Paket abgeschickt haben. Wenn sie jetzt ein solches leeres Datenpaket bekommen haben, haben sie die weiteren Daten sofort abgeschickt. Deshalb wird ein empfangenes Paket immer sofort mit einem solchen Paket quittierte, damit die Gegenstelle weiter senden kann.
 
Aber das würde doch auch ohne diese leeren, bzw. minimal-großen Iso Pakete gehen.
Da auf S7-Kommunikationsseite im Großteil der Telegramme ein Frage und Antwortspiel auf ISO-OSI-Ebene 7 läuft, könnte doch jedes Paket mit Push und Ack gesendet werden.

Ich sehe grade dass das nicht nur die WinAC so macht, sondern auch mein PG. Nur eine "normale" 315 z.B. macht das nicht.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn Du Dein Log anschaust, siehts Du, dass teilweise deutlich über 100 ms zwischen dem FastAck und dem nächsten Datentelegramm vergehen. Wenn die Gegenseite jetzt etwas zu senden hätte, dann könnte sie dies unverzüglich tun. In den Zeiten der 318er bzw. der ersten 443er war es wichtiger. DIe waren nicht in der Lage, die 480 Bytes einer PDU auf einmal zu senden. Wenn da kein FastAck kam, brach die Performance dramatisch ein, da das zweite Häppchen diese 200-300 ms später verschickt wurde. Der effektive Datendurchsatz sank damit auf unter 2 kB/s.
Bei manchen Geräten und Schnittstellen kann dieses FastAck übrigens auch eingestellt werden (habe ich jedenfalls schon einmal gesehen).
 
Ok, nun gehts!

es war auf jeden Fall auch noch falsch das die Sequence Number aus dem vorigen Telegramm nicht übernommen wurde:

Code:
[COLOR=#0000ff][B]while[/B][/COLOR] [COLOR=#006400]([/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]9[/COLOR][COLOR=#006400]]!=[/COLOR][COLOR=#00008b]0[/COLOR][COLOR=#006400])[/COLOR] [COLOR=#006400]{[/COLOR]
        [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]buffer[COLOR=#006400]!=[/COLOR]NULL[COLOR=#006400])[/COLOR] [COLOR=#191970][B]memcpy[/B][/COLOR][COLOR=#006400]([/COLOR]buffer[COLOR=#006400]+[/COLOR]len[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400]);[/COLOR]
        dc[COLOR=#006400]->[/COLOR]resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        dc[COLOR=#006400]->[/COLOR]_resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        len[COLOR=#006400]+=[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400];[/COLOR]
        [COLOR=#191970][B]printf[/B][/COLOR][COLOR=#006400]([/COLOR][COLOR=#ff00ff]"more data\n"[/COLOR][COLOR=#006400]);[/COLOR]
        res[COLOR=#006400]=[/COLOR][COLOR=#191970][B]daveBuildAndSendPDU[/B][/COLOR][COLOR=#006400]([/COLOR]dc[COLOR=#006400],[/COLOR] [COLOR=#006400]&[/COLOR]p2[COLOR=#006400],[/COLOR]pam[COLOR=#006400],[/COLOR] [COLOR=#0000ff][B]sizeof[/B][/COLOR][COLOR=#006400]([/COLOR]pam[COLOR=#006400]),[/COLOR] NULL[COLOR=#006400],[/COLOR] [COLOR=#00008b]1[/COLOR][COLOR=#006400]);[/COLOR]
        [COLOR=#008000]if (res!=daveResOK) return res;     // bugfix from Natalie Kather[/COLOR]
    [COLOR=#006400]}[/COLOR]

muss in
Code:
[COLOR=#0000ff][B]while[/B][/COLOR] [COLOR=#006400]([/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]9[/COLOR][COLOR=#006400]]!=[/COLOR][COLOR=#00008b]0[/COLOR][COLOR=#006400])[/COLOR] [COLOR=#006400]{[/COLOR]
        [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]buffer[COLOR=#006400]!=[/COLOR]NULL[COLOR=#006400])[/COLOR] [COLOR=#191970][B]memcpy[/B][/COLOR][COLOR=#006400]([/COLOR]buffer[COLOR=#006400]+[/COLOR]len[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400]);[/COLOR]
        dc[COLOR=#006400]->[/COLOR]resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        dc[COLOR=#006400]->[/COLOR]_resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        len[COLOR=#006400]+=[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400];[/COLOR]
        [COLOR=#191970][B]printf[/B][/COLOR][COLOR=#006400]([/COLOR][COLOR=#ff00ff]"more data\n"[/COLOR][COLOR=#006400]);[/COLOR]
        pam[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]]=[/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]];[/COLOR]
        res[COLOR=#006400]=[/COLOR][COLOR=#191970][B]daveBuildAndSendPDU[/B][/COLOR][COLOR=#006400]([/COLOR]dc[COLOR=#006400],[/COLOR] [COLOR=#006400]&[/COLOR]p2[COLOR=#006400],[/COLOR]pam[COLOR=#006400],[/COLOR] [COLOR=#0000ff][B]sizeof[/B][/COLOR][COLOR=#006400]([/COLOR]pam[COLOR=#006400]),[/COLOR] NULL[COLOR=#006400],[/COLOR] [COLOR=#00008b]1[/COLOR][COLOR=#006400]);[/COLOR]
        [COLOR=#008000]//if (res!=daveResOK) return res;     // bugfix from Natalie Kather[/COLOR]
    [COLOR=#006400]}[/COLOR]

geändert werden...
 
Warum hast du den Abbruch bei res!=0 auskommentiert? Wenn die Schleife läuft und die Verbindung zur SPS abbricht, wird sie nie mehr verlassen!
 
Ich bin nicht sicher, ob die Fehler konsequent durchgereicht werden, aber
daveBuildAndSendPDU erwartet eine Antwort und sollte mit timeout zurückkehren, wenn die ausbleibt.
Wenn das eine zulässige Reaktion der Steuerung ist,
dürfte halt nur die while-Schleife abgebrochen werde, aber nicht die ganze Funktion...
 
Zuletzt bearbeitet:
Also müssts so passen:

Code:
     [COLOR=#0000ff][B]while[/B][/COLOR] [COLOR=#006400]([/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]9[/COLOR][COLOR=#006400]]!=[/COLOR][COLOR=#00008b]0[/COLOR][COLOR=#006400])[/COLOR] [COLOR=#006400]{[/COLOR]
        [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]buffer[COLOR=#006400]!=[/COLOR]NULL[COLOR=#006400])[/COLOR] [COLOR=#191970][B]memcpy[/B][/COLOR][COLOR=#006400]([/COLOR]buffer[COLOR=#006400]+[/COLOR]len[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400]);[/COLOR]
        dc[COLOR=#006400]->[/COLOR]resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        dc[COLOR=#006400]->[/COLOR]_resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
        len[COLOR=#006400]+=[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400];[/COLOR]
        [COLOR=#191970][B]printf[/B][/COLOR][COLOR=#006400]([/COLOR][COLOR=#ff00ff]"more data\n"[/COLOR][COLOR=#006400]);[/COLOR]
        pam[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]]=[/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]];[/COLOR]
        res[COLOR=#006400]=[/COLOR][COLOR=#191970][B]daveBuildAndSendPDU[/B][/COLOR][COLOR=#006400]([/COLOR]dc[COLOR=#006400],[/COLOR] [COLOR=#006400]&[/COLOR]p2[COLOR=#006400],[/COLOR]pam[COLOR=#006400],[/COLOR] [COLOR=#0000ff][B]sizeof[/B][/COLOR][COLOR=#006400]([/COLOR]pam[COLOR=#006400]),[/COLOR] NULL[COLOR=#006400],[/COLOR] [COLOR=#00008b]1[/COLOR][COLOR=#006400]);[/COLOR]
        [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]res[COLOR=#006400]!=[/COLOR]daveResOK[COLOR=#006400])[/COLOR]
            [COLOR=#000080]break[/COLOR][COLOR=#006400];[/COLOR]
    [COLOR=#006400]}[/COLOR]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du müsstest die folgenden Zeilen aber auch noch anpassen, ansonsten gibt es ein Fehler-Eintrag im Logfile obwohl die Funktion an sich funktioniert hat.
Evtl. nur ein Log-Eintrag wenn :
res != daveResOK und len == 0

Denn dann ist noch kein gültiges Telegramm eingetroffen.
 
Ich würde da lieber strenger sein:
Code:
[COLOR=#0000ff][B]while[/B][/COLOR] [COLOR=#006400]([/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]9[/COLOR][COLOR=#006400]]!=[/COLOR][COLOR=#00008b]0[/COLOR][COLOR=#006400])[/COLOR] [COLOR=#006400]{[/COLOR]
          [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]buffer[COLOR=#006400]!=[/COLOR]NULL[COLOR=#006400])[/COLOR] [COLOR=#191970][B]memcpy[/B][/COLOR][COLOR=#006400]([/COLOR]buffer[COLOR=#006400]+[/COLOR]len[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400],[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400]);[/COLOR]
          dc[COLOR=#006400]->[/COLOR]resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
          dc[COLOR=#006400]->[/COLOR]_resultPointer[COLOR=#006400]=[/COLOR]p2[COLOR=#006400].[/COLOR]udata[COLOR=#006400];[/COLOR]
          len[COLOR=#006400]+=[/COLOR]p2[COLOR=#006400].[/COLOR]udlen[COLOR=#006400];[/COLOR]
           [COLOR=#191970][B]printf[/B][/COLOR][COLOR=#006400]([/COLOR][COLOR=#ff00ff]"more data\n"[/COLOR][COLOR=#006400]);[/COLOR]
           pam[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]]=[/COLOR]p2[COLOR=#006400].[/COLOR]param[COLOR=#006400][[/COLOR][COLOR=#00008b]7[/COLOR][COLOR=#006400]];[/COLOR]
          res[COLOR=#006400]=[/COLOR][COLOR=#191970][B]daveBuildAndSendPDU[/B][/COLOR][COLOR=#006400]([/COLOR]dc[COLOR=#006400],[/COLOR] [COLOR=#006400]&[/COLOR]p2[COLOR=#006400],[/COLOR]pam[COLOR=#006400],[/COLOR] [COLOR=#0000ff][B]sizeof[/B][/COLOR][COLOR=#006400]([/COLOR]pam[COLOR=#006400]),[/COLOR] NULL[COLOR=#006400],[/COLOR] [COLOR=#00008b]1[/COLOR][COLOR=#006400]);[/COLOR]
          [COLOR=#0000ff][B]if[/B][/COLOR] [COLOR=#006400]([/COLOR]res[COLOR=#006400]==0xa[/COLOR][COLOR=#006400]) [/COLOR][COLOR=#000080]break[/COLOR][COLOR=#006400];[/COLOR] // Ich meine, bei einem so aufgebauten Antwortpaket wird auch 0xa zurückgegeben...
          if (res!=daveOk) return res; // alle anderen Fehler nicht ignorieren.
    [COLOR=#006400]}[/COLOR]
 
Zuletzt bearbeitet:
Zurück
Oben