unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, strutils, math;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
function LoadSysFile():boolean;
end;
PRecConflictions = ^RecConflictions;
RecConflictions = record //冲突定义:当A处在AState状态时,B不能进入BState状态,否则就发生冲突
APart:integer; //A的DeviceID(在MyDev中的序号)。特殊定义--->高真空:0,
AState:boolean; //A的状态。特殊定义:真空度为TRUE时表示高真空(<5Pa),否则为低真空
BPart:integer;
BState:boolean;
Next:PRecConflictions;
end;
PRecDevInfo=^RecDevInfo;
RecDevInfo = record //系统下挂的设备
DevId:integer;
Name:string;
Model:string;
//多端口模块下挂的设备端口号,例如5510A下的第1路DO
ConnTo:string; //对于不是直接连COM的设备(阀门等),它是通过谁连上COM的?
ComPort: integer;
ComListId:integer; //指令发向哪个COM线程
Page:integer; //设备在界面上的显示位置 页面位置:0系统决定,1真空阀,2分子泵,3离子源系统,4束流系统,5辅助系统开关设备-输出,6辅助系统开关设备-输入,7辅助系统模拟设备速出,8,辅助系统模拟设备输入
dType:integer; //设备类型:1数字开关,2真空计 3分子泵 4电源 5软件自设 6流量计 7PLC模块 8开关监控量 9模拟输出量 10模拟输入量
Addr: integer;
IsOn:boolean;
PlcData:array[1..8] of char;
PlcAddr:array[1..8] of integer;
Value1:real;
Value2:real;
Range1:real;
Range2:real;
end;
PEquipType = ^EquipType;
EquipType = record
Model:string; //型号
LeiXing:integer; //类型
r1:integer; //值限1
r2:integer; //值限2
end;
var
Form1: TForm1;
DevCount:integer=0;
DevCnflHead: PRecConflictions=nil;
DevCnflTail: PRecConflictions=nil;
MyDev:array of RecDevInfo;
MyCom: array of {TSurveillance;} TObject;
MyTypes:array[0..127] of EquipType;
TypeCount:integer=0;
CnflCount:integer=0;
implementation
function IsDecNumberic(Vaule:String):Boolean; //判断Vaule是不是数字
var
i:integer;
begin
result:=true; //设置返回值为 是(真)
Vaule:=trim(Vaule); //去空格
for i:=1 to length(Vaule) do //准备循环
begin
if not (Vaule[i] in ['0'..'9']) then //如果Vaule的第i个字不是0-9中的任一个
begin
result:=false; //返回值 不是(假)
exit; //退出函数
end;
end;
end;
function DevIdByName(DevName:string):integer;
var
i:integer;
begin
result:=-100;
for i:=0 to DevCount do
begin
if MyDev[i].Name=DevName then
begin
result:=i;
exit;
end;
end;
end;
function PosInArray(value:integer;arr:array of integer):integer;
var
i:integer;
begin
result:=-1;
for i:=0 to length(arr)-1 do
begin
if arr[i]=value then
begin
result:=i;
exit;
end;
end;
end;
procedure CopyMemory(Destination:Pointer; Source:pointer; Length:DWORD);
begin
Move(Source^, Destination^, Length);
end;
{$R unit1.lfm}
{ TForm1 }
function TForm1.LoadSysFile():boolean;
var
MyIniFile:TextFile; //注意,Sys文件必须要保存成UNICODE编码
s,tmp:string;
strs:TStrings;
LineNow:integer=0;
i:integer;
ComId:array of integer;
ComCount:integer=0;
Match,ParantId:integer;
Section:integer;
const TotalSection=4;
SectionName:array[1..TotalSection] of string=('COM','SHEBEI','UNDER_PLC','CHONGTU');
begin
LineNow:=0;
result:=false;
if not fileExists('sys.pzwj') then
begin
// log('系统配置文件丢失');
exit;
end;
SetLength(MyDev,1); //此处多次用SetLength来重设MyDev数组大小,会报执行时内存冲突。估计是Lazarus有问题,改为固定数组后就没问题。
MyDev[0].Name:='高真空';
MyDev[0].IsOn:=false;
MyDev[0].DevId:=0;
MyDev[0].Model:='ComThread';
AssignFile(MyIniFile,'sys.pzwj');
Reset(MyIniFile);
strs:=TStringList.Create;
try
while not eof(MyIniFile) do
begin
inc(LineNow);
Readln(MyIniFile,s);
s:=UpperCase(Trim(s));
if Length(s)=0 then continue; //跳过空行
if leftStr(s,1)='#' then continue; //跳过注释行
strs.DelimitedText:=s;
strs.Delimiter:=#9;
//for i:=0 to strs.Count-1 do
// begin
// strs[i]:=trim(strs[i]);
//rmLog.Lines.Add(strs[i]);
// end;
Match:=0;
if '['=LeftStr(strs[0],1) then
begin
for i:=1 to TotalSection do
begin
if MidStr(strs[0],2,Length(strs[0])-2)=SectionName[i] then
begin
Section:=i;
Match:=i;
break;
end;
end;
if 0=Match then
begin
// log('系统第'+IntToStr(LineNow)+'行错误');
exit;
end;
Section:=Match;
continue;
end;
if (Section<TotalSection) then //除冲突列表外,设备名查重
if 0<DevIdByName(strs[0]) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行重名');
exit;
end;
if 1=Section then
begin
if 'COM'<>leftstr(strs[0],3) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if 4<>strs.Count then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if (not IsDecNumberic(strs[1])) or (not IsDecNumberic(strs[2])) or (not IsDecNumberic(strs[3])) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if (not InRange(strtoint(strs[1]),0,7)) or (not InRange(strtoint(strs[2]),0,3))
or (not InRange(strtoint(strs[3]),100,1000)) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
inc(ComCount);
SetLength(ComId,ComCount);
ComId[ComCount-1]:=strtoint(rightstr(strs[0],length(strs[0])-3));
SetLength(MyCom,ComCount);
// MyCom[ComCount-1]:=TSurveillance.Create(ComId[ComCount-1],strtoint(strs[1]),
// strtoint(strs[2]),strtoint(strs[3]));
end;
if 2=Section then //COM接的设备
begin
if (6<>strs.Count) or (not IsDecNumberic(strs[2])) or (not IsDecNumberic(strs[4])) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if (StrToInt(strs[2])<1) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if 'COM'<>LeftStr(strs[1],3) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if not IsDecNumberic(RightStr(strs[1],length(strs[1])-3)) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
if (strtoint(RightStr(strs[1],length(strs[1])-3))<1) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
tmp:=strs[1];
tmp:=rightstr(tmp,Length(tmp)-3);
if (255<>strtoint(tmp)) and (-1 = PosInArray(strtoint(tmp),ComId)) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误');
exit;
end;
inc(DevCount);
SetLength(MyDev,DevCount+1); //此处多次用SetLength来重设MyDev数组大小,会报执行时内存冲突。估计是Lazarus有问题,改为固定数组后就没问题。
MyDev[DevCount].DevId:=DevCount;
MyDev[DevCount].Name:=strs[0];
MyDev[DevCount].ComPort:=StrToInt(tmp);
MyDev[DevCount].Addr:=StrToInt(strs[2]);
MyDev[DevCount].Model:=strs[3];
MyDev[DevCount].Page:=strtoint(strs[4]);
MyDev[DevCount].dType:=strtoint(strs[5]);
MyDev[DevCount].ConnTo:='';
MyDev[DevCount].IsOn:=false;
if (255<>MyDev[DevCount].ComPort) or (255<>MyDev[DevCount].Addr) then
begin
for i:=0 to TypeCount-1 do //读出该设备对应的可设值限
begin
if MyTypes[i].Model=MyDev[DevCount].Model then
begin
MyDev[DevCount].Range1:=MyTypes[i].r1;
MyDev[DevCount].Range2:=MyTypes[i].r2;
break;
end;
end;
for i:=0 to length(ComId)-1 do //找出指令要发到哪个COM口
begin
if MyDev[DevCount].ComPort = ComId[i] then
begin
MyDev[DevCount].ComListId:=i;
break;
end;
end;
end;
end;
if 3=Section then //不直接挂在COM下的设备,通过PLC连接
begin
ParantId:=DevIdByName(strs[3]);
if ParantId=-100 then
begin
// log('系统文件第'+IntToStr(LineNow)+'行错误,父节点无效');
exit;
end;
inc(DevCount);
SetLength(MyDev,DevCount+1);
MyDev[DevCount].DevId:=DevCount;
MyDev[DevCount].Name:=strs[0];
MyDev[DevCount].Model:=strs[1];
MyDev[DevCount].dType:=strtoint(strs[2]);
MyDev[DevCount].ConnTo:=strs[3];
MyDev[DevCount].Page:=strtoint(strs[4]);
if strs.Count>=7 then
begin
CopyMemory(@MyDev[DevCount].PlcData[1],PChar(strs[5]),1);
MyDev[DevCount].PlcAddr[1]:=strtoint(strs[6]);
end;
if strs.Count>=9 then
begin
CopyMemory(@MyDev[DevCount].PlcData[2],PChar(strs[7]),1);
MyDev[DevCount].PlcAddr[2]:=strtoint(strs[8]);
end;
if strs.Count>=11 then
begin
CopyMemory(@MyDev[DevCount].PlcData[3],PChar(strs[9]),1);
MyDev[DevCount].PlcAddr[3]:=strtoint(strs[10]);
end;
if strs.Count>=13 then
begin
CopyMemory(@MyDev[DevCount].PlcData[4],PChar(strs[11]),1);
MyDev[DevCount].PlcAddr[4]:=strtoint(strs[12]);
end;
if strs.Count>=15 then
begin
CopyMemory(@MyDev[DevCount].PlcData[5],PChar(strs[13]),1);
MyDev[DevCount].PlcAddr[5]:=strtoint(strs[14]);
end;
if strs.Count>=17 then
begin
CopyMemory(@MyDev[DevCount].PlcData[6],PChar(strs[15]),1);
MyDev[DevCount].PlcAddr[6]:=strtoint(strs[16]);
end;
if strs.Count>=19 then
begin
CopyMemory(@MyDev[DevCount].PlcData[7],PChar(strs[17]),1);
MyDev[DevCount].PlcAddr[7]:=strtoint(strs[18]);
end;
if strs.Count>=21 then
begin
CopyMemory(@MyDev[DevCount].PlcData[8],PChar(strs[19]),1);
MyDev[DevCount].PlcAddr[8]:=strtoint(strs[20]);
end;
MyDev[DevCount].ComPort:=MyDev[ParantId].ComPort;
MyDev[DevCount].ComListId:=MyDev[ParantId].ComListId;
MyDev[DevCount].Addr:=MyDev[ParantId].Addr;
for i:=0 to TypeCount-1 do //读出该设备对应的可设值限
begin
if MyTypes[i].Model=MyDev[DevCount].Model then
begin
MyDev[DevCount].Range1:=MyTypes[i].r1;
MyDev[DevCount].Range2:=MyTypes[i].r2;
break;
end;
end;
end;
if TotalSection=Section then //冲突
begin
if (strs.Count<>4) or (('ON'<>strs[1]) and ('OFF'<>strs[1])) or
(('ON'<>strs[3]) and ('OFF'<>strs[3])) or (strs[0]=strs[2])then
begin
// log('系统文件第'+IntToStr(LineNow)+'行,格式错误');
exit;
end;
if (0>DevIdByName(strs[0])) or (0>DevIdByName(strs[2])) then
begin
// log('系统文件第'+IntToStr(LineNow)+'行,设备无效');
exit;
end;
inc(CnflCount);
if nil = DevCnflHead then
begin
DevCnflHead:=new(PRecConflictions);
DevCnflTail:=DevCnflHead;
end
else
begin
DevCnflTail^.Next:=new(PRecConflictions);
DevCnflTail:=DevCnflTail^.Next;
DevCnflTail^.Next:=nil;
end;
DevCnflTail^.APart:=DevIdByName(strs[0]);
DevCnflTail^.AState:=(strs[1]='ON');
DevCnflTail^.BPart:=DevIdByName(strs[2]);
DevCnflTail^.BState:=(strs[3]='ON');
continue;
end;
end;
finally
CloseFile(MyIniFile);
end;
//SetLength(MyDev,DevCount+1);
strs.Free;
result := true;
ShowMessage(
'LineNow = ' + LineNow.ToString + LineEnding +
'ComCount = ' + ComCount.ToString + LineEnding +
'DevCount = ' + DevCount.ToString
);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if LoadSysFile then
// log('加载系统文件成功')
else
begin
// log('加载系统文件失败',clRed);
exit;
end;end;
end.