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

Zuviel Werbung?
-> Hier kostenlos registrieren
Habs gefunden, die davePutProgramBlock() ist nur bei Jochens Bibliothek enthalten.

@Hans54216:
Es wäre nützlich, wenn du nochmal ein paar Aufzeichnungen eines Downloads von verschieden großen Dateien erstellen könntest.

Meine Vermutung ist, dass nach der Anfrage "Request download" im 1. Byte der Antwort die Anzahl an Telegrammen steht, die ohne Abwarten einer Antwort an die NC geschickt werden dürfen (unackcount).
Also steht dort z.B.eine 10, dann können 10 Telegramme gesendet werden, dann gibt es eine Antwort von der NC mit wieder einer neuen Anzahl, dann weitersenden usw. bis fertig.

Bei deinem großen Upload des HMI aus deinem anderen Thread passt das auch gut zusammen.

Bei deinem Anhang "NC_File_Big_Upload" gibt es aber eine Unstimmigkeit.
- Erste Antwort auf download request: NC sagt unackcount=1
- 1 Telegramm schicken, Antwort abwarten, NC sagt unackcount=18
- Es werden aber nur 8 Telegramme geschickt, dann kann man am Zeitstempel sehen, dass etwas gewartet wird, und dann kommt tatsächlich eine Antwort von der NC mit unackcount = 8
- Dann folgt aber nur noch 1 Telegramm und dann ist die Übertragung abgeschlossen

Entweder meine Interpretation des Feldes (unackcount) ist falsch, oder es muss das Verhalten per Definition zwischen den Partnern vereinbart sein (1 Telegramm schicken, abwarten, 8 Telegramme schicken, abwarten), was ich mir aber nicht wirklich vorstellen kann.
 
Zuviel Werbung?
-> Hier kostenlos registrieren

Diese Zeilen finde ich fragwürdig:
6251:
Code:
memcpy(progBlock+4,buffer,maxPBlockLen);
und 6297:
Code:
memcpy(progBlock+4,buffer+(cnt*maxPBlockLen),maxPBlockLen);

Wenn der Buffer nicht ein Vielfaches von maxPBlockLen, wird aus ganz anderem Speicher gelesen. Der wird zwar nicht verschickt, aber das ist trotzdem nicht statthaft.
Und length als Zeiger übergeben, obwohl das überhaupt nicht notwendig ist.
 
Ich habe mal die notwendigen Funktionen dafür erstellt, die zur Zeit so arbeiten wie ich es oben beschrieben habe. Wahrscheinlich wirds nicht funktionieren, wenn die NC sich so verhält wie in deinem einzigen Logfile vom Download einer großen Datei. Bei einer kleinen Datei deren Inhalt in eine PDU passt, sollte es hoffentlich funktionieren.

Es wird noch eine Funktion benötigt, die eine PDU nur absendet und nicht auf Antwort wartet. Soweit ich weiß gibt es diese noch nicht. Für TCP könnte die so aussehen:
Code:
/* Sendet eine PDU, ohne auf Antwort zu warten */
int DECL2 
_daveSendTCP(daveConnection *dc, PDU *p)
{
    int res, totLen, sLen;

    if (daveDebug & daveDebugExchange) {
        LOG2("%s enter _daveSendTCP\n", dc->iface->name);
    }
    dc->partPos = 0;
    totLen = p->hlen + p->plen + p->dlen;
    while (totLen) {
        if (totLen>dc->TPDUsize) {
            sLen = dc->TPDUsize;
            *(dc->msgOut + dc->partPos + 6) = 0x00;
        } else {
            sLen = totLen;
            *(dc->msgOut + dc->partPos + 6) = 0x80;
        }
        *(dc->msgOut + dc->partPos + 5) = 0xf0;
        *(dc->msgOut + dc->partPos + 4) = 0x02;
        _daveSendISOPacket(dc, 3 + sLen);
        totLen -= sLen;
        dc->partPos += sLen;
    }
    return 0;
}

Und die davePutNCProgram:
Code:
int DECL2 
davePutNCProgram(daveConnection *dc, char *filename, char *buffer, int length)
{
    PDU p, p2;
    int res = 0;
    int cnt = 0;
    int size = 0;
    uc unackcount;
    uc seq_num;
    uc dataunitref;
    int blockCont;
    int max_data_len;
    int filename_len;

    /* Request download */
    uc req_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x01, 0x00
    };
    uc req_down_da[]= {
        0xff, 0x09, 0x00, 32,
        /* 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
    };

    /* Download block */
    uc do_down_pa[]= {
        0x00, 0x01, 0x12, 0x08, 0x12, 0x3f, 0x02,
        0x00,       /* sequence number */
        0x00,       /* data unit reference */
        0x01,       /* Last data unit: 0=yes, 1=no */
        0x00, 0x00  /* errorcode */
    };
    /* 1920 ist die von libnodave vorgeschlagene max. PDU-Größe */
    uc do_down_da[1920 + 6]= {
        0xff, 0x09,
        0x00, 0x00, /* block size in bytes */
        0x00, 0xfb,
    };

    /* End download */
    uc end_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x04,
        0x00       /* sequence number */
    };
    uc end_down_da[]= { 
        0xff, 0x09, 0x00, 0x02, 0x00, 0x00
    };

    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_down_da[3] = filename_len;
    memcpy(&req_down_da[4], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_down_pa, sizeof(req_down_pa));
    _daveAddData(&p, req_down_da, 4 + filename_len);

    res = _daveExchange(dc, &p);
    if (res == daveResOK) {
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);

        if (res == 0) {
            seq_num = p2.param[9];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */

            dataunitref = 0;
            do_down_pa[7] = seq_num;
            blockCont = 1;
            cnt = 0;

            /* Max. Länge in datablock = PDUsize - hlen - plen - dheader */
            max_data_len = daveGetMaxPDULen(dc) - 10 - 12 - 6;

            /* Daten senden bis unackcount = 0, dann auf Antwort warten, usw. usf. */
            do {
                do_down_pa[8] = ++dataunitref;

                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                size = max_data_len;

                if (length > ((cnt+1) * max_data_len)) {
                    do_down_pa[9] = 1;  /* Last data unit: 1=no */
                } else {
                    size = length - (cnt * max_data_len);
                    do_down_pa[9] = 0;	/* Last data unit: 0=yes */
                    blockCont = 0;
                }
                do_down_da[2] = size / 256;
                do_down_da[3] = size % 256;

                memcpy(do_down_da + 6, buffer + (cnt * max_data_len), size);

                _daveAddParam(&p, do_down_pa, sizeof(do_down_pa));
                _daveAddData(&p, do_down_da, size + 6);
                if (daveGetDebug() & daveDebugPDU) {
                    _daveDumpPDU(&p);
                }
                if ((--unackcount > 0) || (blockCont == 0)) {
                    /* PDU senden ohne auf Antwort zu warten */
                    res = _daveSendTCP(dc, &p);
                    if (res != daveResOK) {
                        break;
                    }
                } else {
                    /* PDU senden mit Warten auf Antwort von NC */
                    LOG2("davePutNCProgram: unackcount=%d, warte auf Antwort von NC um fortzusetzen...\n", unackcount);
                    res = _daveExchange(dc, &p);
                    if (res == daveResOK) {
                        res = _daveSetupReceivedPDU(dc, &p2);
                        if (daveGetDebug() & daveDebugPDU) {
                            _daveDumpPDU(&p2);
                        }
                        /* Hier weiß ich nicht wie ein Fehler auszuwerten ist, da weder im
                         * Kopf- noch im Parameterteil ein Errorcode vorhanden ist.
                         * Bei Erfolg sollte der Datenteil 6 Bytes groß sein, und unackcount > 0
                         */

                        /*              push-nc                   continue */
                        if ((p2.param[5] == 0x3f && p2.param[6] == 0x03) &&
                           ((PDUHeader*)p2.header)->dlen == 6) {
                            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
                            if (unackcount == 0) {
                                LOG2("davePutNCProgram: in continue response unackcount=%d. Exit!\n", unackcount);
                                res = daveResUnexpectedFunc;
                                break;
                            }
                        } else {
                            LOG2("davePutNCProgram: in continue response, falscher Aufbau der Antwort (p2.param[5] = %d). Exit!\n", p2.param[5]);
                            res = daveResUnexpectedFunc;
                            break;
                        }
                    } else {
                        break;
                    }
                }
                cnt++;
            } while (blockCont);

            if (res == daveResOK) {
                /* End-download senden */
                end_down_pa[7] = seq_num;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                _daveAddParam(&p, end_down_pa, sizeof(end_down_pa));
                _daveAddData(&p, end_down_da, sizeof(end_down_da));
                res = _daveExchange(dc, &p);
                /* Antwort auswerten */
                if (res == daveResOK) {
                    res = _daveSetupReceivedPDU(dc, &p2);
                    if (daveGetDebug() & daveDebugPDU) {
                        _daveDumpPDU(&p2);
                    }
                    if (p2.param[5] == 0xbf && p2.param[6] == 0x05) {
                        /* Errorcode im Parameterteil prüfen */
                        res = daveGetU16from(&p2.param[10]);
                    } else {
                        res = daveResUnexpectedFunc;
                    }
                }
            }
        } else {
            LOG2("davePutNCProgram: errorcode erster Antwort: %04X\n", res);
        }
    }
    return res;
}

Für den Dateinamen habe ich eine maximale Länge von 32 Zeichen erlaubt. Diese Länge ist auch in der Dokumentation der PI-Services angegeben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wollte die Funktionen gerade testen. Beim compilieren kam, das "dc->partPos" und "dc->TPDUsize" fehlen.

Hab diese dann aus "libnodave-0.8.5" übernommen. (in die Struktur + in den Funktionen ("_daveExchangeTCP", "_daveSendISOPacket"))

Hat aber wohl nicht funktioniert. Kann nun keine Verbindung zur Steuerung aufbauen. Laut Wireshark wird auch kein Paket verschickt.
 
Ja, das ist der Teil bei dem große S7-PDUs bei Bedarf in kleinere TPDUs gesplittet werden. Das ist bei Jochens Version nicht enthalten. Musst mal gucken wie bei ihm die daveExchangeTCP Funktion aussieht, da kannst du mehr oder weniger den ersten Code zum Senden übernehmen, und löschst nur den zweiten Teil bei dem Empfangen wird raus.

Ich teste das nur mit libnodave 0.8.5.1, da lässt sich das übersetzen, und es gehen auch Daten raus.

Aber ich kann für den Download absolut keine Logik erkennen, wann die NC nach welcher Anzahl eine Bestätigungsnachricht sendet. In deinem letzten Mitschnitt kommen diese Telegramme ja völlig unregelmäßig rein.
Insgesamt sind es 66 Telegramme zum Download. Wenn das erste Byte im Datenteil von der NC angibt wie viele Telegramme bestätigt werden, komme ich dort in Summe auf 1 + 18 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 8 = 83.
Und wenn ich annehme, die beiden Bytes geben eine Summe an Bytes an die bestätigt werden, dann komme ich auch auf keinen sinnvollen Wert.

Man muss schon wissen wann eine Antwort zu erwarten ist, andernfalls funktioniert das so nicht. Oder man muss nach jedem Senden kurz warten und gucken ob was im Empfangspuffer ist, und wenn nicht dann einfach weitersenden. Das ist aber garantiert nicht so geplant. Kann auch sein dass ich da völlig auf dem Holzweg bin.

Man könnte höchstens an einer NC mal testen, in dem man einzelne Telegramme um z.B. 2s verzögert nacheinander rausschickt, und guckt wann denn da was zurückkommt.
 
Beim Download scheint es auch nochmal ein Kopfteil zu geben, zumindest wenn du dort die Datei im Archiv hochgeladen hast. Also da muss man wohl auch noch etwas voranstellen.

Code:
00058934160509080243    ;$PATH=/_N_WKS_DIR/_N_TEST_JE_WPD
Dateigröße ist 58900 Bytes.
Alle Bytes die beim Download übertragen werden sind in Summe 58958 Bytes (Netto, d.h. ohne 2 Bytes Kopf pro Datenpaket /PDU).

Wenn man den ersten Teil auftrennt in
00058934
16050908
0243

Der hinzugefügte Kopfstring ist inkl. abschließendem Newline 58 Zeichen lang. Wie ich auch rechne komme ich nicht auf 58934. Und die anderen Zahlenwerte sagen mir auch nichts, genausowenig wie der Pfad der dort eingebaut wird.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
00058934160509080243    ;$PATH=/_N_WKS_DIR/_N_TEST_JE_WPD
Und die anderen Zahlenwerte sagen mir auch nichts, genausowenig wie der Pfad der dort eingebaut wird.

Der Pfad bedeutet:
WKS.dir -> Standartverzeichnis Werkstücke
TEST_JE.wpd -> Ordnername

Was die Nummer bedeutet weiß ich nicht.
 
Habs raus.
Die ersten 8 Zeichen sind Länge Dateiinhalt + Länge Pfadangabe. Alles ab ";" zählt sozusagen zu dieser Länge.
Der Rest ist der Zeitstempel der Datei:

160509080243=
09.05.2016, 08:02:43 Uhr

Den Zeitstempel zeigt zumindest auch der Windows Explorer.

Das kann ich in die Funktion noch mit einbauen. Woher soll der Zeitstempel kommen, als Parameter, oder aktuelle Zeit verwenden?

Problem ist also weiterhin nur die Anzahl an Telegrammen nach denen auf eine Antwort von der NC zu warten ist.
 
Den Zeitstempel zeigt zumindest auch der Windows Explorer.

Das kann ich in die Funktion noch mit einbauen. Woher soll der Zeitstempel kommen, als Parameter, oder aktuelle Zeit verwenden?.

Am schönsten ist es, wenn der Zeitstempel der Funktion als Parameter übergeben wird. Dann hat die Datei in der NC den selben Zeitstempel wie das Original.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Jetzt kannst du den Pfad und den Zeitstempel als Parameter übergeben. Der Zeitstempel wird als Zeiger auf eine struct tm (aus time.h) übergeben. In C ist das Standard, aber du willst es ja in .Net benutzen. Alternativ könnte man den Zeitstempel auch als String übergeben, dann muss der Anwender aber wissen wie das Format auszusehen hat.
Code:
int DECL2 
davePutNCProgram(daveConnection *dc, char *filename, char *pathname, struct tm *ts, char *buffer, int length)
{
    PDU p, p2;
    int res = 0;
    int size = 0;
    uc unackcount = 0;
    uc seq_num = 0;
    uc dataunitref = 0;
    int max_data_len = 0;
    int filename_len = 0;
    int prefix_len = 0;
    int buffer_pos = 0;
    int tot_len = 0;

    /* Request download */
    uc req_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x01, 0x00
    };
    uc req_down_da[]= {
        0xff, 0x09, 0x00, 32,
        /* 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
    };

    /* Download block */
    uc do_down_pa[]= {
        0x00, 0x01, 0x12, 0x08, 0x12, 0x3f, 0x02,
        0x00,       /* sequence number */
        0x00,       /* data unit reference */
        0x01,       /* Last data unit: 0=yes, 1=no */
        0x00, 0x00  /* errorcode */
    };
    /* 1920 ist die von libnodave vorgeschlagene max. PDU-Größe */
    uc do_down_da[1920 + 6]= {
        0xff, 0x09,
        0x00, 0x00, /* block size in bytes */
        0x00, 0xfb,
    };

    /* End download */
    uc end_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x04,
        0x00       /* sequence number */
    };
    uc end_down_da[]= { 
        0xff, 0x09, 0x00, 0x02, 0x00, 0x00
    };

    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_down_da[3] = filename_len;
    memcpy(&req_down_da[4], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_down_pa, sizeof(req_down_pa));
    _daveAddData(&p, req_down_da, 4 + filename_len);

    res = _daveExchange(dc, &p);
    if (res == daveResOK) {
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        if (res == 0) {
            seq_num = p2.param[9];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
            do_down_pa[7] = seq_num;
            /* Max. Länge in datablock = PDUsize - hlen - plen - dheader */
            max_data_len = daveGetMaxPDULen(dc) - 10 - 12 - 6;
            do_down_da[6] = '/0';
            sprintf(do_down_da + 6, "%08d%02d%02d%02d%02d%02d%02d    ;$PATH=%s\n", 
                length + strlen(pathname) + 8, /* ;$PATH= + \n */
                ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec,
                pathname);
            prefix_len = strlen(do_down_da + 6);
            tot_len = prefix_len + length;
            /* Daten senden bis unackcount = 0, dann auf Antwort warten, usw. usf. */
            while (tot_len) {
                do_down_pa[8] = ++dataunitref;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                if (tot_len > max_data_len) {
                    size = max_data_len;
                    do_down_pa[9] = 1;  // Last data unit: 1=no
                } else {
                    size = tot_len;
                    do_down_pa[9] = 0;	// Last data unit: 0=yes
                }
                memcpy(do_down_da + 6 + prefix_len, buffer + buffer_pos, size - prefix_len);
                tot_len -= size;
                buffer_pos += size - prefix_len;
                prefix_len = 0;
                do_down_da[2] = (size+2) / 256;
                do_down_da[3] = (size+2) % 256;

                _daveAddParam(&p, do_down_pa, sizeof(do_down_pa));
                _daveAddData(&p, do_down_da, size + 6);
                if (daveGetDebug() & daveDebugPDU) {
                    _daveDumpPDU(&p);
                }
                if (--unackcount > 0) {
                    /* PDU senden ohne auf Antwort zu warten */
                    res = _daveSendTCP(dc, &p);
                    if (res != daveResOK) {
                        break;
                    }
                } else {
                    /* PDU senden mit Warten auf Antwort von NC */
                    LOG2("davePutNCProgram: unackcount=%d, warte auf Antwort von NC um fortzusetzen...\n", unackcount);
                    res = _daveExchange(dc, &p);
                    if (res == daveResOK) {
                        res = _daveSetupReceivedPDU(dc, &p2);
                        if (daveGetDebug() & daveDebugPDU) {
                            _daveDumpPDU(&p2);
                        }
                        /* Hier weiß ich nicht wie ein Fehler auszuwerten ist, da weder im
                         * Kopf- noch im Parameterteil ein Errorcode vorhanden ist.
                         * Bei Erfolg sollte der Datenteil 6 Bytes groß sein, und unackcount > 0
                         */

                        /*              push-nc                   continue */
                        if ((p2.param[5] == 0x3f && p2.param[6] == 0x03) &&
                           ((PDUHeader*)p2.header)->dlen == 6) {
                            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
                            if (unackcount == 0) {
                                LOG2("davePutNCProgram: in continue response unackcount=%d. Exit!\n", unackcount);
                                res = daveResUnexpectedFunc;
                                break;
                            }
                        } else {
                            LOG2("davePutNCProgram: in continue response, falscher Aufbau der Antwort (p2.param[5] = %d). Exit!\n", p2.param[5]);
                            res = daveResUnexpectedFunc;
                            break;
                        }
                    } else {
                        break;
                    }
                }
            };

            if (res == daveResOK) {
                /* End-download senden */
                end_down_pa[7] = seq_num;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                _daveAddParam(&p, end_down_pa, sizeof(end_down_pa));
                _daveAddData(&p, end_down_da, sizeof(end_down_da));
                res = _daveExchange(dc, &p);
                /* Antwort auswerten */
                if (res == daveResOK) {
                    res = _daveSetupReceivedPDU(dc, &p2);
                    if (daveGetDebug() & daveDebugPDU) {
                        _daveDumpPDU(&p2);
                    }
                    if (p2.param[5] == 0xbf && p2.param[6] == 0x05) {
                        /* Errorcode im Parameterteil prüfen */
                        res = daveGetU16from(&p2.param[10]);
                    } else {
                        res = daveResUnexpectedFunc;
                    }
                }
            }
        } else {
            LOG2("davePutNCProgram: errorcode erster Antwort: %04X\n", res);
        }
    }
    return res;
}

Wahrscheinlich musst du in der nodave.h noch die time.h includieren.
 
Was benutzt denn "daveSetPLCTime" für ein Format? Vlt. sollte man das gleich halten?

@Thomas
Ich schau morgen mal nach den von dir angesprochen Punkten
 
Ich hab zum Testen die Funktion so umgebaut, das das Datum als String übergeben wird. (dt.ToString("yyMMddHHmmss"))
Scheint aber nicht zu funktionieren. (Wireshark im Anhang)
Kopfzeile wird an den Schluss geschrieben.
filename und Datum fehlt -> woher weiß sprintf bei ("%s", Pointer) die länge des Strings?


Code:
int DECL2 davePutNCProgram(daveConnection *dc, char *filename, char *pathname, uc *ts, char *buffer, int length)
...
//sprintf(do_down_da + 6, "%08d%02d%02d%02d%02d%02d%02d    ;$PATH=%s\n", 
//    length + strlen(pathname) + 8, /* ;$PATH= + \n */
//    ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec,
//    pathname);

sprintf(do_down_da + 6, "%08d%s    ;$PATH=%s\n", length + strlen(pathname) + 8, ts, pathname);
...
Anhang anzeigen dave_NC_File_Download1.rar
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In C sind Strings Nullterminiert. D.h. solange ab der Adresse auf die Pointer zeigt ein Zeichen ungleich '\0' vorhanden ist, werden die Zeichen in den String vom ersten Parameter von sprintf kopiert.

Wenn ich die Funktion so wie von dir beschrieben umbaue, dann funktioniert das wenn ich diese in C mit z.B.
Code:
res = davePutNCProgram2(dc, "_N_TEILEPROG3_MPF", "_N_MPF_DIR", "160422175457", buffer, 512);
aufrufe.

Ich habe das jetzt einfach mal so getestet, indem ich die Telegramme an eine SPS sende, aber die Abfragen ob der Austausch erfolgreich war "überbrückt" habe. Darum kann ich sehen was zumindest theoretisch rausgeht.

Bei deiner Aufzeichnung ist auch seltsam, dass bei dir zweimal hintereinander ein Request-Download angefordert wird. Bei mir ist das nicht der Fall. In der Funktion davePutNCProgram() wird das auf jeden Fall nicht so gemacht.

Kannst du das nicht erstmal direkt aus einem C-Programm testen? Dann ist die zusätzliche Fehlerquelle durch die ganze .Net Schnittstelle schonmal eliminiert. Wahrscheinlich fertigt C# da irgendeinen UTF kodierten String an.


daveSetPLCTime() nimmt auch ein char array an, die dann auch direkt 1:1 so übertragen werden. Damit man diese Funktion überhaupt verwenden kann, muss man aber wissen wie der Zeitstempel aufgebaut ist der übertragen wird. Also ich weiß das nicht aus dem Kopf und müsste das auch erst nachsehen wie ich das in Wireshark programmiert habe. Im S7-Protokoll gibt es mindestens 2 unterschiedliche Zeitstempel-Formate.
 
@Hans54216

Korrigiere mal diese Zeile bei mir, d.h. von [9] auf [7]
Code:
seq_num = p2.param[7];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
Vielleicht funktioniert dann zumindest der Download einer kleinen Datei. Denn für alle Telegramme wird die Sequenznummer aus der ersten Antwort von der NC verwendet, zumindest war das in den von dir gezeigten Aufzeichnungen so.
 
Hab den Fehler von gestern gefunden. Problem war, das ich übersah dass du zusätzlich zum "filename" nun auch nen String für den "pathname" übergibst.

Mit der Änderung von gestern Abend kommt von der NC kein Fehler zurück.
Es fehlt jedoch der Befehl sowie die Quittierung "Download ended".

Wireshark im Anhang:
Kurzes Programm "Teileprog3" wird von der NC hochgeladen und anschließend als "Teileprog4" mit selbem Inhalt zur NC hinunter geladen.

dave_NC_File_Download2.pcapng -> vor der Änderung von gestern Abend
dave_NC_File_Download3.pcapng -> inc. letzter Änderung
extern_NC_File_Download2.pcapng -> Erfolgreicher up- und download

Anhang anzeigen dave_NC_File_Download2.rar
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Diese Zeilen finde ich fragwürdig:
6251:
Code:
memcpy(progBlock+4,buffer,maxPBlockLen);
und 6297:
Code:
memcpy(progBlock+4,buffer+(cnt*maxPBlockLen),maxPBlockLen);

Wenn der Buffer nicht ein Vielfaches von maxPBlockLen, wird aus ganz anderem Speicher gelesen. Der wird zwar nicht verschickt, aber das ist trotzdem nicht statthaft.
Und length als Zeiger übergeben, obwohl das überhaupt nicht notwendig ist.

Sollte gefixt sein: https://github.com/dotnetprojects/D...mmit/cf5ef71772887ed91ec853502d146a7184f46202
 
Hab den Fehler von gestern gefunden. Problem war, das ich übersah dass du zusätzlich zum "filename" nun auch nen String für den "pathname" übergibst.

Mit der Änderung von gestern Abend kommt von der NC kein Fehler zurück.
Es fehlt jedoch der Befehl sowie die Quittierung "Download ended".
Hm, probiere mal folgende Änderung:
Code:
if (--unackcount > 0 || do_down_pa[9] == 0) {
    /* PDU senden ohne auf Antwort zu warten */
    res = _daveSendTCP(dc, &p);
    if (res != daveResOK || do_down_pa[9] == 0) {
        break;
    }
Dann sollte, wenn die zuletzt gesendete PDU die letzte war, nicht mehr auf eine Antwort gewartet werden, sondern direkt der Download abgeschlossen werden.

Wenn das funktioniert, könntest du mal schrittweise das Programm vergrößern, damit es über mehrere PDUs übertragen werden muss. Wird sich zeigen ob es dann auch noch funktioniert.
 
Wenn ich das so anpasse siehts in Wireshark genau so aus.
Funktion bleibt aber in einer Dauerschleife, anstelle dass sie einen Fehler zurück meldet.


Wie kann ich den Code im Studio ausführen, damit ich ihn Debuggen kann?
Brauch ja zunächst die "daveConnection" zur NCU, um deine Funktion aufzurufen.
 
Zurück
Oben