TIA Parsen eines Herstellerprotokolls auf UDP Basis

flixz_

Level-2
Beiträge
6
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich verzweifle Momentan ein wenige an der folgenden Aufgabe. Verwendet wird dabei eine 1512SP und TIA V18.

Von einem Hersteller haben wir eine Protokollbeschreibung erhalten, welche wir nun in userer Steuerung umsetzen müssen. Das ganze basiert auf UDP. Die Pakete bestehen aus einem Header mit fester Größe, Nutzdaten mit variabler Größe und einem Trailer mit fester Größe (enthält CRC32 von Header und Nutzdaten).

Der Header besteht aus:
- einer ID (2 Byte)
- einer Sequenz (2 Byte)
- einem Telegramtyp (1 Byte)
- der Länge des Telegrams (2 Byte)

Der Telegramtyp beschreibt den zu erwarteten Inhalt der Nutzdaten. Die Größe der Nutzdaten kann hierbei auch bei dem gleichen Telegramtyp varieren.

Ein Telegramtyp ist Bespielsweise "Befehl". Bei "Befehl" haben wir in den Nutzdaten des Telegrams:
- eine Auftragsnummer (UINT16)
- die Befehlsanzahl (UINT8)
- Befehlsnutzdaten (?Byte)

Die Befehlsnutzdaten bestehen wiederrum aus:
- Satznummer (UINT16)
- Befehlssatztyp (UINT8)
- Nutzdaten (?Byte, abhängig vom Befehlssatztyp)

Mein aktueller Stand ist, dass mit TCON die "Verbindung" aufgebaut wird und sobald das Fehlerfrei durch ist wird mit TURCV das Empfangen gestartet. Bei vollständigem Empfang werden die Daten in ein Array[0..2047] kopiert und die tatsächliche Anzahl der empfangenen Bytes gespeichert.

Folgenden Fragen ergeben sich bis jetzt:
- Ist die Herangehensweise soweit sinnvoll oder gibt es bereits hier einen besseren Weg?
- Wie wandle ich am besten meine Bytes aus dem Array in die entsprechenden Datentypen um? (z.B.: Array[12..13] -> Var_X:UINT)
- Wie gehe ich am besten durch mein Array um die Daten zu extrahieren und in entsprechende Strukturen zu schreiben? Viele verschachtelte CASE Anweisungen sind bis hier meine einzige Idee.
 
Wenn ihr Trennzeichen habt dann arbeite mit denen,

Bytes würde ich entweder in CHAR direkt 1:1 umschieben und dann Chars_TO_Strg verwenden um daraus was lesbares zu basteln. Da kannste dann mit Schleifen und mit FIND usw arbeiten.

Ich mache das zB anders rum in einem, dass ich verschiedene Variablen mit verschiedenen Datentypen in einen Bytestream umwandeln muss.. dort hab ich für verschiedene Datentypen FCs die mir die Arbeit für diesen Datentyp abnehmen.

Irgendwoher musst du ja wissen, je nach Telegrammtyp, was du wo zu erwarten hast.. das sollte ja hoffentlich definiert sein/definiert werden können.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Trennzeichen haben wir keine, es handelt sich um einen reinen Bytestream. Somit fallen Strings und Find komplett raus. Die Definition was wo zu finden ist haben wir. Prinzipiell muss man wohl von oben nach unten durchgehen und dann immer abhängig vom angegebenen Inhalt weiter auswerten also etwa: Telegramtyp:Befehl -> wir schauen auf Befehlsanzahl -> in einer Schleife alle Befehle nach ihrem Typ abfragen und entsprechend in ein UDT oder so abspeichern.
Stellt sich natürlich noch die Frage in was für einer Struktur man das ganze anlegt, wenn bei der Programmierung nicht bekannt ist wie viele Befehle bspw. ankommen. Eventuell in einen FIFO Buffer schieben?
Und gibt es eine gute Option einen Teil von Bytes aus einem Array in einen neuen Datentyp zu schieben? Hatte dazu nur mal die Möglichkeit mit den Slice Zugriff gefunden.
 
Da könntest du auch wieder mit FOR und dann mit dem Zusatz TO arbeiten.

Müsst ihr auf die Kodierung achten (ASCII/UTF usw..)?

Würde wie gesagt alles erstmal in ein Array of CHAR knallen, kannst dir dann auch in der Beobachtungstabelle als Zeichen anzeigen lassen und dann siehste ja erstmal den Inhalt vom Stream und kannst dann den dann zerlegen wie du es brauchst.

Kann mir nicht vorstellen dass es keinerlei Trennzeichen gibt, bzw keine Definition in welchen Bereichen welche Datenpunkte stehen..

Was ist das denn für ein Gerät?

FIFO ist dafür natürlich auch eine Idee, gibts auch ein Anwendungsbeispiel von Siemens dazu, falls ihr keinen fertigen FIFO habt.
 
Kodierung gibt es laut meinem Verständnis keine, da bei unserer Anwendung immer nur Zahlenwerte verwendet werden.

Die Definition wo was steht ist immer nur über die Länge der vorherigen Elemente gegeben, von welchen die Länge ja mehr oder weniger immer bekannt ist, zumindest wenn man einmal durch alles vorherige duchgegangen ist. Wenn im Header steht, dass im Nutzdatenbereich bspw. ein Befehl zu erwarten ist, kann ich sagen an welcher Stelle im Array bspw. der Befehlsatztyp zu erwarten ist, weil die Reihenfolge der Bytes bzw. Daten definiert ist.

Es handelt sich um eine Leitsteuerung für Fahrerloses Transportfahrzeuge.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also wenn ich das richtige verstehe kommt eine Nachricht X an, in der Nachricht hast du einen fest definierten Header mit allem was du brauchst um die Nutzdaten auswerten zu können (Telegrammlänge).

Müsstest du nicht einfach nach Erhalt der Nachricht, den Header einmal analysieren um zu wissen wie viel Byte des Streams du ab welchem Byte (fix, da Header ja fix) du wie viele Byte auslesen musst? Du weißt nur nicht wie die längste mögliche Nachricht aussieht?

Damit hast du doch alles was du brauchst, oder übersehe ich etwas?

Diesen Abschnitt des Streams (FOR i:= #StartByte TO #TelegrammLaenge) schiebst du in ein Array[0..n] of Char und kannst damit dann weiterarbeiten.

Die Leitsteuerung ist von einem anderen Softwarelieferanten projektiert worden, oder ist das ein fertiges Produkt?
Da würde ich mal erfragen, wie lange denn die längste Nachricht sein könnte und danach dann die Empfangs und Arbeitsbereiche definieren.

Ich würde persönlich erst einmal schauen dass ich eine saubere Kommunikation mit der Leitsteuerung hinbekomme die auch wirklich alle Fälle an empfangenden Nachrichten verarbeiten kann und mich dann um das Verarbeiten der Inhalte kümmern.
 
Das Problem ist tatsächlich eher die Auswertung der Nutzdaten, nicht die Kommunikation.

Diesen Abschnitt des Streams (FOR i:= #StartByte TO #TelegrammLaenge) schiebst du in ein Array[0..n] of Char und kannst damit dann weiterarbeiten.
Wie lege ich dieses Array dann zur Laufzeit an? Und was ist der Vorteil, wenn man mit Array of Char statt mit Array of Byte arbeitet? Sollte doch keinen Unterschied machen, wenn man die Bytes am Ende sowieso noch in bspw. ein DInt kopiert?

Die maximale Länge sollte durch TURCV ja sowieso auf 2048 Byte beschränkt sein, damit kann man sich die Bereiche im Program ja schon herleiten.
Realstisch wird das Protokoll das auch nicht ausnutzen.
 
CHAR ist halt schon direkt ASCII codiert.. ich weiß ja nicht welche Inhalte du hast, oben steht nur was von UInt..

Wenn du zB weißt in welchem Bereich dein Wert für UInt steht kannst du natürlich auch auf die Bytes direkt zugreifen

#MeineUInt.%XB0, glaube ich war das und da deine Bytes reihenweise reinschreiben.. da kannst du halt nur nicht mehr mit Schleifen arbeiten. (Eventuell noch Msb/Lsb beachten)

Ich schaue gleich mal in mein Projekt wie ich das gemacht hab.

Ansonsten ist natürlich Serialize auch noch eine Möglichkeit.. hab ich aber persönlich noch nie genutzt.

Vielleicht hilft dir auch die AT Sicht..

Wie programmieren Sie in STEP 7 (TIA Portal) die Überlagerung von Variablen mit dem Schlüsselwort "AT"?​


Variablen mit AT überlagern
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Tatsächlich bestehen die Daten fast immer nur aus Zahlenwerten, also irgendwelchen Integers. Diese können dann halt immer nur aus den Bytes geholt werden. Habe nochmal ein Beispiel für einen Befehl anghängt (der Teil der am Ende in den Nutzdaten des Telegrams liegt). Da sieht man, dass die Art der Folgedaten von dem Befehlssatztyp abhängt. Also so wie es auch im Header des Telegrams funktioniert.
 

Anhänge

  • Screenshot 2024-01-03 160944.png
    Screenshot 2024-01-03 160944.png
    22,3 KB · Aufrufe: 14
Jetzt wirds bisschen deutlicher..

Also du weißt wie viele Datensätze pro Telegramm ankommen.. und du weißt auch wie jeder Typ definiert ist.

Ich würde dann für jeden Typ an Befehlssatz eine UDT erstellen (die sollten ja immer eindeutig sein) und dann mit Serialize arbeiten.

Die Schwierigkeit besteht halt leider darin, dass die Telegramme wohl nicht immer gleich fix aufgebaut sind und daraus dann ein Case Schlachtfeld wird.. in Graph denke ich wirds auch nicht unkomplizierter aussehen.

Wäre da zwischen jedem Datensatz ein Trennzeichen, wäre das alles viel simpler zu gestalten, da du anhand der Informationen im Header ja weißt, wie viele Datensätze und somit Trennzeichen du erwartest.. so könntest du dich dann von Trennzeichen zu Trennzeichen hangeln, den Typ auslesen und die UDT darüber klatschen.

Vielleicht kannst du auch, nach dem verarbeiten eines Datensatzes diesen Bereich im Arbeitsbereich dann mit "leer" überschreiben, sodass du dann nur noch im Arbeitsbereich die Informationen hast die du noch nicht über die Case abgearbeitet hast.
 
So in die Richtung hatte ich gerade auch eine Überlegung. Nur dass ich mit Deserialize die Daten raushole und dann mein Array quasi ab dem Punkt über sich selbst drüberkopiere mit MOVE_BLK, an dem es dann weitergeht und dabei die bereits mit deserialize bearbeiteten Daten überschreibe und das solange bis alles abgearbeitet ist. Bin mir aber nicht sicher ob das so möglich ist. Wie man es auch macht, wirklich schön wird es denke ich nicht.

Trotzdem Danke bis hier hin und ich melde mich noch mal wenn ich schlauer bin.
 
Zurück
Oben