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