DotNetSiemensPLCToolBoxLibrary (LibNoDave) Zugriff auf Dual-Port RAM / FB15

Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn ich MAXUNACKED auf 1 setze funktionierts. Wenn ich DEBUG_CALLS einkommentiere funktioniert das Kompilieren nicht. Hab aber gesehen, dass in der Ausgabe von VS auch was zu sehen ist.

Code:
daveGetNCfile: Response start upload, param.errorcode=0x0000
daveGetNCfile: Verwendete Sequenznummer=71
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=0
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=1
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=2
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=3
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=4
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=5
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=6
daveGetNCfile: continue upload, param.errorcode=0x340d
 
Ich meinte per daveSetDebug das Debugging in libnodave aktivieren, dann werden auch ggf. die gesamten PDUs gedumpt.
Vielleicht kommt man dann zusammen mit einem Wireshark log dahinter woran es hakt. Denn es sieht so aus als ob das Problem auftritt wenn mehrere PDUs in einem Telegramm vorhanden sind. Das sollten aber die unterlagerten Funktionen von libnodave eigentlich korrekt verarbeiten können. Bei der normalen S7-Kommunikation kommt dieser Fall aber nie vor, zumindest nicht wenn man beim Verbindungsaufbau mit der SPS angibt, dass man nur ein Telegramm zur Zeit verarbeiten kann.
 
Das ist gediegen. Meine Vermutung ist aber, dass es mit debug funktioniert weil das Programm durch die debug-Ausgaben entsprechend langsamer arbeitet. Aber an welcher Stelle das Problem liegt sehe ich so nicht, _daveReadISOPacket() sollte so wie es aussieht damit klarkommen wenn mehrere PDUs in einem Telegramm sind.

Speicherst du die Ausgaben mittels einer Pipe in eine Textdatei, oder lässt du dir das auf der Konsole ausgeben? Mit einer Pipe wird es vlt. etwas schneller, sodass wir damit auch debug-Ausgaben bekommen sollten wenn der Fehler auftritt.

Ich habe mal ein paar von meinen PDU-Dumps entfernt, die sind nämlich doppelt weil in einigen Funktionen auch schon gedumpt wird. Bereinigt also:
Code:
#define MAXUNACKED 20
int DECL2 
daveGetNCfile(daveConnection *dc, const char *filename, char *buffer, int *length)
{
    PDU p, p2;
    int res = 0;
    uc unackcount = 0;
    int filename_len = 0;
    int tot_len = 0;
    int part_len = 0;

    /* Request upload */
    uc req_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x06, 0x00
    };
    uc req_up_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20  */
        MAXUNACKED, 0x00,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    /* Continue upload */
    uc cont_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x3f, 0x08, 0x00
    };
    uc cont_up_da[]= {
        0xff, 0x09, 0x00, 0x02,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20 */
        MAXUNACKED, 0x00
    };

    *length = 0;
    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_up_da[3] = filename_len + 2;    /* + 1 Byte Anzahl Telegramme + 1 Byte unbekannt */
    memcpy(&req_up_da[6], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_up_pa, sizeof(req_up_pa));
    _daveAddData(&p, req_up_da, 6 + filename_len);

    res = _daveExchange(dc, &p);
    if (res != daveResOK) {
        return res;
    }
    res = _daveSetupReceivedPDU(dc, &p2);
    /* Errorcode im Parameterteil prüfen */
    res = daveGetU16from(&p2.param[10]);
    LOG2("daveGetNCfile: Response start upload, param.errorcode=0x%04x\n", res);
    if (res != 0) {
        return -2;
    }
    cont_up_pa[7] = p2.param[7];      /* Sequenznummer für alle folgenden Continue-Uploads verwenden */
    LOG2("daveGetNCfile: Verwendete Sequenznummer=%d\n", cont_up_pa[7]);
    res = _daveTestResultData(&p2);
    if (res != daveResOK) {
        return res;
    }
    LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
    /* Vor den eigentlichen Daten sind hier noch 2 Bytes unbekannter Funktion eingeschoben */
    part_len = p2.udlen - 2;
    if (part_len <= 0) {
        return -3;
    }
    memcpy(buffer + tot_len, p2.data + 6, part_len);
    tot_len += part_len;
    /* Wenn ab hier noch nicht alles gelesen, dann werden bis zu 20 Telegramme gesendet die 
     * nicht bestätigt werden müssen. Dann gibt es ein ack usw. usf.
     */
    while (p2.param[9] != 0) {     /* 0 = Last data unit */
        LOG2("daveGetNCfile: unackcount=%d\n", unackcount);
        /* Nach 20 Telegrammen continue Telegramm senden */
        if (unackcount == MAXUNACKED) {
            LOG1("daveGetNCfile: Sende continue Telegramm\n");
            p.header = dc->msgOut + dc->PDUstartO;
            _daveInitPDUheader(&p, 7);
            _daveAddParam(&p, cont_up_pa, sizeof(cont_up_pa));
            _daveAddData(&p, cont_up_da, sizeof(cont_up_da));
            res = _daveSendTCP(dc, &p);
            if (res != daveResOK) {
                return res;
            }
            unackcount = 0;
        }
        LOG1("daveGetNCfile: Empfange Upload Push-Telegramm\n");
        res = _daveGetResponseISO_TCP(dc);
        if (res != daveResOK) {
            return res;
        }
        res = _daveSetupReceivedPDU(dc, &p2);
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        LOG2("daveGetNCfile: continue upload, param.errorcode=0x%04x\n", res);
        if (res != 0) {
            return -4;
        }
        res = _daveTestResultData(&p2);
        if (res != daveResOK) {
            return res;
        }
        LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
        part_len = p2.udlen - 2;
        if (part_len <= 0) {
            return -5;
        }
        memcpy(buffer + tot_len, p2.data + 6, part_len);
        tot_len += part_len;
        unackcount++;
    }
    *length = tot_len;
    return res;
}
 
Liegt hier vielleicht ein Netzwerkproblem vor?
In deinem Wireshark Log daveGetNcFile_BigUpload_Debug dauert es nämlich vom letzten Telegramm von der NC in #277 bis zum Continue in #3086 etwa 84 Sekunden. Beim zweiten Mal zwischen #3118 und #5785 sind es 82 Sekunden. Oder liegt es an den Debug-Ausgaben?
 
Liegt hier vielleicht ein Netzwerkproblem vor?
In deinem Wireshark Log daveGetNcFile_BigUpload_Debug dauert es nämlich vom letzten Telegramm von der NC in #277 bis zum Continue in #3086 etwa 84 Sekunden. Beim zweiten Mal zwischen #3118 und #5785 sind es 82 Sekunden. Oder liegt es an den Debug-Ausgaben?

Ich rufe die Methoden in meinen VS Testprojekt auf. Die Ausgabe erfolgt über die integrierte Ausgabe von VS. Die Ausgabe ist schon recht zäh. Hab schon gedacht, dass das gar nicht mehr aufhört.

Was meinst du mit "Pipe in eine Textdatei"?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In diesem Fall ist es keine Pipe sondern eine Ausgabeumleitung, mit der die Ausgaben auf stdout in eine Textdatei umgeleitet werden. Das geht meistens etwas schneller als die Ausgabe von stdout auf dem Bildschirm. Das funktioniert unter Windows mit dem Größer-Zeichen in einer Eingabeaufforderung. Beispiel:

testISO_TCP.exe 192.168.1.40 > dump.txt

Die Ausgaben landen dann in der Textdatei dump.txt

Die Pipe ist der vertikale Balken |. Damit kannst du stdout eines Programms mit stdin eines anderen verbinden. Verwendbar an beispielsweise in so einer Funktion:
netstat -ano | find ":102 " > ergebnis.txt

Die Ausgabe von netstat wird dann als Eingabe an find weitergeleitet, der darin nach ":102 " sucht und deren Ausgabe dann in die Textdatei ergebnis.txt ausgeben.
 
Ich bring die TestISO_TCP.exe nicht zum laufen. Wie muss ich den PI-Dienst starten?

Code:
            uc param[2];
            param[0]= "P01";
            param[1]= "/_N_WKS_DIR/_N_TEST_JE_WPD/_N_TEST_UPLOAD2_MPF";
            printf("Start PI-Service...\n");
            res = davePIstart_nc(dc, "_N_F_XFER", &param, 2);
 
Aufruf der PI-Funktion war meine ich z.B. so:
Code:
const char *pistart_parameter[] = {
    "P01",
    "_N_MPF_DIR/_N_TEILEPROG2_MPF",
    ""
};

res = davePIstart_nc(dc, "_N_F_OPEN", pistart_parameter, 2);

Ich nutze das ja alles selber überhaupt nicht.
 
Da scheint etwas in der libnodave-Funktion readISOpacket() nicht ganz sauber zu sein:

daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=11
daveGetNCfile: Empfange Upload Push-Telegramm
readISOpacket: 791 bytes read, 967 needed

daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=12
daveGetNCfile: Empfange Upload Push-Telegramm
readISOpacket: 1460 bytes read, 12320 needed

readISOpacket() liest erst nur den TPKT Header, und versucht dann die dort angegebene Anzahl an Bytes zu lesen und diese zu verarbeiten. Jetzt scheint es so also ob es sein kann, dass wenn der Header schon im Puffer ist, aber die Daten noch nicht vollständig, einfach so versucht wird die nicht vollständigen Daten zu verarbeiten. Dann gibt es einen Versatz und danach bricht alles zusammen.

Entweder man versucht wenn die Anzahl nicht im Puffer ist, Zeit x zu warten und dann nochmal zu versuchen, oder schreibt das in einen Zwischenpuffer und setzt das dann mit dem nächsten Lesebefehl zusammen.
Ich hatte so einen ähnlichen Fehler auch bei mir in Nettoplcsim, TCP ist nämlich nicht immer so einfach wie man denkt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Probier mal folgende Änderung an der _daveReadISOPacket. Die Änderungen von mir sind die mit "FIX"

Code:
int DECL2 _daveReadISOPacket(daveInterface * di,uc *b) {
	int res,i,length, follow;
    int remaining;  /* FIX */
	uc lhdr[7];
	i=_daveTimedRecv(di, b, 4);
	if (i<0) return 0;
	res=i;
        if (res<4) {
	    if (daveDebug & daveDebugByte) {
		LOG2("res %d ",res);
		_daveDump("readISOpacket: short packet", b, res);
	    }
	    return (0); /* short packet */
	}
	length=b[3]+0x100*b[2];
	i=_daveTimedRecv(di, b+4, length-4);
	res+=i;
	if (daveDebug & daveDebugByte) {
	    LOG3("readISOpacket: %d bytes read, %d needed\n",res, length);
	    _daveDump("readISOpacket: packet", b, res);
	}
    /* FIX START: Force to read the complete TPKT if first was not complete */
    remaining = length - res;
    while (remaining > 0)
        LOG2("readISOpacket: Trying to read %d remaining bytes of the complete TPKT\n", remaining);
        i = _daveTimedRecv(di, b+4 + res, remaining);
        if (i < 0) return 0;
        res += i;
        remaining = length - res;
    }
    /* FIX END */
	follow=((b[5]==0xf0)&& ((b[6] & 0x80)==0) );
	while (follow) {
	    if (daveDebug & daveDebugByte) {
		LOG2("readISOpacket: more data follows %d\n",b[6]);
	    }
	    i=_daveTimedRecv(di, lhdr, 7);
	    length=lhdr[3]+0x100*lhdr[2];
	    if (daveDebug & daveDebugByte) {
		_daveDump("readISOpacket: follow %d %d", lhdr, i);
	    }
	    i=_daveTimedRecv(di, b+res, length-7);
	    if (daveDebug & daveDebugByte) {
		_daveDump("readISOpacket: follow %d %d", b+res, i);
	    }
	    res+=i;
	    follow=((lhdr[5]==0xf0)&& ((lhdr[6] & 0x80)==0) );
	}
	return (res);
}
 
Zurück
Oben