Typ-Casting, Pointer, call by reference, wie geht das mit PCWORX?

e-hyp

Level-1
Beiträge
9
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!
Kurze Erklärung vorweg:
Ich programmiere eigentlich nur Hochsprachen (meist C++) und entwickle gerade ein neues Steuerungs-System unter Windows.
Als I/O-Ebene und für die nötigen Echtzeit-Routinen sind Phoenix ILC's geplant, die wir bislang nur für eher kleine Steuerungsaufgaben und dann meist mit der Web-Client-Schnittstelle verwendet haben. (Das machen bislang aber andere Kollegen)

Die Kommunikation soll über UDP und Sockets laufen, Tests mit kleinen Datenpaketen funktionieren bereits. Nun aber zu meinem Problem (das ist dann auch grundsätzlicher Natur):

Ich möchte eine Struktur (Sollwerte, Parameter, Outputs etc., insgesamt rund 8 KB) aus der Windows-Welt zyklisch auf die SPS-Ebene übertragen. Die Struktur beinhaltet INT16, INT32, Arrays, Chars usw. Auf PC-Seite wird dieser Block aufgrund der maximalen UDP-Paketgröße in 1400-Byte-Häppchen geteilt und versendet. (Dort caste ich die Struktur auf einen Char-Pointer und lasse eine Funktion entsprechend diesen 8K-Block 1:1 verschicken)

Auf der SPS-Seite habe ich die gleiche Struktur als TYP erstellt und möchte nun die jeweils empfangenen Pakete zu je 1400Byte wieder zu einem 8K-Block zusammenfügen und diesen Block dann entweder in die Struktur kopieren oder gleich jedes Paket an die richtige Stelle in die Struktur einfügen. Dazu hatte ich erwartet, einfach einen gecasteten Byte-Pointer auf den Anfang der Struktur (die ja eigentlich auch nur ein Memory-Block irgendwo im Speicher ist) legen zu können und die Einzel-Pakete uninterpretiert dort an die entsprechenden Stellen (alle 1400 Byte) hinein zu kopieren.
Aber ich finde bislang keine Möglichkeit dazu, auch die Kollegen kennen keine Pointer in dieser SPS und gucken mich mitleidig an wie einen Alien.
Ein Versuch über einen FB, der als Parameter einen Blockcounter, den Receive-Buffer und die Struktur bekommt (Was ja über sog. "Call-by-Reference", also Pointer erfolgt) bringt mich nicht weiter, weil PCWORX mich innerhalb des FB ebenfalls nur über die Struktur darauf zugreifen lässt.

Das muss doch irgendwie gehen!?!
(Und ich weiß auch, dass ich noch alle INTs noch Motorolafreundlich drehen darf - Das mache ich aber vorher schon auf dem PC)

Und wenn es schon keine CAST-Direktiven gibt, kennt jemand zumindest einen Workaround?

Danke im voraus..
 
Also ich würde von Hand die Bytes zusammenstricken und dann an die Struktur übergeben. So mach ich das immer bei TCP und UDP.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also, mit Verlaub, aber genau das will ich doch gerade NICHT machen.
Ich möchte doch nicht ausrechnen und fest codieren müssen, an welcher Position im x. Empfangsbuffer sich ein Element meiner (komplexen) Struktur befindet, um von dort entsprechende Bytes zu kopieren.
Und wenn ich zukünftig die Struktur erweitern muss, darf ich alle Adressen neu berechnen?

mal davon abgesehen, dass so aus einem simplen universellen 5-zeiler ein unflexibles, fehleranfälliges Byte-geschubbse über mehrere Seiten wird.

..nee, ich will wirklich nicht in diese mittelalterliche programmierhölle. :)
 
Oh entschuldigen sie euer Hohheit.
Wusste nicht, dass sie eine weniger arbeitsintensive Möglichkeit suchen.

Evtl. können sich es auch mit den BUF_TO_* Bausteinen hinbekommen.
Aber da müssten sie auch die Startadresse angeben. Also auch wieder Mist.

Und zum ausrechnen der Adressen bei einer Änderung, können sie sich ja ein kleines Tool schreiben.
Sie können ja eine Hochsprache.

Na dann viel Spaß.
 
Warum Hoheit?
Weil mich der Vorschlag nicht weiter bringt? hm.


Egal, nun wissen Sie ja, dass ich in der Tat eine weniger arbeitsintensive Variante suche. Und nein, Faulheit ist nicht der Grund, sondern weil diese Art eine einfache Funktionalität enorm verkompliziert, fehleranfällig macht und zukünftige Erweiterungen nur schwer berücksichtigen kann. Die Struktur hat etwa 8KB Datenumfang, Arrays, Ints, Chars bunt gemischt.

Der BUF_TO_* - FB konvertiert nur EINEN Standard-Datentyp, macht hier also keinen Sinn.

Trotzdem Danke, Knappe Mobi.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Warum Hoheit?
Weil mich der Vorschlag nicht weiter bringt? hm.
Ne wegen dem "mit Verlaub". Das hab ich beim letzten Mal in einem Märchen gehört.
Wusste garnicht, dass das noch im deutschen Sprachgebrauch drin ist.

Egal, nun wissen Sie ja,
Sie können ruhig du zu mir sagen.

dass ich in der Tat eine weniger arbeitsintensive Variante suche. Und nein, Faulheit ist nicht der Grund, sondern weil diese Art eine einfache Funktionalität enorm verkompliziert, fehleranfällig macht und zukünftige Erweiterungen nur schwer berücksichtigen kann. Die Struktur hat etwa 8KB Datenumfang, Arrays, Ints, Chars bunt gemischt.
Faulheit hätte ich jetzt nicht gesagt, ich weiß schon das man nach der leichtesten Möglichkeit sucht. Aber manchmal klappt es halt nicht.
Naja die Fehleranfälligkeit liegt ja beim Programmierer, je nachdem wiegut er die Verarbeitung und das Errorhandling macht.

Der BUF_TO_* - FB konvertiert nur EINEN Standard-Datentyp, macht hier also keinen Sinn.
Wie nur einen? Da gibt es doch mehrere Varianten von.

Trotzdem Danke, Knappe Mobi.
Bitte, bitte euer Hohheit ;)


Aber haben sie evtl. eine Beispielübertragung und den genauen Aufbau der Struktur. Evtl. kann ich ihnen da ein bisschen unter die Arme greifen.
Einfach mal mit Wireshark ein paar Pakete aufzeichnen, dann kann man den Part für die SPS am leichtesten aufbauen.
 
Moin.

Das Problem ist ja nicht die Übertragung (Wireshark ist also nicht nötig), sondern das ausfriemeln von Bytes aus mehreren 1400 Byte großen unstrukturierten Buffern (Receivebuffer) in einen Strukturierten Bereich. Die Daten liegen ja schon 1:1 an den richtigen Stellen, nur im falschen Buffer..


Das ist die Struktur (eine von zweien, die mit den Sollwerten, es gibt noch eine mit Istwerten) auf der PC-Seite: (ST_RT_COM_JOB) ist Bestandteil von ST_DUPO_O. ST_DUPO_O wird an die SPS versendet. MAX_DO und MAX_AO ist erstmal 32, MAX_RTSLOTS ist erstmal 200. in den RTSLOTS stehen Echtzeiterforderliche-Aufgaben, die die SPS ausführen soll. Die SPS arbeitet also als eine Art Interpreter und soll für die einzelnen Projekte nicht jeweils neu programmiert werden.

--------------------------------------------------------------------------------------------------
typedef struct
{
bool HSHAKE; // Handshake zum RT-Bereich (Flag: neuer Befehl)
bool READY; // Rückmeldung: 1=OK, 0=unbenutzt/in Arbeit
bool USED; // ComPath ist belegt
short command;
short sub;
char ea_1[2]; // Modul + Kanal
char ea_2[2]; // Modul + Kanal
char ea_3[2]; // Modul + Kanal
short bis, ab_puls;
short puls, pause;
short status;
} ST_RT_COM_JOB;


typedef struct
{
short WATCHDOG; // Flag: Watchdog (2)
bool REPARATUR; // Flag: Reparatur-Modus (1)
char externdo [MAX_DO][32]; // MAX_DO Module zu je 32 Kanäle (EXTERN) (1024)
short externao [MAX_AO][16]; // MAX_AO Module zu je 16 Kanäle (EXTERN) (1024)
ST_RT_COM_JOB RTSlotJob [MAX_RTSLOTS]; // Struktur der RealTime Jobs (Echtzeit-Aufgaben von Waagen, Ausgänge etc.)
} ST_RT_DP_O;
--------------------------------------------------------------------------------------------------



Die Struktur auf SPS-Seite lautet demnach:
--------------------------------------------------------------------------------------------------
(* Struktur der COM-JOBS zum Abarbeiten der Externen Aufträge ----------------------- *)
TYPE ST_RT_COM_JOB : STRUCT


HSHAKE : BOOL;
READY : BOOL;
USED : BOOL;
command : INT;
sub_com : INT;
ea_1m : BYTE;
ea_1k : BYTE;
ea_2m : BYTE;
ea_2k : BYTE;
ea_3m : BYTE;
ea_3k : BYTE;
bis : INT;
ab_puls : INT;
puls : INT;
pause : INT;
status : INT;
END_STRUCT;
END_TYPE


(* Struktur der übergebenen Soll-Ausgänge von Extern ----------------------- *)


TYPE AST_RT_COM_JOB : ARRAY [0..199] OF ST_RT_COM_JOB; END_TYPE


TYPE ST_RT_DP_O : STRUCT
WATCHDOG : INT;
REPARATUR : BOOL;
externdo : DO_ARRAY;
externao : AO_ARRAY;
RTSlotJob : AST_RT_COM_JOB;
END_STRUCT;
END_TYPE
--------------------------------------------------------------------------------------------------


Das Senden auf PC-Seite: (SOCKBLLEN ist 1400, der Socket M4IO.m_SPSSocket wurde vorher geöffnet)
--------------------------------------------------------------------------------------------------
char sendbuf [SOCKBLLEN+2], *pb;
int b, blocks;

blocks = sizeof (m_DUPO_O)/SOCKBLLEN;
for (pb=(char *)&m_DUPO_O, b=0; b<blocks; b++, pb+=SOCKBLLEN)
{
sendbuf [0] = 100+b; // Paketnummer (ab #100)
sendbuf [1] = blocks+1; // Anzahl der zu sendenden Pakete
memcpy (&sendbuf[2], pb, SOCKBLLEN);
send (M4IO.m_SPSSocket, pb, SOCKBLLEN, 0);
}
send (M4IO.m_SPSSocket, pb, sizeof (m_DUPO_O)-b*SOCKBLLEN, 0); // Den restlichen (kleineren) Block
----------------------------------------------------------------------------------------------------

Wie man sehen kann, lege ich den char-Pointer *pb auf die (gecastete) Instanz m_DUPO_O der Struktur ST_DUPO_O, und versende sie in SOCKBLEN-Große Päckchen per Socketstream an die SPS. (Dort kommen Sie auch prima an)
(Fehlerroutinen hab ich hier zum besseren Verständnis weggelassen.)

Ich suche nun eine Möglichkeit, auf der SPS-Seite das entsprechende Gegenstück zu implementieren.

Hab ich mich halbwegs verständlich machen können?

Andreas
 
Sorry, fehlten noch ein paar Datentypen auf der SPS-Seite:

TYPE BYTE32_ARRAY : ARRAY [0..31] OF BYTE; END_TYPE
TYPE INT16_ARRAY : ARRAY [0..15] OF INT; END_TYPE


TYPE DI_ARRAY : ARRAY [0..31] OF BYTE32_ARRAY; END_TYPE (* DI-FELD *)
TYPE DO_ARRAY : ARRAY [0..31] OF BYTE32_ARRAY; END_TYPE (* DO-FELD *)
TYPE AI_ARRAY : ARRAY [0..31] OF INT16_ARRAY; END_TYPE (* AI-FELD *)
TYPE AO_ARRAY : ARRAY [0..31] OF INT16_ARRAY; END_TYPE (* AO-FELD *)

(Und irgendwie klaut die thread-Darstellung meine Formatierung..)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja haste.

Trotzdem würde ich gerne mal ein gesendetes Paket sehen. Also die reinen Bytes.
Sowie man das bei Wireshark sieht. Mir würde dann auch die *.pcapng reichen.
So kann ich mir das besser vorstellen.
Und dann wo die reinen Werte stehen in der Struktur, welche dann den Bytes entsprechen.

Kannst mir es auch per PN schicken, wenn du es nicht hier zeigen willst.
 
Wobei, wenn das ganze so kompliziert ist, würde ich das mit XML-HTTP-Request lösen. Damit kannst du Variablen lesen und schreiben. Du musst da nicht mal viel vorbereiten in PC WorX. Nur die Variablen für die Kommunikation mit PDD kennzeichen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Auf der PC-Seite ist die physikalische Darstellung in Bits und Modul-Reihenfolge zu abstrahieren.

Und die Strukturen sollen auf beiden Seiten identisch sein. Das ist ja gerade die Idee daran. Ähnlich einem Dual-Port-RAm
(Daher auch die Namen der Strukturen "DUPO")

Aber es ist doch auch unerheblich, um was für Daten es sich handelt.

im Wireshark bekommst du nur 1402 Byte lange Pakete, deren Inhalt nur aus 0en besteht (ausser Byte 0 für Blocknummer und Byte 1 für Blockanzahl)
Was willst du daran sehen??
 
Wieso nur 0x00? Wenn dann schon Werte, damit ich weiß, von wo bis wo das geht.
Ich will mir das ganze auch mal nachbauen, mit einem Testtool, welches die 8KB dauernd sendet. zum testen.

Aber wie gesagt am einfachsten ist es mit HTTP-Request, mit GET und POST.
 
Aber das hat doch alles nichts mit der Übertragung zu tun!
Das gleiche Problem ist doch auch, wenn ich Daten aus einer Datei oder irgendeinem anderen Kanal mit Datenstrom bekomme.

OK. Folgendes Problem OHNE Übertragung:
Ich habe auf der SPS Seite einen BYTE-ARRAY von z.B. 8000 Bytes. Fix und fertig gefüllt mit übertragenen Werten und aus kleinen Häppchen korrekt zusammengesetzt.
Dann habe ich eine hübsche STRUC, die ebenfalls insgesamt 8000 Bytes lang ist.
Nun möchte ich den Inhalt des Blocks in diese Struktur mit möglichst wenig Programmieraufwand übertragen. Zum Glück liegen die Daten in exakt der gleichen Reihenfolge im Buffer, die auch die Struktur abbildet. Sogar auf korrekte gerade Adressierung innerhalb der Struktur ist geachtet.

Am liebsten wäre etwas ähnliches, wie

CopyMemory ((char *)Struktur, (char *)Block, 8000);

aber nicht etwas, wie

Struktur.abc := Block[404]*0xff + Block[405];
Struktur.def := Block[406];
Struktur.ghi := Block[407]*0xff + Block[408];
... usw...usw..usw..usw...
(Und ein BUF_TO_* statt "Block[404]*0xff + Block[405]" macht es auch nicht einfacher.)

Kann man einen Baustein basteln, der das Kann?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich weiß schon was du meinst. Am besten wäre sowas wie bei Codesys mit Pointern. Aber das geht hier nicht.
Deswegen würde ich einen Baustein machen, der die Bytes einfach zuordnet.
Den würde ich dir gerne machen, aber dazu bräuchte ich halt das von Wireshark um es selber zu testen.
Ich baue mir dann selber ein Tool, zwar nicht in C++ sondern in AutoIt, aber das ist genauso gut ind em Fall.
 
So?

Rechts siehst du die Struktur. Und "Test" ist das Array.
Das Array ist hier im Beispiel ARRAY_OF_BYTE_0_99 : ARRAY[0..99] OF BYTE;
Und die Struktur ist
Code:
TYPE
    udtData :
    STRUCT
        Byte0 : BYTE;
        Byte1 : BYTE;
        Word2 : WORD;
        DWord4 : DWORD;
    END_STRUCT;
END_TYPE
 

Anhänge

  • MEMCPY.jpg
    MEMCPY.jpg
    34,7 KB · Aufrufe: 19
Ich habs zwar nicht so mit der Darstellung der kleinen bunten Kästchen (wie gesagt, hoheitlicher hochsprachenprogrammierer), aber prinzipiell geht es wohl in die richtige Richtung.

Nur: was macht der Baustein innen drin?
 
Jetzt mische ich mich dazu auch noch ein. Soweit ich es verstanden habe geht es um Datenübertragung von der SPS zum PC.

Aber wie gesagt am einfachsten ist es mit HTTP-Request, mit GET und POST.
Das ist meiner Meinung auch eine sehr einfache Lösung.

D.h. man hat in der SPS eine Variable mit der Struct als PDD gekennzeichnet.
Nun kann man die einzelnen Werte dieser Struct per HTML Request abfragen. Der Aufbau der Struct ist ja bekannt.
Ich habe aber noch nicht weiter getestet ob man die Struct gleich in einem ganzen Stück abfragen kann.
 
Zurück
Oben