📄 driveru.pas
字号:
{*
* 模块名称:OPC.OMRON设备驱动程序的处理模块
* 模块功能:实现与外场设备的数据交互、协议解析
* 生成日期:2004/11/05
* 模块作者:李杰
* 版本说明:1.0版
*}
unit DriverU;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Contnrs, Variants, Math, ExtCtrls, ComObj,
DrvIntfDefinesU, PubDefinesU, EventLogU, CommU;
const
//**************** 接口定义 ********************
gsDriverGUID = '{B66EE5D7-4152-4E47-9B67-2A68E638C388}'; //驱动的标识
gsModuleName = 'OPC.OMRON驱动程序'; //DLL的描述
grcdDriverInfo: TDriverInfo = (cbSize: SizeOf(TDriverInfo);
szDriverName: gsModuleName; szDriverVer: '1.0'; szDriverDesc: gsModuleName;
szDriverGUID: gsDriverGUID; szFileName: 'OPC.DRV';
szCommPortParam: 'O:MachineName;ServerName;GroupName';
szCommPortParamDesc: 'O:[机器名];[OPC服务名];[分组名]';
szVariantParamDesc: '[RTU编号]+[读变量]+[写变量]';
szAddressConfigDesc: '[变量前缀]';
dwSampleTime: 1000; dwSyncTime: 0);
gCommPortAddressItemNumber = 1; //设备的地址信息
gDriverVariantItemNumber = 7; //设备变量中属性元素的个数(RTU编号 + 读变量 + 写变量)
//szVariantParam参数说明(例:1+52+1+1 功能组+数据类型+采集周期+数据种类)
//数据种类: 状态-1、 数值-2、字符串-3
grcdDriverVariantInfo: array[0..46] of TDriverVarInfo = (
//(车辆检测器)
(dwVariantId:90010001; szVariantDesc:'VD车流量'; szVariantParam:'001+052+60+02'),
(dwVariantId:90010002; szVariantDesc:'VD平均车速'; szVariantParam:'001+053+60+02'),
(dwVariantId:90010003; szVariantDesc:'VD占有率'; szVariantParam:'001+054+60+02'),
(dwVariantId:90011001; szVariantDesc:'VD故障'; szVariantParam:'001+001+00+01'),
(dwVariantId:90011002; szVariantDesc:'VD通信故障'; szVariantParam:'001+099+00+01'),
//(可变情报板)
(dwVariantId:90030001; szVariantDesc:'CSLS播放表'; szVariantParam:'004+047+00+03'),
(dwVariantId:90030002; szVariantDesc:'CMS播放表'; szVariantParam:'004+048+00+03'),
(dwVariantId:90030003; szVariantDesc:'开屏'; szVariantParam:'004+049+00+01'),
(dwVariantId:90030004; szVariantDesc:'关屏'; szVariantParam:'004+050+00+01'),
(dwVariantId:90031001; szVariantDesc:'控制器故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031002; szVariantDesc:'显示模组故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031003; szVariantDesc:'显示模组电源故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031004; szVariantDesc:'单像素管故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031005; szVariantDesc:'检测系统故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031006; szVariantDesc:'输入交流电故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031007; szVariantDesc:'防雷器故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031008; szVariantDesc:'光敏部件故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031009; szVariantDesc:'温度异常故障'; szVariantParam:'004+001+20+01'),
(dwVariantId:90031010; szVariantDesc:'CMS通信故障'; szVariantParam:'004+099+00+01'),
//(照明控制系统)
(dwVariantId:90040001; szVariantDesc:'光照强度数据'; szVariantParam:'194+048+60+02'),
(dwVariantId:90040002; szVariantDesc:'照明操作模式'; szVariantParam:'194+017+00+01'),
(dwVariantId:90040003; szVariantDesc:'照明控制级别'; szVariantParam:'194+065+00+01'),
(dwVariantId:90040004; szVariantDesc:'照明工作模式'; szVariantParam:'194+018+00+01'),
(dwVariantId:90041001; szVariantDesc:'照明设备自检故障'; szVariantParam:'194+001+00+01'),
(dwVariantId:90041002; szVariantDesc:'照明设备通信故障'; szVariantParam:'194+099+00+01'),
//(通风控制系统)
(dwVariantId:90050001; szVariantDesc:'通风操作模式'; szVariantParam:'195+017+00+01'),
(dwVariantId:90050002; szVariantDesc:'一氧化碳浓度'; szVariantParam:'195+048+60+02'),
(dwVariantId:90050003; szVariantDesc:'烟雾浓度'; szVariantParam:'195+049+60+02'),
(dwVariantId:90050004; szVariantDesc:'风机运行时间'; szVariantParam:'195+056+60+02'),
(dwVariantId:90050005; szVariantDesc:'风机运行状态'; szVariantParam:'195+064+00+01'),
(dwVariantId:90050007; szVariantDesc:'风机手动控制'; szVariantParam:'195+065+00+01'),
(dwVariantId:90050008; szVariantDesc:'隧道内风速'; szVariantParam:'195+051+60+02'),
(dwVariantId:90050009; szVariantDesc:'隧道内风向'; szVariantParam:'195+052+60+02'),
(dwVariantId:90051001; szVariantDesc:'通风设备自检故障'; szVariantParam:'195+001+00+01'),
(dwVariantId:90051002; szVariantDesc:'通风设备通信故障'; szVariantParam:'195+099+00+01'),
//(火灾告警系统)
(dwVariantId:90060001; szVariantDesc:'区段自动火灾报警'; szVariantParam:'196+048+00+01'),
(dwVariantId:90060002; szVariantDesc:'区段手动火灾报警'; szVariantParam:'196+064+00+01'),
(dwVariantId:90061001; szVariantDesc:'火灾设备自检故障'; szVariantParam:'196+001+00+01'),
(dwVariantId:90061002; szVariantDesc:'火灾设备通信故障'; szVariantParam:'196+099+00+01'),
//(交通控制系统)
(dwVariantId:90070001; szVariantDesc:'交通操作模式'; szVariantParam:'212+017+00+01'),
(dwVariantId:90070003; szVariantDesc:'信号灯状态'; szVariantParam:'212+064+00+01'),
(dwVariantId:90070004; szVariantDesc:'交通控制方案'; szVariantParam:'212+065+00+02'),
(dwVariantId:90071001; szVariantDesc:'交通设备自检故障'; szVariantParam:'212+001+00+01'),
(dwVariantId:90071002; szVariantDesc:'交通设备通讯故障'; szVariantParam:'212+099+00+01'),
//RTU通讯状态
(dwVariantId:90080001; szVariantDesc:'RTU通讯状态'; szVariantParam:'254+078+00+01'),
(dwVariantId:90080002; szVariantDesc:'RTU通讯保持'; szVariantParam:'254+254+60+02'),
(dwVariantId:90080003; szVariantDesc:'RTU门开报警'; szVariantParam:'254+002+00+04'));
//************************************************
CONST_NULL_ITEMNAME = 'NULL';
Const_TIME_COMMFAILED = 600000; //10分钟
Const_TIME_REFRESHDATA = 300000; //5分钟
Const_RTUCOMM_NORMAL = 0;
//==========================================
//帧类型
Const_FrameType_Invalid = 0; //无效数据帧
Const_FrameType_Normal = 1; //普通数据帧
Const_FrameType_SCMS = 2; //CMS、CSLS数据帧
//==========================================
Const_Event_SendDataReq = 101; //发送数据
Const_Event_RecvDataInd = 102; //接收数据
Const_Event_LoopCheck = 103; //查询数据
Const_Event_WaitAnswer = 104; //等待应答数据(针对SCMS)
Const_FrameSendTimeOut = 5000; //发送超时时间(5秒)
Const_FrameSendFailed = 20000; //发送失败检测时间(20秒)
Const_DataSort_Sta = 1; //状态数据
Const_DataSort_Num = 2; //数值数据
Const_DataSort_Chr = 3; //字符串
Const_DataSort_BLN = 4; //布尔型
//功能组描述
Const_FG_TRF = 1; //交通功能组
Const_FG_SCMS = 4; //情报板功能组
Const_FG_LIGHT = 194; //照明控制功能组
Const_FG_Ven = 195; //通风控制功能组
Const_FG_FIRE = 196; //火灾功能组
Const_FG_BAS90 = 212; //交通控制功能组
Const_FG_SYSTEM = 254; //系统功能组
//==========================================
//数据类型描述
//公用数据类型
Const_Type_Error = 1; //设备故障
Const_Type_CommErr = 99; //通信故障类型
Const_Type_Mode = 17; //操作模式的类型
//VD数据类型
Const_Type_VDTrf = 52; //VD车流量数据
Const_Type_VDSpd = 53; //VD车速数据
Const_Type_VDHld = 54; //VD占有率数据
//情报板数据类型
Const_Type_CSLSLST = 47; //限速标志播放表
Const_Type_CMSLST = 48; //情报板播放表
Const_Type_OPENSCN = 49; //开屏
Const_Type_CLOSESCN = 50; //关屏
//照明数据类型
Const_Type_BrtValue = 48; //照明强度数据
Const_Type_BrtLevel = 65; //照明级别
//通风数据类型
Const_Type_COValue = 48; //CO浓度
Const_Type_VIValue = 49; //VI浓度
Const_Type_FANTime = 56; //风机运行时间
Const_Type_FANState = 64; //风机运行状态
Const_Type_FANManu = 65; //风机手动控制
Const_Type_WindSpd = 51; //风速数据
Const_Type_WindDct = 52; //风向数据
//火灾数据类型
Const_Type_FireAuto = 48; //火灾自动报警
Const_Type_FireManu = 64; //火灾手动报警
//交通控制数据类型
Const_Type_TrfProgram = 65; //交通控制方案
Const_Type_TrfLightSta = 64; //信号灯状态
//系统功能组数据类型
Const_Type_RTUCommState = 78; //RTU通讯状态
Const_Type_RTUCommCheck = 254; //RTU通讯检查(自动下发数据)
//=================================
Const_Re_Error = -1; //函数返回失败
Const_Re_OK = 0; //函数返回成功
Const_Re_Other = 1; //函数返回其他
type
TDeviceVar = class;
TDriver = class;
TDriverList = class;
TIntegerArray = array of Integer;
TDWordArray = array of DWord;
TStringArray = array of string;
//设备变量寻址信息
TAddressInfo = record
dwRTUNo: DWord; //RTU编号
dwReadItem: string[100]; //读变量名称
dwWriteItem: string[100]; //写变量名称
dwFuncGroup: DWord; //功能组
dwDataType: DWord; //数据类型
dwSampleTime: DWord; //采集周期(毫秒)
dwDataSort: DWord; //数据类别
end;
TAddressInfoArray = array of TAddressInfo;
//应用数据结构
TAppDataInfo = record
dwLocalIndex: Integer; //本地设备变量索引
rcdAddress: TAddressInfo; //设备变量的地址信息
AppData: Variant; //接收数据内容
dtDateTime: TDateTime; //报文中的时间(或系统时间)
end;
TAppDataInfoArray = array of TAppDataInfo;
//设备变量的运行信息
PAddressParseInfo = ^TAddressParseInfo;
TAddressParseInfo = record
dwDeviceVarId: DWord; //设备变量编号
dwLocalIndex: Integer; //该设备变量在本地的列表中的索引
rcdAddress: TAddressInfo; //设备变量地址信息
end;
TAddressParseInfoArray = array of TAddressParseInfo;
//读取数据的地址信息
PReadInfo = ^TReadInfo;
TReadInfo = record
szItemName: string[50]; //数据项的名称
arrVarList: TIntegerArray; //关联到的设备变量的索引数组
dwReadSample: DWord; //采样周期(毫秒)
dwPriorRead: DWord; //上一次读取的时间
end;
TReadInfoArray = array of TReadInfo;
//自动下发数据的地址信息
PWriteInfo = ^TWriteInfo;
TWriteInfo = record
szItemName: string[50]; //数据项的名称
dwWriteSample: DWord; //采样周期(毫秒)
dwPriorWrite: DWord; //上一次下发的时间
dwWriteValue: Word; //随机数
end;
TWriteInfoArray = array of TWriteInfo;
//读取数据的有效地址列表信息
PReadListInfo = ^TReadListInfo;
TReadListInfo = record
dwRTUNo: DWord; //RTU编号
bCommState: Boolean; //通讯状态
rcdReadInfo: TReadInfoArray; //读取数据的数组
end;
TReadListInfoArray = array of TReadListInfo;
//CMS通讯故障数据结构
TCMSCommErrorInfo = record
szCMSName: string; //CMS的读地址
dwCount: DWord; //连续中断次数
bStatus: Boolean; //通讯状态
end;
TCMSCommErrorInfoArray = array of TCMSCommErrorInfo;
//设备变量地址解析
TAddressParse = class(TObject)
private
FLock: TRTLCriticalSection;
FAutoWriteInfos: TWriteInfoArray; //自动下发的数据项列表
FItemNameList: TStringArray; //保存有效的OPCITEM名称信息
FRTUFaultList: TList; //保存RTU通讯中断编号
FSCMSFaultList: TCMSCommErrorInfoArray; //保存限速标志通讯中断地址信息
FReadListInfos: TReadListInfoArray; //读取数据的采样列表(该列表按OPC ITEM唯一排序)
FNormalInfos: TAddressParseInfoArray; //正常节点的列表
FCommErrorInfos: TAddressParseInfoArray; //通信故障节点的列表
function ItemIsNull(ItemName: string): Boolean;
function SplitValue(const DeviceVar: TDeviceVar; DataPkt: Variant;
var Value: Variant): Boolean;
function FindItems(Addr: TAddressInfo): TIntegerArray;
function FindCommErrorItems: TIntegerArray;
function FindRTUCommErrorItems(RTUNo: DWord): TIntegerArray;
public
constructor Create;
destructor Destroy; override;
function AddInfo(Info: TAddressParseInfo): Integer;
function GetItemNameList: TStringArray;
procedure FinishedAdd;
procedure SetCommState(State: Boolean);
procedure SetRecvData(AppDataInfo: TAppDataInfo);
procedure GetQueryData(var ReadInfos: TReadInfoArray);
procedure GetWriteData(var WriteInfos: TWriteInfoArray);
procedure SetRTUFault(RTUNo: DWord; CommState: Boolean);
end;
TFrame = class(TObject)
private
FDataPkt: Variant; //数据内容(数据帧的数据部分)
FAddrInfo: TAddressInfo; //数据的地址信息
FLocalIndex: Integer; //设备变量本地索引
FItemName: string; //访问OPCITEM的名称
FFrmType: Integer; //数据帧类型
FSending: Boolean; //是否发送
FNeedAck: Boolean; //是否需要回应
FStarted: DWord; //开始发送的TICKCOUNT
FDeleted: Boolean; //是否删除
FFormed: Boolean; //是否打包
public
constructor Create(DataPkt: Variant; Xmit: Boolean);
destructor Destroy; override;
procedure SetParams(const AddrInfo: TAddressInfo; LocalIndex: Integer = -1);
procedure FormFrame;
procedure Marked;
published
property DataPacket: Variant read FDataPkt;
property AddrInfo: TAddressInfo read FAddrInfo;
property LocalIndex: Integer read FLocalIndex;
property ItemName: string read FItemName;
property NeedAck: Boolean read FNeedAck;
property Sending: Boolean read FSending;
property Deleted: Boolean read FDeleted;
property FrmType: Integer read FFrmType;
property Started: DWord read FStarted;
end;
//滑动窗口
TSlidingWindow = class(TObject)
private
FSyncObj: TRTLCriticalSection;
FFrameList: TStringList; //发送数据帧列表
function GetFrameCount: Integer;
procedure ClearFrames;
public
constructor Create;
destructor Destroy; override;
procedure AddFrame(Frm: TFrame);
procedure Reset;
procedure ProcessSendFailed(SendFrm: TFrame);
function ProcessSendTimeOut(var ItemNameList: TStringArray): TIntegerArray;
function ProcessRecvAnswer(RecvFrm: TFrame): Boolean;
function GetNextFrame: TFrame;
published
property FrameCount: Integer read GetFrameCount;
end;
//设备变量对象
TDeviceVar = class(TAutoRelease)
private
FOwner: TDriver; //所属设备对象
FDeviceVarId: DWord; //设备变量编号
FDeviceVarState: Integer; //设备变量状态
FDeviceVarType: Integer; //设备变量类型
FServerIndex: Integer; //服务端设备变量对象索引
FLocalIndex: Integer; //该设备变量在本地的列表中的索引
FAddressIndex: Integer; //设备变量在地址树中的绝对位置
FAddressInfo: TAddressInfo; //为了获得测试数据加入的
FLastSendData: Variant; //最后一次发送的数据内容
FLastRecvData: Variant; //最后一次接收的数据内容
procedure SetState(State: Integer);
public
constructor Create(AOwner: TDriver; Info: TAddressParseInfo);
destructor Destroy; override;
function GetTestValue(var Value: Variant): Boolean;
function SendData(Value: Variant; ATime: TDateTime): Boolean;
function RecvData(Value: Variant; ATime: TDateTime): Boolean;
published
property Owner: TDriver read FOwner;
property DeviceVarId: DWord read FDeviceVarId write FDeviceVarId;
property DeviceVarType: Integer read FDeviceVarType write FDeviceVarType;
property DeviceVarState: Integer read FDeviceVarState write SetState;
property ServerIndex: Integer read FServerIndex write FServerIndex;
property LocalIndex: Integer read FLocalIndex;
property AddressIndex: Integer read FAddressIndex;
property AddressInfo: TAddressInfo read FAddressInfo;
property LastSendData: Variant read FLastSendData;
property LastRecvData: Variant read FLastRecvData;
end;
//设备变量列表对象
TDeviceVarList = class(TObjectList)
private
procedure FreeResource;
public
constructor Create;
destructor Destroy; override;
function AddItem(const DeviceVar: TDeviceVar): Integer;
function GetItem(const Index: Integer): TDeviceVar;
procedure MakeTestData;
class function AddrAnalyze(Src: String; var Dst: TAddressInfo): Boolean;
class function GetDeviceVarList: TDeviceVarList;
class function CreateDeviceVar(AOwner: TDriver; Info: TDeviceVarInfo): TDeviceVar;
end;
//通信设备类
TDriver = class(TLayer)
private
FSyncObj: TRTLCriticalSection; //发送数据时的同步对象
//串口属性
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -