?? driveru.pas
字號:
Continue;
//獲得需要主動查詢的信息
ReadInfo.szItemName := FNormalInfos[I].rcdAddress.dwReadItem;
ReadInfo.dwReadSample := FNormalInfos[I].rcdAddress.dwSampleTime * 1000; //采集周期為毫秒
ReadInfo.dwPriorRead := GetTickCount; //上一讀取周期的時間
SetLength(ReadInfo.arrVarList, 1); //與該OPCITEM關聯的設備變量的索引信息
ReadInfo.arrVarList[0] := FNormalInfos[I].dwLocalIndex;
//查找變量所在的RTU編號
Idx := -1;
FindIt := False;
for J := 0 to High(FReadListInfos) do
begin
if FReadListInfos[J].dwRTUNo = FNormalInfos[I].rcdAddress.dwRTUNo then
begin
FindIt := True;
Idx := J;
Break;
end;
end;
//不存在則添加一個RTU編號
if not FindIt then
begin
SetLength(FReadListInfos, Length(FReadListInfos) + 1);
FReadListInfos[High(FReadListInfos)].dwRTUNo := FNormalInfos[I].rcdAddress.dwRTUNo;
FReadListInfos[High(FReadListInfos)].bCommState := True;
SetLength(FReadListInfos[High(FReadListInfos)].rcdReadInfo, 0);
Idx := High(FReadListInfos);
end;
//過濾掉FReadListInfos中存在的變量描述
FindIt := False;
for J := 0 to High(FReadListInfos) do //查找的第一層(RTU層)
begin
for K := 0 to High(FReadListInfos[J].rcdReadInfo) do //查找的第二層(變量信息)
begin
if AnsiCompareText(FReadListInfos[J].rcdReadInfo[K].szItemName, ReadInfo.szItemName) = 0 then
begin
//更新關聯設備變量的索引信息
FindIt := True;
SetLength(FReadListInfos[J].rcdReadInfo[K].arrVarList, Length(FReadListInfos[J].rcdReadInfo[K].arrVarList) + 1);
FReadListInfos[J].rcdReadInfo[K].arrVarList[High(FReadListInfos[J].rcdReadInfo[K].arrVarList)] := FNormalInfos[I].dwLocalIndex;
Break;
end;
end;
if FindIt then
Break;
end;
//如果沒有找到
if not FindIt then
begin
//將ReadInfo信息加入到FReadInfo中
SetLength(FReadListInfos[Idx].rcdReadInfo, Length(FReadListInfos[Idx].rcdReadInfo) + 1);
FReadListInfos[Idx].rcdReadInfo[High(FReadListInfos[Idx].rcdReadInfo)] := ReadInfo;
SetLength(FReadListInfos[Idx].rcdReadInfo[High(FReadListInfos[Idx].rcdReadInfo)].arrVarList, 1);
FReadListInfos[Idx].rcdReadInfo[High(FReadListInfos[Idx].rcdReadInfo)].arrVarList[0] := ReadInfo.arrVarList[0];
end;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
{*
* 函數名稱:SetCommState
* 函數功能:通知該通信端口的所有通信狀態類型的設備變量
* 并改變這些設備變量的數據
* 入口參數:1、State: Boolean。通信狀態
* True -- 通信正常;False -- 通信中斷
* 出口參數:無
* 返回值:無
*}
procedure TAddressParse.SetCommState(State: Boolean);
var
I: Integer;
Data: Integer;
Infos: TIntegerArray;
DeviceVar: TDeviceVar;
begin
EnterCriticalSection(FLock);
try
//根據通信狀態判斷要設置的數值
if State then
Data := Const_Value_CommNormal
else
Data := Const_Value_CommError;
Infos := FindCommErrorItems;
for I := Low(Infos) to High(Infos) do
begin
DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(Infos[I]);
if Assigned(DeviceVar) then
DeviceVar.RecvData(Data, Now);
end;
finally
LeaveCriticalSection(FLock);
end;
end;
{*
* 函數名稱:SetRecvData
* 函數功能:根據接收到的數據報文設置相關設備變量的數據
* 1、將接收的地址信息轉換為設備變量的索引信息
* 2、根據設備變量的類型從接收數據中取出有用的數據
* 入口參數:1、AppDatas: TAppDataInfoArray。從報文中分析出的DT塊信息
* 出口參數:無
* 返回值:無
*}
procedure TAddressParse.SetRecvData(AppDataInfo: TAppDataInfo);
var
I: Integer;
DeviceVar: TDeviceVar;
ReadValue: Variant;
VarList: TIntegerArray;
begin
EnterCriticalSection(FLock);
try
VarList := FindItems(AppDataInfo.rcdAddress);
for I := Low(VarList) to High(VarList) do
begin
DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(VarList[I]);
if Assigned(DeviceVar) then
begin
if SplitValue(DeviceVar, AppDataInfo.AppData, ReadValue) then
begin
DeviceVar.RecvData(ReadValue, AppDataInfo.dtDateTime);
try
if (DeviceVar.AddressInfo.dwFuncGroup = Const_FG_SYSTEM) and
(DeviceVar.AddressInfo.dwDataType = Const_Type_RTUCommState) then
SetRTUFault(DeviceVar.AddressInfo.dwRTUNo, (ReadValue = Const_RTUCOMM_NORMAL));
except
end;
end;
end;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
{*
* 函數名稱:SetRTUFault
* 函數功能:設置RTU故障信息
* 入口參數:1、RTUNo: DWord。RTU編號
* 2、CommState: Boolean。通訊狀態。TRUE-正常
* 出口參數:無
* 返回值:無
*}
procedure TAddressParse.SetRTUFault(RTUNo: DWord; CommState: Boolean);
var
I: Integer;
Value: Variant;
ValueDate: TDateTime;
DeviceVar: TDeviceVar;
VarIndexs: TIntegerArray;
FindIt, OpFlag: Boolean;
begin
EnterCriticalSection(FLock);
try
//初始化變量
FindIt := False;
OpFlag := False;
SetLength(VarIndexs, 0);
//首先維護RTU故障列表
for I := 0 to FRTUFaultList.Count - 1 do
begin
if DWord(FRTUFaultList.Items[I]) = RTUNo then
begin
FindIt := True;
Break;
end;
end;
if FindIt and CommState then
begin
FRTUFaultList.Remove(Pointer(RTUNo));
OpFlag := True;
end;
if (Not FindIt) and (not CommState) then
begin
FRTUFaultList.Add(Pointer(RTUNo));
OpFlag := True;
end;
if not OpFlag then
Exit;
//設置查詢列表中的RTU故障,這樣就不再輪循該地址的數據
for I := 0 to High(FReadListInfos) do
begin
if FReadListInfos[I].dwRTUNo = RTUNo then
begin
FReadListInfos[I].bCommState := CommState;
Break;
end;
end;
//查詢該RTU下的所有通訊故障變量,通知系統設備故障
ValueDate := Now;
VarIndexs := FindRTUCommErrorItems(RTUNo);
for I := Low(VarIndexs) to High(VarIndexs) do
begin
DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(VarIndexs[I]);
if Assigned(DeviceVar) then
begin
if CommState then //通訊正常后,應結合設備的實際狀態綜合判斷
begin
Value := Integer(Const_Value_CommNormal);
if not ItemIsNull(DeviceVar.AddressInfo.dwReadItem) then //能夠獲得通訊故障的采集點
begin
if not VarIsEmpty(DeviceVar.FLastRecvData) then
Value := Value or DeviceVar.FLastRecvData;
end;
end
else begin
Value := Integer(Const_Value_CommError);
end;
DeviceVar.RecvData(Value, ValueDate);
end;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
{*
* 函數名稱:GetQueryData
* 函數功能:獲得需要讀取數據的設備變量信息
* 1、系統根據各個設備變量的
* 入口參數:無
* 出口參數:1、AddrInfos: TAddressInfoArray。
* 返回值:無
*}
procedure TAddressParse.GetQueryData(var ReadInfos: TReadInfoArray);
var
I, J: Integer;
ReadInfo: TReadInfo;
begin
EnterCriticalSection(FLock);
try
SetLength(ReadInfos, 0);
for I := 0 to High(FReadListInfos) do
begin
if not FReadListInfos[I].bCommState then
Continue;
for J := 0 to High(FReadListInfos[I].rcdReadInfo) do
begin
ReadInfo := FReadListInfos[I].rcdReadInfo[J];
if ReadInfo.dwReadSample = 0 then
Continue;
if (ReadInfo.dwPriorRead = 0) or (GetTimeInterval(ReadInfo.dwPriorRead) >= ReadInfo.dwReadSample) then //達到采集周期
begin
FReadListInfos[I].rcdReadInfo[J].dwPriorRead := GetTickCount;
SetLength(ReadInfos, Length(ReadInfos) + 1);
ReadInfos[High(ReadInfos)] := ReadInfo;
end;
end;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
{*
* 函數名稱:GetWriteData
* 函數功能:獲得需要下發數據的設備變量信息
* 1、系統根據各個設備變量的
* 入口參數:無
* 出口參數:1、WriteInfos: TWriteInfoArray。下發數據列表
* 返回值:無
*}
procedure TAddressParse.GetWriteData(var WriteInfos: TWriteInfoArray);
var
I: Integer;
WriteInfo: TWriteInfo;
begin
EnterCriticalSection(FLock);
try
SetLength(WriteInfos, 0);
for I := 0 to High(FAutoWriteInfos) do
begin
WriteInfo := FAutoWriteInfos[I];
if (WriteInfo.dwPriorWrite = 0) or (GetTimeInterval(WriteInfo.dwPriorWrite) >= WriteInfo.dwWriteSample) then //達到采集周期
begin
WriteInfo.dwPriorWrite := GetTickCount;
if (WriteInfo.dwWriteValue + 1) > High(WriteInfo.dwWriteValue) then
WriteInfo.dwWriteValue := 0
else
WriteInfo.dwWriteValue := WriteInfo.dwWriteValue + 1;
FAutoWriteInfos[I] := WriteInfo;
SetLength(WriteInfos, Length(WriteInfos) + 1);
WriteInfos[High(WriteInfos)] := WriteInfo;
end;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
//**************************************************************************
// 類名:TDriver
// 功能:通信設備對象
//**************************************************************************
{*
* 函數名稱:GetPortId
* 函數功能:查詢通信端口的編號
* 入口參數:無
* 出口參數:無
* 返回值:DWord。通信端口編號
*}
function TDriver.GetPortId: DWord;
begin
Result := FPortInfo.dwCommPortId;
end;
{*
* 函數名稱:SendPktToComm
* 函數功能:向通訊端口發送數據
* 入口參數:1、WriteData: Variant。數據包
* 3、Address: DWord。發送地址
* 出口參數:無
* 返回值:Boolean。True -- 發送成功
*}
function TDriver.SendPktToComm(WriteData: Variant; Address: string): Boolean;
begin
try
{$IFDEF DEBUG}
FrmOPC.AddPacket(Format('<--: 地址(%s). 數據(%s).', [Address, String(WriteData)]));
WriteDebugLog(Format('<--: 服務(%s). 地址(%s). 數據(%s).', [FOPCComm.MachineName, Address, String(WriteData)]));
{$ENDIF}
Result := FOPCComm.SendData(Address, WriteData);
if not Result then
SetDriveStatus(COMM_STATUS_DISCONNECT);
except
Result := False;
end;
end;
{*
* 函數名稱:SetDriveStatus
* 函數功能:設置通信端口狀態
* 通知與該通信端口關聯的所有通信狀態類型的設備變量
* 入口參數:1、Value: Integer。通信端口狀態
* 出口參數:無
* 返回值:無
*}
procedure TDriver.SetDriveStatus(Value: Integer);
begin
if FDriveStatus <> Value then
begin
FDriveStatus := Value;
//設置通信狀態類型的設備變量
FAddressParse.SetCommState((FDriveStatus = COMM_STATUS_Connected));
//根據更新的狀態進行相應的處理
if FDriveStatus <> COMM_STATUS_Connected then
FWindow.Reset; //刪除FWindow中所有未發送報文
//Add 2003/11/16
TDriverList.GetDriverList.SetTrgEvent;
//End Add
end;
end;
{*
* 函數名稱:SendApplicationFrm
* 函數功能:發送應用數據報文
* 入口參數:Frm: TFrame
* 出口參數:無
* 返回值:True -- 發送成功
*}
function TDriver.SendApplicationFrm(Frm: TFrame): Boolean;
begin
EnterCriticalSection(FSyncObj);
try
FWindow.AddFrame(Frm);
NotifyToSendPkt;
Result := True;
finally
LeaveCriticalSection(FSyncObj);
end;
end;
{*
* 函數名稱:GeneralWriteData
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -