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

📄 driveru.pas

📁 omroln OPC 用delphi描述了同OMROLnOPC通讯的过程
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    FPortInfo: TCommPortInfo; //通信设备属性
    FOPCComm: TOPCComm; //通讯操作对象
    FDriveStatus: Integer; //通信设备状态
    FRefreshDataPnt: DWord; //查询数据
    FCommStateChkPnt: DWord; //通讯状态检查
    FCommAddress: string; //通讯端口的

    //用于后台调度的事件
    FInputHandler: TInputHandler; //接收端口数据到达事件通知对象
    FSendHandler: TInputHandler; //接收下发数据事件通知对象
    FSendEvent: THandle; //发送数据事件通知对象
    FLoopTimer: TTimerHandler; //轮询检测的定时器
    FWaitTimer: TTimerHandler; //等待应答的定时器
    FWaitCount: Integer; //等待应答次数
    FScheduler: TScheduler; //调度事件对象

    //发送数据缓冲区
    FWindow: TSlidingWindow; //发送数据滑动窗口
    FAddressParse: TAddressParse; //设备变量的寻址对象

    function GetPortId: DWord;
    function SendPktToComm(WriteData: Variant; Address: string): Boolean;
    procedure SetDriveStatus(Value: Integer);
    procedure CheckReSendTime;
    procedure NotifyToSendPkt;
    function SendApplicationFrm(Frm: TFrame): Boolean;
    function GeneralWriteData(const LocalIndex: Integer; Value: Variant;
      var Info: TAppDataInfo): Boolean;
  protected
    function SendNextDataPacket: Boolean;
    procedure ReceiveCommData;
    procedure QueryCommData;

    //有关事件调度的函数
    procedure StartInputHandler;
    procedure StartSendHandler;
    procedure StartLoopTimer;
    procedure StartWaitTimer;

    procedure StopInputHandler;
    procedure StopSendHandler;
    procedure StopLoopTimer;
    procedure StopWaitTimer;
  public
    constructor Create(PortInfo: TCommPortInfo);
    destructor Destroy; override;
    procedure EventCallback(EventId: Integer); override;
    procedure StartDriver; //启动驱动
    procedure StopDriver; //停止驱动
    function SendData(const LocalIndex: Integer; Value: Variant): Boolean;
  published
    property PortId: DWord read GetPortId;
    property Status: Integer read FDriveStatus;
    property CommAddress: string read FCommAddress;
  end;

  //通信设备列表类
  TDriverList = class(TObjectList)
  private
    FEvent: THandle;
    procedure FreeResource;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(const Driver: TDriver);
    procedure Delete(const Driver: TDriver);
    function GetDriver(const ID: DWord): TDriver;
    procedure StartDrivers;
    procedure StopDrivers;
    procedure SetTrgEvent;
    class function GetDriverList: TDriverList;
  published
    property Event: THandle read FEvent;
  end;

  function GetJobNo: Byte;

var
  gDriverList: TDriverList;
  gDeviceVarList: TDeviceVarList;
  gJobNo: Byte; //SCMS发送的任务号

implementation
{$IFDEF DEBUG}
uses
  OPC;
{$ENDIF}

//**************************************************************************
//                  类名:TAddressParse
//                  功能:设备变量地址解析
//**************************************************************************

{*
 *                函数名称:ItemIsNull
 *                函数功能:判断OPCITEM的名称是否为空
 *                入口参数:1、ItemName: string。 OPCITEM名称
 *                出口参数:无
 *                  返回值:True -- 该变量为空
 *}

function TAddressParse.ItemIsNull(ItemName: string): Boolean;
begin
  Result := False;
  if (Length(ItemName) = 0) or
    (AnsiPos(CONST_NULL_ITEMNAME, UpperCase(ItemName)) <> 0) then
    Result := True;
end;

{*
 *                函数名称:SplitValue
 *                函数功能:根据地址信息拆分出指定设备变量的数据
 *                入口参数:1、DeviceVar: TDeviceVar。设备变量
 *                          2、DataPkt: TDataPacket。数据
 *                出口参数:1、Value: Variant。拆分出的数据
 *                  返回值:True -- 该变量有数据
 *}

function TAddressParse.SplitValue(const DeviceVar: TDeviceVar; DataPkt: Variant;
  var Value: Variant): Boolean;
begin
  try
    case DeviceVar.AddressInfo.dwDataSort of
      Const_DataSort_Sta
      : Value := Integer(DataPkt);
      Const_DataSort_Num
      : Value := Integer(DataPkt);
      Const_DataSort_Chr
      : Value := String(DataPkt);
      Const_DataSort_Bln
      : Value := Integer(StrToBool(String(DataPkt)));
      else
        Value := DataPkt;
    end;
    Result := True;
  except
    WriteDebugLog('在SplitValue函数中,根据变量的类型进行类型转换时发生错误');
    Result := False;
  end;
end;

{*
 *                函数名称:FindItems
 *                函数功能:根据地址信息查找设备变量的索引信息
 *                入口参数:1、Addr: TAddressInfo。设备变量地址信息
 *                出口参数:无
 *                  返回值:TIntegerArray。设备变量索引数组
 *}

function TAddressParse.FindItems(Addr: TAddressInfo): TIntegerArray;
var
  I, J, K: Integer;
begin
  SetLength(Result, 0);
  for I := 0 to High(FReadListInfos) do
  begin
    for J := 0 to High(FReadListInfos[I].rcdReadInfo) do
    begin
      if AnsiCompareText(Addr.dwReadItem, FReadListInfos[I].rcdReadInfo[J].szItemName) = 0 then
      begin
        SetLength(Result, Length(FReadListInfos[I].rcdReadInfo[J].arrVarList));
        for K := 0 to High(FReadListInfos[I].rcdReadInfo[J].arrVarList) do
          Result[K] := FReadListInfos[I].rcdReadInfo[J].arrVarList[K];
        Exit;
      end;
    end;
  end;
end;

{*
 *                函数名称:FindCommErrorItems
 *                函数功能:获得与指定通信端口关联的设备通信故障变量索引
 *                入口参数:无
 *                出口参数:无
 *                  返回值:TIntegerArray。设备变量索引数组
 *}

function TAddressParse.FindCommErrorItems: TIntegerArray;
var
  I, Count: Integer;
begin
  Count := Length(FCommErrorInfos);
  SetLength(Result, Count);
  for I := 0 to Count - 1 do
    Result[I] := FCommErrorInfos[I].dwLocalIndex;
end;

{*
 *                函数名称:FindRTUCommErrorItems
 *                函数功能:查找指定RTU连接设备通信故障变量索引
 *                入口参数:无
 *                出口参数:无
 *                  返回值:TIntegerArray。设备变量索引数组
 *}

function TAddressParse.FindRTUCommErrorItems(RTUNo: DWord): TIntegerArray;
var
  I, Count: Integer;
begin
  Count := Length(FCommErrorInfos);
  SetLength(Result, 0);
  for I := 0 to Count - 1 do
  begin
    if (FCommErrorInfos[I].rcdAddress.dwRTUNo = RTUNo) then
    begin
      SetLength(Result, Length(Result) + 1);
      Result[High(Result)] := FCommErrorInfos[I].dwLocalIndex;
    end;
  end;
end;

{*
 *                函数名称:Create
 *                函数功能:构造函数
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

constructor TAddressParse.Create; 
begin
  InitializeCriticalSection(FLock);
  FRTUFaultList := TList.Create;
  SetLength(FSCMSFaultList, 0);
  SetLength(FCommErrorInfos, 0);
  SetLength(FNormalInfos, 0);
end;

{*
 *                函数名称:Destroy
 *                函数功能:析构函数
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

destructor TAddressParse.Destroy;
begin
  FNormalInfos := nil;
  FCommErrorInfos := nil;
  FSCMSFaultList := nil;
  FRTUFaultList.Free;
  DeleteCriticalSection(FLock);
  inherited;
end;

{*
 *                函数名称:AddInfo
 *                函数功能:增加设备变量的寻址信息
 *                入口参数:1、Info: TAddressParseInfo。设备变量运行信息
 *                出口参数:无
 *                  返回值:无
 *}

function TAddressParse.AddInfo(Info: TAddressParseInfo): Integer;
var
  I: Integer;
  FindIt: Boolean;
  WriteInfo: TWriteInfo;
begin
  EnterCriticalSection(FLock);
  try
    Result := -1;
    if Info.rcdAddress.dwDataType = Const_Type_CommErr then //通信故障的功能组
    begin
      SetLength(FCommErrorInfos, Length(FCommErrorInfos) + 1);
      FCommErrorInfos[High(FCommErrorInfos)] := Info;
      Result := -High(FNormalInfos);
    end;
    if not ItemIsNull(Info.rcdAddress.dwReadItem) then
    begin
      //将设备变量的读地址信息添加到数组中
      SetLength(FNormalInfos, Length(FNormalInfos) + 1);
      FNormalInfos[High(FNormalInfos)] := Info;
      Result := High(FNormalInfos);
    end;
    if ItemIsNull(Info.rcdAddress.dwReadItem) then
    begin
      Result := -High(Integer);
    end;

    //将有效的OPCITEM名称加入列表中
    FindIt := False;
    if not ItemIsNull(Info.rcdAddress.dwReadItem) then
    begin
      for I := 0 to High(FItemNameList) do
      begin
        if AnsiCompareText(FItemNameList[I], Info.rcdAddress.dwReadItem) = 0 then
        begin
          FindIt := True;
          Break;
        end;
      end;

      if not FindIt then
      begin
        SetLength(FItemNameList, Length(FItemNameList) + 1);
        FItemNameList[High(FItemNameList)] := Info.rcdAddress.dwReadItem;
      end;
    end;

    //将有效的OPCITEM名称加入列表中
    FindIt := False;
    if not ItemIsNull(Info.rcdAddress.dwWriteItem) then
    begin
      for I := 0 to High(FItemNameList) do
      begin
        if AnsiCompareText(FItemNameList[I], Info.rcdAddress.dwWriteItem) = 0 then
        begin
          FindIt := True;
          Break;
        end;
      end;

      if not FindIt then
      begin
        SetLength(FItemNameList, Length(FItemNameList) + 1);
        FItemNameList[High(FItemNameList)] := Info.rcdAddress.dwWriteItem;
      end;
    end;

    //判断变量是否需要定时下发
    if (Info.rcdAddress.dwFuncGroup = Const_FG_SYSTEM) and
      (Info.rcdAddress.dwDataType = Const_Type_RTUCommCheck) then
    begin
      if ItemIsNull(Info.rcdAddress.dwWriteItem) then
        Exit;

      FindIt := False;
      for I := 0 to High(FAutoWriteInfos) do
      begin
        if AnsiCompareText(FAutoWriteInfos[I].szItemName, Info.rcdAddress.dwWriteItem) = 0 then
        begin
          FindIt := True;
          Break;
        end;
      end;

      if FindIt then
        Exit;

      WriteInfo.szItemName := Info.rcdAddress.dwWriteItem;
      WriteInfo.dwWriteSample := Info.rcdAddress.dwSampleTime * 1000;
      WriteInfo.dwPriorWrite := 0;
      WriteInfo.dwWriteValue := 0;
      SetLength(FAutoWriteInfos, Length(FAutoWriteInfos) + 1);
      FAutoWriteInfos[High(FAutoWriteInfos)] := WriteInfo;
    end;
  finally
    LeaveCriticalSection(FLock);
  end;
end;

{*
 *                函数名称:GetItemNameList
 *                函数功能:获得数据项名称的列表
 *                入口参数:无
 *                出口参数:无
 *                  返回值:数据项名称列表
 *}

function TAddressParse.GetItemNameList: TStringArray;
var
  I: Integer;
begin
  SetLength(Result, Length(FItemNameList));
  for I := 0 to High(FItemNameList) do
    Result[I] := FItemNameList[I];
end;

{*
 *                函数名称:FinishedAdd
 *                函数功能:完成添加设备变量的寻址信息
 *                          1、根据设备变量寻址信息中的读地址进行排序
 *                          2、根据设备变量的寻址信息生成采样周期判定数组
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TAddressParse.FinishedAdd;
var
  FindIt: Boolean;
  ReadInfo: TReadInfo;
  I, J, K, Idx, Count: Integer;
begin
  EnterCriticalSection(FLock);
  try
    SetLength(FReadListInfos, 0);
    Count := Length(FNormalInfos);
    if Count = 0 then
      Exit;

    for I := 0 to Count - 1 do
    begin
      //判断处理的变量是否需要主动查询
      if ItemIsNull(FNormalInfos[I].rcdAddress.dwReadItem) then

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -