📄 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 + -