TCP Send/Receive mit IE-CP
OK, für SoftMachine und andere Interessierte ein paar Worte zum Send/Receive mit IE-CP.
Die CPx43-1 wickeln selbständig die Kommunikation mit Partnern über Ethernet ab.
Schnittstelle zwischen dem Anwenderprogramm und dem CP sind die Bausteine AG_SEND und AG_RECV.
(die T-Bausteine für "offene Kommunikation" können nur mit den CPU-integrierten PN-Schnittstellen genutzt werden!)
Die CP empfangen Telegramme unabhängig davon, ob AG_RECV aufgerufen wird oder nicht (bis der Empfangspuffer voll ist).
Der Baustein AG_RECV hat KEINEN EXTRA Eingangsparameter, an dem man angeben könnte, wieviele Byte man als Telegrammlänge erwartet oder den man auf 0 setzen könnte für "beliebige Länge".
Ein offenbar weit verbreiteter Irrglaube ist, daß der Baustein AG_RECV irgendwie Daten empfangen würde. Er holt lediglich eine vorgegebene Anzahl Zeichen aus dem Empfangspuffer des CP in das eigene Anwenderprogramm. Man muß am Eingangsparameter RECV einen Any-Pointer auf einen eigenen Datenbereich mit der gewünschten Anzahl zu holender Byte angeben (ein Any-Pointer auf einen Datenbereich mit der Länge 0 würde keinen Sinn machen!). Bei TCP-Verbindungen liefert der Baustein AG_RECV
ERST DANN Bytes aus dem Empfangspuffer des CP, wenn der CP
MINDESTENS die im Any-Pointer angegebene Anzahl Zeichen empfangen hat. Er liefert dann immer
GENAU die Anzahl Zeichen die im Any-Pointer angegeben wurde, auch wenn mehr Zeichen als angegeben empfangen wurden.
Hier offenbart sich das Dilemma beim Empfang unterschiedlich langer Telegramme, wenn man nicht exakt weiß, wieviele Bytes das nächste Telegramm lang ist.
Ist das Telegramm länger als im Any-Pointer angegeben, dann wird nur ein Teil des Telegramms abgeholt, dann wird das Telegramm auf mehrere AG_RECV-Empfangsaufträge zerstückelt.
Ist das Telegramm kürzer als im Any-Pointer angegeben, dann liefert AG_RECV
SOLANGE NICHTS, bis so viele Telegramme empfangen wurden, daß die im Any-Pointer angegebene Byteanzahl mindestens erreicht ist. Wenn der Sender nur 1 Telegramm sendet und danach auf Antwort wartet, dann kann er ewig warten. Das Empfangsprogramm weiß noch gar nichts von diesem Telegramm.
Bei solchen nicht exakt zur Telegrammlänge passenden Längenangaben im Any-Pointer ist zusätzlich zu beachten, daß die Empfangsdaten nicht immer an der selben Position im Anwender-Puffer stehen, sie verschieben sich und "wandern" bei jedem Telegramm-Empfang. Auch bei einer eigentlich fest vereinbarten Telegrammlänge kann es sich verheerend auswirken, wenn der Partner auch nur einmal 1 Zeichen zuviel oder zuwenig sendet oder der CP zuwenig empfängt und das Empfangsprogramm das nicht erkennt!
Deshalb: Bei TCP-Verbindungen immer einen eigenen Telegramm-Rahmen mit Start/Ende-Zeichen oder Header vereinbaren!
Möglichkeiten zum Empfang von Telegrammen mit variabler Länge:
A. Man könnte immer genau 1 Zeichen mit AG_RECV abholen und die Empfangstelegramme im eigenen Anwenderprogramm zeichenweise wieder zusammensetzen. Das wird dann aber sehr langsam, weil günstigstenfalls je OB1-Zyklus nur 1 Zeichen aus dem CP geholt wird. Sendet der Partner zu schnell Telegramme, dann läuft der Empfangspuffer des CP über. (oder man ruft AG_RECV in einer Schleife auf)
B. Man vereinbart einen festen Telegramm-Header, in dem die Länge des folgenden variabel langen Datenteils angegeben ist (oder die Gesamtlänge des Telegramms inklusive Header).
Dann empfängt man mit 2 verschiedenen AG_RECV-Aufrufen abwechselnd den festen Header und den variablen Datenteil.
Möglichkeit B siehe Beitrag #12 von Lars Weiß oder dieses Handbuch:
Projektierungshandbuch: S7−CPs für Industrial Ethernet Projektieren und in Betrieb nehmen Teil A - Allgemeine Anwendung
Kapitel 4 SEND/RECEIVE−Schnittstelle im Anwenderprogramm
4.4.1 Datenübertragung über TCP−Verbindungen programmieren
Bei TCP−Verbindungen gibt es im Protokoll keine Informationen über das Ende
einer Nachricht bzw. den Anfang einer neuen Nachricht.
Daher muss die Empfängerstation wissen, wieviel Bytes zu einer Nachricht
gehören und demnach einen exakt dieser Länge entsprechenden ANY−Pointer
beim Aufruf des FC AG_RECV/AG_LRECV übergeben.
[...]
Wenn Sie Daten mit variabler Länge empfangen möchten, gehen Sie wie folgt
vor:
Fügen Sie vor den eigentlichen Nutzdaten im Telegramm eine Information über
die Länge der Nutzdaten ein. Werten Sie in der Empfängerstation zunächst nur
die Längeninformation aus. Holen Sie in einem weiteren Empfangsauftrag die
entsprechende Nutzdatenmenge ab, indem Sie dann einen ANY−Pointer entsprechender
Länge an der der FC−Schnittstelle zum Abholen der eigentlichen
Nutzdaten mitgeben.
PS:
Beim ISO-on-TCP-Protokoll enthält jedes Telegramm eine Information über die Telegrammlänge und der CP synchronisiert selbständig die AG_RECV-Empfangsaufträge mit den Telegrammlängen. AG_RECV liefert auch Telegramme, die kürzer sind als im RECV-Any-Pointer angegeben. Hier sollte man den Ausgang LEN auswerten.
Harald