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, Vcl.ComCtrls, cxTextEdit, System.Net.URLClient, System.Net.HttpClientComponent, System.Net.HttpClient, system.DateUtils, system.Hash, System.NetEncoding, AlarmLog, RegisterClasses_base, empmst, System.JSON, cxCurrencyEdit, MachineMst; type TSMSOptions = record // ToNumber: string; ToNumber: TStrings; FromNumber: string; Text: string; end; type TF_LSPLCAgent = class(TForm) ClientSocket1_old: TClientSocket; Tmr_PLCRead: TTimer; TrayIcon1: TTrayIcon; tmrExit: TTimer; FDConnection1: TFDConnection; FDQuery1: TFDQuery; FDPhysPgDriverLink1: TFDPhysPgDriverLink; FDGUIxWaitCursor1: TFDGUIxWaitCursor; Tmr_DBInsert: TTimer; FDQuery2: TFDQuery; PageControl1: TPageControl; TabSheet1: TTabSheet; ALARM: TTabSheet; GroupBox4: TGroupBox; Label23: TLabel; Label24: TLabel; Label25: TLabel; Label26: TLabel; Label30: TLabel; Edit25: TEdit; Edit26: TEdit; Edit27: TEdit; Edit28: TEdit; Edit32: TEdit; GroupBox6: TGroupBox; Label31: TLabel; Label32: TLabel; Label33: TLabel; Edit30: TEdit; Button9: TButton; Memo3: TMemo; Edit31: TEdit; Memo4: TMemo; Memo5: TMemo; Edit33: TEdit; RadioButton3: TRadioButton; RadioButton4: TRadioButton; RadioGroup1: TRadioGroup; GroupBox5: TGroupBox; cxGrid3: TcxGrid; cxGridTableView3: TcxGridTableView; cxGridTableView3Column1: TcxGridColumn; cxGridTableView3Column2: TcxGridColumn; cxGridTableView3Column3: TcxGridColumn; cxGridTableView3Column4: TcxGridColumn; cxGridLevel3: TcxGridLevel; TabSheet2: TTabSheet; ListBox1: TListBox; ListBox2: TListBox; ListBox3: TListBox; Panel2: TPanel; Label17: TLabel; Label16: TLabel; Label3: TLabel; ComboBox5: TComboBox; Button13: TButton; Edit10: TEdit; GridAddressList: TcxGrid; GridAddressListTV: TcxGridTableView; GridAddressListTVColumn1: TcxGridColumn; GridAddressListTVColumn2: TcxGridColumn; GridAddressListTVColumn3: TcxGridColumn; GridAddressListTVColumn4: TcxGridColumn; GridAddressListTVColumn5: TcxGridColumn; GridAddressListTVColumn6: TcxGridColumn; GridAddressListLv: TcxGridLevel; GroupBox1: TGroupBox; Label14: TLabel; Label15: TLabel; Label1: TLabel; Label2: TLabel; Edit5: TEdit; Edit6: TEdit; Button11: TButton; Button1: TButton; Edit1: TEdit; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Edit2: TEdit; Button6: TButton; Button7: TButton; CheckBox1: TCheckBox; RadioButton1: TRadioButton; RadioButton2: TRadioButton; Panel1: TPanel; Splitter2: TSplitter; Memo1: TMemo; Memo2: TMemo; Splitter1: TSplitter; GridAddressListTVColumn7: TcxGridColumn; GroupBox2: TGroupBox; Label4: TLabel; Edit3: TEdit; Button8: TButton; Button10: TButton; cb_logview: TCheckBox; Timer_runningCK: TTimer; lb_status: TLabel; 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); procedure Button9Click(Sender: TObject); procedure RadioButton4Click(Sender: TObject); procedure Button8Click(Sender: TObject); procedure Button10Click(Sender: TObject); procedure Timer_runningCKTimer(Sender: TObject); private { Private declarations } FsmsObj: TSMSOptions; 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(status,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); function AlarmSend(devName, alarm_detail, alarm_status : string):Boolean; procedure EmgAlarmlistrefresh; function xGenerateHMACSHA256(const Key, Data: string): string; function xSendSMS(const Options: TSMSOptions; const ServiceId, AccessKey, SecretKey: string): string; function qCreateGetUniqueString(clsName: string): string; procedure PLC_statusUpdate(Plc_status: string); function Alarm_use_CK: Boolean; 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; Alarm_re : integer; Alarm_use : Boolean; lastDBInsert : TDateTime; const PLC_NO = 1; // ¼Ò°á·Î 1È£ implementation uses WinSock; const METHOD = 'POST'; CONTENT_TYPE = 'application/json; charset=utf-8'; COUNTRY_CODE = '82'; {$R *.dfm} function TF_LSPLCAgent.Alarm_use_CK:Boolean; var sql : string; begin Result := false; try if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin sql := 'SELECT * FROM "MachineMst"'; sql := sql + ' WHERE "Name"=''ALARM'' '; sql := sql + ' AND "IsValid"=''t'' '; sql := sql + ' AND "LcStatus"=''ON'' ; '; FDQuery1.Close; FDQuery1.SQL.Clear; FDQuery1.SQL.Text := sql; FDQuery1.Open; if FDQuery1.RecordCount> 0 then begin result := True; end; end; except on e : exception do begin Memo1_ADD('Database Select Error :: '+e.Message); end; end; end; 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.Timer_runningCKTimer(Sender: TObject); begin if LoadCK and (not Button6.Enabled) then begin if IncSecond(lastDBInsert,30) < now then begin Tmr_DBInsert.Enabled := True; end; 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) + ' '; Memo2_ADD('>> ¼ö½Å ¿øº» (HEX) : '+ S); // Memo2_ADD(S); 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.zzz :: ',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.zzz :: ',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 // if cb_logview.Checked then begin while Memo1.Lines.Count > 50 do begin Memo1.Lines.Delete(0); end; Memo1.Lines.Add(msg); // end; log_save('SYS',msg); end; procedure TF_LSPLCAgent.Memo2_ADD(msg:string); begin if cb_logview.Checked then begin while Memo2.Lines.Count > 50 do begin Memo2.Lines.Delete(0); end; Memo2.Lines.ADD(msg); end; 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[16] := 18; // 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 = 'BIT_A') 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.Button10Click(Sender: TObject); begin EmgAlarmlistrefresh; 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; if lb_status.Caption <> '´ë±â' then begin PLC_statusUpdate('´ë±â'); 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; Recv_count_ck : integer; alarmreadck : Boolean; // ===== [Ãß°¡] ¼ÒÄÏ ¹öÆÛ ºñ¿ì±â¸¦ À§ÇÑ º¯¼ö ===== JunkBuf: array[0..1023] of Byte; ClearLen: Integer; // ===== [Ãß°¡] ¼ÒÄÏ ¹öÆÛ¸¦ ±ú²ýÇÏ°Ô ºñ¿ì´Â ³»ºÎ ÇÔ¼ö ===== procedure FlushSocketBuffer; begin // ¼ö½Å ¹öÆÛ¿¡ µ¥ÀÌÅͰ¡ ³²¾ÆÀÖ´Â µ¿¾È °è¼Ó Àо Æó±âÇÔ while ClientSocket1.Socket.ReceiveLength > 0 do begin ClearLen := ClientSocket1.Socket.ReceiveLength; if ClearLen > SizeOf(JunkBuf) then ClearLen := SizeOf(JunkBuf); ClientSocket1.Socket.ReceiveBuf(JunkBuf, ClearLen); Sleep(10); // Åë½Å Áö¿¬À¸·Î ²¿¸®¿¡ ºÙ¾î¿À´Â ÀÜ¿© µ¥ÀÌÅͱîÁö È®½ÇÈ÷ ´ë±â ÈÄ Æó±â end; Memo2_ADD('¼ö½Å ¹öÆÛ Ŭ¸®¾î ¿Ï·á (Åë½Å µ¿±âÈ­ Àç¼³Á¤)'); end; begin alarmreadck := False; Result := False; if PLCconnectCK <> 2 then exit; Button1.Enabled := False; try try Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLCDataLoad - start'); GridAddressListTV.DataController.BeginUpdate; for i := 0 to GridAddressListTV.DataController.RecordCount - 1 do begin with GridAddressListTV.DataController do begin if ClientSocket1.Active then begin BuildReadPacket(Values[i, GridAddressListTVColumn6.Index],Values[i, GridAddressListTVColumn2.Index]); Sent := ClientSocket1.Socket.SendBuf(TxBuf, 38); if Sent <> 38 then begin Memo2_ADD('ÆÐŶ Àü¼Û ½ÇÆÐ PLCDataLoad: ['+IntToStr(Sent)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); LoadCK := False; end else begin Sleep(StrToIntDef(Edit1.Text,0)); Recv := ClientSocket1.Socket.ReceiveBuf(RxBuf, 34); Recv_count_ck := 34; if (Values[i, GridAddressListTVColumn6.Index] = 'BIT') or (Values[i, GridAddressListTVColumn6.Index] = 'BIT_A') then Recv_count_ck := 33; if Recv < Recv_count_ck then begin Memo2_ADD('ÀÀ´ä ¼ö½Å ½ÇÆÐ PLCDataLoad: [Sent:'+IntToStr(Sent)+']-[Recv:'+IntToStr(Recv)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); // 2. Memo2: ÇØ¼®µÈ °á°ú - ½ÇÆÐ°¡ ³ª¸é ¹ÞÀº µ¥ÀÌÅͰ¡ ¾øÀ½.20251204 if (Values[i, GridAddressListTVColumn6.Index] = 'BIT') then begin var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(hexStr); end else if (Values[i, GridAddressListTVColumn6.Index] = 'BIT_A') then begin var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(hexStr); end else if Values[i, GridAddressListTVColumn6.Index] = 'WORD' then begin var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(hexStr); end; if Recv = -1 then begin LastError := WSAGetLastError; case LastError of 10054: ErrorMsg := 'Connection reset by peer (PLC¿¡¼­ ¿¬°á °­Á¦ Á¾·á)'; 10060: ErrorMsg := 'Connection timed out (¼ö½Å ŸÀӾƿô)'; 10004: ErrorMsg := 'Interrupted function call (ºí·ÎÅ· µ¿ÀÛ Áß Ãë¼Ò)'; else ErrorMsg := 'Unknown socket error'; end; Memo2_ADD('¼ÒÄÏ ¿À·ù Recv: ['+IntToStr(Recv)+'] - WSAGetLastError: ['+IntToStr(LastError)+'] - Message: ['+ErrorMsg+']'); end else if Recv = 0 then begin Memo2_ADD('°æ°í PLC¿¡¼­ ¿¬°áÀ» Á¤»ó Á¾·áÇÔ (Recv: 0) - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); end else begin Memo2_ADD('ÀÀ´ä ¼ö½Å ºÒ¿ÏÀü (Recv < 34) PLCDataLoad: [Sent:'+IntToStr(Sent)+']-[Recv:'+IntToStr(Recv)+']-[ '+Values[i, GridAddressListTVColumn2.Index]+' ]'); end; LoadCK := False; FlushSocketBuffer; // ¼ö½ÅÀÌ ºÒ¿ÏÀüÇÒ ¶§µµ ¹öÆÛ ºñ¿ì±â ½ÇÇà end else begin // 4. [½Å±Ô Ãß°¡] ¿äûÇÑ µ¥ÀÌÅÍ Å¸ÀÔ°ú ¼ö½ÅµÈ Payload ±æÀÌ ÀÏÄ¡ °ËÁõ var PayloadLen: Integer := RxBuf[16] + (RxBuf[17] shl 8); var ExpectedLen: Integer := 0; // BIT ¿äûÀÏ °æ¿ì ÀÀ´ä ÆäÀ̷εå´Â 13¹ÙÀÌÆ® (0x0D) ¿©¾ß ÇÔ if (Values[i, GridAddressListTVColumn6.Index] = 'BIT') or (Values[i, GridAddressListTVColumn6.Index] = 'BIT_A') then ExpectedLen := 13 // WORD ¿äûÀÏ °æ¿ì ÀÀ´ä ÆäÀ̷εå´Â 14¹ÙÀÌÆ® (0x0E) ¿©¾ß ÇÔ else if Values[i, GridAddressListTVColumn6.Index] = 'WORD' then ExpectedLen := 14; // 1. Çì´õ ½Ã±×´Ïó °ËÁõ if (RxBuf[0] <> $4C) or (RxBuf[1] <> $53) or (RxBuf[2] <> $49) or (RxBuf[3] <> $53) or (RxBuf[4] <> $2D) or (RxBuf[5] <> $58) or (RxBuf[6] <> $47) or (RxBuf[7] <> $54) then begin Memo2_ADD('ÆÐŶ °ËÁõ ½ÇÆÐ (¾²·¹±â °ª): LSIS-XGT ½Ã±×´Ïó ºÒÀÏÄ¡ - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); LoadCK := False; FlushSocketBuffer; // ¹öÆÛ ºñ¿ì±â Continue; end; // 2. ÇÁ·¹ÀÓ ¹æÇâ °ËÁõ (0x11: ÀÀ´ä) if RxBuf[13] <> $11 then begin Memo2_ADD('ÆÐŶ °ËÁõ ½ÇÆÐ: PLC ÀÀ´ä ÇÁ·¹ÀÓÀÌ ¾Æ´Ô ['+IntToHex(RxBuf[13], 2)+'] - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); LoadCK := False; FlushSocketBuffer; // ¹öÆÛ ºñ¿ì±â Continue; end; // 3. ¸í·É¾î Á¾·ù °ËÁõ (0x55: Read ÀÀ´ä) if RxBuf[20] <> $55 then begin Memo2_ADD('ÆÐŶ °ËÁõ ½ÇÆÐ: Read ÀÀ´ä(0x55) ¸í·É¾î°¡ ¾Æ´Ô ['+IntToHex(RxBuf[20], 2)+'] - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); LoadCK := False; FlushSocketBuffer; // ¹öÆÛ ºñ¿ì±â Continue; end; // 4-1. ¿¹»ó ±æÀÌ¿Í ½ÇÁ¦ ¼ö½ÅµÈ ±æÀ̰¡ ´Ù¸£¸é ´Ù¸¥ ÆÐŶÀÌ ¼¯¿© µé¾î¿Â °Í(¹Ð¸² Çö»ó)ÀÓ if (ExpectedLen > 0) and (PayloadLen <> ExpectedLen) then begin Memo2_ADD('ÆÐŶ °ËÁõ ½ÇÆÐ: ÆÐŶ ¾ûÅ´ °¨Áö. ±â´ë±æÀÌ:['+IntToStr(ExpectedLen)+'] ½ÇÁ¦±æÀÌ:['+IntToStr(PayloadLen)+'] - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); LoadCK := False; FlushSocketBuffer; // ¾ûŲ ¹öÆÛ¸¦ ¸ðµÎ ³¯·Á¹ö¸®°í ´ÙÀ½ Åë½ÅºÎÅÍ Á¤»óÈ­ Continue; end; // 5. [¸Å¿ì Áß¿ä] ¿¡·¯ »óÅ °ËÁõ (RxBuf[26], RxBuf[27]) // PLC¿¡¼­ º¸³»´Â ¿¡·¯ ÀÀ´ä(ªÀº ÆÐŶ)Àº À§ 1,2,3¹ø °ËÁõÀ» ¹«»çÈ÷ Åë°úÇÕ´Ï´Ù. ¿©±â¼­ °É·¯³»¾ß ÇÕ´Ï´Ù! if (RxBuf[26] <> $00) or (RxBuf[27] <> $00) then begin var ErrorStatus: Word := RxBuf[26] + (RxBuf[27] shl 8); Memo2_ADD('ÆÐŶ °ËÁõ ½ÇÆÐ: PLC Ãø ¿¡·¯ ÀÀ´ä ¹ß»ý [¿¡·¯ÄÚµå: 0x'+IntToHex(ErrorStatus, 4)+'] - ÁÖ¼Ò: ['+Values[i, GridAddressListTVColumn2.Index]+']'); LoadCK := False; FlushSocketBuffer; // ¿¡·¯ ÆÐŶÀ¸·Î ²¿ÀÎ ¹öÆÛ ¿Ïº® ºñ¿ì±â Continue; end; // ========================================== // °ËÁõ Åë°ú - ÀÌÇÏ ±âÁ¸ Á¤»ó µ¥ÀÌÅÍ ÆÄ½Ì ·ÎÁ÷ // ========================================== if Values[i, GridAddressListTVColumn6.Index] = 'BIT' then begin var value := RxBuf[32]; var hexStr_ := ''; for var x := 0 to 38 - 1 do hexStr_ := hexStr_ + IntToHex(TxBuf[x], 2) + ' '; var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(Values[i, GridAddressListTVColumn2.Index]+ ' // '+'DEC : '+IntToStr(value) + ' // '+'HEX : '+IntToHex(value, 2) + ' // '+'TxBuf: '+hexStr_ + ' // '+'RxBuf: '+hexStr ); Values[i, GridAddressListTVColumn4.Index] := IntToHex(value, 2); Values[i, GridAddressListTVColumn5.Index] := FormatDateTime('yymmdd hhnnss.zzz',Now); Values[i, GridAddressListTVColumn7.Index] := 0; if value = 0 then begin Values[i, GridAddressListTVColumn3.Index] := 'False'; end else begin Values[i, GridAddressListTVColumn3.Index] := 'True'; end; end else if Values[i, GridAddressListTVColumn6.Index] = 'BIT_A' then begin var value := RxBuf[32]; var hexStr_ := ''; for var x := 0 to 38 - 1 do hexStr_ := hexStr_ + IntToHex(TxBuf[x], 2) + ' '; var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(Values[i, GridAddressListTVColumn2.Index]+ ' // '+'DEC : '+IntToStr(value) + ' // '+'HEX : '+IntToHex(value, 2) + ' // '+'TxBuf: '+hexStr_ + ' // '+'RxBuf: '+hexStr ); Values[i, GridAddressListTVColumn4.Index] := IntToHex(value, 2); Values[i, GridAddressListTVColumn5.Index] := FormatDateTime('yymmdd hhnnss.zzz',Now); if value = 0 then begin Values[i, GridAddressListTVColumn3.Index] := 'False'; if Values[i, GridAddressListTVColumn7.Index] > 0 then begin Alarm_use := Alarm_use_CK; if AlarmSend('Áø°ø¼Ò°á·Î-0'+inttostr(PLC_NO),Values[i, GridAddressListTVColumn1.Index],'¿Ï·á') then begin Values[i, GridAddressListTVColumn7.Index] := 0; end; end; end else begin alarmreadck := true; Values[i, GridAddressListTVColumn3.Index] := 'True'; if (Values[i, GridAddressListTVColumn7.Index] = 0) or (Values[i, GridAddressListTVColumn7.Index] >= Alarm_re) then begin Alarm_use := Alarm_use_CK; if AlarmSend('Áø°ø¼Ò°á·Î-0'+inttostr(PLC_NO),Values[i, GridAddressListTVColumn1.Index],'¹ß»ý') then begin Values[i, GridAddressListTVColumn7.Index] := 1; end else begin Values[i, GridAddressListTVColumn7.Index] := Values[i, GridAddressListTVColumn7.Index] + 1; end; end else begin Values[i, GridAddressListTVColumn7.Index] := Values[i, GridAddressListTVColumn7.Index] + 1; end; end; end else if Values[i, GridAddressListTVColumn6.Index] = 'WORD' then begin var DataWord: Word := RxBuf[32] + (RxBuf[33] shl 8); var SignedValue: SmallInt := SmallInt(DataWord); var hexStr_ := ''; for var x := 0 to 38 - 1 do hexStr_ := hexStr_ + IntToHex(TxBuf[x], 2) + ' '; var hexStr := ''; for var x := 0 to Recv - 1 do hexStr := hexStr + IntToHex(RxBuf[x], 2) + ' '; Memo2_ADD(Values[i, GridAddressListTVColumn2.Index]+ ' // '+'DEC : '+IntToStr(SignedValue) + ' // '+'HEX : '+IntToHex(DataWord, 4) + ' // '+'TxBuf: '+hexStr_ + ' // '+'RxBuf: '+hexStr ); Values[i, GridAddressListTVColumn3.Index] := IntToStr(SignedValue); Values[i, GridAddressListTVColumn4.Index] := IntToHex(DataWord, 4); Values[i, GridAddressListTVColumn5.Index] := FormatDateTime('yymmdd hhnnss.zzz',Now); end; LoadCK := True; end; end; end; end; Refresh; end; except on E: Exception do begin Memo1_ADD('PLCDataLoad Error : ' + E.Message); LoadCK := False; FlushSocketBuffer; // ¿¹¿Ü ¹ß»ý ½Ã¿¡µµ ¹öÆÛ ¾ÈÀüÇÏ°Ô ÃʱâÈ­ end; end; finally Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] PLCDataLoad - end'); Result := LoadCK; GridAddressListTV.DataController.EndUpdate; Button1.Enabled := True; Refresh; if alarmreadck then DB_Insert; 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('yymmdd 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(status,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; lastDBInsert := now; if (status = '°¡µ¿') and (lb_status.Caption <> status) then begin lb_status.Caption := '°¡µ¿'; end; end; except on e : exception do begin Memo2_ADD('[insertSQL()]Database insertSQL 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; if not Button6.Enabled then 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; if not Button6.Enabled then 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 if lb_status.Caption <> '´ë±â' then begin PLC_statusUpdate('´ë±â'); end; 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; if not LoadCK then begin if lb_status.Caption <> '´ë±â' then begin PLC_statusUpdate('´ë±â'); end; end; // end; end; end; procedure TF_LSPLCAgent.PLC_statusUpdate(Plc_status:string); var update_sql : string; begin try update_sql := ''; update_sql := 'UPDATE "plc_Data" SET '+ '"dev_status"='''+Plc_status+''', '+ '"UpdateDT"=now() '+ ' WHERE "plcID"='+inttostr(PLC_NO); if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery1.Active := false; FDQuery1.SQL.Clear; FDQuery1.SQL.Add(update_sql); FDQuery1.ExecSQL; lastDBInsert := now; if lb_status.Caption <> Plc_status then begin lb_status.Caption := Plc_status; end; end; except on e : exception do begin Memo2_ADD('[insertSQL()]Database Connect Error :: '+e.Message); 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, GridAddressListTVColumn6.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; Sleep(500); Tmr_DBInsert.Enabled := False; Tmr_DBInsert.Interval := StrToIntDef(Edit2.Text,1000); Tmr_DBInsert.Enabled := True; Timer_runningCK.Enabled := False; Timer_runningCK.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.Button8Click(Sender: TObject); var Ini: TIniFile; begin inifilename := StringReplace(Application.ExeName,'.exe','.ini',[rfReplaceAll]); Ini := TIniFile.Create(inifilename); try if Trim(Edit3.Text) <> '' then Alarm_re := strtoint(Edit3.Text) else Alarm_re := 60; Ini.WriteInteger('ALARM_RE','sec',Alarm_re); finally Ini.Free; end; end; procedure TF_LSPLCAgent.Button9Click(Sender: TObject); begin Alarm_use := Alarm_use_CK; if AlarmSend(Edit30.Text,Edit31.Text,Edit33.Text) then begin ShowMessage('SMS Àü¼Û ¿Ï·á'); end else begin ShowMessage('SMS Àü¼Û ½ÇÆÐ'); end; end; function TF_LSPLCAgent.qCreateGetUniqueString(clsName: string): string; var randomInt: Integer; tmStmp: TTimeStamp; dbName: string; begin //****************OBID±ÔÄ¢*****************// //Result := clsName(Ŭ·¡½º³×ÀÓ) + '-ŸÀÔ½ºÅÆÇÁ-' + '-6ÀÚ¸®·£´ý¼ö-' + 'µðºñ³×ÀÓ'; //****************OBID±ÔÄ¢*****************// Result := ''; tmStmp := DateTimeToTimeStamp(Now); randomInt := random(899998) + 100001; //100001 ~ 999999 dbName := 'neol_data'; Result := 'T' + clsName + '-' + IntToStr(tmStmp.Date) + IntToStr(tmStmp.Time) + '-' + IntToStr(randomInt) + '-' + dbName; end; procedure TF_LSPLCAgent.RadioButton4Click(Sender: TObject); begin if RadioButton1.Checked then begin Memo3.Clear; Memo3.Lines.Add('[³×¿Ã]'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('ÇöÀç %s¡É'); Memo3.Lines.Add('https://neol.co.kr'); end else begin Memo3.Clear; Memo3.Lines.Add('[³×¿Ã]'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('-'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('-'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('-'); Memo3.Lines.Add('https://neol.co.kr'); end; end; function TF_LSPLCAgent.xGenerateHMACSHA256(const Key, Data: string): string; var HashBytes: TBytes; begin HashBytes := THashSHA2.GetHMACAsBytes(TEncoding.UTF8.GetBytes(Data), TEncoding.UTF8.GetBytes(Key), SHA256); Result := TNetEncoding.Base64.EncodeBytesToString(HashBytes); end; function TF_LSPLCAgent.xSendSMS(const Options: TSMSOptions; const ServiceId, AccessKey, SecretKey: string): string; var i: Integer; Client: TNetHTTPClient; Request: TStringStream; JsonObj, MsgObj: TJSONObject; JsonArray: TJSONArray; Response: IHTTPResponse; Timestamp: Int64; SignTarget, Signature, URL: string; begin Client := TNetHTTPClient.Create(nil); try Timestamp := DateTimeToUnix(TTimeZone.Local.ToUniversalTime(Now)) * 1000; //SignTarget := METHOD + ' ' + URL + #10 + IntToStr(Timestamp) + #10 + AccessKey; SignTarget := METHOD + ' ' + '/sms/v2/services/' + ServiceId + '/messages' + #10 + IntToStr(Timestamp) + #10 + AccessKey; //HMAC-SHA256 ¼­¸í »ý¼º (`THashSHA2` »ç¿ë) Signature := xGenerateHMACSHA256(SecretKey, SignTarget); URL := Format(Edit25.Text, [ServiceId]); JsonObj := TJSONObject.Create; try if RadioButton1.Checked then JsonObj.AddPair('type', 'SMS') else JsonObj.AddPair('type', 'MMS'); JsonObj.AddPair('contentType', 'COMM'); JsonObj.AddPair('countryCode', COUNTRY_CODE); JsonObj.AddPair('from', Options.FromNumber); JsonObj.AddPair('content', Options.Text); JsonArray := TJSONArray.Create; for i := 0 to Options.ToNumber.Count-1 do begin MsgObj := TJSONObject.Create; MsgObj.AddPair('to', Options.ToNumber.Strings[i]); MsgObj.AddPair('content', Options.Text); JsonArray.AddElement(MsgObj); end; JsonObj.AddPair('messages', JsonArray); Request := TStringStream.Create(JsonObj.ToJSON, TEncoding.UTF8); try Client.CustomHeaders['Content-Type'] := CONTENT_TYPE; Client.CustomHeaders['x-ncp-apigw-timestamp'] := IntToStr(Timestamp); Client.CustomHeaders['x-ncp-iam-access-key'] := AccessKey; Client.CustomHeaders['x-ncp-apigw-signature-v2'] := Signature; Response := Client.Post(Format(Edit25.Text, [ServiceId]), Request); Result := Response.ContentAsString; finally Request.Free; end; finally JsonObj.Free; end; finally Client.Free; end; end; procedure TF_LSPLCAgent.EmgAlarmlistrefresh; var empmst : Tempmst; tmpList : TList; row, x : integer; begin try tmpList := TList.Create; empmst := Tempmst.Create(self); tmpList := empmst.xGetStrSqlEmpMstList(FDQuery1,'ÀçÁ÷','',''); with cxGridTableView3.DataController do begin try BeginUpdate; RecordCount := 0; finally EndUpdate; end; end; for x := 0 to tmpList.Count-1 do begin empmst := tmpList.Items[x]; if StrToBool(empmst.IsAlarm) then begin with cxGridTableView3.DataController do begin try BeginUpdate; row := AppendRecord; Values[row,cxGridTableView3Column1.Index] := StringReplace(empmst.EmpTelNum, '-', '', [rfReplaceAll]); Values[row,cxGridTableView3Column2.Index] := empmst.Name; Values[row,cxGridTableView3Column3.Index] := empmst.Position; Values[row,cxGridTableView3Column4.Index] := empmst.Role; finally EndUpdate; end; end; end; end; finally tmpList.free; end; end; function TF_LSPLCAgent.AlarmSend(devName,alarm_detail,alarm_status:string):Boolean; var i: Integer; Response, pID, aKey, sKey: string; sql : string; ToNum : string; ToNumlist : TStringList; begin Result := False; EmgAlarmlistrefresh; if RadioGroup1.ItemIndex = 1 then begin //TEST //ȸ»ç °èÁ¤..Å¥¼¾ÅØ.. pID := 'ncp:sms:kr:337071110685:qst'; aKey := 'qW8o6nlh4ORI7zpt0ai2'; sKey := 'Uqt8kJECZxvrBBYN1EMlmJfEGQuR4hStkvVuiSTS'; //Å¥¼¾ÅØ ¹ß½ÅÀÎÁõ ¹øÈ£.. FsmsObj.FromNumber := '07082802424'; end else begin // REAL //³×¿Ã..Access key, Secret key.. pID := Edit32.Text; aKey := Edit26.Text; sKey := Edit27.Text; //³×¿Ã ¹ß½ÅÀÎÁõ ¹øÈ£.. FsmsObj.FromNumber := '0336480037'; end; try ToNumlist := TStringList.Create; with cxGridTableView3.DataController do begin for I := 0 to RecordCount-1 do begin ToNumlist.Add(Values[i,cxGridTableView3Column1.Index]); end; end; // ¼ö½ÅÀÚ¹øÈ£ FsmsObj.ToNumber := ToNumlist; if Alarm_use then begin if (FormatDateTime('hh:nn',Now) <= '02:55') and (FormatDateTime('hh:nn',Now) >= '03:05') then begin FsmsObj.Text := Format(Memo3.Text, [alarm_status,devName,alarm_detail]); end else begin FsmsObj.Text := '[¾Ë¶÷ Á¦¿Ü] '+Format(Memo3.Text, [alarm_status,devName,alarm_detail]); end; end else begin FsmsObj.Text := '[¾Ë¶÷ ¹ÌÀü¼Û] '+Format(Memo3.Text, [alarm_status,devName,alarm_detail]); end; if (Trim(FsmsObj.FromNumber) <> '') and (Trim(FsmsObj.Text) <> '') and (FsmsObj.ToNumber.Count > 0) then begin Memo4.Clear; Memo5.Clear; if Alarm_use then begin if (FormatDateTime('hh:nn',Now) <= '02:55') and (FormatDateTime('hh:nn',Now) >= '03:05') then begin Response := xSendSMS(FsmsObj, pID, aKey, sKey); end else begin Response := '[¾Ë¶÷ Á¦¿Ü] : success'; end; end else begin Response := '[¾Ë¶÷ ¹ÌÀü¼Û] : success'; end; ToNum := ''; for i := 0 to FsmsObj.ToNumber.Count-1 do begin Memo4.Lines.Add(FsmsObj.ToNumber.Strings[i]); if i = 0 then ToNum := FsmsObj.ToNumber.Strings[i] else ToNum := ToNum +' / '+ FsmsObj.ToNumber.Strings[i]; end; Memo4.Lines.Add(FsmsObj.FromNumber); Memo4.Lines.Add(FsmsObj.Text); Memo5.Lines.Add('ÀÀ´ä: ' + Response); if pos('success',Response) > 0 then result := True; sql := ''; sql := 'INSERT INTO "AlarmLog" VALUES( '+ ''''+''+''', '+ ''''+qCreateGetUniqueString('AlarmLog')+''', '+ ''''+'AlarmLog'+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '+ ''''+F_LSPLCAgent.Caption+''', '+ ''''+'t'+''', '+ ''''+'Working'+''', '+ ''''+devName+''', '+ ''''+'¼Ò°á'+''', '+ ''''+StringReplace(FsmsObj.Text, #$D#$A, '', [rfReplaceAll])+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '+ ''''+ToNum+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '+ ''''+alarm_detail+''', '+ ''''+alarm_detail+''', '+ ''''+alarm_status+''', '+ 'NULL '+ ')'; // ShowMessage(sql); insertSQL('¾Ë¶÷',sql); end else begin if Trim(FsmsObj.FromNumber) = '' then begin Memo4.Lines.Add('¹ß½ÅÀÚ¹øÈ£ È®ÀÎÇÊ¿ä!'); end; if Trim(FsmsObj.Text) = '' then begin Memo4.Lines.Add('¸Þ¼¼Áö ³»¿ë È®ÀÎÇÊ¿ä!'); end; if FsmsObj.ToNumber.Count <= 0 then begin Memo4.Lines.Add('¼ö½ÅÀÚ¹øÈ£ È®ÀÎÇÊ¿ä!'); end; end; finally ToNumlist.Free; end; 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) + ' '; Memo2_ADD('>> ¼ö½Å ¿øº» (HEX) : ' + S); // Memo2_ADD(S); 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; Timer_runningCK.Enabled := False; 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; lastDBInsert := now; 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); Alarm_re := Ini.ReadInteger('ALARM_RE','sec',60); Edit3.Text := IntToStr(Alarm_re); 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, 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] := ''; Values[CK_ROW, GridAddressListTVColumn6.Index] := ListBox3.Items[i]; Values[CK_ROW, GridAddressListTVColumn7.Index] := '0'; 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 '; with GridAddressListTV.DataController do begin for i := 0 to RecordCount - 1 do begin if Trim(Values[i, GridAddressListTVColumn3.Index]) <> '' then begin if (Values[i, GridAddressListTVColumn6.Index] = 'BIT') then begin if Values[i, GridAddressListTVColumn3.Index] = 'True' then begin sql := sql +','+ '1.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 1.0 , '; end else begin sql := sql +','+ '0.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 0.0 , '; end; end else if (Values[i, GridAddressListTVColumn6.Index] = 'BIT_A') then begin if Values[i, GridAddressListTVColumn3.Index] = 'True' then begin sql := sql +','+ '1.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 1.0 , '; end else begin sql := sql +','+ '0.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 0.0 , '; end; end else begin sql := sql +','+ floattostr(Values[i, GridAddressListTVColumn3.Index]); update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = '+ floattostr(Values[i, GridAddressListTVColumn3.Index])+' , '; end; end else begin sql := sql +','+ '0.0'; update_sql := update_sql + '"data'+format('%.2d',[i+1])+'" = 0.0 , '; end; end; end; sql := sql + ' ) '; update_sql := update_sql + '"dev_status"=''°¡µ¿'', '+ '"UpdateDT"=now() '+ ' WHERE "plcID"='+inttostr(PLC_NO); insertSQL('°¡µ¿',update_sql); insertSQL('·Î±×',sql); Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] DB Update,Insert ok.'); except on E: Exception do begin Memo1_ADD('['+FormatDateTime('yymmdd hhnnss.zzz',now)+'] 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; x : Integer; begin try sql := 'CREATE TABLE IF NOT EXISTS "plc_Data" ('+ '"Idx" SERIAL NOT NULL,'+ '"UpdateDT" TIMESTAMP ,'+ '"plcID" INTEGER ,'; for x := 1 to 50 do begin sql := sql + '"data'+format('%.2d',[x])+'" REAL ,'; end; sql := sql + '"MachCode" VARCHAR(20) ,' + '"devName" VARCHAR(50) ,' + '"dev_status" VARCHAR(10) ,' + 'CONSTRAINT plc_Data_pkey PRIMARY KEY ("Idx"));'; { '"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 49 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 exit; 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; x : integer; begin try sql := 'CREATE TABLE IF NOT EXISTS "plc_'+format('%.3d',[PLC_NO])+'" ('+ '"Idx" SERIAL NOT NULL,'+ '"CreateDT" TIMESTAMP ,'+ '"plcID" INTEGER ,'; for x := 1 to 50 do begin sql := sql + '"data'+format('%.2d',[x])+'" REAL ,'; end; sql := sql + 'CONSTRAINT plc_'+format('%.3d',[PLC_NO])+'_pkey PRIMARY KEY ("Idx"));'; { '"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 ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" REAL ,'+ '"data30" 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.