unit TestComUnit;interfaceuses Windows, Messages, SysUtils, DateUtils;var h_Thread: THandle; //线程句柄 ThreadEvent: THandle; //线程同步事件procedure TestCom(P: Pointer); stdcall;implementation uses CommonUnit,DmUnit;procedure ChangeLineState(dType: Byte; dNum: WORD; State: Byte); //通知设备状态窗口,通信状态改变 var W: integer; begin if SsJkHandle>0 then //如果设备状态显示窗口存在 begin W:=dType; W:=W shl 16; W:=W or dNum; //W的高16位代表设备类型,低16位代表设备编号 PostMessage(SsJkHandle,WM_CHANGELINESTATE,W,State); //lParam为1表示通信故障,0表示通信正常 end; end;procedure TestOnLine(p_DkXx: PDkXx); //设备通信测试函数 var Nbw: LongWord; SndStr: string; Coms: TComStat; lpErrors: Cardinal; i: integer; begin if p_DkXx^.hCom>0 then begin SndStr:=p_DkXx^.TestStr; PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR); WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil); for i:=1 to 10 do begin Sleep(300); if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then //说明线程要退出。 Break; ClearCommError(p_DkXx^.hCom,lpErrors,@Coms); if Coms.cbInQue>0 then //说明设备返回了数据,说明通信是正常的。 begin if not p_DkXx^.isOnline then //原来是通信异常 begin p_DkXx^.isOnline:=True; //把通信状态设为正常 ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0); end; Break; end else //如果设备未返回消息 if (i=10)and(p_DkXx^.isOnline) then //原来是通信正常 begin p_DkXx^.isOnline:=False; //把通信状态设为异常 ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1); end; end; end else //如果没有创建端口,说明通信肯定异常 if p_DkXx^.isOnline then begin p_DkXx^.isOnline:=False; ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1); end; end;function Parse_CJ_Data(var Buf: array of Byte; var Len: Cardinal; P: Pointer): Boolean; procedure Parse_Date(var YY,MM,DD: WORD; P: Pointer); var Y: WORD; M,D,L: Byte; bP: ^Byte; begin bP:=P; Inc(bP); Y:=0; Y:=(Y+bP^) shl 8; Inc(bP); Y:=(Y+bP^) shr 1; M:=(bP^ and $01); M:=M shl 3; Inc(bP); L:=bP^ and $E0; M:=M+L shr 5; D:=bP^ and $1F; YY:=Y; MM:=M; DD:=D; end;
procedure Parse_Time(var HH,MM,SS: WORD; P: Pointer); var H,M,S,L: Byte; bP: ^Byte; begin bP:=P; H:=bP^ and $07; H:=H shl 2; Inc(bP); L:=bP^ and $C0; L:=L shr 6; H:=H+L; M:=bP^ and $3F; Inc(bP); S:=bP^ shr 2; HH:=H; MM:=M; SS:=S; end;var bP: ^Byte; W,Lan,wL,C: WORD; i,j,X: WORD; dL: DWORD; lDT: TDateTime; Year,Month,Day,Hour,Minute,Second: WORD; lTpoint: pTpoint; L: integer; begin Result:=False; try L:=-1; for i:=0 to Len-1 do if (Buf[i]=$5A)and(Buf[i+1]=$31)and((i+672)<=Len)and(ComputeCrc8(@Buf[i],10)=Buf[i+10]) then begin L:=i; Break; end; if L>-1 then begin lTpoint:=P; C:=0; for i:=0 to 5 do begin X:=L+i*112; if (Buf[X]=$5A)and(Buf[X+1]=$31)and(ComputeCrc8(@Buf[X+11],$64)=Buf[X+111]) then begin bP:=@Buf[X+17]; Lan:=bP^+1; Inc(bP); Parse_Date(Year,Month,Day,bP); Inc(bP,4); Parse_Time(Hour,Minute,Second,bP); lDT:=EncodeDateTime(Year,Month,Day,Hour,Minute,0,0); lTpoint^.Time:=IncHour(lDT,8); Inc(bP,8); if (bP^ and $80)>0 then begin if (bP^ or $80)=$80 then begin W:=bP^ and $7F; W:=W shl 8; Inc(bP); W:=W or bP^; Inc(bP); lTpoint^.Lane[Lan].AveSpd:=Round(W+(bP^/256)); end else begin W:=bP^; W:=W shl 8; Inc(bP); W:=W or bP^; W:=$FFFF xor W; lTpoint^.Lane[Lan].AveSpd:=W+1; end; end else begin Inc(bP,2); lTpoint^.Lane[Lan].AveSpd:=0; end; Inc(bP); dL:=bP^; dL:=dL shl 16; Inc(bP); dL:=(dL or bP^) shl 8; Inc(bP); dL:=dL or bP^; lTpoint^.Lane[Lan].Volume:=dL; Inc(bP); wL:=bP^; Inc(bP); lTpoint^.Lane[Lan].AveOcy:=wL+bP^/256; Inc(bP,11); for j:=1 to 5 do begin Inc(bP); dL:=bP^; dL:=dL shl 16; Inc(bP); dL:=(dL or bP^) shl 8; Inc(bP); dL:=dL or bP^; lTpoint^.Lane[Lan].LenBin[j]:=dL; end;
Inc(C); end else Break; end; if C=6 then Result:=True; end; except Result:=False; end; end;function Get_CJ_Data(p_DkXx: PDkXx; var lSJ: TTPoint; SndStr: string): Boolean; var j: integer; Coms: TComStat; Nbw: LongWord; lpErrors,cbNum,ReadLen,Len: Cardinal; Buf: array[0..1023] of Byte; RecvS: array[0..1023] of Byte; begin Result:=False; PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR); WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil); Len:=0; for j:=1 to 10 do begin Sleep(300); if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then Break; //等待超时,说明线程要退出
ClearCommError(p_DkXx^.hCom,lpErrors,@Coms); if Coms.cbInQue>0 then begin cbNum:=Coms.cbInQue; if ReadFile(p_DkXx^.hCom,Buf,cbNum,ReadLen,nil) then begin CopyMemory(@RecvS[Len],@Buf,ReadLen); Len:=Len+ReadLen; end; end; if Len>=672 then Break; end; if Len>=672 then begin ZeroMemory(@lSJ,SizeOf(TTpoint)); //清空临时存放时间点数据的内存 if Parse_CJ_Data(RecvS,Len,@lSJ) then Result:=True; end; if (Len>0)and(not p_DkXx^.isOnline) then //原来是通信异常 begin p_DkXx^.isOnline:=True; //把通信状态设为正常 ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0); end else if (Len=0)and(p_DkXx^.isOnline) then begin p_DkXx^.isOnline:=False; //把通信状态设为异常 ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1); end; end;procedure GetData(p_DkXx: PDkXx); //获取数据函数 var lSJ: TTpoint; BH: integer; L_ane: TLane; Y,M,OldD,NewD: WORD; begin if p_DkXx^.hCom>0 then begin case p_DkXx^.LX of 'C': begin if Get_CJ_Data(p_DkXx,lSJ,p_DkXx^.GetStr) then begin lSJ.isFill:=True; BH:=p_DkXx^.BH; p_DkXx^.cTime:=GetTickCount; if BH=3 then //如果是3号车检,要把车道顺序颠倒 begin L_ane:=lSJ.Lane[1]; lSJ.Lane[1]:=lSJ.Lane[6]; lSJ.Lane[6]:=L_ane; L_ane:=lSJ.Lane[2]; lSJ.Lane[2]:=lSJ.Lane[5]; lSJ.Lane[5]:=L_ane; L_ane:=lSJ.Lane[3]; lSJ.Lane[3]:=lSJ.Lane[4]; lSJ.Lane[4]:=L_ane; end; if DateTimeToStr(lSJ.Time)<>DateTimeToStr(Sensor[BH].Tpoint[CSHOWCOUNT].Time) then begin DecodeDate(lSJ.Time,Y,M,NewD); DecodeDate(Sensor[BH].Tpoint[CSHOWCOUNT].Time,Y,M,OldD); MoveMemory(@(Sensor[BH].Tpoint[1]),@(Sensor[BH].Tpoint[2]),SizeOf(TTpoint)*(CSHOWCOUNT-1)); CopyMemory(@(Sensor[BH].Tpoint[CSHOWCOUNT]),@lSJ,SizeOf(TTpoint)); CJ_CommitDatabase(@lSJ,BH); if SsJkHandle>0 then PostMessage(SsJkHandle,WM_SHOWCJDATA,BH,CSHOWCOUNT); //通知状态窗口显示最后一个元素 SendMnp(Sensor[BH].Tpoint[CSHOWCOUNT],BH); //把新收到的数据发往模拟屏 if OldD<>NewD then MergeData(DateToStr(EncodeDate(Y,M,OldD)),BH); //合并此车检这一天的数据 end; end; end; end; end else //如果没有创建端口,说明通信肯定异常 if p_DkXx^.isOnline then begin p_DkXx^.isOnline:=False; //把通信状态设为异常 ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1); end; end;procedure TestCom(P: Pointer); stdcall; //通信测试线程函数 var AID,i: integer; ThreadExit: Boolean; begin AID:=0; ThreadExit:=False; while not ThreadExit do //通信测试循环 begin EnterCriticalSection(DkXx[AID].Section); //进入临界区 try if (DkXx[AID].LX<>'X')and(DkXx[AID].LX<>'M') then //不是大小情报板 begin if Abs(GetTickCount-DkXx[AID].cTime)>=DkXx[AID].TimeJG then //到设定时间时取数据 GetData(@DkXx[AID]) //到时间时取数据 else //未到时间时测试通信情况,不取数据 TestOnLine(@DkXx[AID]); end else //如果是大小情报板,则只是测试通信,不获取数据。 TestOnLine(@DkXx[AID]); finally LeaveCriticalSection(DkXx[AID].Section); //离开临界区 end;
Inc(AID); if AID>High(DkXx) then AID:=0; for i:=1 to 10 do //延时 if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then //如果超时,则退出线程 begin ThreadExit:=True; Break; end else Sleep(50); end; SetEvent(ThreadEvent); end;initialization ThreadEvent:=CreateEvent(nil,True,True,'XcGsTxEvt'); //创建线程同步信号finalization CloseHandle(ThreadEvent); DeleteObject(ThreadEvent);end.
Windows, Messages, SysUtils, DateUtils;var
h_Thread: THandle; //线程句柄
ThreadEvent: THandle; //线程同步事件procedure TestCom(P: Pointer); stdcall;implementation
uses
CommonUnit,DmUnit;procedure ChangeLineState(dType: Byte; dNum: WORD; State: Byte); //通知设备状态窗口,通信状态改变
var
W: integer;
begin
if SsJkHandle>0 then //如果设备状态显示窗口存在
begin
W:=dType;
W:=W shl 16;
W:=W or dNum; //W的高16位代表设备类型,低16位代表设备编号
PostMessage(SsJkHandle,WM_CHANGELINESTATE,W,State); //lParam为1表示通信故障,0表示通信正常
end;
end;procedure TestOnLine(p_DkXx: PDkXx); //设备通信测试函数
var
Nbw: LongWord;
SndStr: string;
Coms: TComStat;
lpErrors: Cardinal;
i: integer;
begin
if p_DkXx^.hCom>0 then
begin
SndStr:=p_DkXx^.TestStr;
PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR);
WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil); for i:=1 to 10 do
begin
Sleep(300);
if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then //说明线程要退出。
Break;
ClearCommError(p_DkXx^.hCom,lpErrors,@Coms);
if Coms.cbInQue>0 then //说明设备返回了数据,说明通信是正常的。
begin
if not p_DkXx^.isOnline then //原来是通信异常
begin
p_DkXx^.isOnline:=True; //把通信状态设为正常
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0);
end;
Break;
end
else //如果设备未返回消息
if (i=10)and(p_DkXx^.isOnline) then //原来是通信正常
begin
p_DkXx^.isOnline:=False; //把通信状态设为异常
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
end;
end;
end
else //如果没有创建端口,说明通信肯定异常
if p_DkXx^.isOnline then
begin
p_DkXx^.isOnline:=False;
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
end;
end;function Parse_CJ_Data(var Buf: array of Byte; var Len: Cardinal; P: Pointer): Boolean;
procedure Parse_Date(var YY,MM,DD: WORD; P: Pointer);
var
Y: WORD;
M,D,L: Byte;
bP: ^Byte;
begin
bP:=P;
Inc(bP);
Y:=0;
Y:=(Y+bP^) shl 8;
Inc(bP);
Y:=(Y+bP^) shr 1;
M:=(bP^ and $01);
M:=M shl 3;
Inc(bP);
L:=bP^ and $E0;
M:=M+L shr 5;
D:=bP^ and $1F;
YY:=Y;
MM:=M;
DD:=D;
end;
procedure Parse_Time(var HH,MM,SS: WORD; P: Pointer);
var
H,M,S,L: Byte;
bP: ^Byte;
begin
bP:=P;
H:=bP^ and $07;
H:=H shl 2;
Inc(bP);
L:=bP^ and $C0;
L:=L shr 6;
H:=H+L;
M:=bP^ and $3F;
Inc(bP);
S:=bP^ shr 2;
HH:=H;
MM:=M;
SS:=S;
end;var
bP: ^Byte;
W,Lan,wL,C: WORD;
i,j,X: WORD;
dL: DWORD;
lDT: TDateTime;
Year,Month,Day,Hour,Minute,Second: WORD;
lTpoint: pTpoint;
L: integer;
begin
Result:=False;
try
L:=-1;
for i:=0 to Len-1 do
if (Buf[i]=$5A)and(Buf[i+1]=$31)and((i+672)<=Len)and(ComputeCrc8(@Buf[i],10)=Buf[i+10]) then
begin
L:=i;
Break;
end;
if L>-1 then
begin
lTpoint:=P;
C:=0;
for i:=0 to 5 do
begin
X:=L+i*112;
if (Buf[X]=$5A)and(Buf[X+1]=$31)and(ComputeCrc8(@Buf[X+11],$64)=Buf[X+111]) then
begin
bP:=@Buf[X+17];
Lan:=bP^+1; Inc(bP);
Parse_Date(Year,Month,Day,bP);
Inc(bP,4);
Parse_Time(Hour,Minute,Second,bP);
lDT:=EncodeDateTime(Year,Month,Day,Hour,Minute,0,0);
lTpoint^.Time:=IncHour(lDT,8); Inc(bP,8);
if (bP^ and $80)>0 then
begin
if (bP^ or $80)=$80 then
begin
W:=bP^ and $7F;
W:=W shl 8;
Inc(bP);
W:=W or bP^;
Inc(bP);
lTpoint^.Lane[Lan].AveSpd:=Round(W+(bP^/256));
end
else
begin
W:=bP^;
W:=W shl 8;
Inc(bP);
W:=W or bP^;
W:=$FFFF xor W;
lTpoint^.Lane[Lan].AveSpd:=W+1;
end;
end
else
begin
Inc(bP,2);
lTpoint^.Lane[Lan].AveSpd:=0;
end; Inc(bP);
dL:=bP^;
dL:=dL shl 16;
Inc(bP);
dL:=(dL or bP^) shl 8;
Inc(bP);
dL:=dL or bP^;
lTpoint^.Lane[Lan].Volume:=dL; Inc(bP);
wL:=bP^;
Inc(bP);
lTpoint^.Lane[Lan].AveOcy:=wL+bP^/256; Inc(bP,11);
for j:=1 to 5 do
begin
Inc(bP);
dL:=bP^;
dL:=dL shl 16;
Inc(bP);
dL:=(dL or bP^) shl 8;
Inc(bP);
dL:=dL or bP^;
lTpoint^.Lane[Lan].LenBin[j]:=dL;
end;
Inc(C);
end
else
Break;
end;
if C=6 then
Result:=True;
end;
except
Result:=False;
end;
end;function Get_CJ_Data(p_DkXx: PDkXx; var lSJ: TTPoint; SndStr: string): Boolean;
var
j: integer;
Coms: TComStat;
Nbw: LongWord;
lpErrors,cbNum,ReadLen,Len: Cardinal;
Buf: array[0..1023] of Byte;
RecvS: array[0..1023] of Byte;
begin
Result:=False; PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR);
WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil);
Len:=0;
for j:=1 to 10 do
begin
Sleep(300);
if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then
Break; //等待超时,说明线程要退出
ClearCommError(p_DkXx^.hCom,lpErrors,@Coms);
if Coms.cbInQue>0 then
begin
cbNum:=Coms.cbInQue;
if ReadFile(p_DkXx^.hCom,Buf,cbNum,ReadLen,nil) then
begin
CopyMemory(@RecvS[Len],@Buf,ReadLen);
Len:=Len+ReadLen;
end;
end;
if Len>=672 then
Break;
end; if Len>=672 then
begin
ZeroMemory(@lSJ,SizeOf(TTpoint)); //清空临时存放时间点数据的内存
if Parse_CJ_Data(RecvS,Len,@lSJ) then
Result:=True;
end; if (Len>0)and(not p_DkXx^.isOnline) then //原来是通信异常
begin
p_DkXx^.isOnline:=True; //把通信状态设为正常
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0);
end
else
if (Len=0)and(p_DkXx^.isOnline) then
begin
p_DkXx^.isOnline:=False; //把通信状态设为异常
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
end;
end;procedure GetData(p_DkXx: PDkXx); //获取数据函数
var
lSJ: TTpoint;
BH: integer;
L_ane: TLane;
Y,M,OldD,NewD: WORD;
begin
if p_DkXx^.hCom>0 then
begin
case p_DkXx^.LX of
'C': begin
if Get_CJ_Data(p_DkXx,lSJ,p_DkXx^.GetStr) then
begin
lSJ.isFill:=True;
BH:=p_DkXx^.BH;
p_DkXx^.cTime:=GetTickCount; if BH=3 then //如果是3号车检,要把车道顺序颠倒
begin
L_ane:=lSJ.Lane[1];
lSJ.Lane[1]:=lSJ.Lane[6];
lSJ.Lane[6]:=L_ane;
L_ane:=lSJ.Lane[2];
lSJ.Lane[2]:=lSJ.Lane[5];
lSJ.Lane[5]:=L_ane;
L_ane:=lSJ.Lane[3];
lSJ.Lane[3]:=lSJ.Lane[4];
lSJ.Lane[4]:=L_ane;
end; if DateTimeToStr(lSJ.Time)<>DateTimeToStr(Sensor[BH].Tpoint[CSHOWCOUNT].Time) then
begin
DecodeDate(lSJ.Time,Y,M,NewD);
DecodeDate(Sensor[BH].Tpoint[CSHOWCOUNT].Time,Y,M,OldD); MoveMemory(@(Sensor[BH].Tpoint[1]),@(Sensor[BH].Tpoint[2]),SizeOf(TTpoint)*(CSHOWCOUNT-1));
CopyMemory(@(Sensor[BH].Tpoint[CSHOWCOUNT]),@lSJ,SizeOf(TTpoint));
CJ_CommitDatabase(@lSJ,BH);
if SsJkHandle>0 then
PostMessage(SsJkHandle,WM_SHOWCJDATA,BH,CSHOWCOUNT); //通知状态窗口显示最后一个元素 SendMnp(Sensor[BH].Tpoint[CSHOWCOUNT],BH); //把新收到的数据发往模拟屏 if OldD<>NewD then
MergeData(DateToStr(EncodeDate(Y,M,OldD)),BH); //合并此车检这一天的数据
end;
end;
end;
end;
end
else //如果没有创建端口,说明通信肯定异常
if p_DkXx^.isOnline then
begin
p_DkXx^.isOnline:=False; //把通信状态设为异常
ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
end;
end;procedure TestCom(P: Pointer); stdcall; //通信测试线程函数
var
AID,i: integer;
ThreadExit: Boolean;
begin
AID:=0;
ThreadExit:=False;
while not ThreadExit do //通信测试循环
begin
EnterCriticalSection(DkXx[AID].Section); //进入临界区
try
if (DkXx[AID].LX<>'X')and(DkXx[AID].LX<>'M') then //不是大小情报板
begin
if Abs(GetTickCount-DkXx[AID].cTime)>=DkXx[AID].TimeJG then //到设定时间时取数据
GetData(@DkXx[AID]) //到时间时取数据
else //未到时间时测试通信情况,不取数据
TestOnLine(@DkXx[AID]);
end
else //如果是大小情报板,则只是测试通信,不获取数据。
TestOnLine(@DkXx[AID]);
finally
LeaveCriticalSection(DkXx[AID].Section); //离开临界区
end;
Inc(AID);
if AID>High(DkXx) then
AID:=0; for i:=1 to 10 do //延时
if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then //如果超时,则退出线程
begin
ThreadExit:=True;
Break;
end
else
Sleep(50);
end; SetEvent(ThreadEvent);
end;initialization
ThreadEvent:=CreateEvent(nil,True,True,'XcGsTxEvt'); //创建线程同步信号finalization
CloseHandle(ThreadEvent);
DeleteObject(ThreadEvent);end.