# SPS Daten über eine Socket Schnittstelle senden. Aber wie???



## Energie85 (28 November 2011)

Hallo zusammen, 


  ich möchte mit C oder  C++ eine TCP Socket Schnittstelle programmieren, die mit einer CP 343-1 von Siemens Daten austauschen kann. Das Problem ist das ich nicht weiß wie ich das Protokoll verarbeiten soll, da Siemens keine Anleitung für die Socket Schnittstelle zur Verfügung stellt. Es wird immer von den Send\Recv und fetch\write Bausteinen gesprochen. Habt Ihr eine Idee wie ich das angehen soll? Würde mich über eine Antwort freuen.


----------



## vierlagig (28 November 2011)

werte einfach libnodave aus ODER, welch verrückter gedanke, benutze einfach libnodave!


----------



## Energie85 (28 November 2011)

Ich weiß das es mit Libnodave geht, dies ist allerdings eine nicht kommerzielle Bibliothek eines Programmierers. 
Dies muss ich mit C oder C++ machen und auf ein Echzeit Betriebssystem übertragen :-(


----------



## Thomas_v2.1 (28 November 2011)

Wenn du dich mit dem API der BSD-Sockets (z.B. Windows/Linux PC) in C auskennst, hilft dir vielleicht diese Gegenüberstellung der Netzwerkfunktionen weiter:

1)
Socket erstellen
PC: socket()
S7: Über Verbindungsparametrierung in Netpro

2)
Socket parametrieren (Adressen, Ports):
PC: SOCKADDR_IN Struktur beschreiben
S7: Über Verbindungsparametrierung in Netpro

3)
Verbindung herstellen
PC: connect()
S7: Verbindungsauf- und Abbau übernimmt das Betriebssystem der SPS

4)
Daten senden
PC: send()
S7: AG_SEND

5)
Daten empfangen
PC: recv()
S7: AG_RECV

Bei der S7 stellst du bei der Verbindungsparametrierung in Netpro ein, ob die Verbindung zum Partner aktiv aufgebaut werden soll (Client) oder auf eine Verbindung warten soll (Server).
Soll die S7 aktiv sein, so versucht diese sobald die CPU in RUN ist die TCP-Verbindung zur projektierten Client-Adresse aufzubauen. Der Datenaustausch muss dann im SPS-Programm über die oben erwähnten Funktionen ausprogrammiert werden.


----------



## Energie85 (29 November 2011)

Hallo zusammen,

bis Punkt fünf hab ich es geschafft. Aber ein kleines Problem hab ich noch :-( ich weiß nicht wie ich die Variablen der SPS im Socket Programm ansprechen soll.
Die SPS ist bei mir client und das Socket Programm Server. Natürlich möchte ich es auch umgekehrt machen.
Dank dir Thomas deine Anleitung war echt super


----------



## Thomas_v2.1 (29 November 2011)

Energie85 schrieb:


> bis Punkt fünf hab ich es geschafft. Aber ein kleines Problem hab ich noch :-( ich weiß nicht wie ich die Variablen der SPS im Socket Programm ansprechen soll.
> Die SPS ist bei mir client und das Socket Programm Server. Natürlich möchte ich es auch umgekehrt machen.



Über die TCP-Verbindung kannst du direkt keine SPS-Adressen ansprechen. Die Daten die über eine aufgebaute Verbindung ausgetauscht werden, landen genau wie auch auf der PC-Seite in einem Empfangspuffer. Auf S7-Seite ist dieser Empfangspuffer der Datenbereich der bei der AG_RECV Funktion am Parameter RECV angegeben wurde.

Wenn dein PC-Programm send() mit den Daten "ABC" absendet, landen diese Daten immer in dem Datenbaustein des Empfangsbereichs.
Du musst also im SPS-Programm den empfangenen Datenstrom in irgendeiner Weise auswerten.
Da ein TCP-Datenstrom keine Start- oder Endekennung besitzt, musst du dir selber einen Telegrammrahmen ausdenken damit das SPS-Programm erkennen kann wo ein Datensatz beginnt und wo dieser endet.

Um es auf SPS-Seite einfacher zu handhaben, kannst du auch anstelle der TCP-Verbindung eine ISO-on-TCP Verbindung verwenden. Dann muss dein PC-Programm aber ebenfalls dieses Protokoll beherrschen, und du bist auf Port 102 festgenagelt.


----------



## Energie85 (29 November 2011)

Siemens stellt keine Anleitung zur Beschreibung des Protokolls zur verfügung. Gibt es keine andere möglichkeit die empfangenen Protokolle auf der PC Seite (SPS-->) auszuwerten oder das man den aufbau des Protokolls einsehen kann.


----------



## Thomas_v2.1 (29 November 2011)

Energie85 schrieb:


> Siemens stellt keine Anleitung zur Beschreibung des Protokolls zur verfügung.


ISO-on-TCP ist dokumentiert:
http://tools.ietf.org/html/rfc1006
und unterlagert:
http://www.synapse.de/ban/HTML/P_ISO/Ger/P_iso92.html

Was nicht dokumentiert ist, ist das S7-Protokoll. Dessen Nutzdaten werden in ein ISO-on-TCP-Telegramm eingepackt. Das ist das was libnodave verwendet, und das du nicht nutzen willst (auch wenn es fast die einfachste Möglichkeit darstellt von einem PC mit einer S7 Daten aus auszutauschen).



Energie85 schrieb:


> Gibt es keine andere möglichkeit die empfangenen Protokolle auf der PC Seite (SPS-->) auszuwerten oder das man den aufbau des Protokolls einsehen kann.


"DU" musst dir das Protokoll selber überlegen.
Wenn deine Telegrammlänge immer gleich ist (z.B. 100 Bytes) kannst du evtl. auf den Rahmen verzichten, kann da aber keine Erfahrungswerte vorweisen ob das zuverlässig funktioniert.
Hier gibt es von Siemens auch noch ein rel. aufwändiges Beispiel dazu:
http://support.automation.siemens.com/WW/view/de/19033929

Das Problem ist jetzt aber nicht SPS spezifisch. Man angenommen du schreibst mit den Socket-Funktionen am PC ein einfaches Programm, mit dem Daten unbestimmter Länge von dem einen auf den anderen Rechner übertragen werden sollen. Dann weiß der Empfänger auch nicht wann die Daten vollständig übertragen werden, außer er bekommt es auf irgendeine Weise mitgeteilt.

Bei serieller Kopplung verwendet man dazu oftmals bekannte Steuerzeichen (STX, ETX, ...). Wenn dann ein "Hallo" übertragen werden soll, wird das in "STX"Hallo"ETX" eingepackt. Die Steuerzeichen dürfen dann nicht im Datenstrom vorkommen, oder müssen entsprechend gekennzeichnet sein (wie wenn du in C mittels printf einen backslash ausgeben möchtest).


----------



## Question_mark (29 November 2011)

*Ich mache mir ein eigenes Protokoll*

Hallo,

alles was Thomas_v2.1 hier geschrieben hat, kann ich nur bestätigen. IsoOnTCP gemäß RFC1006 ist die beste Lösung für Dein Problem. Hierbei wird das S7 Protokoll in einen TCP Frame reingestopft und man muss sich als Anwender da keine besonderen Krücken bauen. 



			
				Thomas_v2.1 schrieb:
			
		

> Da ein TCP-Datenstrom keine Start- oder Endekennung besitzt, musst du dir selber einen Telegrammrahmen ausdenken damit das SPS-Programm erkennen kann wo ein Datensatz beginnt und wo dieser endet.



Im einfachsten Fall reservierst Du die ersten 2 Bytes im Telegramm um die Länge der übertragenden Bytes dort einzustellen, diese Anzahl der Bytes auswerten und auslesen. Damit hast Du die einfachste und simpelste Art eines Protokolls implementiert (aber eben nur auf der untersten Ebene TCP). 
Was mich manchmal wundert, das selbst so renommierte Firmen wie Inat/Softing dann von Ihren Protokollwandlern immer von einem TCP/IP Protokoll schreiben, das ganze hat auf dieser Ebene nichts mit dem IP Protokoll zu tun, sondern nur mit TCP ...

Gruß

Question_mark


----------



## Energie85 (29 November 2011)

Dank euch beiden für die antwort 
Was hält Ihr von der fetch\write Methode?


----------



## Thomas_v2.1 (30 November 2011)

Energie85 schrieb:


> Was hält Ihr von der fetch\write Methode?



Das Protokoll für fetch/write ist relativ einfach und auch dokumentiert. In diesem Fall ist deine SPS aber in jedem Fall passiv. Wenn das nicht stört ist es sicher eine einfache Möglichkeit Daten in der SPS anzusprechen, da in der SPS relativ wenig programmiert werden muss.
Da das Protokoll aus S5 Zeiten stammt, hast du aber die Begrenzung auf Datenbausteinnummern bis max. 255, da im Telegramm für diese Nummer nur ein Byte vorgesehen ist.


----------



## Energie85 (1 Dezember 2011)

Das muss schon in beide richtungen gehen. Die fetch\write Methode ist dann nichts für mich schade :-(
Ich hab da eine Doku im Internet gefunden. 
http://cache.automation.siemens.com...51101016_NET_receive_TCP_variable_data_de.pdf
Was hälst du von der Methode?
Könntest  du mir paar Bücher für die Socket Programmierung empfehlen? In S7 bin  ich einigermaßen fit aber in C++ hab ich noch nicht den großen überblick  :-(


----------



## Energie85 (5 Dezember 2011)

ich darf das doch mit der fetch/write Methode machen  ich bin auf die seite von pvbrowser gestoßen und habe da ein gutes beispiel gefunden. Kann man das C++ Programm anpassen und von dort aus ohne Lizenskosten übernehmen? 
Auf die Seite bin ich gestoßen: http://pvbrowser.de/pvbrowser/sf/manual/rllib/html/classrlSiemensTCP.html


----------



## Thomas_v2.1 (5 Dezember 2011)

Energie85 schrieb:


> ich darf das doch mit der fetch/write Methode machen  ich bin auf die seite von pvbrowser gestoßen und habe da ein gutes beispiel gefunden. Kann man das C++ Programm anpassen und von dort aus ohne Lizenskosten übernehmen?


Wenn du jetzt doch fertige Bibliotheken verwendet darfst, wieso dann nicht libnodave? Dann muss in der SPS gar nichts projektiert und programmiert werden.

Die von die erwähnte Bibliothek steht wie auch libnodave unter der LGPL.
Ich hoffe ich bekomme es auf die Reihe was du darfst und was du musst, ohne Anspruch auf Vollständigkeit und Korrektheit:

- du musst einen Hinweis darauf geben, dass du in deinem Programm Software die unter einer OSS(OpenSourceSoftware)-Lizenz steht verwendest. Leg einfach mal eine Siemens Step7/WinCCflexible Installations-CD in deinen Rechner, und wirf einen Blick in die "Liesmich_OSS" oder so was in der Richtung. Da kannst du mal sehen wie Siemens das macht.

- du darfst die unveränderte Bibliothek dynamisch (z.B. in Form einer dll) oder statisch linken. Dein eigenes Projekt kannst du unter deine eigene Lizenz stellen.

- wenn du Änderungen an der Bibliothek vornimmst musst du den Quellcode mit den gemachten Änderungen zur Verfügung stellen

- wenn du den Quellcode in dein eigenes Projekt reinkopierst und alles zusammenmixt, erstellst du ein abgeleitetes Werk (derivative work) und dein gesamtes Projekt fällt unter die LGPL


----------



## Eleu (5 Dezember 2011)

Hi,

also ich habe schon mehrere Verbindungen ausprobiert.

Wenn es eine Socket Verbindung werden soll, kann ich die Betriebsart SEND/RECEIVE empfehlen.
http://support.automation.siemens.com/WW/view/de/17853532
Als Verbindung eine UDP-Verbindung.
Das ist besser zu handeln als eine TCP-Verbindung (Bei einer TCP-Verbindung muss der Empfangspuffer 
genauso groß sein, wie die Daten, die gesendet werden)

Bei der Fetch / Write Verbindung und auch bei Libnodave muss man, wenn man die Anwendung schließt 
eine weile warten, bis man die Anwendung wieder starten kann. Ansonsten gibt es einen Socket Fehler.
Irgendwie braucht es lange, bis die Socket Verbindung (Port102) wieder frei wird.
Wieso weiß ich auch nicht.

Gruß
Eleu


----------



## Energie85 (7 Dezember 2011)

Ich habe es endlich geschafft Daten auszutauschen zwischen dem socket und der SPS  (PC-->SPS) dies habe ich mit dem G_Resv Baustein gemacht.
Jetzt möchte ich das ganze mit dem G_Send Baustein in die andere Richtung machen (SPS-->PC) aber leider weiß ich nicht genau wo ich anfangen soll :-(
Habt ihr vielleicht einen Tip für mich.


----------



## Eleu (8 Dezember 2011)

Moin,

wo kneift es denn genau ?
Ein Schuß ins blaue: Hast Du vergessen das Taktmerkerbyte in der HW-Konfig zu konfigurieren ? Wäre der Klassiker 
Mit welchem Tool willst Du denn die Daten zyklisch empfangen  ?

Gruß
Eleu


----------



## Energie85 (8 Dezember 2011)

Morgen,

Danke für den Tipp Eleu J
ich habe es hinbekommen Daten von der SPS zum Socket (SPSàSocket) zu verschicken. Das Problem ist das ich die verschickten Werte auf Variablen im C++ Programm verteilen möchte. Muss ich da mehrere Datenbausteine erstellen um dies zu erreichen?
Mein Ziel ist es einfach mehrere Variablen im Socket Programm zu kontrollieren.  
Dies natürlich auch umgekehrt.

Meine nächste Frage wäre: Wenn ich etwas vom Socket zur SPS verschicke (SocketàSPS) z.B. verschicke ich eine Variable mit dem Wert 1234 diese Werte werden im Datenbaustein abgelegt. 

*Beispiel:*

DB222.DBB 0   Zeichen   1 à
DB222.DBB 1   Zeichen   2-à diese sollen im Programm einen Wert ergeben *(1234)*
DB222.DBB 2   Zeichen   3-à
DB222.DBB 3   Zeichen   4-à

Mein Problem ist das ich mit den Wert den ich verschickt habe arbeiten möchte. Mit den Werten im Datenbaustein weiß ich nichts anzufangen L Gibt es eine Möglichkeit die Werte im Datenbaustein als einen Wert zu erstellen?


----------



## Eleu (8 Dezember 2011)

Also ich bin kein C++ Programmierer
In C wäre das ein Char - Array was übertragen wird, aber ich glaube in C++ geht auch ein String als Variable.
Der DB sollte genauso groß sein wie der String der Übertragen wird.
Wenn Du in Step 7 eine Variablentabelle aufmachst, kannst Du Dir die einzelnen Byte etweder in HEX oder als Zeichen anzeigen lassen.

Was soll in der SPS damit gemacht werden ?


----------



## Energie85 (8 Dezember 2011)

Ich will mit den Werten z.B. einen Motor steuern. z.B. der wert 120. Aber wenn die Werte auf verschiedenen Datenbausteinen liegen kann ich nichts damit anfangen :-( Das die Werte auf der Variablentabelle abgelegt werden weiß ich. Es ist nicht mein Ziel die Werte zu beobachen. Mein Ziel ist es die Variablen einzusetzen.


----------



## Eleu (8 Dezember 2011)

Du musst Deinen Empfangs - DB so groß wählen, dass alle Daten die Du übertragen möchtest, dort ankommen.
Dann kannst Du im S7 Anwenderprogramm z.B. ein einzelnes Byte auswerten.
Das CHAR Zeichen '2' ist z.B. Hexadezimal B#16#32 
In dem Byte sind dann Bit 1, 4 und 5 logisch "1" 
Dezimal sind das dann 50.
Mehr als 255 ist nicht darstellbar pro byte.
Wenn Du größere Zahlen aus den Zeichen extrahieren willst, musst Du das im S7 - Anwenderprogramm programmieren. 
Du musst dann mit den Formaten hantieren und Variable zusammensetzen.

Das ganze ist halt nicht so komfortabel wie z.B. in WinCC.


----------

