⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 driveru.pas

📁 omroln OPC 用delphi描述了同OMROLnOPC通讯的过程
💻 PAS
📖 第 1 页 / 共 5 页
字号:
        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 + -