IP_USEND und IP_URCV

vmolchanov

Level-1
Beiträge
13
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag!

Ich versuche die TCP/IP-Kommunikation mit dem Barcodereader in PC WORX zu implementieren. Dafür sind FB IP_Connect, IP_USND und IP_URCV nützlich. Gesendet und empfangen müssen STRINGs.
Die folgenden Fehler treten auf:

Der VAR_IN_OUT-Parameter 'SD_1' ist mit keiner Variablen verbunden!
Der VAR_IN_OUT-Parameter 'RD_1' ist mit keiner Variablen verbunden!

Woran kann es liegen?

Danke im Voraus. Der Code ist beigefügt.

P:S. Noch eine Frage: Wie kann man ENUM in PC WORX erstellen?

Code:
[B]Inhalt von[/B] [B]Datentypen/basic:[/B]

TYPE
    STRING12: STRING(12);
    STRING15: STRING(15);
    T_SendeDaten :
    STRUCT
        LaengeDerNutzdaten : INT;
        Nutzdaten : STRING;
    END_STRUCT;
END_TYPE;
[HR][/HR][B]Inhalt von BarcodereaderV:
[/B]
bEnable BOOL VAR_INPUT
xComScan BOOL VAR_INPUT
xComReset BOOL VAR_INPUT

xComDone BOOL VAR_OUTPUT
xComError BOOL VAR_OUTPUT
sTraycode STRING12 VAR_OUTPUT

stSendToServer T_SendeDaten VAR
sToServer STRING  VAR
fbIPConnect IP_CONNECT VAR
fbIPSend IP_USEND VAR
fbIPReceive IP_URCV VAR
bStartSending BOOL VAR
bStartReceiving BOOL VAR
state INT VAR
[HR][/HR] [B]Inhalt von POE Barcodereader:
[/B]
fbIPConnect(EN_C := bEnable, PARTNER := '/ACTIVE /PORT=9005 /IP=192.168.3.201');

stSendToServer.LaengeDerNutzdaten := LEN(sToServer);
stSendToServer.Nutzdaten := sToServer;
fbIPSend(REQ:=bStartSending, ID:=fbIPConnect.ID, SD_1 := stSendToServer);

fbIPReceive(EN_R:=bStartReceiving, ID:=fbIPConnect.ID);

CASE state OF
    0:(* init state *)
        xComDone := FALSE;
        xComError := FALSE;
        bStartSending := FALSE;
        bStartReceiving := FALSE;
        state := 1;
    1:
        (* check connection *)
        IF fbIPConnect.VALID THEN
            IF (xComScan) THEN
                bStartSending := TRUE;
                bStartReceiving := FALSE;
                state := state + 1;
            END_IF;
        ELSE
            state := 0;
        END_IF;
    2:
        (* send string to server *)
        IF fbIPConnect.VALID THEN
            IF fbIPSend.DONE THEN
                bStartSending := FALSE;
                bStartReceiving := TRUE;
                state := state + 1;
            ELSIF fbIPSend.ERROR THEN
                state := 60;
            END_IF;
        ELSE
            state := 0;
        END_IF;

    3:
        (* receive string from server *)
        IF fbIPConnect.VALID THEN
            IF fbIPReceive.NDR THEN
                sTraycode := fbIPReceive.RD_1;
                state := state + 1;
            ELSIF fbIPReceive.ERROR THEN
                state := 60;
            END_IF;
        ELSE
            state := 0;
        END_IF;
    4:
        xComDone := TRUE;
        IF NOT(xComScan) THEN
            state := 0;
        END_IF;
    60:
        sTraycode := '';
        state := 0;
END_CASE;
 
Zuletzt bearbeitet:
OK, habe die Fehlermeldungen rausgekriegt. Die Korrekturen am Anfang des Codes sind wie folgt (ob der Code funktioniert, habe ich noch nicht getestet wegen fehlender Hardware):

Code:
...
fbIPSend(REQ:=bStartSending, ID:=fbIPConnect.ID, SD_1 := stSendToServer);
stSendToServer := fbIPSend.SD_1;

fbIPReceive(EN_R:=bStartReceiving, ID:=fbIPConnect.ID, RD_1 := sTraycode);
...
 
Zuletzt bearbeitet:
Hallo,

ja, ich benutze PC Worx. Ich war mir sicher, die Trennungslinien zwischen den Codeabschnitten zeigen es deutlich an, dass sie nicht in einem POE sind. Gut, habe zusätzlich Kommentare in bold hinzugefügt.

Was ist mit ENUM in PC Worx? Wie kann man es definieren?

Grüße
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Schade, dass ENUM nicht da ist. Gibt es dann eine Alternative?

Die Deklaration
TON_ARR_32: ARRAY[1..32] OF TON;
verursacht Fehler:
Betreffender Datentyp 'TON' nicht deklariert!

Gibt es eine Möglichkeit, ein Array von Timers oder anderen FBs zu deklarieren? Wenn nicht, kann man eine Alternative vorschlagen? Sonst muss man mehrere Zeilen anstatt 3-Zeilen FOR-Schleife schreiben, was sehr unattraktiv ist.

Danke
 
Da muss ich dich leider schon wieder enttäuschen.

Eine richtige Alternative gibt es nicht. Auch können Arrays und Strukturen nur Elemente enthalten die auf elementaren Datentypen beruhen.
 
Wiedermal schade...

Gut, können Sie bitte mir sagen, ob das Einlesen bei mir richtig implementiert ist - ich bekomme den Fehler 0x0033:
Allgemeiner Timeout, Empfänger antwortet nicht mehr bzw. Sender hat Übertragung nicht beendet.
Die Variable sTraycode ist vom Type STRING(12).

Es kann auch daran liegen, dass das Senden falsch ist. Soll LEN(sToServer) in die STRUCT T_SendeDaten? Aus Doku: "Im ersten Wort des Sendepuffers SD_1 müssen Sie die Anzahl der nachfolgenden Datenbytes eintragen (Intel-Format beachten)."

Code:
...
stSendToServer.LaengeDerNutzdaten := LEN(sToServer);
stSendToServer.Nutzdaten := sToServer;
fbIPSend(REQ:=bStartSending, ID:=fbIPConnect.ID, SD_1 := stSendToServer);

fbIPReceive(EN_R:=bStartReceiving, ID:=fbIPConnect.ID, [B]RD_1 := sTraycode[/B]);
...
CASE step OF
...
    3:
        (* receive string from server *)
        IF fbIPConnect.VALID THEN
            IF fbIPReceive.NDR THEN
                [B]sTraycode := fbIPReceive.RD_1;[/B]
                state := state + 1;
            ELSIF fbIPReceive.ERROR THEN
                state := 60;
            END_IF;
        ELSE
            state := 0;
        END_IF;
...
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
RD_1 ist als Datentyp ANY. Also ich würde da ein Word-Array nehmen. Und mit BUF_TO_STRING kannst du dann den Inhalt zu einem String konvertieren und in sTraycode eintragen.
 
So, gesendet muss die Zeile '[ESC]LON[CR]'. Wie lautet die entsprechende STRING? Ist das Format für Sonderzeichen richtig? Ich komme damit nicht klar... Ein funkzionierendes Beispiel der TCP/IP-Kommunikation wäre sehr hilfreich...

Code:
sToServer := ''$1BLON$0D'';
stSendToServer.LaengeDerNutzdaten := LEN(sToServer);
stSendToServer.Nutzdaten := sToServer;
fbIPSend(REQ:=bStartSending, ID:=fbIPConnect.ID, SD_1 := stSendToServer);
stSendToServer := SD_1;
...
 
Dann musst du das so ungefähr machen:
Code:
STRING_TO_BUF_1(REQ := ONBOARD_INPUT_BIT0, BUF_FORMAT := FALSE, BUF_OFFS := DINT#2, BUF_CNT := INT_TO_DINT(LEN(sToServer)), SRC := sToServer, BUFFER := abSendData);
sToServer := STRING_TO_BUF_1.SRC;
abSendData := STRING_TO_BUF_1.BUFFER;

IP_USEND_1(REQ := STRING_TO_BUF_1.DONE, ID := IP_CONNECT_1.ID, SD_1 := abSendData);
abSendData := IP_USEND_1.SD_1;


sToServer := CONCAT(BYTE_TO_STRING(BYTE#16#1B, '%c'), 'LON');
sToServer := CONCAT(sToServer, BYTE_TO_STRING(BYTE#16#0D, '%c'));

Ob du jetzt Intel- oder Motorola-Format hast, weiß ich ja nicht.

abSendData ist ein ARRAY[0..?] OF BYTE.

In den ersten beiden Bytes musst du natürlich noch die Länge eintragen der nachfolgenden Bytes.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke, Mobi!

Da ich eine konstante Zeile übersenden will ([ESC]LON[CR]), kann ich die Konvertierung sparen (glaube ich):
Code:
(*bytes 05 [ESC]LON[CR]*)
abSendData[1] := INT_TO_BYTE(0);
abSendData[2] := INT_TO_BYTE(5);  (*Länge der Nachricht*)
abSendData[3] := BYTE#16#1B;       (*[ESC]*)
abSendData[4] := BYTE#16#4C;       (*L*)
abSendData[5] := BYTE#16#4F;        (*O*)
abSendData[6] := BYTE#16#4E;        (*N*)
abSendData[7] := BYTE#16#0D;        (*[CR]*)
abSendData ist ARRAY[1..7] OF BYTE.
Leider bekomme ich den Fehler:
0x0062 Datentyp von Sender und Empfänger sind ungleich.
Wie kann es sein? Welches Typ? Wir senden und empfangen ja einfach Bytes!

Zurück zu deinem Beispiel: Wenn ich noch die Länge (5 in meinem Fall) in den ersten 2 Bytes angeben soll, würde ich so vorgehen:
Code:
sToServer := CONCAT(BYTE_TO_STRING(BYTE#16#1B, '%c'), 'LON');
sToServer := CONCAT(sToServer, BYTE_TO_STRING(BYTE#16#0D, '%c'));         (*sToServer hat hier den Wert "N" in der Watch-Liste. Komisch...)

STRING_TO_BUF_1(REQ  := ONBOARD_INPUT_BIT0, BUF_FORMAT := FALSE, [B]BUF_OFFS := DINT#2[/B], BUF_CNT  := INT_TO_DINT(LEN(sToServer)), SRC := sToServer, BUFFER :=  abSendData);
sToServer := STRING_TO_BUF_1.SRC;
abSendData := STRING_TO_BUF_1.BUFFER;[B][B]
abSendData[0] := INT_TO_BYTE(0);[/B]
abSendData[1] := INT_TO_BYTE(5);  (*6 macht keinen Unterschied*)[/B]

IP_USEND_1(REQ := STRING_TO_BUF_1.DONE, ID := IP_CONNECT_1.ID, SD_1 := abSendData);
abSendData := IP_USEND_1.SD_1;

Hier: abSendData ist ARRAY[0..7] OF BYTE (2 BYTES für Länge, 5 BYTES für Massage, 1 BYTE für Null-Zeichen). Ist es richtig? Komisch, dass in der Watch-Liste die STRING Variable sToServer als nur "N" gezeigt wird. Ich hoffe, dass es nur ein Darstellungsproblem. Der Fehler ist wieder:
0x0062 Datentyp von Sender und Empfänger sind ungleich.
 
Zuletzt bearbeitet:
Ein Array beginnt immer bei 0. Also musst du bei deiner Version auch bei 0 beginnen. Und die INT_TO_BYTE(5) würde ich dann ins Index 0 machen und die INT_TO_BYTE(0) ins Index 1.
Ein NULL-Zeichen brauchst du nicht, da du ja die Länge der Nutzdaten angibst.
 
Finally I have a solution for my problem: TCP/IP connection with camera (in my case Keyence SR-1000W) and data exchange (triggering the camera and receiving a scanned barcode or error message). The solution is based on FB IP_CONTROL from OSCAT-library. Unfortunately, application example from the OSCAT-documentation required debugging and some corrections, see below.

So, the following libraries were used:
oscat_network_121
oscat_basic_333 (required by the former)
The libraries and documentation are to be downloaded for free from www.oscat.de, added to the project and compiled (relative simple: right-click on the library, open as separate project, make; though, I had to do it several times before it worked). Without compilation, one receives many errors saying that types used are not known.

Now the code:
Code:
(* main FB *)
[B]IP_CONTROL_1(IP := IP4,
            PORT := IP_C.C_PORT,
            IP_C := IP_C,
            TIME_OUT := TIME_1,
            S_BUF := S_BUF_1,
            R_BUF := R_BUF_1);
IP_C := IP_CONTROL_1.IP_C;
S_BUF_1 := IP_CONTROL_1.S_BUF;
R_BUF_1 := IP_CONTROL_1.R_BUF;[/B]


CASE state OF
00: (* auf Freigabe warten *)
      IF bTrigger THEN
        bTrigger := FALSE;
        state := 10;
            IP_STATE := [B]BYTE#[/B]1; (* Anmelden *)
      END_IF;
10:    (* Warten auf Zugriffsfreigabe zum Verbindung aufbauen und Datensenden *)
      IF IP_STATE = [B]BYTE#[/B]3 THEN    (* Zugriff erlaubt ? *)
        sOutput := '';
        sError := '';
        TIME_1 := T#5000ms;
        (* IP Datenverkehr einrichten *)
        IP_C.C_PORT := wPort;
        (* Port-Nummer eintragen *)
        [B]IP4_DECODE_1(STR:='192.168.37.1');
        IP_C.C_IP := IP4_DECODE_1.IP4_DECODE;    (* IP eintragen *)[/B]
  (* Mode:                                                            *)
  (*  0: TCP + ACTIVE  + PORT + IP                                    *)
  (*  1: UDP + ACTIVE  + PORT + IP                                    *)
  (*  2: TCP + PASSIVE + PORT + IP                                    *)
  (*  3: UDP + PASSIVE + PORT + IP                                    *)
  (*  4: TCP + PASSIVE + PORT                                         *)
  (*  5: UDP + PASSIVE + PORT                                         *)
        IP_C.C_MODE := [B]BYTE#[/B]00;  (*BYTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)        
        IP_C.C_ENABLE := TRUE;     (* Verbindungsaufbau freigeben *)
        IP_C.TIME_RESET := TRUE; (* Zeitüberwachung rücksetzen *)
        IP_C.R_OBSERVE := FALSE; (* Datenempfang überwachen *)
        
        R_BUF_1.SIZE := [B]INT_TO_UINT[/B](0); (* Empfangslänge rücksetzen *)
        (* Sendedaten eintragen: in meinem Fall [ESC]LON[CR] *)
        S_BUF_1.BUFFER[0] := BYTE#16#1B;
        S_BUF_1.BUFFER[1] := BYTE#16#4C;
        S_BUF_1.BUFFER[2] := BYTE#16#4F;
        S_BUF_1.BUFFER[3] := BYTE#16#4E;
        S_BUF_1.BUFFER[4] := BYTE#16#0D;
        S_BUF_1.SIZE := [B]INT_TO_UINT[/B](5); (* Sendelänge eintragen *)

        timer(IN := FALSE, 
            PT := TIME_1);
    
        state := 30;
      [B]END_IF;[/B]                    (*missed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
30:
    timer(IN := TRUE, 
            PT := TIME_1);
    IF timer.Q THEN
        sError := 'Timeout';
        sOutput := '';
        IP_STATE := BYTE#4;    (* Abmelden – Zugriff wieder für andere freigeben *)
           state := 00;
    END_IF;    

    (* Fehlerauswertung durchführen *)
    IF IP_C.ERROR <> [B]INT_TO_DWORD[/B](0) THEN
        [B]sError := 'ERROR occured';
        IP_STATE := BYTE#4;    (* Abmelden – Zugriff wieder für andere freigeben *)
        state := 0;[/B]
    ELSIF S_BUF_1.SIZE = [B]INT_TO_UINT[/B](0) AND R_BUF_1.SIZE >= [B]INT_TO_UINT[/B](5) THEN    (* Empfangene Daten auswerten *)
            bConvert := TRUE;
            state := 40;
    END_IF;
40:
    IF BUF_TO_STRING_1.DONE THEN
        IF EQ_STRING(LEFT(sOutput, 5), 'ERROR') THEN
            sOutput := '';
        END_IF;            
        bConvert := FALSE;
        IP_STATE := BYTE#4;    (* Abmelden – Zugriff wieder für andere freigeben *)
           state := 00;
    ELSIF BUF_TO_STRING_1.ERROR THEN
        sOutput := '';
        IP_STATE := BYTE#4;    (* Abmelden – Zugriff wieder für andere freigeben *)
           state := 00;
    END_IF;
END_CASE;

(* IP_FIFO Zyklisch aufrufen *)
IP_FIFO_1(FIFO:=IP_C.FIFO,
            STATE:=IP_STATE,
            ID:=IP_ID_1);
IP_C.FIFO:=IP_FIFO_1.FIFO;
IP_STATE := IP_FIFO_1.STATE;
IP_ID_1:=IP_FIFO_1.ID;

BUF_TO_STRING_1(REQ:=bConvert,
                BUF_FORMAT:=TRUE,
                BUF_OFFS:=DINT#0,
                BUF_CNT:=UINT_TO_DINT(R_BUF_1.SIZE),
                BUFFER:=R_BUF_1.BUFFER,
                DST:=sOutput);
R_BUF_1.BUFFER := BUF_TO_STRING_1.BUFFER;
sOutput := BUF_TO_STRING_1.DST;

My corrections are marked bold (missing call of the main FB, missing end-if, type conversions...). I added: readable IP-address, a custom timer (the build-in timer was disabled by IP_C.R_OBSERVE := FALSE; ), and a conversion of the received barcode to a readable string. Since I hate that one should always guess the types of the variables used in examples (naming some part of variables after FB is also misleading IMHO), below is the list of my variables:
Code:
state    INT
IP_C    oscat_IP_C
wPort    WORD
IP4    DWORD
R_BUF_1    oscat_NETWORK_BUFFER
S_BUF_1    oscat_NETWORK_BUFFER
IP4_DECODE_1    IP4_DECODE
IP_STATE    BYTE
IP_CONTROL_1    IP_CONTROL
FREIGABE    BOOL
IP_FIFO_1    IP_FIFO
IP_ID_1    BYTE
TIME_1    TIME
sError    STRING
sOutput    STRING
BUF_TO_STRING_1    BUF_TO_STRING
bConvert    BOOL
bTrigger    BOOL
timer    TON

My first week of learning PC WORX finishes here...
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Das alles hättest du mit den FBs aus PC Worx auch hinbekommen.
Spricht man jetzt in Bremen neuerdings englisch oder ist dein deutsch auf einmal verschwunden?
 
Ich habe gestern 1,5 Stunden mit Phoenix Support telefoniert. Trotz aller Mühen hat es uns nicht gelungen, den Aufnahmebefehl an die Kamera zu schicken. Der Berater hat selbst entfernt alles auf neu in FBD programmiert - nix da. Ich glaube, ich könnte es letztendlich schaffen aber die Zeit brauche ich für die nächsten Aufgaben.

Deutsch ist für mich eine Fremdsprache genauso wie Englisch. Ich habe meinen Beitrag erst auf Englisch geschrieben und wollte es dann nicht extra übersetzen. Ich glaube, ich habe hier schon einige Beiträge auf Englisch gesehen, und ich gehe davon aus, dass hier alle Englisch verstehen.
 
Um was für eine Kamera/Barcodereader handelt es sich? Wenn ich eine besorgt bekomme, werde ich es auf jeden Fall versuchen, auch wenn es 5 Stunden dauert. Aber bis jetzt habe ich alles hinbekommen.

Bei den englischen Beiträgen sind meistens die gesamten Threads auf englisch. Bei 64.448 Mitglieder in diesem Forum und einer unbekannten Anzahl Gästen, kannst du davon ausgehen, dass nicht alle englisch können. Die meisten suchen bei Problemen auf deutsch und kommen dann z.B. von Google hier hin. Viele suchen auch extra auf deutsch, damit sie eventuelle Lösungen einfacher verstehen und umsetzen können. Wenn du beim nächsten Mal wieder ein Problem hast, dann mach es doch so wie der User emilg und frage gleich direkt auf englisch. Dann haben wir nicht diesen Misch-Masch.
 
Zurück
Oben