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

📄 driveru.pas

📁 omroln OPC 用delphi描述了同OMROLnOPC通讯的过程
💻 PAS
📖 第 1 页 / 共 5 页
字号:
 *                函数功能:根据设备变量编号和索引查找地址信息并生成发送数据
 *                入口参数:1、LocalIndex: Integer。地址索引信息
 *                          2、Value: Variant。发送数据
 *                出口参数:1、Info: TAppDataInfo。应用数据信息
 *                  返回值:Boolean。执行情况
 *}

function TDriver.GeneralWriteData(const LocalIndex: Integer;
  Value: Variant; var Info: TAppDataInfo): Boolean;
var
  DeviceVar: TDeviceVar;
  Data: string;
begin
  Result := False;
  DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(LocalIndex);
  if not Assigned(DeviceVar) then
  begin
    WriteErrorLog(Format('下发数据时发生错误!地址索引无效!(%d)', [LocalIndex]));
    Exit;
  end;

  Data := Value;
  Info.dwLocalIndex := LocalIndex;
  Info.rcdAddress := DeviceVar.AddressInfo;
  Info.AppData := Data;
  Info.dtDateTime := Now;
  Result := True;
end;

{*
 *                函数名称:CheckReSendTime
 *                函数功能:检查发送数据超时
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.CheckReSendTime;
var
  I: Integer;
  VarList: TIntegerArray;
  ItemNames: TStringArray;
  DeviceVar: TDeviceVar;
begin
  //超过一定时间没有读写操作则尝试查询
  if GetTimeInterval(FRefreshDataPnt) >= Const_TIME_REFRESHDATA then
  begin
    FRefreshDataPnt := GetTickCount;
    FOPCComm.RefershData;
  end;

  //检查通讯是否中断, 中断后则尝试重新打开端口
  if FOPCComm.CommStatus = Const_STATUS_DISCONNECT then
  begin
    ComObj.CoInitializeEx(nil, 0);
    FOPCComm.StopComm;
    FOPCComm.StartComm;
    FOPCComm.RefershData;
  end;

  //超过规定的期限则认为通讯中断
  if GetTimeInterval(FCommStateChkPnt) >= Const_TIME_COMMFAILED then
  begin
    FCommStateChkPnt := GetTickCount;
    SetDriveStatus(COMM_STATUS_DISCONNECT);
  end;

  //先获得发送数据帧列表
  SetLength(VarList, 0);

  //获得超时设备变量索引列表 和 地址列表
  VarList := FWindow.ProcessSendTimeOut(ItemNames);

  //根据设备变量索引编号设置发送失败
  for I := Low(VarList) to High(VarList) do
  begin
    DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(VarList[I]);
    if Assigned(DeviceVar) then
      DeviceVar.SetState(ITEM_STATUS_SendFailed);
    NotifyToSendPkt;
  end;
end;

{*
 *                函数名称:NotifyToSendPkt
 *                函数功能:通知调度对象发送数据
 *                          1、设置FSendEvent对象为有信号状态
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.NotifyToSendPkt;
begin
  SetEvent(FSendEvent);
end;

{*
 *                函数名称:SendNextDataPacket
 *                函数功能:从发送队列中取出一个数据,发送
 *                          1、发送成功
 *                             如果是无应答数据帧,则认定发送任务成功
 *                             如果是应答数据帧,则等待接收数据
 *                          2、发送失败
 *                             如果是无应答数据帧,则认定发送任务失败
 *                             如果是应答数据帧,则认定发送任务失败
 *                入口参数:无
 *                出口参数:无
 *                  返回值:True -- 发送成功
 *}

function TDriver.SendNextDataPacket: Boolean;
var
  Frm: TFrame;
  DeviceVar: TDeviceVar;
begin
  Result := False;
  Frm := FWindow.GetNextFrame;
  if Assigned(Frm) then
  begin
    Frm.FormFrame;
    Result := SendPktToComm(Frm.DataPacket, Frm.ItemName);
    if Result then //发送成功
    begin
      if (not Frm.NeedAck) and (Frm.LocalIndex >= 0) then
      begin
        DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(Frm.LocalIndex);
        if Assigned(DeviceVar) then
          DeviceVar.SetState(ITEM_STATUS_SendSuccess);
      end;
    end
    else begin //发送失败,则根据错误码判断通讯中断
      FWindow.ProcessSendFailed(Frm);
      if (Frm.LocalIndex >= 0) then
      begin
        DeviceVar := TDeviceVarList.GetDeviceVarList.GetItem(Frm.LocalIndex);
        if Assigned(DeviceVar) then
          DeviceVar.SetState(ITEM_STATUS_SendFailed);
      end;
    end;
    NotifyToSendPkt;
  end;
end;

{*
 *                函数名称:QueryCommData
 *                函数功能:主动查询变量数据
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.QueryCommData;
var
  I, Count: Integer;
  ItemName: string;
  SendValue: Variant;
  ItemNames: TStringArray;
  ReadInfos: TReadInfoArray;
  WriteInfos: TWriteInfoArray;
begin
  //获得当前所有可以读取的模拟量OPCITEM信息
  SetLength(ReadInfos, 0);
  SetLength(WriteInfos, 0);
  
  FAddressParse.GetQueryData(ReadInfos);
  Count := Length(ReadInfos);
  if Count > 0 then
  begin
    SetLength(ItemNames, 0);
    for I := 0 to Count - 1 do
    begin
      if FAddressParse.ItemIsNull(ReadInfos[I].szItemName) then
        Continue;
      SetLength(ItemNames, Length(ItemNames) + 1);
      ItemNames[High(ItemNames)] := ReadInfos[I].szItemName;
    end;
    FOPCComm.QueryData(ItemNames);
  end;
  
  //查询要自动下发的数据,并指定下发
  FAddressParse.GetWriteData(WriteInfos);
  Count := Length(WriteInfos);
  if Count > 0 then
  begin
    for I := 0 to Count - 1 do
    begin
      if FAddressParse.ItemIsNull(WriteInfos[I].szItemName) then
        Continue;

      ItemName := WriteInfos[I].szItemName;
      SendValue := WriteInfos[I].dwWriteValue;
      FOPCComm.SendData(ItemName, SendValue);
    end;
  end;
end;

{*
 *                函数名称:ReceiveCommData
 *                函数功能:从通讯端口读取数据
 *                          获得当前所有可以读取的地址信息
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.ReceiveCommData;
var
  ItemName: string; //数据项名称
  ItemTime: TDateTime; //采集时间
  ItemValue: Variant; //数据项的数值
  AddrInfo: TAddressInfo;
  AppDataInfo: TAppDataInfo;
begin
  if not FOPCComm.ReadData(ItemName, ItemValue, ItemTime) then
    Exit;

  SetDriveStatus(COMM_STATUS_CONNECTED);
  FRefreshDataPnt := GetTickCount;
  FCommStateChkPnt := GetTickCount;
  
  {$IFDEF DEBUG}
  FrmOPC.AddPacket(Format('-->: 地址(%s). 数据(%s).', [ItemName, String(ItemValue)]));
  WriteDebugLog(Format('-->: 服务(%s). 地址(%s). 数据(%s).', [FOPCComm.MachineName, ItemName, String(ItemValue)]));
  {$ENDIF}
  
  AddrInfo.dwReadItem := ItemName;
  AppDataInfo.rcdAddress := AddrInfo;
  AppDataInfo.AppData := ItemValue;
  AppDataInfo.dtDateTime := ItemTime;
  try
    FAddressParse.SetRecvData(AppDataInfo);
  except
    WriteDebugLog('sss');
  end;
end;

{*
 *                函数名称:StartInputHandler
 *                函数功能:创建端口数据到达事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StartInputHandler;
begin
  if Assigned(FInputHandler) then
    Exit;

  FInputHandler := TInputHandler.Create(Self, Self);
  FInputHandler.InitEvent(FOPCComm.ReadEvent, Const_Event_RecvDataInd);
  FScheduler.AddEventHandler(FInputHandler);
end;

{*
 *                函数名称:StartSendHandler
 *                函数功能:创建发送数据事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StartSendHandler;
begin
  if Assigned(FSendHandler) then
    Exit;

  FSendEvent := CreateEvent(nil, False, False, '');
  FSendHandler := TInputHandler.Create(Self, Self);
  FSendHandler.InitEvent(FSendEvent, Const_Event_SendDataReq);
  FScheduler.AddEventHandler(FSendHandler);
end;

{*
 *                函数名称:StartLoopTimer
 *                函数功能:启动定时读数事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StartLoopTimer;
begin
  FLoopTimer := TTimerHandler.Create(Self, Self);
  FLoopTimer.InitEvent(Const_Event_LoopCheck, grcdDriverInfo.dwSampleTime, True);
  FScheduler.AddEventHandler(FLoopTimer);
end;

{*
 *                函数名称:StartWaitTimer
 *                函数功能:启动发送超时检查事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StartWaitTimer;
begin
  FWaitTimer := TTimerHandler.Create(Self, Self);
  FWaitTimer.InitEvent(Const_Event_WaitAnswer, Const_FrameSendTimeOut, True);
  FScheduler.AddEventHandler(FWaitTimer);
end;

{*
 *                函数名称:StopInputHandler
 *                函数功能:释放端口数据到达事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StopInputHandler;
begin
  if not Assigned(FInputHandler) then
    Exit;

  FInputHandler.SetMarked;
  FInputHandler := nil;
end;

{*
 *                函数名称:StopSendHandler
 *                函数功能:释放发送数据事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StopSendHandler;
begin
  if not Assigned(FSendHandler) then
    Exit;

  FSendHandler.SetMarked;
  FSendHandler := nil;
  CloseHandle(FSendEvent);
end;

{*
 *                函数名称:StopLoopTimer
 *                函数功能:停止轮询检查事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StopLoopTimer;
begin
  try
    if Assigned(FLoopTimer) then
    begin
      FLoopTimer.SetMarked;
      FLoopTimer := nil;
    end;
  except
    WriteDebugLog('停止轮询读数事件失败!');
  end;
end;

{*
 *                函数名称:StopWaitTimer
 *                函数功能:停止发送超时检查事件
 *                入口参数:无
 *                出口参数:无
 *                  返回值:无
 *}

procedure TDriver.StopWaitTimer;
begin
  try
    if Assigned(FWaitTimer) then
    begin
      FWaitTimer.SetMarked;
      FWaitTimer := nil;
      FWaitCount := 0;
    end;
  except
    WriteDebugLog('停止超时定时事件失败!');
  end;
end;

{*
 *                函数名称:Create
 *                函数功能:构造函数
 *                入口参数:1、PortInfo: TCommPortInfo。通信端口参数
 *                出口参数:无
 *                  返回值:无
 *}

constructor TDriver.Create(PortInfo: TCommPortInfo);
var
  Param: TCommParam;
begin
  //初始化属性
  FPortInfo := PortInfo;
  FDriveStatus := COMM_STATUS_UnKnown;

⌨️ 快捷键说明

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