FB_SocketReceive, Daten empfangen

kai86

Level-1
Beiträge
158
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
arbeite mich gerade in Beckhoff ein.
Ich würde gern einfach nur 5 Bytes senden und empfangen. das senden klappt super nur das empfangen will nicht so wie ich.

Hier mal der Code, ich will halt senden und Empfangen auslagern:
Hier mein Puffer:
Code:
TYPE Buffer :
STRUCT
    SendBuff : ARRAY[1..5] OF BYTE;
    RecvBuff : ARRAY[1..5] OF BYTE;
END_STRUCT
END_TYPE
Hier mein Vars von der Main:
Code:
PROGRAM MAIN
VAR
    hServer         : T_HSERVER;
    bListen         : BOOL;

    fbServerConnection : FB_ServerClientConnection;

    Send        : BOOL := FALSE;
    Recv        : BOOL := FALSE;
    data            : Buffer;    
    Emp        : UDINT;

END_VAR
Hier meine MAIN, über die Bools Send und Recv steuere ich was ich gerade machen will.
Code:
F_CreateServerHnd(    sSrvNetID        := '', 
                    sLocalHost         := '',
                     nLocalPort         := 6000, 
                    nMode             := LISTEN_MODE_CLOSEALL, 
                    bEnable            := TRUE,
                    hServer            := hServer);

fbServerConnection(    eMode             := eACCEPT_ALL,
                    sRemoteHost     := '',
                    nRemotePort         := 0,
                    bEnable             := TRUE,
                    tReconnect         := T#1s,
                    hServer             := hServer);

IF Send THEN
    Senden(hSocket := fbServerConnection.hSocket ,len := 5, pPlace := ADR(data.SendBuff ));
END_IF;

IF Recv THEN
    Empfangen(hSocket := fbServerConnection.hSocket ,len := 5, pPlace := ADR(data.RecvBuff ));
END_IF;

Hier das empfangen was nicht klappt.

Code:
FUNCTION Empfangen : UDINT
VAR_INPUT
    hSocket     : T_HSOCKET;
    len        : DINT;
    pPlace     : DWORD;
END_VAR
VAR
    fbrecv    : FB_SocketReceive;
END_VAR

Code:
fbrecv( bExecute := FALSE );
fbrecv(    sSrvNetId        := '',    
        hSocket            := hSocket,        
        cbLen            := len,            
        pDest            := pPlace,            
        bExecute        :=TRUE,            
        tTimeout            := T#5s); 

Empfangen := fbrecv.nRecBytes;

Und hier das senden was klappt wenn der Sende Puffer was drin hat.

Code:
FUNCTION Senden : BOOL
VAR_INPUT
    hSocket     : T_HSOCKET;
    len        : DINT;
    pPlace     : DWORD;
END_VAR
VAR
    fbSend : FB_SocketSend;
END_VAR

Code:
fbSend( bExecute := FALSE );
fbSend(    sSrvNetId        := '',    
        hSocket            := hSocket,        
        cbLen            := len,            
        pSrc            :=pPlace,            
        bExecute        :=TRUE,            
        tTimeout            := T#5s);

Senden := fbSend.bError;

Das senden und empfangen teste ich mit TELNET.

Über etwas hilfe wäre ich sehr glücklich.

grüße kai
 
Ja also, TCP mit Beckhoff habe ich auch schon mal abgehandelt.

Folgendes fällt mir zu deinen Post ein:

1) Bei der Server Connection sollte der Port nicht 0 sein (alles über 10000
geht gut)

2) Wenn du deine FB`s instanzierst drücke vorher mal F2 und wähle diesen
dann in der "lokalen Liste" aus. Vorteil: TwinCAT zeigt dir die komplette
Beschaltung des FB`s

3) Mach aus der Funktion Empfangen mal einen FB, dann siehst du die
Zustände, Send und Receive informieren über "ErrID" was passiert ist !!!

4) Das Durchschleifen vom ADR() Operator in Function Empfangen halte ich
für schwierig, sollte man prüfen ob das überhaupt so geht

5) Grundsätzlich wird der Receive Baustein "pollend" angesprochen, sprich
er reagiert nur auf eine positive Flanke (da muss ein Trigger ran, der
zyklisch der zyklisch EXECUTE aufruft), dann ein Event generieren wenn
ReceivedBytes = Telegrammlänge

6) Es ist zu empfehlen mit StateMachines zu arbeiten (Schrittketten, die den
Empfang und Sendevorgang über Transitionen durchlaufen), da es doch
nicht untypisch ist mal eine Fehlermeldung bspw. beim Senden zu
bekommen

7) Für die Querkommunikation zwischen Beckhoff Systemen ist das ADS
Protokoll besser als TCP ! Also über Datenfächer Variablen austauschen.

So long,

SteelWorker
 
fbrecv( bExecute := FALSE );
fbrecv( sSrvNetId := '',
hSocket := hSocket,
cbLen := len,
pDest := pPlace,
bExecute :=TRUE,
tTimeout := T#5s);

Empfangen := fbrecv.nRecBytes

Du rufst den Baustein zweimal hintereinander auf, einmal mit bExecute=False, dann mit True.

Kenne die Beckhoff FBs nicht, aber in der Beckhoff Info steht was von Toggeln des Execute Eingangs.

Der zweite Aufruf des FBs ist zwar auf True, aber ich denke mal, das zur Aktualisierung des Empfangsvorgangs vielleicht doch immer ein SPS-Zyklus vergehen muss. Ich würde es mal probieren, den ersten Aufruf mit False zu streichen, und dann zyklisch bei jedem FB-Aufruf den Execute-Eingang zu toggeln.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der zweite Aufruf des FBs ist zwar auf True, aber ich denke mal, das zur Aktualisierung des Empfangsvorgangs vielleicht doch immer ein SPS-Zyklus vergehen muss.


Nein, es reicht den FB zweimal aufzurufen, so dass der code ausgeführt wird:

fb_xxx(start=False);
fb_xxx(start=true);
 
Zu SteelWorker:
zu 1.
die null ist ja nur beim remote Host da ich ja der Server bin sollte das doch ok sein (ich meine mich zu erinnern, dass bei 0 alle Ports zugelassen werden).
zu 3.
da Error immer false war habe ich die id dazu nicht ausgelesen.
zu 4.
ich habe das so schon in einem anderen beispiel gesehen sollte also möglich sein, ich bekomme auch eine speicheradresse rein. beim senden klappts ja auch.
zu 5.
kannst du das genauer erklären, das verstehe ich noch nicht ganz wie du das meinst.
zu 6.
bei dem programm kommts auf die geschwindigkeit an und statemaschis sind sehr langsam.
zu 7.
ich muss tcp verwenden.

danke auch für die anderen die sich beteiligen
grüße kai
 
Nein, es reicht den FB zweimal aufzurufen, so dass der code ausgeführt wird:

Sicher? Hatte mir folgendes überlegt: (Als nicht Beckhoff-User)

Wenn der Baustein mehr als nur einen Zyklus benötigen würde, den Empfangsvorgang auszuführen, würde in jedem Zyklus der Vorgang durch Execute=False abgebrochen und danach mit Execute wieder gestartet. So würde er nie fertig werden.
In der Beckhoff Hilfe steht auch irgendwas mit steigenden Flanken im 100ms Takt. Warum machen die dann so ein federlesens wenns auch mit zwei Aufrufen hintereinander geht?

Aber interessieren täts mich dann aber doch.....
 
so mache jetzt das receive nur noch alle 11 zyklen. aber das kanns doch auch nicht sein oder?
also es geht auf jedenfall nicht
warum macht ist das für beckhoff so schwer oder bin ich nur zu doof :)
 
So ich bins wieder selbes Thema(Verbindung wird zwischen PC und PLC aufgebaut):

Und zwar sende ich mit der PLC Linktests (4Byte große) alle 5sek und erwarte auf das gesendete ein ACK dieses wird meistens richtig empfangen. wenn ich aber andere nachrichten vom PC aus an die PLC sende, empfängt der nichts mehr. Bei den Daten handelt es sich ebenfalls um einen Linktest 4 Byte oder um Nachrichten beliebig groß. Nach mehreren Neustarts und neuladen komme ich aber auch mal in den Zustand das immer alles geht und wenn ich wieder neustarte gehts wieder nicht mehr.
Ich habe nun die Zykluszeit von 10 auf 1 ms runtergesetzt und die im Systemmanager von 1ms auf 100µs nun gehts immer, zumindest bei mir. Aber auf nem anderen Rechner wo beckkoff auf einer virtuellen maschine läuft geht das empfangen überhaupt nicht.

Der Code liegt bei mache ich was beim empfangsaufruf falsch??? Oder woran liegt es. Bei den Beispiel Beckhoff Projekte geht das Empfangen ja auch.

Für eure Hilfe wäre ich sehr dankbar. Code liegt bei.

Code:
PROGRAM MAIN
VAR

    Connected         : BOOL;
    Step            : INT := 0;
    LinkTestSEND    : FB_LinkTestSEND;
    LinkTestTimer    : TON;                        (*Timer für den Linktest*)
    ACKTimer        : TON;                        (*Timer für den Ack der gesendeten Daten*)
    WaitForAckLink    : BOOL;
    WaitForAckData    : BOOL;

(*Test Variablen*)
    Disconnect    : BOOL := FALSE;
END_VAR

CASE Step OF
    0:      Connected := F_DCP_TCP_ConnectionStatus(Step := Step);
        LinkTestTimer(IN := FALSE,PT:=T#5s);
        ACKTimer(IN := FALSE,PT:=T#3s);
        WaitForAckLink    := FALSE;
        WaitForAckData    := FALSE;

     1:      IF NOT Connected THEN Step := 0; RETURN; END_IF;
        LinkTestTimer(IN := TRUE);
        StepSend();
        LinkTestSEND(LinkTimer := LinkTestTimer,ACKTimer:=ACKTimer,Connected =>Connected, WaitForAck := WaitForAckLink);
        StepRecv( ACKTimer:=ACKTimer, WaitForAckLink := WaitForAckLink, WaitForAckData := WaitForAckData);
END_CASE;

Code:
FUNCTION_BLOCK FB_StepRecv
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR_IN_OUT
    ACKTimer        : TON;
    WaitForAckLink    : BOOL;
    WaitForAckData    : BOOL;
END_VAR
VAR
    RecvB             : UDINT;
    MsgSize            : DWORD;
    MsgSizeACK        : DWORD;
END_VAR

(*Ersten 4 Bytes Empfangen mit der Länge*)
IF MsgSize = 0 THEN
    Recv(msglen := 4,pRecv := ADR(SR_Buffer[0]),RecvBytes => RecvB);
    IF RecvB <4 THEN RETURN; END_IF;
    MsgSize := F_ArrayToDWord(ADR(SR_BUFFER[0]));
END_IF
(*Was war das für eine Message*)
CASE MsgSize OF
    4:    (*Eingehender Linktest*)
        SR_Buffer[0] := 0;
        SR_Buffer[1] := 0;
        SR_Buffer[2] := 0;
        SR_Buffer[3] := 8;
        SR_Buffer[4] := 0;
        SR_Buffer[5] := 0;
        SR_Buffer[6] := 0;
        SR_Buffer[7] := 4;
        Send(msglen :=  8, pSend:= ADR(SR_Buffer));
        MsgSize := 0;
    8:    (*ACK für gesendete Daten oder Linktest*)
        ACKTimer(IN := FALSE);                                        
        Recv(msglen := 4,pRecv := ADR(SR_Buffer[3]),RecvBytes => RecvB);
        IF RecvB <4 THEN RETURN; END_IF;
        MsgSizeACK := F_ArrayToDWord(ADR(SR_BUFFER[0]));
        IF MsgSizeACK = 4 THEN
            (*LinktestACK gekommen*)
            IF NOT WaitForAckLink THEN        (*ACK kam rein obwohl vorher kein Linktest gesendet wurde !!!*)
                ERROR_Report(Error := 1);            (*Fehler 1*)
            END_IF
            WaitForAckLink := FALSE;
        ELSE
            ;(*ACK für gesendete Daten*)
            IF NOT WaitForAckData THEN        (*ACK kam rein obwohl vorher keine Daten gesendet wurden !!!*)
                ERROR_Report(Error := 2);            (*Fehler 2*)
            END_IF
            WaitForAckData := FALSE;
        END_IF; 
        MsgSize := 0;
    ELSE
        IF MsgSize > 8 THEN
            (*Eingehende Daten*)
            Recv(msglen := DWORD_TO_DINT(MsgSize-4), pRecv := ADR(SR_Buffer[3]), RecvBytes => RecvB);
            IF RecvB <DWORD_TO_DINT(MsgSize-4) THEN RETURN; END_IF;
            MsgSize := 0;
            (*Hier kommt der Command in den Buffer von Dirk*)
        END_IF;
END_CASE;

Code:
FUNCTION_BLOCK FB_DCP_TCP_Receive
VAR_INPUT
    msglen            : DINT;
    pRecv            : DWORD;
END_VAR
VAR_OUTPUT
    RecvBytes        : UDINT;
END_VAR
VAR
    Error    : BOOL;
    fbrecv            : FB_SocketReceive;
    cbReceived         : UDINT := 0;
END_VAR

fbrecv( bExecute := FALSE );
RecvBytes := fbrecv.nRecBytes;
fbrecv(    sSrvNetId        := '',    
        hSocket            := DCP_TCP_hSocket,        
        cbLen            := msglen-cbReceived,            
        pDest            := pRecv+cbReceived,            
        bExecute        :=TRUE,            
        tTimeout            := T#5s);
cbReceived := cbReceived + RecvBytes;
RecvBytes := 0;
IF cbReceived = msglen THEN
    cbReceived := 0;
    RecvBytes := msglen;
END_IF;
 
Zurück
Oben