Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

TCP primers / start point?

Status
Not open for further replies.

CADTenchy

Technical User
Dec 12, 2007
237
GB

A new project has arisen for me today, which I'm really interested in but essentially know nothing about!

I need to do a simple app that can talk via the PC ethernet port to a hardware device on an IP address. Most likely it will be on an intranet but it may need to be controlled over the internet.

The hardware will be a PIC with ethernet based unit, to control some IO lines, and read back some data.

I've googled some examples, but the ones I found that I can understand must be an earlier version of Delphi, as the sample code raised syntax errors, and used properties that my components seem not to possess.

Which type of TCP Client and server should I be using, from Indy palette or Internet one?

Until the hardware is designed, can I simulate it with another app on another PC on my intranet?
(Previously, for good 'ol serial comms stuff I could write an app to respond as if it was the hardware, put hardware app on com1 and control app on com2 and join the two serial ports together)

Any up to date code samples someone knows url of?



Steve (Delphi 2007 & XP)
 
You should have two application.one what will start and procces data to the second.the second will comunicate with the PIC.For the first you have good example in mastering delphi 6 book from marcu cantu.You can find the example on the web site for this book.
 
We have done this (PIC to PC via Ethernet)

Don't worry about the intra/inter net thing it all the same IP protocol! Just need to make sure firewall and the like know about your IP addresses.

We used Indy 9 there are several diffrences in the syntax of Indy 10, that will be where your errors originate, not from your Delphi version.

I wrote the PC end (a test application in D7 using a DLL to do the lower level stuff as our client wanted to write the main application [A SCADA type system] in VB.
It would have been much easier to drop the Indy comps on a normal form I can tell you.

So. One use the Indy components.

The first problem is how to get help, most people who have been specialising with this will assume that you know far more than you do. A lot of other Delphi developers spend all thier time writing Database applications, and wont have a clue.
But keep at it. The answers are out there!

Second problem is to decide if your PC application is a Client or a Server, this isn't obvious, ours turned out to a client as the PIC units need to be able to communicate with more than one base unit.

There are several demos with the Indy suite that will give you some good clues.

The low level client stuff is remarkable simple.
As we couldn't use a form in a DLL the components are dropped onto a Data Unit.

Indy Client, Indy IPWatch component and a timer

This is the entire thing, it fills a buffer with the messages as they come in.

Code:
unit DataUnit3;

interface

uses
  SysUtils, Classes,  IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdThreadMgr, IdThreadMgrDefault, IdIPWatch,
  IdAntiFreezeBase, IdAntiFreeze, getver, ExtCtrls;

type
  TCommBlock = record   // the recived Communication Protocol
                  RCmd: Byte;
                  RCard: Byte;
                  RData: array [0..127] of Byte;  // name of receiver
               end;


type
   TDataModule2 = class(TDataModule)
    Client: TIdTCPClient;
    IPWatch: TIdIPWatch;
    GetVer: TGetVersionInfoFromFile;
    Response: TTimer;
    procedure ResponseTimer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TClientHandleThread = class(TThread)
     private
         procedure HandleInput;
     protected
         procedure Execute; override;
  end;


var
  DataModule2: TDataModule2;
  Memrecv: Tstringlist;
  Data: TCommBlock;
  DataRxd: boolean;
  Timeout: boolean;
  ClientHandleThread: TClientHandleThread;   // variable (type see above)

const ACK = $FF;
      DAT = $F0;

implementation

{$R *.dfm}

procedure TClientHandleThread.HandleInput;
begin
   DataRxd := True;
   case Data.RCmd of
   ACK:  Memrecv.Add('Message Acknowleged');
   DAT:  begin
            Memrecv.Add('Data Recieved');

         end;
   else  Memrecv.Add('Unknown token "' + inttostr(Data.RCmd) +'"');
   end;
   // ensure memrecv dosnt fill up the memory!!
   if memrecv.Count > 100 then
       memrecv.Clear;
end;


procedure TClientHandleThread.Execute;
begin
  while not Terminated do
     begin
        if not DataModule2.Client.Connected then
           Terminate
        else
           try
              DataModule2.Client.ReadBuffer(Data, 130);
              Synchronize(HandleInput);
           except
           end;
     end;
end;


procedure TDataModule2.ResponseTimer(Sender: TObject);
begin
   //check for response from  ethernet
   Response.Enabled := false;
   Timeout := not DataRxd;
end;

end.

The actual Main code is a little more complex so I wont post it all. As I said the funtions are in a DLL.

This to inialise the indy client and handle errors, you will get plenty of these.

Code:
{-------------------------------------------------------------------------
Client Object Interface
--------------------------------------------------------------------------}

function EthernetActivateClient(HIP: PChar; HPort: integer; Timeout: integer): integer; stdcall;
begin
   if DataModule2.Client.Connected then
     begin
        result := 4;   // error 4 ignore reconnect message
        exit;
     end
   else
     result := 0;

   with DataModule2 do
      try
        DataRxd := False;
        Client.Host := HIP;
        Client.Port := HPort;
        Client.Connect(Timeout);  // Connect delay
        ClientHandleThread := TClientHandleThread.Create(True);
        ClientHandleThread.FreeOnTerminate := True;
        ClientHandleThread.Resume;
      except
          on E: Exception  do
           begin
              if pos('10013', E.Message) > 0 then result := 10;   // permission denied
              if pos('10048', E.Message) > 0 then result := 11;   // already in use
              if pos('10053', E.Message) > 0 then result := 14;   // Software caused abort
              if pos('10054', E.Message) > 0 then result := 13;   // connection reset by peer
              if pos('10061', E.Message) > 0 then result := 12;   // connection refused
              if pos('Connect timed out.',E.Message)> 0 then  result := 2;  // Error 2
           end;

      end;
end;


The client component will handle all data received, read the buffer as required.

The Indy clients methods ware used to send stuff
e.g.

Code:
// send the entire buffer to card
function SendBuffer(Num: integer): integer; stdcall;
begin
   result := 0;
   try
      DataModule2.Client.WriteBuffer(Data, Num);
   except
      result := 6;  // Error 6
   end;
end;

and good luck with the PIC end Microchip provide an excellent Library with a working Demo (it generates a web page on Chip) we just cut out the bits we didn't need.

A word of warning if the PIC locks up it can hang the Comms and the default IP timeouts are usually 10 seconds, this is a long time for the Delphi end to wait, but you cannot assume a short delay with TCP/IP, so we didnt find any other way to detect this sort of error short of a time out.


Steve: N.M.N.F.
If something is popular, it must be wrong: Mark Twain
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top