unit Controller_IonCounter; interface uses Controllers, MMTimer; const cDataSignature='IonCounter'; cBasePort=$100; cValidPorts=[$20..$27]; cValidReadPorts=[$21..$23,$27]; cValidWritePorts=[$20..$27]; type tFlag=(fTimeCtrlWord, fCounterCtrlWord, fDivisorCtrlWord, fGate, fTrigger); tFlags=set of tFlag; tCountByte=0..1; tWord=record Counter:tCountByte; case byte of 0:(w:word); 1:(b:array[tCountByte] of byte); end; tDataWordWordCounter=0..1; tDataWordByteCounter=0..3; tDataWordCounter=record Read,Write:tDataWordByteCounter; end; tDataWord=record DataWordCounter:tDataWordCounter; case byte of 0:(c:cardinal); 1:(w:array[tDataWordWordCounter] of word); 2:(b:array[tDataWordByteCounter] of byte); end; tTimeTimer=record Counter:byte; case byte of 0:(w:word); 1:(b:array[0..1]of byte); end; tData=record Flags :tFlags; TimerDivideCoefficient :tWord; DataWord :tDataWord; countVI53 :byte; end; tTmpData=record IonSgn :extended; ReadySignal :boolean; TimeTimer :tTimeTimer; end; tIonCounter=class(tController) private Data :tData; TmpData :tTmpData; Timer :TMMTimer; InProgress :boolean; TimeIntegr :cardinal; procedure SetTimerDivideCoeff(bv:byte); procedure SetTimer(bv:byte); procedure SetDataWord(b:byte; Count:tDataWordByteCounter); procedure SetDataWordBytes34(b:byte); procedure SetCtrlWord(b:byte); procedure Gate; procedure Trigger; procedure ReCountVI53; procedure Start; function Progress:byte; procedure GetReady; procedure GetSignal; function GetDataByte(Count:tDataWordByteCounter):byte; function GetDataByte34:byte; procedure OnMyTimer(Sender:tObject); public constructor Create; destructor Destroy; override; procedure Init; override; function InB(Port:word):byte; override; procedure OutB(b:byte; Port:word); override; function ValidPort(Port:word; BasePort:word):boolean; override; function ValidReadPort(Port:word):boolean; override; function ValidWritePort(Port:word):boolean; override; procedure SetSignalDate(Sgnl:extended); function DataSize:cardinal; override; function SetData(aData:Pointer):boolean; override; function GetData(aData:Pointer):boolean; override; function SubPath:string; override; end; implementation uses Windows, Messages, Hardware, SysUtils; //***************************************************************************** // //***************************************************************************** //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- constructor tIonCounter.Create; begin Timer:=tMMTimer.Create; Timer.Resolution:=10; Timer.OnTimer:=OnMyTimer; Timer.TimerType:=ttOnce; Timer.Enabled:=true; TimeIntegr:=1000; inherited end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- destructor tIonCounter.Destroy; begin Timer.Enabled:=false; FreeAndNil(Timer); inherited; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.Init; begin Data.Flags:=[fTimeCtrlWord, fCounterCtrlWord, fDivisorCtrlWord, fGate, fTrigger]; Data.TimerDivideCoefficient.Counter:=0; Data.TimerDivideCoefficient.w:=1000; Data.DataWord.DataWordCounter.Write:=3; Data.DataWord.DataWordCounter.Read:=3; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.OutB(b:byte; Port:word); var f:text; begin case Port of $27:begin SetDataWordBytes34(b); end; $26:begin SetTimerDivideCoeff(b); end; $25:begin SetTimer(b); end; $24:begin SetCtrlWord(b); end; $20:begin Trigger; end; $22:begin Gate; end; $21:begin ReCountVI53; end; $23:begin Start; end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.InB(Port:word):byte; begin Result:=$FF; case Port of $21:begin Result:=Progress; end; $22:begin Result:=GetDataByte(1); end; $23:begin Result:=GetDataByte(0); end; $27:begin Result:=GetDataByte34; end; end; if (fTrigger in Data.Flags) then begin Result:=255; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.ValidPort(Port:word; BasePort:word):boolean; begin Result:=(Port in cValidPorts) and (BasePort=cBasePort); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.ValidReadPort(Port:word):boolean; begin Result:=Port in cValidReadPorts; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.ValidWritePort(Port:word):boolean; begin Result:=Port in cValidWritePorts; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetTimerDivideCoeff(bv:byte); begin with Data.TimerDivideCoefficient do begin b[Counter]:=bv; if Counter=0 then Counter:=1 else Counter:=0; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetTimer(bv:byte); begin with TmpData.TimeTimer do begin b[Counter]:=bv; if Counter=1 then Counter:=0 else Counter:=1; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetDataWord(b:byte; Count:tDataWordByteCounter); begin Data.DataWord.b[Count]:=b; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetDataWordBytes34(b:byte); begin SetDataWord(b,Data.DataWord.DataWordCounter.Write); if Data.DataWord.DataWordCounter.Write=2 then Data.DataWord.DataWordCounter.Write:=3 else Data.DataWord.DataWordCounter.Write:=2; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetCtrlWord(b:byte); begin case b of $34:begin Exclude(Data.Flags, fCounterCtrlWord); end; $74:begin Exclude(Data.Flags, fDivisorCtrlWord); end; $B2:begin Exclude(Data.Flags, fTimeCtrlWord); end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.Gate; begin Exclude(Data.Flags, fGate); SetDataWord(0,0); SetDataWord(0,1); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.ReCountVI53; begin Inc(Data.countVI53); if Data.countVI53>2 then begin Data.countVI53:=1; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.Start; var s:string; begin if (Data.Flags=[]) and (Data.countVI53=2) and (not InProgress) then begin TmpData.ReadySignal:=false; InProgress:=true; TimeIntegr:=round(TmpData.TimeTimer.w*(1000 / Data.TimerDivideCoefficient.w)); if TimeIntegr>0 then Timer.Interval:=TimeIntegr else begin Timer.Interval:=1; TimeIntegr:=1; end; Timer.UpdateTimer; end else begin { s:=''; if (fGate in Data.Flags) then s:=s+'fGate '; if (fTimeCtrlWord in Data.Flags) then s:=s+'fTimeCtrlWord '; if (fCounterCtrlWord in Data.Flags) then s:=s+'fCounterCtrlWord '; if (fDivisorCtrlWord in Data.Flags) then s:=s+'fDivisorCtrlWord '; if (fTrigger in Data.Flags) then s:=s+'fTrigger'; ShowMessage('IonCounter, start '+s); RunError(201); } end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.GetReady; begin if not (TmpData.ReadySignal or InProgress) then begin GetSignal; TmpData.ReadySignal:=true; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.GetSignal; var sgnl:extended; begin sgnl:=(TmpData.IonSgn); sgnl:=(TmpData.IonSgn+MI1201AGM.GetNoise(TimeIntegr,sgnl)) * TmpData.TimeTimer.w * 1000 / Data.TimerDivideCoefficient.w; Data.DataWord.c:=round(sgnl); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.GetDataByte(Count:tDataWordByteCounter):byte; begin Result:=$FF; if not InProgress then begin GetReady; Result:=Data.DataWord.b[Count]; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.GetDataByte34:byte; begin Result:=$FF; if not InProgress then begin GetReady; Result:=not Data.DataWord.b[Data.DataWord.DataWordCounter.Read]; if Data.DataWord.DataWordCounter.Read=3 then Data.DataWord.DataWordCounter.Read:=2 else Data.DataWord.DataWordCounter.Read:=3; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.DataSize:cardinal; begin Result:=SizeOf(Data); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.SetData(aData:Pointer):boolean; begin Result:=false; try Move(aData^, Data, DataSize); Result:=True; except end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.GetData(aData:Pointer):boolean; begin Result:=false; try Move(Data, aData^, DataSize); Result:=True; except end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.SubPath:string; begin Result:=cDataSignature; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.SetSignalDate(Sgnl:extended); begin TmpData.IonSgn:=Sgnl; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.OnMyTimer(Sender:TObject); begin InProgress:=False; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tIonCounter.Progress:byte; begin Result:=byte(InProgress); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tIonCounter.Trigger; begin Exclude(Data.Flags, fTrigger); end; end.