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.