lazarus-ccr/examples/serial_filesend/mainform.pas
2010-09-27 13:26:17 +00:00

243 lines
6.1 KiB
ObjectPascal

unit mainform;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
EditBtn, ExtCtrls, ComCtrls,
synaser;
type
{ TformSerial }
TformSerial = class(TForm)
btnConnect: TButton;
comboClientServer: TComboBox;
editDevice: TEdit;
editFileName: TFileNameEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
editFileSize: TLabeledEdit;
editReceivedFileName: TLabeledEdit;
ScrollBox1: TScrollBox;
StatusBar: TStatusBar;
timerClientConnect: TTimer;
timerServerConnect: TTimer;
procedure btnConnectClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure timerClientConnectTimer(Sender: TObject);
procedure timerServerConnectTimer(Sender: TObject);
private
{ private declarations }
connected: Boolean;
ser: TBlockSerial;
procedure ServerSendFile();
procedure ClientReceiveFile();
public
{ public declarations }
end;
var
formSerial: TformSerial;
implementation
const
INT_COMBO_SERVER = 0;
INT_COMBO_CLIENT = 1;
// Data records
BYTE_REQUEST_CONNECTION = $00;
// Followed by nothing else
BYTE_ACCEPT_CONNECTION = $01;
// Followed by nothing else
BYTE_FILE_NAME = $02;
// Followed by:
// File name size - 1 Byte indicating the size sz_size. The name doesn't include path.
// File name - sz_size bytes in UTF-8
BYTE_FILE_DATA = $03;
// Followed by:
// File size - 8 Bytes, a Int64 in Little Endian, indicates sz_size
// File data - sz_size bytes
{$R *.lfm}
{ TformSerial }
procedure TformSerial.FormCreate(Sender: TObject);
begin
ser := TBlockSerial.Create;
end;
procedure TformSerial.btnConnectClick(Sender: TObject);
begin
btnConnect.Enabled := False;
try
if connected then raise Exception.Create('Already connected');
// Check the input data
if (editDevice.Text = '') then raise Exception.Create('Invalid serial port name');
if (editFileName.Text = '') then raise Exception.Create('Invalid file path');
if (comboClientServer.ItemIndex = INT_COMBO_SERVER)
and (not FileExists(editFileName.Text)) then raise Exception.Create('Invalid input file. It doesn''t exist');
if (comboClientServer.ItemIndex = INT_COMBO_CLIENT)
and (not DirectoryExists(editFileName.Text)) then raise Exception.Create('Invalid output directory. It doesn''t exist');
StatusBar.SimpleText := 'Connecting';
Application.ProcessMessages;
ser.Connect(editDevice.Text); //ComPort
Sleep(1000);
Application.ProcessMessages;
ser.config(115000, 8, 'N', SB1, False, False);
Sleep(1000);
Application.ProcessMessages;
StatusBar.SimpleText := 'Device: ' + ser.Device +
' Status: ' + ser.LastErrorDesc + ' ' +
Inttostr(ser.LastError);
if ser.LastError = 0 then connected := True;
if comboClientServer.ItemIndex = INT_COMBO_SERVER then
timerServerConnect.Enabled := True
else
timerClientConnect.Enabled := True;
finally
btnConnect.Enabled := True;
end;
end;
procedure TformSerial.FormDestroy(Sender: TObject);
begin
ser.free;
end;
procedure TformSerial.timerClientConnectTimer(Sender: TObject);
var
Data: Byte;
begin
Data := ser.RecvByte(timerClientConnect.Interval div 2);
if (Data = BYTE_REQUEST_CONNECTION) and (ser.LastError = 0) then
begin
Connected := True;
timerClientConnect.Enabled := False;
ser.SendByte(BYTE_ACCEPT_CONNECTION);
ClientReceiveFile();
end;
end;
procedure TformSerial.timerServerConnectTimer(Sender: TObject);
var
Data: Byte;
begin
ser.SendByte(BYTE_REQUEST_CONNECTION);
Data := ser.RecvByte(timerServerConnect.Interval div 2);
if (Data = BYTE_ACCEPT_CONNECTION) and (ser.LastError = 0) then
begin
Connected := True;
timerServerConnect.Enabled := False;
ServerSendFile();
end;
end;
procedure TformSerial.ServerSendFile();
var
ShortStr: shortstring;
Data, StrLen: Byte;
i: Integer;
lStream: TFileStream;
lSize: Int64;
begin
StatusBar.SimpleText := 'Sending file';
Application.ProcessMessages;
// Send the file name:
ShortStr := ExtractFileName(editFileName.Text);
StrLen := Length(ShortStr);
ser.SendByte(BYTE_FILE_NAME);
ser.SendByte(StrLen);
for i := 1 to StrLen do
ser.SendByte(Byte(ShortStr[i]));
// Send the file data:
lStream := TFileStream.Create(editFileName.Text, fmOpenRead);
try
lSize := Length(ShortStr);
ser.SendByte(BYTE_FILE_DATA);
ser.SendBuffer(@lSize, 8);
for i := 0 to lSize - 1 do
begin
Data := lStream.ReadByte();
ser.SendByte(Data);
// Process messages each 100 bytes
if (i div 100) = 0 then Application.ProcessMessages();
end;
finally
lStream.Free;
end;
end;
procedure TformSerial.ClientReceiveFile();
var
ShortStr: shortstring;
Data, StrLen: Byte;
i: Integer;
lStream: TFileStream;
lSize: Int64;
filePath: string;
begin
StatusBar.SimpleText := 'Receiving file';
Application.ProcessMessages;
// Read the file name:
Data := ser.RecvByte(5000);
// Process any remaining connect messages
while (Data = BYTE_REQUEST_CONNECTION) do
Data := ser.RecvByte(5000);
if (Data <> BYTE_FILE_NAME) then raise Exception.Create('Expected record BYTE_FILE_SIZE, but received: ' + IntToStr(Data));
StrLen := ser.RecvByte(5000);
ShortStr := '';
for i := 1 to StrLen do
ShortStr := ShortStr + Char(ser.RecvByte(1000));
editReceivedFileName.Text := ShortStr;
// Read the file data:
Data := ser.RecvByte(5000);
if (Data <> BYTE_FILE_DATA) then raise Exception.Create('Expected record BYTE_FILE_DATA, but received: ' + IntToStr(Data));
filePath := IncludeTrailingPathDelimiter(editFileName.Text) + editReceivedFileName.Text;
lStream := TFileStream.Create(filePath, fmOpenWrite or fmCreate);
try
ser.RecvBuffer(@lSize, 8);
for i := 0 to lSize - 1 do
begin
Data := ser.RecvByte(1000);
lStream.WriteByte(Data);
// Process messages each 100 bytes
if (i div 100) = 0 then Application.ProcessMessages();
end;
finally
lStream.Free;
end;
end;
end.