397 lines
12 KiB
Plaintext
397 lines
12 KiB
Plaintext
unit uMain;
|
|
|
|
interface
|
|
|
|
uses
|
|
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
|
|
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
|
|
System.IniFiles, Data.DB, U_DM, uLogManagerThread;
|
|
|
|
type
|
|
TfrmMain = class(TForm)
|
|
GroupBox1: TGroupBox;
|
|
btnRedOn: TButton;
|
|
btnRedBlink: TButton;
|
|
btnRedOff: TButton;
|
|
btnYellowOn: TButton;
|
|
btnYellowBlink: TButton;
|
|
btnYellowOff: TButton;
|
|
btnGreenOn: TButton;
|
|
btnGreenBlink: TButton;
|
|
btnGreenOff: TButton;
|
|
btnBlueOn: TButton;
|
|
btnBlueBlink: TButton;
|
|
btnBlueOff: TButton;
|
|
btnWhiteOn: TButton;
|
|
btnWhiteBlink: TButton;
|
|
btnWhiteOff: TButton;
|
|
GroupBox2: TGroupBox;
|
|
btnSoundOff: TButton;
|
|
btnSound1: TButton;
|
|
btnSound2: TButton;
|
|
btnSound3: TButton;
|
|
btnSound4: TButton;
|
|
btnSound5: TButton;
|
|
Label1: TLabel;
|
|
edtIP1: TEdit;
|
|
edtIP2: TEdit;
|
|
edtIP3: TEdit;
|
|
edtIP4: TEdit;
|
|
GroupBox3: TGroupBox;
|
|
edtPort: TEdit;
|
|
rgModel: TRadioGroup;
|
|
btnStatRead: TButton;
|
|
btnReset: TButton;
|
|
btnExit: TButton;
|
|
GroupBox4: TGroupBox;
|
|
lbStatus: TListBox;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure btnLampClick(Sender: TObject);
|
|
procedure btnSoundClick(Sender: TObject);
|
|
procedure btnStatReadClick(Sender: TObject);
|
|
procedure btnResetClick(Sender: TObject);
|
|
procedure btnExitClick(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
c_pIdata: array[0..14] of Byte;
|
|
c_pIpadd: array[0..3] of Byte;
|
|
|
|
// 환경 설정 변수
|
|
FDBHost, FDBUser, FDBPass, FDBName: string;
|
|
FDBPort: Integer;
|
|
|
|
// 폴링 타이머
|
|
FPollingTimer: TTimer;
|
|
|
|
function SendCommand: Boolean;
|
|
procedure LogMessage(const Msg: string);
|
|
procedure LoadSettings;
|
|
procedure InitDB;
|
|
procedure OnPollingTimer(Sender: TObject);
|
|
public
|
|
{ Public declarations }
|
|
end;
|
|
|
|
var
|
|
frmMain: TfrmMain;
|
|
|
|
function Tcp_Qu_RW(iPort: Integer; var pbIp: Byte; var pbData: Byte): Boolean; stdcall; external 'Qtvc_dll.dll';
|
|
|
|
implementation
|
|
|
|
{$R *.dfm}
|
|
|
|
const
|
|
C_lampoff = 0;
|
|
C_lampon = 1;
|
|
C_lampblink = 2;
|
|
D_not = 100;
|
|
|
|
procedure TfrmMain.LoadSettings;
|
|
var
|
|
Ini: TIniFile;
|
|
begin
|
|
Ini := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'settings.ini');
|
|
try
|
|
FDBHost := Ini.ReadString('DB', 'Host', '0.0.0.0');
|
|
FDBPort := Ini.ReadInteger('DB', 'Port', 33063);
|
|
FDBUser := Ini.ReadString('DB', 'User', 'mmcl_user');
|
|
FDBPass := Ini.ReadString('DB', 'Password', '');
|
|
FDBName := Ini.ReadString('DB', 'Database', 'mmcl_db');
|
|
finally
|
|
Ini.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.InitDB;
|
|
begin
|
|
DM.fdConnEtc.Close;
|
|
DM.fdConnEtc.Params.Clear;
|
|
DM.fdConnEtc.Params.Add('DriverID=MySQL');
|
|
DM.fdConnEtc.Params.Add('Server=' + FDBHost);
|
|
DM.fdConnEtc.Params.Add('Port=' + IntToStr(FDBPort));
|
|
DM.fdConnEtc.Params.Add('Database=' + FDBName);
|
|
DM.fdConnEtc.Params.Add('User_Name=' + FDBUser);
|
|
if FDBPass <> '' then
|
|
DM.fdConnEtc.Params.Add('Password=' + FDBPass);
|
|
DM.fdConnEtc.Params.Add('CharacterSet=utf8mb4');
|
|
|
|
try
|
|
DM.fdConnEtc.Connected := True;
|
|
LogMessage('DB 연결 성공 (' + FDBHost + ')');
|
|
AddLog_Thread('DB 연결 성공 (' + FDBHost + ')');
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
LogMessage('DB 연결 실패: ' + E.Message);
|
|
AddLog_Thread('DB 연결 실패: ' + E.Message);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FormCreate(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
// Initialize LED data
|
|
for i := 0 to 14 do c_pIdata[i] := D_not;
|
|
c_pIdata[0] := 1; // 1-write, 0-read
|
|
c_pIdata[1] := 0; // type default
|
|
|
|
// 1. 로그 시스템 초기화
|
|
InitLogger(ExtractFilePath(Application.ExeName) + 'Logs', 'LEDAgent', rtDaily);
|
|
AddLog_Thread('=== LEDAgent 시작 ===');
|
|
|
|
// 2. INI 설정 로드
|
|
LoadSettings;
|
|
|
|
// 3. DB 연결
|
|
InitDB;
|
|
|
|
// 4. 폴링 타이머 가동 (1초=1000ms)
|
|
FPollingTimer := TTimer.Create(Self);
|
|
FPollingTimer.Interval := 1000;
|
|
FPollingTimer.OnTimer := OnPollingTimer;
|
|
FPollingTimer.Enabled := True;
|
|
end;
|
|
|
|
procedure TfrmMain.FormDestroy(Sender: TObject);
|
|
begin
|
|
if Assigned(FPollingTimer) then
|
|
begin
|
|
FPollingTimer.Enabled := False;
|
|
FPollingTimer.Free;
|
|
end;
|
|
|
|
if Assigned(DM) and DM.fdConnEtc.Connected then
|
|
DM.fdConnEtc.Close;
|
|
|
|
AddLog_Thread('=== LEDAgent 종료 ===');
|
|
StopLogger;
|
|
end;
|
|
|
|
procedure TfrmMain.OnPollingTimer(Sender: TObject);
|
|
var
|
|
SensorNo, DbLedPort: Integer;
|
|
DbLedIp: string;
|
|
T1, T2, T3: Integer;
|
|
IpParts: TArray<string>;
|
|
SendSuccess: Boolean;
|
|
i: Integer;
|
|
begin
|
|
FPollingTimer.Enabled := False; // 겹침 방지
|
|
try
|
|
if not DM.fdConnEtc.Connected then Exit;
|
|
|
|
DM.fdQryEtc.Close;
|
|
DM.fdQryEtc.SQL.Text :=
|
|
'SELECT sensor_no, target_ch1_statusID, target_ch2_statusID, target_ch3_statusID, led_ip, led_port ' +
|
|
'FROM sensor_info ' +
|
|
'WHERE sensor_typeid = 2 ' +
|
|
' AND (target_ch1_statusID != value_ch1_statusID ' +
|
|
' OR target_ch2_statusID != value_ch2_statusID ' +
|
|
' OR target_ch3_statusID != value_ch3_statusID) ' +
|
|
'LIMIT 1';
|
|
|
|
try
|
|
DM.fdQryEtc.Open;
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
AddLog_Thread('DB 폴링 에러: ' + E.Message);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if not DM.fdQryEtc.IsEmpty then
|
|
begin
|
|
SensorNo := DM.fdQryEtc.FieldByName('sensor_no').AsInteger;
|
|
T1 := DM.fdQryEtc.FieldByName('target_ch1_statusID').AsInteger; // Green
|
|
T2 := DM.fdQryEtc.FieldByName('target_ch2_statusID').AsInteger; // Yellow
|
|
T3 := DM.fdQryEtc.FieldByName('target_ch3_statusID').AsInteger; // Red
|
|
DbLedIp := DM.fdQryEtc.FieldByName('led_ip').AsString;
|
|
DbLedPort := DM.fdQryEtc.FieldByName('led_port').AsInteger;
|
|
if DbLedPort = 0 then DbLedPort := 20000;
|
|
|
|
LogMessage(Format('DB 명령 감지 - Sensor:%d, IP:%s (Target: G:%d Y:%d R:%d)', [SensorNo, DbLedIp, T1, T2, T3]));
|
|
AddLog_Thread(Format('DB 명령 감지 - Sensor:%d, IP:%s (Target: G:%d Y:%d R:%d)', [SensorNo, DbLedIp, T1, T2, T3]));
|
|
|
|
// 1. LED 전송용 데이터 배열 구성
|
|
for i := 0 to 14 do c_pIdata[i] := D_not;
|
|
c_pIdata[0] := 1; // write 모드
|
|
c_pIdata[1] := 0; // 모델 기본값
|
|
c_pIdata[7] := 0; // 사운드 끄기 기본
|
|
|
|
c_pIdata[4] := T1; // Green (2: Red, 3: Yellow, 4: Green)
|
|
c_pIdata[3] := T2; // Yellow
|
|
c_pIdata[2] := T3; // Red
|
|
|
|
// 2. IP 및 Port 준비 (DB 기준)
|
|
IpParts := DbLedIp.Split(['.']);
|
|
if Length(IpParts) = 4 then
|
|
begin
|
|
c_pIpadd[0] := StrToIntDef(IpParts[0], 192);
|
|
c_pIpadd[1] := StrToIntDef(IpParts[1], 168);
|
|
c_pIpadd[2] := StrToIntDef(IpParts[2], 200);
|
|
c_pIpadd[3] := StrToIntDef(IpParts[3], 114);
|
|
end;
|
|
|
|
// 3. DLL 호출하여 하드웨어 제어
|
|
SendSuccess := Tcp_Qu_RW(DbLedPort, c_pIpadd[0], c_pIdata[0]);
|
|
|
|
if SendSuccess then
|
|
begin
|
|
AddLog_Thread('하드웨어 제어 성공');
|
|
LogMessage('하드웨어 제어 성공');
|
|
|
|
// 4. DB 상태 갱신 (Handshake 완료)
|
|
DM.fdQryEtc.Close;
|
|
DM.fdQryEtc.SQL.Text :=
|
|
'UPDATE sensor_info ' +
|
|
'SET value_ch1_statusID = :v1, value_ch2_statusID = :v2, value_ch3_statusID = :v3 ' +
|
|
'WHERE sensor_no = :sno';
|
|
DM.fdQryEtc.ParamByName('v1').AsInteger := T1;
|
|
DM.fdQryEtc.ParamByName('v2').AsInteger := T2;
|
|
DM.fdQryEtc.ParamByName('v3').AsInteger := T3;
|
|
DM.fdQryEtc.ParamByName('sno').AsInteger := SensorNo;
|
|
DM.fdQryEtc.ExecSQL;
|
|
|
|
AddLog_Thread('DB 완료 갱신 (Handshake 종료)');
|
|
LogMessage('DB 반영 완료');
|
|
end
|
|
else
|
|
begin
|
|
AddLog_Thread('TCP/IP 제어 실패 (하드웨어 연결 확인)');
|
|
LogMessage('LED 통신 실패');
|
|
end;
|
|
end;
|
|
finally
|
|
FPollingTimer.Enabled := True;
|
|
end;
|
|
end;
|
|
|
|
//---------------------------------------------------------
|
|
// 기존 UI 매뉴얼 테스트 로직 (수동 테스트용 유지)
|
|
//---------------------------------------------------------
|
|
procedure TfrmMain.LogMessage(const Msg: string);
|
|
begin
|
|
lbStatus.Items.Insert(0, FormatDateTime('hh:nn:ss', Now) + ' ' + Msg);
|
|
end;
|
|
|
|
function TfrmMain.SendCommand: Boolean;
|
|
var
|
|
iPort: Integer;
|
|
begin
|
|
Result := False;
|
|
try
|
|
c_pIpadd[0] := StrToIntDef(edtIP1.Text, 192);
|
|
c_pIpadd[1] := StrToIntDef(edtIP2.Text, 168);
|
|
c_pIpadd[2] := StrToIntDef(edtIP3.Text, 200);
|
|
c_pIpadd[3] := StrToIntDef(edtIP4.Text, 114);
|
|
iPort := StrToIntDef(edtPort.Text, 20000);
|
|
|
|
c_pIdata[1] := rgModel.ItemIndex;
|
|
|
|
Result := Tcp_Qu_RW(iPort, c_pIpadd[0], c_pIdata[0]);
|
|
if Result then
|
|
LogMessage('[Success send]')
|
|
else
|
|
LogMessage('[Send Error]');
|
|
except
|
|
on E: Exception do
|
|
LogMessage('[Error] ' + E.Message);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.btnLampClick(Sender: TObject);
|
|
var
|
|
Btn: TButton;
|
|
ColorIdx: Integer;
|
|
Action: Integer;
|
|
i: Integer;
|
|
begin
|
|
for i := 2 to 6 do c_pIdata[i] := D_not;
|
|
c_pIdata[7] := D_not;
|
|
c_pIdata[0] := 1;
|
|
|
|
Btn := Sender as TButton;
|
|
|
|
if (Btn = btnRedOn) or (Btn = btnRedBlink) or (Btn = btnRedOff) then ColorIdx := 2
|
|
else if (Btn = btnYellowOn) or (Btn = btnYellowBlink) or (Btn = btnYellowOff) then ColorIdx := 3
|
|
else if (Btn = btnGreenOn) or (Btn = btnGreenBlink) or (Btn = btnGreenOff) then ColorIdx := 4
|
|
else if (Btn = btnBlueOn) or (Btn = btnBlueBlink) or (Btn = btnBlueOff) then ColorIdx := 5
|
|
else if (Btn = btnWhiteOn) or (Btn = btnWhiteBlink) or (Btn = btnWhiteOff) then ColorIdx := 6
|
|
else Exit;
|
|
|
|
if Btn.Caption = 'ON' then Action := C_lampon
|
|
else if Btn.Caption = 'ON/OFF' then Action := C_lampblink
|
|
else Action := C_lampoff;
|
|
|
|
c_pIdata[ColorIdx] := Action;
|
|
SendCommand;
|
|
end;
|
|
|
|
procedure TfrmMain.btnSoundClick(Sender: TObject);
|
|
var
|
|
Btn: TButton;
|
|
i: Integer;
|
|
begin
|
|
for i := 2 to 6 do c_pIdata[i] := D_not;
|
|
c_pIdata[0] := 1;
|
|
|
|
Btn := Sender as TButton;
|
|
if Btn = btnSoundOff then c_pIdata[7] := 0
|
|
else if Btn = btnSound1 then c_pIdata[7] := 1
|
|
else if Btn = btnSound2 then c_pIdata[7] := 2
|
|
else if Btn = btnSound3 then c_pIdata[7] := 3
|
|
else if Btn = btnSound4 then c_pIdata[7] := 4
|
|
else if Btn = btnSound5 then c_pIdata[7] := 5
|
|
else c_pIdata[7] := D_not;
|
|
|
|
SendCommand;
|
|
end;
|
|
|
|
procedure TfrmMain.btnStatReadClick(Sender: TObject);
|
|
var
|
|
iPort: Integer;
|
|
Success: Boolean;
|
|
StatusStr: string;
|
|
begin
|
|
try
|
|
c_pIpadd[0] := StrToIntDef(edtIP1.Text, 192);
|
|
c_pIpadd[1] := StrToIntDef(edtIP2.Text, 168);
|
|
c_pIpadd[2] := StrToIntDef(edtIP3.Text, 200);
|
|
c_pIpadd[3] := StrToIntDef(edtIP4.Text, 114);
|
|
iPort := StrToIntDef(edtPort.Text, 20000);
|
|
c_pIdata[0] := 0;
|
|
|
|
Success := Tcp_Qu_RW(iPort, c_pIpadd[0], c_pIdata[0]);
|
|
if Success then
|
|
begin
|
|
StatusStr := '[Read Success] ';
|
|
if c_pIdata[2] = 0 then StatusStr := StatusStr + 'R-OFF ' else if c_pIdata[2] = 1 then StatusStr := StatusStr + 'R-ON ' else if c_pIdata[2] = 2 then StatusStr := StatusStr + 'R-BLINK ';
|
|
if c_pIdata[3] = 0 then StatusStr := StatusStr + 'Y-OFF ' else if c_pIdata[3] = 1 then StatusStr := StatusStr + 'Y-ON ' else if c_pIdata[3] = 2 then StatusStr := StatusStr + 'Y-BLINK ';
|
|
if c_pIdata[4] = 0 then StatusStr := StatusStr + 'G-OFF ' else if c_pIdata[4] = 1 then StatusStr := StatusStr + 'G-ON ' else if c_pIdata[4] = 2 then StatusStr := StatusStr + 'G-BLINK ';
|
|
LogMessage(StatusStr);
|
|
end
|
|
else
|
|
LogMessage('[Read Error]');
|
|
except
|
|
on E: Exception do
|
|
LogMessage('[Error] ' + E.Message);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.btnResetClick(Sender: TObject);
|
|
begin
|
|
lbStatus.Clear;
|
|
end;
|
|
|
|
procedure TfrmMain.btnExitClick(Sender: TObject);
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
end.
|