Komunikace s PLC pres TCP/IP
Slavomir Skopalik
skopalik na elektlabs.cz
Čtvrtek Prosinec 26 17:26:22 CET 2013
Dobry den,
pokud chcete pouzit TCP server misto jednoho konce seriove linky, tak Vas
ceka nekolik
nesnazi:
1. TCP server obecne muze mit navazano vice spojeni, nez jedno.
Resi se to tak, ze je jeden thread, kde je tzv. listener, jenz prijima a
spojeni a predava jej do tzv. workeru, jenz
pak resi vlastni komunikaci. Neco jako inetd v linuxu.
2. TCP ma delsi odezvy, nez RSxxx, je treba s tim pocitat
3. Doporucuji vsechny TCP funkce volat s vlastnim TimeOutem, aby recovery
spojeni bylo pod kontrolou.
4. Zvazit nastaveni NoDelay, viz kod nize
Ukazka meho kodu (pouziva synapse + vlastni RS232):
Berte to prosim jen jako nastrel toho, jak to muze vypadat, slozitost je
dana pozadavku na univerzalnost
knihoven (RS, TCP, UDP, server x klient).
function TComThread.WriteBuf(const Data; Count: Integer;
TCPTimeOut:integer=500): Integer;
var
B: DWORD; s:AnsiString;
tp: TThreadPriority;
begin
Result := -1;
if FTCP then begin
if TCPConnect then begin
FSocket.SetSendTimeout(TCPTimeOut);
result:=FSocket.SendBuffer(@Data,Count);
if FSocket.LastError<>0 then begin
DoLog('TCP: Write:'+AnsiString(FSocket.LastErrorDesc),lgTx);
TCPClose;
end;
end;
end else begin
if FDefered then DeferedConnect;
if FRTSIsDirection then
EscapeCommFunction(ComHandle,SETRTS);
if WriteFile(FComHandle, Data, Count, B, nil) then Result := B else
DeferedClose;
if FRTSIsDirection then begin
tp:=Priority;
Priority:=tpTimeCritical;
FlushFileBuffers(ComHandle);
Sleep(Max(1,Ceil((1000*BitsPerChar/TcmBaudrateToBaudRate[BaudRate])))); //
wait for last char in Tx Buffer
EscapeCommFunction(ComHandle,CLRRTS);
Priority:=tp;
end;
end;
if (result=Count)and EnableLog then begin
SetLength(s,result);
move(Data,s[1],result);
DoLog('Tx:'+s,lgTx);
end;
end;
function TComThread.TryReadBuf(var Data; Count:
Integer;TCPTimeOut:integer=1000): Integer;
var
B: DWORD; s:AnsiString;
begin
if FTCP then begin
TCPConnect;
result:=FSocket.RecvBufferEx(@data,Count,TCPTimeOut);
end else begin
if ReadFile(FComHandle, Data, Count, B, nil) then Result := B
else Result := -1;
end;
if EnableLog then begin
if result>0 then begin
SetLength(s,result);
move(Data,s[1],result);
DoLog(Format('Rx(%d):',[result])+string(s),lgRx);
end;
end;
end;
function TComThread.SetNoDelay(NoDelay:boolean): boolean;
var flag:LongInt;
begin
result:=false;
if not TCP then exit;
flag:=ord(Nodelay);
result:=synsock.SetSockOpt(Socket.Socket,IPPROTO_TCP,TCP_NODELAY, na flag,sizeo
f(flag))=0;
end;
A jeste ukazka listeneru:
procedure TComThread.MultiServerListener;
type TCTC=class of TComThread;
var p:TComThread; c:TCTC;
{$ifdef synapse}
s,prot,user,pass,host,port,path,para:string;
sock:TTCPBlockSocket;
hSock:TSocket;
{$endif}
begin
SetThreadName('Listener:'+ClassName+':'+DeviceName);
s:=copy(FDeviceName,pos(_TCPServer,FDeviceName)+Length(_TCPServer),MaxInt);
ParseURL(s,prot,user,pass,host,port,path,para);
while not Terminated do begin
Event.ResetEvent;
if FServerSocket.Socket=INVALID_SOCKET then begin
FServerSocket.Bind(host,port);
if FServerSocket.LastError<>0 then begin
DoLog(Format('Binding socket %s:%s error:
%s',[host,port,FServerSocket.LastErrorDesc]),lgErrorLevel1);
FServerSocket.CloseSocket;
Event.WaitFor(2000);
continue;
end;
FServerSocket.Listen;
end;
if FServerSocket.CanRead(500) then begin
c:=TCTC(self.ClassType);
hSock:=FServerSocket.Accept;
if FWorkersList.Count>80 then begin
sock:=TTCPBlockSocket.create;
sock.Socket:=hSock;
sock.AbortSocket;
sock.Free;
DoLog('Maximum worker threads reached, incoming connection
Aborted',lgErrorLevel1);
end else begin
p:=c.Create(_TCPSocket+IntToStr(hSock));
p.Assign(self); // copy of communication setup
SO.Enter;
FWorkersList.Add(p);
SO.Leave;
p.Event.SetEvent;
sleep(20); // prevet too many thread start in one moment
DoLog('TCP Accept
connection:'+AnsiString(p.Socket.GetRemoteSinIP+':'+IntToStr(p.Socket.GetRem
oteSinPort)),lgConnect);
end;
end;
SO.Enter;
try
FWorkersList.FreeTerminated;
FConnected:=FWorkersList.Count>0;
finally
SO.Leave;
end;
end;
end;
Slavek
Ing. Slavomir Skopalik
Jednatel spolecnosti
Elekt Labs s.r.o.
Sber a vyhodnoceni dat ze stroju a laboratori
systemem MASA (http://www.elektlabs.cz/m2demo)
----------------------------------------------
Adresa:
Elekt Labs s.r.o.
Chaloupky 158
783 72 Velky Tynec
Czech Republic
----------------------------------------------
Mobil: +420 724 207 851
icq:199 118 333
skype:skopaliks
e-mail:skopalik na elektlabs.cz
http://www.elektlabs.cz
> -----Original Message-----
> From: Hw-list [mailto:hw-list-bounces na list.hw.cz] On Behalf
> Of Milan Kratochvíl
> Sent: Thursday, December 26, 2013 4:28 PM
> To: HW-news
> Subject: Re: Komunikace s PLC pres TCP/IP
>
>
> Jsem doma takže upřesnění, místo třídy TBlockSerial použít třídu
> TSocket. Krom nastavení mají tyto třídy hodně stejných funkcí
> takže je
> nebudete muset přepisovat. Krásný příklad serveru je v Synapsi přímo
> Synapse\source\demo\httpserv kde se nastaví na poslouchání na nějakém
> portu (v demu 80) a potom samostatné thready obsluhují jednotlivá
> příchozí spojení. Pokud z toho threadu vyhážete tu obsluhu html
> protokolu a dáte tam to co máte na sériovém portu tak by to
> mohlo chodit. Milan
>
> Dne 26.12.2013 10:35, Milan Kratochvíl napsal(a):
> > Tak to by mělo být pro vás velice jednoduché. Autor někde píše, že
> > stačí nahradit třídu TSerial třídou THttp (jestli si ty třídy dobře
> > pamatuji). Nemám to u sebe a tak to píšu z hlavy. Jinak když to
> > stahnete tak je tam pár příkladů podle kterých se to dá udělat.
> > Milan
> >
> > Dne 26.12.2013 8:47, Martin Záruba napsal(a):
> >> Ja v to doufal, pouze naprosto nevim jak. Nemate nejaky priklad? Ma
> >> se to
> >> chovat uplne stejne jako puvodni seriovy port, pouze bych
> potreboval,
> >> aby v
> >> rezimu server umel dat informaci, ze klient se pokousi o navazani
> >> spojeni.
> >>
> >> Martin Zaruba
> >> ----- Original Message -----
> >> From: "Milan Kratochvíl" <krata.milan na seznam.cz>
> >> To: "HW-news" <hw-list na list.hw.cz>
> >> Sent: Thursday, December 26, 2013 7:23 AM
> >> Subject: Re: Komunikace s PLC pres TCP/IP
> >>
> >>
> >> Zdravim
> >> Použijte opět projekt Synapse. Umí jak klienta tak server, má dost
> >> příkladů a v Lazaru funguje. Milan
> >>
> >> Dne 26.12.2013 6:53, Martin Záruba napsal(a):
> >>> Pred rokem mi pan Zdenek Aster velmi pomohl s informaci, jak v
> >>> Delphi/Lazarus udelat komunikaci s PLC pres seriovy port pomoci
> >>> knihovny synaser. Vse krasne funguje, ale nyni se ukazuje nutna
> >>> komunikaci na vetsi
> >>> vzdalenost. Chci k tomu pouzit XPort nebo WiPort. Na
> strane PLC mi vse
> >>> funguje a pokud na strane PC pouziji portredirector, funguje to
> >>> (vetsinou)
> >> i
> >>> na strane PC. Zkusil jsem nekolik portredirectoru, ten od
> Lantronixu
> >>> je zcela nepouzitelny, nektere dalsi s obtizemi (PLC musi
> pracovat
> >>> jako klient - nema verejnou IP). Nejradeji bych proto komumikoval
> >>> primo z vlastniho programu bez portredirectoru. To umi napr.
> >>> vyvojove prostredi k PLC, kde si lze zvolit bud seriovy port nebo
> >>> Ethernet a prislusny port. V
> >>> rezimu server pak program ceka na pozadavek od klienta,
> vypise jeho
> >>> IP a
> >> pak
> >>> jiz staci jen povolit komunikaci. Zjevne je to zcela standardni,
> >>> protoze i
> >>> kdyz je vyvojove prostredi k PLC, navazalo komunikaci s WiPortem
> >>> Lantronix
> >>> bez problemu.
> >>> Jak ale tuto komunikaci udelat ve vlastnim programu?
> Jakou knihovnu pro
> >>> komunikaci pres IP pouzit v Delphi/Lazarus?
> >>>
> >>> Martin Zaruba
> >>>
> >>> _______________________________________________
> >>> HW-list mailing list - sponsored by www.HW.cz Hw-list na list.hw.cz
> >>> http://list.hw.cz/mailman/listinfo/hw-list
> >>>
> >> _______________________________________________
> >> HW-list mailing list - sponsored by www.HW.cz Hw-list na list.hw.cz
> >> http://list.hw.cz/mailman/listinfo/hw-list
> >>
> >> _______________________________________________
> >> HW-list mailing list - sponsored by www.HW.cz Hw-list na list.hw.cz
> >> http://list.hw.cz/mailman/listinfo/hw-list
> >>
> >
> > _______________________________________________
> > HW-list mailing list - sponsored by www.HW.cz Hw-list na list.hw.cz
> > http://list.hw.cz/mailman/listinfo/hw-list
> >
>
> _______________________________________________
> HW-list mailing list - sponsored by www.HW.cz
> Hw-list na list.hw.cz http://list.hw.cz/mailman/listinfo/hw-list
>
Další informace o konferenci Hw-list