unit U_LSPLCAgent; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Win.ScktComp, Vcl.ExtCtrls, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters, cxStyles, cxCustomData, cxFilter, cxData, cxDataStorage, cxEdit, cxNavigator, dxDateRanges, dxScrollbarAnnotations, cxGridCustomTableView, cxGridTableView, cxGridLevel, cxClasses, cxGridCustomView, cxGrid, Data.DB, Datasnap.DBClient, math, IniFiles, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Phys.PGDef, FireDAC.VCLUI.Wait, FireDAC.Comp.UI, FireDAC.Phys.PG, FireDAC.Comp.DataSet, FireDAC.Comp.Client, System.StrUtils; type TF_LSPLCAgent = class(TForm) GroupBox1: TGroupBox; Label14: TLabel; Edit5: TEdit; Label15: TLabel; Edit6: TEdit; Button11: TButton; ClientSocket1_old: TClientSocket; Button1: TButton; ListBox1: TListBox; ListBox2: TListBox; Splitter1: TSplitter; GridAddressList: TcxGrid; GridAddressListTV: TcxGridTableView; GridAddressListTVColumn1: TcxGridColumn; GridAddressListTVColumn2: TcxGridColumn; GridAddressListTVColumn3: TcxGridColumn; GridAddressListTVColumn4: TcxGridColumn; GridAddressListTVColumn5: TcxGridColumn; GridAddressListLv: TcxGridLevel; Label1: TLabel; Edit1: TEdit; Panel1: TPanel; Memo1: TMemo; Splitter2: TSplitter; Memo2: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Tmr_PLCRead: TTimer; Label2: TLabel; Edit2: TEdit; Button6: TButton; Button7: TButton; TrayIcon1: TTrayIcon; tmrExit: TTimer; CheckBox1: TCheckBox; FDConnection1: TFDConnection; FDQuery1: TFDQuery; FDPhysPgDriverLink1: TFDPhysPgDriverLink; FDGUIxWaitCursor1: TFDGUIxWaitCursor; RadioButton1: TRadioButton; RadioButton2: TRadioButton; Tmr_DBInsert: TTimer; FDQuery2: TFDQuery; Panel2: TPanel; Label17: TLabel; Label16: TLabel; ComboBox5: TComboBox; Button13: TButton; Edit10: TEdit; Label3: TLabel; cb_logview: TCheckBox; ListBox3: TListBox; GridAddressListTVColumn6: TcxGridColumn; procedure Button11Click(Sender: TObject); procedure ClientSocket1_oldConnecting(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocket1_oldDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocket1_oldError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ClientSocket1_oldRead(Sender: TObject; Socket: TCustomWinSocket); procedure Button13Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure ClientSocket1_oldConnect(Sender: TObject; Socket: TCustomWinSocket); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); procedure Tmr_PLCReadTimer(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure TrayIcon1Click(Sender: TObject); procedure tmrExitTimer(Sender: TObject); procedure CheckBox1Click(Sender: TObject); procedure Tmr_DBInsertTimer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } inifilename : string; ExitOk : boolean; close_ck : Boolean; TxBuf, RxBuf : array [0..1024-1] of byte; ClientSocket1: TClientSocket; procedure BuildReadPacket(type_ck,str:string); procedure BuildReadPacketMulti(const AddrList: TStrings); function PLCDataLoad: boolean; function PLCDataLoadMulti: boolean; procedure AppEvtMinimize(Sender: TObject); procedure ParseMultiReadResponse(var RxBuf: array of Byte; AddrCount: Integer; out Values: TArray); procedure insertSQL(sql: string); function DB_MainTableCreate: Boolean; function DB_MainTableDescriptCreate: Boolean; function DB_LogTableCreate: Boolean; procedure Memo1_ADD(msg: string; ck:Integer = 0); procedure Memo2_ADD(msg: string); procedure PLC_connect; function PingHost(const AHost: string): Boolean; procedure SafeReconnect; procedure OnConnect(Sender: TObject; Socket: TCustomWinSocket); procedure OnConnecting(Sender: TObject; Socket: TCustomWinSocket); procedure OnDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure OnRead(Sender: TObject; Socket: TCustomWinSocket); procedure OnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ClientSocket_Close; function My_ExecuteAndWait(const CmdLine: string; var ExitCode: DWord): Boolean; procedure log_save(cx, msg: string); public { Public declarations } dbIP_PG, dbUser_PG, dbPW_PG, dbSchema_PG : string; dbPort_PG : integer; function DB_Connect:Boolean; function DB_Close:Boolean; procedure DB_Insert; end; var F_LSPLCAgent: TF_LSPLCAgent; LoadCK : Boolean; PLCconnectCK : Integer; const PLC_NO = 1; // ¼Ò°á·Î 1È£ implementation uses WinSock; {$R *.dfm} procedure TF_LSPLCAgent.SafeReconnect; begin try // ClientSocket1.Active := False; ClientSocket_Close; ClientSocket1 := TClientSocket.Create(nil); ClientSocket1.ClientType := ctNonBlocking; ClientSocket1.Host := Edit5.Text; ClientSocket1.Port := StrToIntDef(Edit6.Text, 2004); ClientSocket1.OnConnect := OnConnect; ClientSocket1.OnConnecting := OnConnecting; ClientSocket1.OnDisconnect := OnDisconnect; ClientSocket1.OnError := OnError; ClientSocket1.OnRead := OnRead; // ÀçÁ¢¼Ó ClientSocket1.Active := True; except on E: Exception do Memo1_ADD('SafeReconnect error: ' + E.Message); end; end; procedure TF_LSPLCAgent.OnConnect(Sender: TObject; Socket: TCustomWinSocket); begin Button11.Caption := 'DisConnect'; Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLC ¿¬°á ¼º°ø!'); PLCconnectCK := 2; // ¿¬°áµÊ end; procedure TF_LSPLCAgent.OnConnecting(Sender: TObject; Socket: TCustomWinSocket); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] Á¢¼Ó ½Ãµµ.'); end; procedure TF_LSPLCAgent.OnDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] ¿¬°á ÇØÁ¦µÊ!'); Button11.Caption := 'Connect'; PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ LoadCK := False; end; procedure TF_LSPLCAgent.OnRead(Sender: TObject; Socket: TCustomWinSocket); var Buf: array[0..1023] of Byte; i, Len: Integer; RawData: TBytes; BufCopy: TBytes; S: string; Recv: Integer; begin try Len := Socket.ReceiveBuf(Buf, SizeOf(Buf)); if Len > 0 then begin SetLength(RawData, Len); Move(Buf, RawData[0], Len); // 1. Memo1¿¡ Çí»ç Ç¥½Ã S := ''; for i := 0 to Len - 1 do S := S + IntToHex(RawData[i], 2) + ' '; if cb_logview.Checked then begin Memo2_ADD('>> ¼ö½Å ¿øº» (HEX)'); Memo2_ADD(S); end; end; except on E: Exception do begin Memo1_ADD('Read error: ' + E.Message); LoadCK := False; end; end; end; procedure TF_LSPLCAgent.OnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLC ¿¬°á ½ÇÆÐ: ' + IntToStr(ErrorCode)); PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ ErrorCode := 0; // ¿¹¿Ü ¹ß»ý ¸·±â LoadCK := False; end; procedure TF_LSPLCAgent.log_save(cx, msg:string); var f : TextFile; log: TStringList; i : integer; logfile, buf : string; begin logfile := ''; logfile := ExtractFilePath(Application.ExeName)+'log\'+formatdatetime('yyyymmddhh',now())+'_'+cx+'.log'; if FileExists(logfile) then begin log := TStringList.Create; AssignFile(f, logfile); reset(f); while not eof(f) do begin ReadLn(f, buf); log.Add(buf); end; log.add(FormatDateTime('hh:nn:ss :: ',now)+msg); CloseFile(F); AssignFile(f, logfile); rewrite(f); for i := 0 to log.Count - 1 do begin WriteLn(f, log.strings[i]); end; CloseFile(F); log.Free; end else begin log := TStringList.Create; log.add(FormatDateTime('hh:nn:ss :: ',now)+msg); AssignFile(f, logfile); rewrite(f); for i := 0 to log.Count - 1 do begin WriteLn(f, log.strings[i]); end; CloseFile(F); log.Free; end; end; procedure TF_LSPLCAgent.Memo1_ADD(msg:string; ck:Integer = 0); begin while Memo1.Lines.Count > 50 do begin Memo1.Lines.Delete(0); end; Memo1.Lines.Add(msg); log_save('SYS',msg); end; procedure TF_LSPLCAgent.Memo2_ADD(msg:string); begin while Memo2.Lines.Count > 50 do begin Memo2.Lines.Delete(0); end; Memo2.Lines.ADD(msg); log_save('DATA',msg); end; procedure TF_LSPLCAgent.BuildReadPacket(type_ck,str:string); var i, varcnt, sum: Integer; addrStr: string; begin FillChar(TxBuf, SizeOf(TxBuf), 0); // Çì´õ ±¸¼º TxBuf[0] := $4C; // L TxBuf[1] := $53; // S TxBuf[2] := $49; // I TxBuf[3] := $53; // S TxBuf[4] := $2d; // - TxBuf[5] := $58; // X TxBuf[6] := $47; // G TxBuf[7] := $54; // T TxBuf[8] := $00; // NULL TxBuf[9] := $00; // NULL TxBuf[10] := $00; // Ŭ¶óÀÌ¾ðÆ® -> ¼­¹ö (0x00) TxBuf[11] := $00; TxBuf[12] := $A0; // XGK 0xA0 , XGB(MK) 0xB0 , XGI 0xA4 , XGB(IEC) 0x11 , XGR 0xA8 TxBuf[13] := $33; // Ŭ¶óÀ̾ðÆ®(HMI) -> ¼­¹ö(PLC) (0x33) / ¼­¹ö(PLC) -> Ŭ¶óÀ̾ðÆ®(HMI) (0x11) TxBuf[14] := $00; // ÇÁ·¹ÀÓ°£ÀÇ ¼ø¼­¸¦ ±¸º°Çϱâ À§ÇÑ ID TxBuf[15] := $00; TxBuf[16] := 16; // Length (¸í·É¿µ¿ª 16¹ÙÀÌÆ®) - ¸í·É¾î ±¸Á¶ÀÇ ¹ÙÀÌÆ® Å©±â TxBuf[17] := $00; // ÀÌ´õ³ÝÀ§Ä¡ TxBuf[18] := $00; // ¿¹¾à ¿µ¿ª (0x00) // CheckSum °è»ê sum := 0; for i := 0 to 18 do begin sum := sum + TxBuf[i]; if sum > 255 then sum := sum - 256; end; TxBuf[19] := sum; // ¸í·É ¿µ¿ª TxBuf[20] := $54; // READ TxBuf[21] := 0; // ¿¹¾à ¿µ¿ª ¶Ç´Â º¸Á¶ ¸í·É if type_ck = 'BIT' then // DataType = WORD : $02 , BIT : $00 TxBuf[22] := $00 else if type_ck = 'WORD' then TxBuf[22] := $02 else TxBuf[22] := $02; // WORD TxBuf[23] := 0; // $30; DataType (À̾îÁü) TxBuf[24] := 0; // $30; LinkID (2) TxBuf[25] := 0; // $30; (À̾îÁü) TxBuf[26] := $01; // Variable count TxBuf[27] := 0; // $30; (À̾îÁü) addrStr := Trim(str); varcnt := Length(addrStr); TxBuf[28] := varcnt; TxBuf[29] := 0; for i := 1 to varcnt do TxBuf[29 + i] := Ord(addrStr[i]); end; procedure TF_LSPLCAgent.BuildReadPacketMulti(const AddrList: TStrings); var i, j, sum, pos: Integer; addrStr: string; addrLen: Integer; totalLen: Integer; begin FillChar(TxBuf, SizeOf(TxBuf), 0); // 1. Header ('LSIS-XGT') TxBuf[0] := $4C; // L TxBuf[1] := $53; // S TxBuf[2] := $49; // I TxBuf[3] := $53; // S TxBuf[4] := $2d; // - TxBuf[5] := $58; // X TxBuf[6] := $47; // G TxBuf[7] := $54; // T TxBuf[8] := $00; // NULL TxBuf[9] := $00; // NULL // 2. Fixed header data TxBuf[10] := $00; // Ŭ¶óÀÌ¾ðÆ® -> ¼­¹ö (0x00) TxBuf[11] := $00; TxBuf[12] := $A0; // XGK 0xA0 , XGB(MK) 0xB0 , XGI 0xA4 , XGB(IEC) 0x11 , XGR 0xA8 TxBuf[13] := $33; // Ŭ¶óÀ̾ðÆ®(HMI) -> ¼­¹ö(PLC) (0x33) / ¼­¹ö(PLC) -> Ŭ¶óÀ̾ðÆ®(HMI) (0x11) TxBuf[14] := $00; // ÇÁ·¹ÀÓ°£ÀÇ ¼ø¼­¸¦ ±¸º°Çϱâ À§ÇÑ ID TxBuf[15] := $00; // ÀÏ´Ü °íÁ¤À¸·Î ³Ö°í ³ªÁß¿¡ ¼öÁ¤ÇÒ ¿µ¿ª ±æÀÌ TxBuf[16] := $00; // Length (¸í·É¿µ¿ª 16¹ÙÀÌÆ®) - ¸í·É¾î ±¸Á¶ÀÇ ¹ÙÀÌÆ® Å©±â TxBuf[17] := $00; // ÀÌ´õ³ÝÀ§Ä¡ TxBuf[18] := $00; // ¿¹¾à ¿µ¿ª (0x00) ///////////////////////// 3. Checksum °è»êÀº ³ªÁß¿¡ ó¸®ÇÒ ¿¹Á¤ ¡æ À§Ä¡´Â [19] // 4. ¸í·É ¿µ¿ª TxBuf[20] := $54; // READ TxBuf[21] := 0; // ¿¹¾à ¿µ¿ª ¶Ç´Â º¸Á¶ ¸í·É TxBuf[22] := $02; // DataType = WORD °³º° / $0E - ¿¬¼Ó TxBuf[23] := 0; // $30; DataType (À̾îÁü) TxBuf[24] := 0; // $30; LinkID (2) TxBuf[25] := 0; // $30; (À̾îÁü) TxBuf[26] := AddrList.Count; // Variable Count TxBuf[27] := $00; // $30; (À̾îÁü) pos := 28; // ¸í·É ÀÌÈÄ À§Ä¡ for i := 0 to AddrList.Count - 1 do begin addrStr := Trim(AddrList[i]); // ¿¹: %MW301 addrLen := Length(addrStr); TxBuf[pos] := addrLen; // ¹®ÀÚ¿­ ±æÀÌ TxBuf[pos + 1] := 0; // Reserved for j := 1 to addrLen do TxBuf[pos + 1 + j] := Ord(addrStr[j]); Inc(pos, addrLen + 2); // ´ÙÀ½ À§Ä¡ À̵¿ end; // 5. Àüü Length °è»ê totalLen := pos - 20; // ¸í·É ¿µ¿ªºÎÅÍ ³¡±îÁö TxBuf[16] := totalLen; TxBuf[17] := 0; // 6. Checksum °è»ê (0~18±îÁö ÇÕ»ê) sum := 0; for i := 0 to 18 do begin sum := sum + TxBuf[i]; if sum > 255 then sum := sum - 256; end; TxBuf[19] := sum; // °á°úÀûÀ¸·Î TxBuf ÀÇ Å©±â´Â pos ¹ÙÀÌÆ®±îÁö À¯È¿ÇÔ end; procedure TF_LSPLCAgent.Button11Click(Sender: TObject); begin { TThread.Synchronize(nil, procedure begin try LoadCK := False; if Button11.Caption = 'Connect' then begin ClientSocket1.Host := Edit5.Text; ClientSocket1.Port := StrToIntDef(Edit6.Text,2004); ClientSocket1.Active := True; LoadCK := True; end else begin ClientSocket1.Active := False; end; except on E: Exception do begin Memo1_ADD('PLC Connect Except : ' + E.Message); end; end; end ); } { 20251013 if PLCconnectCK = 0 then begin // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ PLCconnectCK := 1; // Á¢¼ÓÁß try LoadCK := False; if Button11.Caption = 'Connect' then begin ClientSocket1.Host := Edit5.Text; ClientSocket1.Port := StrToIntDef(Edit6.Text,2004); ClientSocket1.Active := True; LoadCK := True; end else begin ClientSocket1.Active := False; end; except on E: Exception do begin Memo1_ADD('Except : ' + E.Message); PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ end; end; end; if PLCconnectCK = 1 then begin if Pos('Á¢¼Ó ½Ãµµ',Memo1.Lines[Memo1.Lines.Count-1]) > 0 then begin Memo1.Lines[Memo1.Lines.Count-1] := Memo1.Lines[Memo1.Lines.Count-1]+'.'; end; end; } if Button11.Caption = 'Connect' then begin PLC_connect; end else begin // ClientSocket1.Active := False; ClientSocket_Close; end; end; function TF_LSPLCAgent.My_ExecuteAndWait(const CmdLine: string; var ExitCode: DWord): Boolean; var StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; CmdLineW: WideString; begin Result := False; FillChar(StartupInfo, SizeOf(StartupInfo), 0); StartupInfo.cb := SizeOf(StartupInfo); // ÇÙ½É ¼öÁ¤: âÀ» º¸ÀÌÁö ¾Ê°Ô ¼³Á¤ StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_HIDE; // â ¼û±è ¿É¼Ç CmdLineW := CmdLine; if CreateProcess(nil, PChar(CmdLineW), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInfo) then begin // ... (ÀÌÇÏ Á¾·á ´ë±â ¹× Á¾·á ÄÚµå È®ÀÎ ·ÎÁ÷Àº µ¿ÀÏ) WaitForSingleObject(ProcessInfo.hProcess, 500); // ¿¹: 500ms ´ë±â if GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then Result := True; CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); end; end; function TF_LSPLCAgent.PingHost(const AHost: string): Boolean; var Code: DWord; begin // edit2.Text := booltostr(WinExec(PAnsiChar(AnsiString('ping -n 1 -w 500 ' + AHost)), SW_HIDE) = 0); if My_ExecuteAndWait('ping -n 1 -w 500 ' + AHost, Code) then begin // ping ¸í·ÉÀÇ Á¾·á Äڵ尡 0ÀÌ¸é ¼º°øÀÔ´Ï´Ù. Result := Code = 0; end else begin Result:= false; Memo1_ADD('Ping Test - Execution Failed'+FormatDateTime('yyyymmdd hhnnss.zzz',Now)); end; end; procedure TF_LSPLCAgent.PLC_connect; begin try if PLCconnectCK = 0 then begin // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ try LoadCK := False; if Button11.Caption = 'Connect' then begin if PingHost(Edit5.Text) then begin { ClientSocket1.Host := Edit5.Text; ClientSocket1.Port := StrToIntDef(Edit6.Text,2004); ClientSocket1.Active := True; LoadCK := True; } // ClientSocket1.Active := False; ClientSocket_Close; ClientSocket1 := TClientSocket.Create(nil); ClientSocket1.ClientType := ctNonBlocking; ClientSocket1.Host := Edit5.Text; ClientSocket1.Port := StrToIntDef(Edit6.Text, 2004); ClientSocket1.OnConnect := OnConnect; ClientSocket1.OnConnecting := OnConnecting; ClientSocket1.OnDisconnect := OnDisconnect; ClientSocket1.OnError := OnError; ClientSocket1.OnRead := OnRead; PLCconnectCK := 1; // Á¢¼ÓÁß // ÀçÁ¢¼Ó ClientSocket1.Active := True; LoadCK := True; end else begin if Pos('ping_PLC NOT Connect',Memo1.Lines[Memo1.Lines.Count-1]) > 0 then begin Memo1.Lines[Memo1.Lines.Count-1] := 'ping_PLC NOT Connect'+' - '+FormatDateTime('yyyymmdd hhnnss.zzz',Now); log_save('SYS','ping_PLC NOT Connect'+' - '+FormatDateTime('yyyymmdd hhnnss.zzz',Now)); end else begin Memo1_ADD('ping_PLC NOT Connect'+' - '+FormatDateTime('yyyymmdd hhnnss.zzz',Now)); end; // ClientSocket1.Active := False; ClientSocket_Close end; end else begin // ClientSocket1.Active := False; ClientSocket_Close; end; except on E: Exception do begin Memo1_ADD('Except : ' + E.Message); PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ end; end; end; if PLCconnectCK = 1 then begin if Pos('Á¢¼Ó ½Ãµµ',Memo1.Lines[Memo1.Lines.Count-1]) > 0 then begin Memo1.Lines[Memo1.Lines.Count-1] := Memo1.Lines[Memo1.Lines.Count-1]+'.'; end; end; except on E: Exception do begin Memo1_ADD('PLC_connect Error : ' + E.Message); end; end; end; procedure TF_LSPLCAgent.ClientSocket_Close; begin if Assigned(ClientSocket1) then begin // ±âÁ¸ ¼ÒÄÏ ¿ÏÀü Á¾·á try if ClientSocket1.Active then ClientSocket1.Active := False; // ³»ºÎ ÇÚµé ¸±¸®Áî º¸Àå ClientSocket1.Close; Sleep(100); // OS ÇÚµé ÇØÁ¦ ´ë±â (ÇÊ¿ä½Ã 100~300ms) // Àç½Ãµµ Àü °´Ã¼ Àç»ý¼º (ÇÚµé ´©¼ö ¹æÁö) FreeAndNil(ClientSocket1); except on E: Exception do Memo1_ADD('Socket close error: ' + E.Message); end; end; end; procedure TF_LSPLCAgent.Button13Click(Sender: TObject); var Sent, Recv: Integer; begin { // °³º° ÁÖ¼Ò°ª Àбâ if not ClientSocket1.Active then PLC_connect; if ClientSocket1.Active then begin try BuildReadPacket(ComboBox5.Text+Edit10.Text); Sent := ClientSocket1.Socket.SendBuf(TxBuf, 36); if Sent <> 36 then begin Memo1_ADD('ÆÐŶ Àü¼Û ½ÇÆÐ : [ '+ComboBox5.Text+Edit10.Text+' ]'); Exit; end; Recv := ClientSocket1.Socket.ReceiveBuf(RxBuf, 34); if Recv < 34 then begin Memo1_ADD('ÀÀ´ä ¼ö½Å ½ÇÆÐ : [ '+ComboBox5.Text+Edit10.Text+' ]'); Exit; end; if cb_logview.Checked then begin // 1. Memo1: ¿øº» HEX var hexStr := ''; for var i := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[i], 2) + ' '; Memo2_ADD(hexStr); // 2. Memo2: ÇØ¼®µÈ °á°ú var value := RxBuf[32] + (RxBuf[33] shl 8); Memo2_ADD('DEC: ' + IntToStr(value)); // StringGrid1.Cells[1,1] := Trim(Edit2.Text) + '=' + IntToStr(value); Memo2_ADD('HEX: ' + IntToHex(value, 4)); end; except on E: ESocketError do begin Memo1_ADD('Ŭ¶óÀÌ¾ðÆ® ¼ÒÄÏ ¿¡·¯: ' + E.Message); // ¿¡·¯ ¹ß»ý ½Ã ¿¬°áÀ» Á¾·á ClientSocket1.Active := False; end; on E: Exception do begin Memo1_ADD('¿¹»óÄ¡ ¸øÇÑ ¿¡·¯: ' + E.Message); ClientSocket1.Active := False; end; end; end; } end; function TF_LSPLCAgent.PLCDataLoad:boolean; var i : integer; Sent, Recv: Integer; LastError: Integer; ErrorMsg: string; begin if PLCconnectCK <> 2 then exit; Button1.Enabled := False; try try GridAddressListTV.DataController.BeginUpdate; for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin with GridAddressListTV.DataController do begin // 20251029 Values[i, GridAddressListTVColumn5.Index] := ''; if ClientSocket1.Active then begin BuildReadPacket(Values[i, GridAddressListTVColumn6.Index],Values[i, GridAddressListTVColumn2.Index]); Sent := ClientSocket1.Socket.SendBuf(TxBuf, 36); if Sent <> 36 then begin if cb_logview.Checked then Memo2_ADD('ÆÐŶ Àü¼Û ½ÇÆÐ PLCDataLoad: ['+IntToStr(Sent)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); LoadCK := False; // Exit; end else begin Sleep(StrToIntDef(Edit1.Text,0)); Recv := ClientSocket1.Socket.ReceiveBuf(RxBuf, 34); if Recv < 34 then begin if cb_logview.Checked then begin Memo2_ADD('ÀÀ´ä ¼ö½Å ½ÇÆÐ PLCDataLoad: [Sent:'+IntToStr(Sent)+']-[Recv:'+IntToStr(Recv)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); if Recv = -1 then begin // -1: ¼ÒÄÏ ¿À·ù ¹ß»ý (WSAGetLastError È£Ãâ) LastError := WSAGetLastError; // ¿À·ù Äڵ忡 µû¸¥ ¸Þ½ÃÁö ¼³Á¤ (¿¹½Ã, Çʿ信 µû¶ó È®Àå °¡´É) case LastError of 10054: ErrorMsg := 'Connection reset by peer (PLC¿¡¼­ ¿¬°á °­Á¦ Á¾·á)'; 10060: ErrorMsg := 'Connection timed out (¼ö½Å ŸÀӾƿô)'; 10004: ErrorMsg := 'Interrupted function call (ºí·ÎÅ· µ¿ÀÛ Áß Ãë¼Ò)'; // ±× ¿Ü Äڵ忡 ´ëÇÑ ¼³¸íÀº Winsock ¹®¼­ ÂüÁ¶ else ErrorMsg := 'Unknown socket error'; end; if cb_logview.Checked then Memo2_ADD('¼ÒÄÏ ¿À·ù Recv: ['+IntToStr(Recv)+'] - WSAGetLastError: ['+IntToStr(LastError)+'] - Message: ['+ErrorMsg+']'); // LoadCK := False; // ¿À·ù ¹ß»ý ½Ã µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ ó¸® end else if Recv = 0 then begin // 0: Á¤»óÀûÀÎ ¿¬°á Á¾·á (PLC Ãø¿¡¼­ ¼ÒÄÏÀ» ´Ý¾ÒÀ½) if cb_logview.Checked then Memo2_ADD('°æ°í PLC¿¡¼­ ¿¬°áÀ» Á¤»ó Á¾·áÇÔ (Recv: 0) - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); end else begin // 0 < Recv < 34: ÆÐŶÀ» ÀϺθ¸ ¼ö½ÅÇ߰ųª, PLC¿¡¼­ ¿À·ù ÀÀ´ä ÆÐŶ(ÀÛÀº Å©±â)À» º¸³ÂÀ» °¡´É¼º if cb_logview.Checked then Memo2_ADD('ÀÀ´ä ¼ö½Å ºÒ¿ÏÀü (Recv < 34) PLCDataLoad: [Sent:'+IntToStr(Sent)+']-[Recv:'+IntToStr(Recv)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); // ÀÌ °æ¿ì, ¼ö½ÅµÈ RxBuf[0] ~ RxBuf[Recv-1]±îÁö¸¦ ºÐ¼®ÇÏ¿© // LSIS XGT ÇÁ·ÎÅäÄÝ ¿À·ù Äڵ带 È®ÀÎÇÏ´Â ·ÎÁ÷ÀÌ ÇÊ¿äÇÕ´Ï´Ù. end; // LoadCK := False; // Exit; // Çʿ信 µû¶ó Åë½ÅÀ» Áß´ÜÇÏ°í ³ª°¥ ¼ö ÀÖ½À´Ï´Ù. end; LoadCK := False; // Exit; end else begin if cb_logview.Checked then begin // 1. Memo1: ¿øº» HEX var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(hexStr); end; // 2. Memo2: ÇØ¼®µÈ °á°ú var value := RxBuf[32] + (RxBuf[33] shl 8); if cb_logview.Checked then begin Memo2_ADD('DEC: ' + IntToStr(value)); // StringGrid1.Cells[1,1] := Trim(Edit2.Text) + '=' + IntToStr(value); Memo2_ADD('HEX: ' + IntToHex(value, 4)); end; Values[i, GridAddressListTVColumn3.Index] := IntToStr(value); Values[i, GridAddressListTVColumn4.Index] := IntToHex(value, 4); Values[i, GridAddressListTVColumn5.Index] := FormatDateTime('hhnnss.zzz',Now); LoadCK := True; end; end; end; end; // Sleep(StrToIntDef(Edit1.Text,0)); // Refresh; end; except on E: Exception do begin Memo1_ADD('PLCDataLoad Error : ' + E.Message); LoadCK := False; end; end; finally Result := True; GridAddressListTV.DataController.EndUpdate; Button1.Enabled := True; Refresh; end; end; function TF_LSPLCAgent.PLCDataLoadMulti:boolean; var t, i, j, t_count : integer; Sent, Recv: Integer; addrList: TStringList; addr_Values: TArray; Addr_Count: Integer; begin Button1.Enabled := False; addrList := TStringList.Create; try try GridAddressListTV.DataController.BeginUpdate; t_count := GridAddressListTV.DataController.RecordCount; if (t_count mod 10) > 0 then begin t := (t_count div 10) +1; end else begin if t_count < 10 then t := 1 else t := (t_count div 10); end; for i := 0 to t - 1 do begin Addr_Count := 0; with GridAddressListTV.DataController do begin addrList.Clear; for j := 0 to 9 do begin if ((i*10) + j) <= t_count then begin // Values[(i*10) + j, GridAddressListTVColumn5.Index] := ''; addrList.Add(Values[(i*10) + j, GridAddressListTVColumn2.Index]); end else begin Break; end; end; if ClientSocket1.Active then begin BuildReadPacketMulti(addrList); Sent := ClientSocket1.Socket.SendBuf(TxBuf, 36); if Sent <> 36 then begin Memo1_ADD('ÆÐŶ Àü¼Û ½ÇÆÐ : [ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); // Exit; end else begin Recv := ClientSocket1.Socket.ReceiveBuf(RxBuf, 34); if Recv < 34 then begin Memo1_ADD('ÀÀ´ä ¼ö½Å ½ÇÆÐ : [ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); // Exit; end else begin ParseMultiReadResponse(RxBuf, addrList.Count, addr_Values); // addr_Values ¹è¿­¿¡ °¢°¢ÀÇ ¿öµå °ªÀÌ ÀúÀåµÊ // ShowMessage('ù¹øÂ° ÁÖ¼Ò°ª: ' + IntToStr(Values[0])); for j := 0 to 9 do begin if ((i*10) + j) <= t_count then begin Values[(i*10) + j, GridAddressListTVColumn3.Index] := addr_Values[j].ToString; Values[(i*10) + j, GridAddressListTVColumn4.Index] := addr_Values[j].ToHexString; Values[(i*10) + j, GridAddressListTVColumn5.Index] := FormatDateTime('hhnnss.zzz',Now); end else begin Break; end; end; end; end; end; end; Sleep(StrToIntDef(Edit1.Text,0)); Refresh; end; except on E: Exception do begin Memo1_ADD('PLCDataLoadMulti Error : ' + E.Message); end; end; finally Result := True; GridAddressListTV.DataController.EndUpdate; Button1.Enabled := True; addrList.Free; end; end; procedure TF_LSPLCAgent.insertSQL(sql : string); begin try if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery1.Active := false; FDQuery1.SQL.Clear; FDQuery1.SQL.Add(sql); FDQuery1.ExecSQL; end; except on e : exception do begin Memo2_ADD('[insertSQL()]Database Connect Error :: '+e.Message); end; end; end; procedure TF_LSPLCAgent.ParseMultiReadResponse(var RxBuf: array of Byte; AddrCount: Integer; out Values: TArray); var i, pos: Integer; begin SetLength(Values, AddrCount); // ±âº» Çì´õ 20¹ÙÀÌÆ®´Â °Ç³Ê¶Ü, ¸í·É ¿µ¿ª ½ÃÀÛ À§Ä¡ pos := 20; // ¸í·ÉÄÚµå üũ if RxBuf[pos] <> $54 then raise Exception.Create('Invalid response command code.'); pos := pos + 7; // pos°¡ 27ÀÌ µÊ (¿äû ½Ã Variable count À§Ä¡) // Variable count È®ÀÎ (°ËÁõ °¡´É) if RxBuf[pos] <> AddrCount then raise Exception.Create('Response variable count mismatch.'); pos := pos + 2; // º¯¼ö µ¥ÀÌÅÍ ½ÃÀÛ À§Ä¡ // µ¥ÀÌÅÍ Àбâ (WORD ŸÀÔ, 2¹ÙÀÌÆ®¾¿) for i := 0 to AddrCount - 1 do begin if pos + 1 > High(RxBuf) then raise Exception.Create('Response packet too short.'); Values[i] := (RxBuf[pos] shl 8) or RxBuf[pos + 1]; Inc(pos, 2); end; end; procedure TF_LSPLCAgent.Tmr_DBInsertTimer(Sender: TObject); begin Tmr_DBInsert.Enabled := False; if LoadCK and (not close_ck) then begin DB_Insert; Tmr_DBInsert.Enabled := True; end; end; procedure TF_LSPLCAgent.Tmr_PLCReadTimer(Sender: TObject); begin Tmr_PLCRead.Enabled := False; if not close_ck then begin if RadioButton1.Checked then Button1.Click else Button5.Click; Tmr_PLCRead.Enabled := True; end; end; procedure TF_LSPLCAgent.tmrExitTimer(Sender: TObject); begin case tmrExit.Tag of 0 : begin tmrExit.Tag := tmrExit.Tag+1; end; 1..4 : tmrExit.Tag := tmrExit.Tag+1; 5 : begin tmrExit.Tag := tmrExit.Tag+1; tmrExit.Enabled := false; ExitOk := true; Close; end; end;//case.. end; procedure TF_LSPLCAgent.TrayIcon1Click(Sender: TObject); begin TrayIcon1.Visible := False; Show; WindowState := wsNormal; Application.BringToFront; end; procedure TF_LSPLCAgent.Button1Click(Sender: TObject); begin if PLCconnectCK <> 2 then begin PLC_connect; end else begin // if PLCconnectCK = 2 then begin if PLCDataLoad then begin // LoadCK := True; if LoadCK then Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLCDataLoad - ok') else Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLCDataLoad - fail'); end else begin LoadCK := False; end; // end; end; end; procedure TF_LSPLCAgent.Button2Click(Sender: TObject); var i : integer; Ini: TIniFile; begin // ini ÆÄÀÏ °»½Å.. Ini := TIniFile.Create(inifilename); try Ini.WriteString('PLC', 'IP', Edit5.Text); Ini.WriteString('PLC', 'PORT', Edit6.Text); finally Ini.Free; end; if FileExists(StringReplace(Application.ExeName,'.exe','_list1.ini',[rfReplaceAll])) then RenameFile(StringReplace(Application.ExeName,'.exe','_list1.ini',[rfReplaceAll]), StringReplace(Application.ExeName,'.exe','_list1_'+FormatDateTime('yymmdd_hhnnss.zzz',now)+'.ini.bak',[rfReplaceAll])); if FileExists(StringReplace(Application.ExeName,'.exe','_list2.ini',[rfReplaceAll])) then RenameFile(StringReplace(Application.ExeName,'.exe','_list2.ini',[rfReplaceAll]), StringReplace(Application.ExeName,'.exe','_list2_'+FormatDateTime('yymmdd_hhnnss.zzz',now)+'.ini.bak',[rfReplaceAll])); if FileExists(StringReplace(Application.ExeName,'.exe','_list3.ini',[rfReplaceAll])) then RenameFile(StringReplace(Application.ExeName,'.exe','_list3.ini',[rfReplaceAll]), StringReplace(Application.ExeName,'.exe','_list3_'+FormatDateTime('yymmdd_hhnnss.zzz',now)+'.ini.bak',[rfReplaceAll])); ListBox3.Clear; ListBox2.Clear; ListBox1.Clear; for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin with GridAddressListTV.DataController do begin ListBox3.Items.Add(Values[i, GridAddressListTVColumn1.Index]); ListBox2.Items.Add(Values[i, GridAddressListTVColumn1.Index]); ListBox1.Items.Add(Values[i, GridAddressListTVColumn2.Index]); end; end; ListBox1.Items.SaveToFile(StringReplace(Application.ExeName,'.exe','_list1.ini',[rfReplaceAll])); ListBox2.Items.SaveToFile(StringReplace(Application.ExeName,'.exe','_list2.ini',[rfReplaceAll])); ListBox3.Items.SaveToFile(StringReplace(Application.ExeName,'.exe','_list3.ini',[rfReplaceAll])); end; procedure TF_LSPLCAgent.Button3Click(Sender: TObject); var SL: TStringList; i, j: Integer; Row: string; begin SL := TStringList.Create; try for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin Row := ''; for j := 0 to GridAddressListTV.ColumnCount - 1 do Row := Row + GridAddressListTV.DataController.DisplayTexts[i, j] + ','; SL.Add(Copy(Row, 1, Length(Row) - 1)); // ¸¶Áö¸· , Á¦°Å end; SL.SaveToFile('.\grid.dat'); finally SL.Free; end; end; procedure TF_LSPLCAgent.Button4Click(Sender: TObject); var SL, Items: TStringList; i, j: Integer; begin SL := TStringList.Create; Items := TStringList.Create; try SL.LoadFromFile('.\grid.dat'); GridAddressListTV.BeginUpdate; GridAddressListTV.DataController.RecordCount := SL.Count; for i := 0 to SL.Count - 1 do begin Items.Delimiter := ','; // ÄÞ¸¶·Î ±¸ºÐ Items.StrictDelimiter := True; // °ø¹éÀº ¹«½Ã Items.CommaText := SL[i]; for j := 0 to Min(Items.Count - 1, GridAddressListTV.ColumnCount - 1) do begin GridAddressListTV.DataController.Values[i, j] := Items[j]; end; end; GridAddressListTV.EndUpdate; finally Items.Free; SL.Free; end; end; procedure TF_LSPLCAgent.Button5Click(Sender: TObject); // Àϰý begin if not ClientSocket1.Active then PLC_connect; if PLCDataLoadMulti then Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLCDataLoadMulti - ok'); end; procedure TF_LSPLCAgent.Button6Click(Sender: TObject); begin if Button11.Caption = 'Connect' then begin PLC_connect; end; Button1.Enabled := False; Tmr_PLCRead.Enabled := False; Tmr_PLCRead.Interval := StrToIntDef(Edit2.Text,1000); Tmr_PLCRead.Enabled := True; Tmr_DBInsert.Enabled := False; Tmr_DBInsert.Interval := StrToIntDef(Edit2.Text,1000); Tmr_DBInsert.Enabled := True; Button6.Enabled := False; Button7.Enabled := True; end; procedure TF_LSPLCAgent.Button7Click(Sender: TObject); begin Button1.Enabled := True; Tmr_PLCRead.Enabled := False; Button6.Enabled := True; Button7.Enabled := False; end; procedure TF_LSPLCAgent.CheckBox1Click(Sender: TObject); var Ini: TIniFile; begin // ini ÆÄÀÏ °»½Å.. Ini := TIniFile.Create(inifilename); try Ini.WriteString('START', 'AUTO', BoolToStr(CheckBox1.Checked)); finally Ini.Free; end; end; procedure TF_LSPLCAgent.ClientSocket1_oldConnect(Sender: TObject; Socket: TCustomWinSocket); begin Button11.Caption := 'DisConnect'; Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLC ¿¬°á ¼º°ø!'); PLCconnectCK := 2; // ¿¬°áµÊ end; procedure TF_LSPLCAgent.ClientSocket1_oldConnecting(Sender: TObject; Socket: TCustomWinSocket); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] Á¢¼Ó ½Ãµµ.'); end; procedure TF_LSPLCAgent.ClientSocket1_oldDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] ¿¬°á ÇØÁ¦µÊ!'); Button11.Caption := 'Connect'; PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ LoadCK := False; end; procedure TF_LSPLCAgent.ClientSocket1_oldError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLC ¿¬°á ½ÇÆÐ: ' + IntToStr(ErrorCode)); PLCconnectCK := 0; // ÃʱⰪ : 0 - ¹ÌÁ¢¼Ó »óÅ ErrorCode := 0; // ¿¹¿Ü ¹ß»ý ¸·±â LoadCK := False; end; procedure TF_LSPLCAgent.ClientSocket1_oldRead(Sender: TObject; Socket: TCustomWinSocket); var Buf: array[0..1023] of Byte; i, Len: Integer; RawData: TBytes; BufCopy: TBytes; S: string; Recv: Integer; begin try Len := Socket.ReceiveBuf(Buf, SizeOf(Buf)); if Len > 0 then begin SetLength(RawData, Len); Move(Buf, RawData[0], Len); // 1. Memo1¿¡ Çí»ç Ç¥½Ã S := ''; for i := 0 to Len - 1 do S := S + IntToHex(RawData[i], 2) + ' '; if cb_logview.Checked then begin Memo2_ADD('>> ¼ö½Å ¿øº» (HEX)'); Memo2_ADD(S); end; end; except on E: Exception do begin Memo1_ADD('Read error: ' + E.Message); LoadCK := False; end; end; end; procedure TF_LSPLCAgent.AppEvtMinimize(Sender: TObject); begin Hide; WindowState := wsMinimized; TrayIcon1.Visible := True; TrayIcon1.Animate := True; TrayIcon1.ShowBalloonHint; end; procedure TF_LSPLCAgent.FormClose(Sender: TObject; var Action: TCloseAction); begin close_ck := true; Tmr_DBInsert.Enabled := False; Tmr_PLCRead.Enabled := False; end; procedure TF_LSPLCAgent.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if ExitOk then begin CanClose := true; end else begin CanClose := false; case MessageBox(handle, '"¿¹(Y)"¸¦ Ŭ¸¯Çϸé, LSPLC Agent01°¡ Æ®·¹ÀÌ·Î ÃÖ¼ÒÈ­ µË´Ï´Ù.'+#$0D#$0A#$0D#$0A+'"¾Æ´Ï¿À(N)"¸¦ Ŭ¸¯Çϸé ÇÁ·Î±×·¥ÀÌ Á¾·áµË´Ï´Ù. ', 'LSPLC Agent01 :: Æ®·¹ÀÌ·Î ÃÖ¼ÒÈ­ ÇÒ±î¿ä?', MB_YESNOCANCEL) of ID_YES : begin TrayIcon1.BalloonTitle := 'LSPLC Agent È­¸éÀ» ´Ù½Ã º¸·Á¸é...'; TrayIcon1.BalloonHint := 'Æ®·¹ÀÌ ¾ÆÀÌÄÜÀ» ´õºíŬ¸¯Çϼ¼¿ä.'; //TrayIcon1.BalloonFlags := bfInfo; AppEvtMinimize(self); end; ID_NO : begin //Á¾·á ŸÀÌ¸Ó ½ÃÀÛÇÏ°í ³¡³ª¸é ExitOk~ tmrExit.Tag := 0; tmrExit.Enabled := true; end; end;//case.. end;//if~ end; procedure TF_LSPLCAgent.FormCreate(Sender: TObject); var i, j : Integer; Sections: TStringList; CK_ROW : integer; Ini: TIniFile; begin close_ck := False; LoadCK := False; PLCconnectCK := 0; inifilename := StringReplace(Application.ExeName,'.exe','.ini',[rfReplaceAll]); Ini := TIniFile.Create(inifilename); try Edit5.Text := Ini.ReadString('PLC', 'IP', '192.168.100.11'); Edit6.Text := Ini.ReadString('PLC', 'PORT', '2004'); CheckBox1.Checked := Ini.ReadBool('START', 'AUTO', False); dbIP_PG := Ini.ReadString('DATABASE_PG','IP','192.168.200.199'); dbUser_PG := Ini.ReadString('DATABASE_PG','User','root'); dbPW_PG := Ini.ReadString('DATABASE_PG','PW','54323'); dbSchema_PG := Ini.ReadString('DATABASE_PG','Schema','neol'); dbPort_PG := Ini.ReadInteger('DATABASE_PG','Port',3306); finally Ini.Free; end; if FileExists(StringReplace(Application.ExeName,'.exe','_list1.ini',[rfReplaceAll])) then ListBox1.Items.LoadFromFile(StringReplace(Application.ExeName,'.exe','_list1.ini',[rfReplaceAll])); if FileExists(StringReplace(Application.ExeName,'.exe','_list2.ini',[rfReplaceAll])) then ListBox2.Items.LoadFromFile(StringReplace(Application.ExeName,'.exe','_list2.ini',[rfReplaceAll])); if FileExists(StringReplace(Application.ExeName,'.exe','_list3.ini',[rfReplaceAll])) then ListBox3.Items.LoadFromFile(StringReplace(Application.ExeName,'.exe','_list3.ini',[rfReplaceAll])); try GridAddressListTV.DataController.BeginUpdate; GridAddressListTV.DataController.RecordCount:=0; finally GridAddressListTV.DataController.EndUpdate; end; try GridAddressListTV.DataController.BeginUpdate; for i := 0 to ListBox1.Items.Count - 1 do begin CK_ROW := 0; with GridAddressListTV.DataController do begin CK_ROW := AppendRecord; Values[CK_ROW, GridAddressListTVColumn6.Index] := ListBox3.Items[i]; Values[CK_ROW, GridAddressListTVColumn1.Index] := ListBox2.Items[i]; Values[CK_ROW, GridAddressListTVColumn2.Index] := ListBox1.Items[i]; Values[CK_ROW, GridAddressListTVColumn3.Index] := ''; Values[CK_ROW, GridAddressListTVColumn4.Index] := ''; Values[CK_ROW, GridAddressListTVColumn5.Index] := ''; end; end; finally GridAddressListTV.DataController.EndUpdate; end; // PG ¼­¹öÁ¢¼Ó if not DB_Connect then begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] Database Connect Error :: PG'); end; // ÀÚµ¿ ·Î±× ½ÃÀÛ if CheckBox1.Checked then Button6.Click; end; function TF_LSPLCAgent.DB_Connect:Boolean; begin FDPhysPgDriverLink1.VendorLib := '.\libpq-10.dll'; FDConnection1.Connected := False; FDConnection1.Params.Clear; FDConnection1.Params.DriverID := 'PG'; FDConnection1.Params.Database := Trim(dbSchema_PG); FDConnection1.Params.UserName := Trim(dbUser_PG); FDConnection1.Params.Password := Trim(dbPW_PG); FDConnection1.Params.Add('Server=' + Trim(dbIP_PG)); FDConnection1.Params.Add('Port=' + Trim(IntToStr(dbPort_PG))); FDConnection1.Params.Add('CharacterSet=UTF8'); try FDConnection1.Connected := True; DB_MainTableCreate; DB_MainTableDescriptCreate; DB_LogTableCreate; Result := True; // Memo1_ADD('¿¬°á ¼º°ø'); // Memo1_ADD('"Q1" ¹öưÀ» ´©¸¥ ÈÄ "Äõ¸®" ¹öưÀ» ´©¸£¼¼¿ä!!'); except on E: Exception do begin Result := False; // Memo1_ADD('¿¬°á ½ÇÆÐ: ' + E.Message); end; end; end; procedure TF_LSPLCAgent.DB_Insert; var sql, update_sql : string; i : Integer; ck_data : Float64; begin try sql := ''; sql := 'INSERT INTO "plc_'+format('%.3d',[PLC_NO])+'" '+ ' ( "Idx","CreateDT","plcID"' ; for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin sql := sql +', "data'+format('%.2d',[i+1])+'"'; end; sql := sql + ' ) '; sql := sql + ' VALUES (DEFAULT, '+ 'now(),'+ inttostr(PLC_NO) ; update_sql := ''; update_sql := 'UPDATE "plc_Data" SET '; for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin if Trim(GridAddressListTV.DataController.Values[i, GridAddressListTVColumn3.Index]) <> '' then begin sql := sql +','+ floattostr(GridAddressListTV.DataController.Values[i, GridAddressListTVColumn3.Index]); update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = '+floattostr(GridAddressListTV.DataController.Values[i, GridAddressListTVColumn3.Index])+' , '; end else begin sql := sql +','+ '0.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 0.0 , '; end; end; sql := sql + ' ) '; update_sql := update_sql + '"UpdateDT"=now()'+ ' WHERE "plcID"='+inttostr(PLC_NO); insertSQL(update_sql); insertSQL(sql); if cb_logview.Checked then Memo1_ADD('DB Update,Insert ok.'); except on E: Exception do begin Memo1_ADD('DB_Insert Error : ' + E.Message); end; end; end; function TF_LSPLCAgent.DB_Close:Boolean; begin try if FDConnection1.Connected then FDConnection1.Connected := False; Result := True; except Result := False; end; end; function TF_LSPLCAgent.DB_MainTableCreate:Boolean; var sql : string; i : integer; begin try sql := 'CREATE TABLE IF NOT EXISTS "plc_Data" ('+ '"Idx" SERIAL NOT NULL,'+ '"UpdateDT" TIMESTAMP ,'+ '"plcID" INTEGER ,'+ '"data01" REAL ,'+ '"data02" REAL ,'+ '"data03" REAL ,'+ '"data04" REAL ,'+ '"data05" REAL ,'+ '"data06" REAL ,'+ '"data07" REAL ,'+ '"data08" REAL ,'+ '"data09" REAL ,'+ '"data10" REAL ,'+ '"data11" REAL ,'+ '"data12" REAL ,'+ '"data13" REAL ,'+ '"data14" REAL ,'+ '"data15" REAL ,'+ '"data16" REAL ,'+ '"data17" REAL ,'+ '"data18" REAL ,'+ '"data19" REAL ,'+ '"data20" REAL ,'+ '"data21" REAL ,'+ '"data22" REAL ,'+ '"data23" REAL ,'+ '"data24" REAL ,'+ '"data25" REAL ,'+ '"data26" REAL ,'+ '"data27" REAL ,'+ '"data28" REAL ,'+ '"data29" REAL ,'+ '"data30" REAL ,'+ 'CONSTRAINT plc_Data_pkey PRIMARY KEY ("Idx"));'; insertSQL(sql); if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery2.Close; FDQuery2.SQL.Clear; FDQuery2.SQL.Text := 'SELECT * FROM "plc_Data" WHERE "plcID"='+IntToStr(PLC_NO); FDQuery2.Open; if FDQuery2.RecordCount <= 0 then begin sql := ''; sql := 'INSERT INTO "plc_Data" ' + 'VALUES (DEFAULT, '+ 'now(), '+ inttostr(PLC_NO)+ ' ' ; for i := 0 to 29 do begin sql := sql +','+ '0.0'; end; sql := sql + ' ) '; insertSQL(sql); end; end; except on E: Exception do begin Memo1_ADD('DB_MainTableCreate Error : ' + E.Message); end; end; end; function TF_LSPLCAgent.DB_MainTableDescriptCreate:Boolean; var sql : string; i : integer; begin try sql := 'CREATE TABLE IF NOT EXISTS "plc_Data_Desc" ('+ '"Idx" SERIAL NOT NULL,'+ '"UpdateDT" TIMESTAMP ,'+ '"plcID" INTEGER ,'+ '"fieldname" VARCHAR(50) ,'+ '"address" VARCHAR(50) ,'+ '"addressDescription" VARCHAR(200) ,'+ 'CONSTRAINT plc_Data_Desc_pkey PRIMARY KEY ("Idx"));'; insertSQL(sql); { if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery2.Close; FDQuery2.SQL.Clear; FDQuery2.SQL.Text := ' SELECT * FROM "plc_Data_Desc" '+ ' WHERE "plcID" = '+IntToStr(PLC_NO)+ ' and "address" = '''+'*****'+''''; FDQuery2.Open; if FDQuery2.RecordCount <= 0 then begin sql := ''; sql := 'INSERT INTO "plc_Data_Desc" ' + 'VALUES (DEFAULT, '+ 'now(), '+ inttostr(PLC_NO)+ ' '''+'*****'+''', '+ ' '''+'*****'+''', '+ ' '''+'*****'+'''); '; insertSQL(sql); end; end; } except on E: Exception do begin Memo1_ADD('DB_MainTableDescriptCreate Error : ' + E.Message); end; end; end; function TF_LSPLCAgent.DB_LogTableCreate:Boolean; var sql : string; begin try sql := 'CREATE TABLE IF NOT EXISTS "plc_'+format('%.3d',[PLC_NO])+'" ('+ '"Idx" SERIAL NOT NULL,'+ '"CreateDT" TIMESTAMP ,'+ '"plcID" INTEGER ,'+ '"data01" REAL ,'+ '"data02" REAL ,'+ '"data03" REAL ,'+ '"data04" REAL ,'+ '"data05" REAL ,'+ '"data06" REAL ,'+ '"data07" REAL ,'+ '"data08" REAL ,'+ '"data09" REAL ,'+ '"data10" REAL ,'+ '"data11" REAL ,'+ '"data12" REAL ,'+ '"data13" REAL ,'+ '"data14" REAL ,'+ '"data15" REAL ,'+ '"data16" REAL ,'+ '"data17" REAL ,'+ '"data18" REAL ,'+ '"data19" REAL ,'+ '"data20" REAL ,'+ '"data21" REAL ,'+ '"data22" REAL ,'+ '"data23" REAL ,'+ '"data24" REAL ,'+ '"data25" REAL ,'+ '"data26" REAL ,'+ '"data27" REAL ,'+ '"data28" REAL ,'+ '"data29" REAL ,'+ '"data30" REAL ,'+ 'CONSTRAINT plc_'+format('%.3d',[PLC_NO])+'_pkey PRIMARY KEY ("Idx"));'; insertSQL(sql); except on E: Exception do begin Memo1_ADD('DB_LogTableCreate Error : ' + E.Message); end; end; end; end.