unit Controller_CVF; //============================================================================= // Контроллер ПНЧ //============================================================================= interface uses Controllers, Windows, Messages, SysUtils, MMTimer; const cDataSignature='CVF'; // ветвь в реестре // порты контроллера cBasePort=$ED00; cValidPorts=[$60..$7F]-[$79]; cValidReadPorts=[$61,$62,$63,$65,$66,$67,$69,$6A,$6B,$6D,$6E,$6F,$71,$72,$73,$75,$76,$77,$7A,$7B,$7C,$7E,$7F]; cValidWritePorts=cValidPorts; type tChannel=1..9; // Управляющие слова tCtrlWordCounter=array[0..1] of byte; tCtrlWord=record CtrlWordCounter:tCtrlWordCounter; case byte of 0:(c:cardinal); 1:(w:array[0..1] of word); 2:(b:array[0..3] of byte); end; tCtrlWords=array[tChannel] of tCtrlWord; // Информация счета tDataInfoCounter0=array[0..1] of byte; tDataInfoCounter=record Read,Write:tDataInfoCounter0; end; tDataInfo=record DataInfoCounter:tDataInfoCounter; case byte of 0:(c:cardinal); 1:(w:array[0..1] of word); 2:(b:array[0..3] of byte); end; tDatasInfo=array[tChannel] of tDataInfo; // Флаги готовности начала счета tReadyFlag=(rfCtrlWord, rfGate, rfTimerCtrlWord); tReadyFlags=set of tReadyFlag; // Блоки реле ПНЧ tCVFRele=(rbZeroOnBase, rbInputIsEMU, rbInvertSignal); tCVFReles=set of tCVFRele; // Коеф. tKoef=array[tChannel] of real; // Таймер tCounterTimer=record Read, Write:byte; end; tTimeTimer=record Counter:tCounterTimer; case byte of 0:(w:word); 1:(b:array[0..1] of byte); end; // сохраняемые параметры tData = record CVFReles :tCVFReles; Koef :tKoef; end; // несохраняемые параметры tTmpData = record CtrlWords :tCtrlWords; SumCtrlWord :Cardinal; ReadyFlags :tReadyFlags; DatasInfo :tDatasInfo; ReadyData :boolean; TimeTimer :tTimeTimer; end; // класс контроллера tCVF = class(tController) private Data :tData; TmpData :tTmpData; MT :tMMTimer; InProgress :boolean; TimeIntgr :cardinal; procedure SetCtrlWord(b:byte; Port:word); procedure DoSetCtrlWord(Channel:tChannel; bv:byte; LoHi:byte); procedure SetTimerCtrlWord(b:byte); procedure SetGate; procedure SetDatasInfo(b:byte; Port:word); procedure DoSetDatasInfo(bv:byte; Channel:tChannel; LoHiWord:byte); procedure SetCVFReles(b:byte); procedure Start; procedure GetReady; function GetDatasInfo(Port:word):byte; function DoGetDatasInfo(Channel:tChannel; LoHiWord:byte):byte; procedure GetSignal; procedure SetTime(bv:byte); function GetTime:byte; function Progress:byte; procedure OnMyTimer(Sender:tObject); public constructor Create; destructor Destroy; override; procedure Init; override; function CheckCtrlWord(Channel:tChannel):boolean; 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; function DataSize:cardinal; override; function SetData(aData:Pointer):boolean; override; function GetData(aData:Pointer):boolean; override; function SubPath:string; override; function GetCVFReles:byte; end; //***************************************************************************** IMPLEMENTATION uses Hardware; //***************************************************************************** // t C V F //***************************************************************************** //----------------------------------------------------------------------------- // Инициализирует класс контроллера, устанавливает значения рабочих параметров класса. //----------------------------------------------------------------------------- constructor tCVF.Create; var i:tChannel; begin MT:=tMMTimer.Create; MT.Resolution:=10; MT.OnTimer:=OnMyTimer; MT.TimerType:=ttOnce; MT.Enabled:=true; TimeIntgr:=1000; inherited; Data.CVFReles:=[]; end; //----------------------------------------------------------------------------- // Деинициализирует класс контроллера, сохраняя значения рабочих параметров. //----------------------------------------------------------------------------- destructor tCVF.Destroy; begin MT.Enabled:=false; FreeAndNil(MT); inherited; end; //----------------------------------------------------------------------------- // Устанавливает значения рабочих параметров по умолчанию. //----------------------------------------------------------------------------- procedure tCVF.Init; var i :tChannel; begin TmpData.TimeTimer.w:=0; TmpData.TimeTimer.Counter.Read:=0; TmpData.TimeTimer.Counter.Write:=0; for i:=1 to 9 do begin Data.Koef[i]:=1; TmpData.CtrlWords[i].w[0]:=0; TmpData.CtrlWords[i].w[1]:=0; TmpData.CtrlWords[i].CtrlWordCounter[0]:=0; TmpData.CtrlWords[i].CtrlWordCounter[1]:=2; TmpData.DatasInfo[i].DataInfoCounter.Read[0]:=0; TmpData.DatasInfo[i].DataInfoCounter.Write[0]:=0; TmpData.DatasInfo[i].DataInfoCounter.Read[1]:=2; TmpData.DatasInfo[i].DataInfoCounter.Write[1]:=2; end; TmpData.SumCtrlWord:=0; TmpData.ReadyFlags:=[]; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.OutB(b:byte; Port:word); begin case Port of $60,$64,$68,$6C,$70,$74:begin SetCtrlWord(b,Port); end; $78:begin SetTimerCtrlWord(b); end; $7D:begin SetGate; end; $61..$63,$65..$67, $69..$6B,$6D..$6F, $71..$73,$75..$77: begin SetDatasInfo(b,Port); end; $7B:begin SetTime(b); end; $7E:begin SetCVFReles(b); end; $7C:begin Start; end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.InB(Port:word):byte; begin case Port of $7C:begin Init; end; $7A:begin result:=0; end; $7B: begin Result:=GetTime; end; $7E: begin Result:=GetCVFReles; end; $7F: begin Result:=Progress; end; $61..$63,$65..$67, $69..$6B,$6D..$6F, $71..$73,$75..$77: begin Result:=GetDatasInfo(Port); end; end; end; //----------------------------------------------------------------------------- // Возвращает TRUE если Port и BasePort соответствуют порту данного класса контроллер, // иначе возвращает FALSE. //----------------------------------------------------------------------------- function tCVF.ValidPort(Port:word; BasePort:word):boolean; begin Result:=(Port in cValidPorts) and (BasePort=cBasePort); end; //----------------------------------------------------------------------------- // Возвращает TRUE если Port соответствуют порту, разрешенному для чтения байта // из него, данного класса контроллера. Иначе возращает FALSE. //----------------------------------------------------------------------------- function tCVF.ValidReadPort(Port:word):boolean; begin Result:=Port in cValidReadPorts end; //----------------------------------------------------------------------------- // Возвращает TRUE если Port соответствуют порту, разрешенному для записи байта // в данный порт, данного класса контроллера. Иначе возвращает FALSE. //----------------------------------------------------------------------------- function tCVF.ValidWritePort(port:word):boolean; begin Result:=Port in cValidWritePorts end; //----------------------------------------------------------------------------- // Запись старших (LoHi=1) или младших (LoHi=0) байт управляющего слова // для канала Channel //----------------------------------------------------------------------------- procedure tCVF.DoSetCtrlWord(Channel:tChannel; bv:byte; LoHi:byte); begin with TmpData.CtrlWords[Channel] do begin Dec(TmpData.SumCtrlWord,w[LoHi]); b[CtrlWordCounter[LoHi]]:=bv; if CtrlWordCounter[LoHi]=2*LoHi then CtrlWordCounter[LoHi]:=1+2*LoHi else CtrlWordCounter[LoHi]:=2*LoHi; Inc(TmpData.SumCtrlWord,w[LoHi]); end; if TmpData.SumCtrlWord=$828 then begin Include(TmpData.ReadyFlags, rfCtrlWord); end else begin Exclude(TmpData.ReadyFlags, rfCtrlWord); end; end; //----------------------------------------------------------------------------- // запись управляющих слов //----------------------------------------------------------------------------- procedure tCVF.SetCtrlWord(b:byte; Port:word); var Channel :tChannel; begin case b of $34: Channel:=1; $74: Channel:=2; $B4: Channel:=3; else begin MessageBox(0,'SetCtrlWord','CVF',MB_OK) end; end; case Port of $68,$6C: Inc(Channel,3); $70,$74: Inc(Channel,6); end; case Port of $60, $68, $70:begin DoSetCtrlWord(Channel,b,0); end; $64, $6C, $74:begin DoSetCtrlWord(Channel,b,1); end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.SetTimerCtrlWord(b:byte); begin if b=$32 then begin Include(TmpData.ReadyFlags, rfTimerCtrlWord); end else begin Exclude(TmpData.ReadyFlags, rfTimerCtrlWord); end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.SetGate; begin Include(TmpData.ReadyFlags, rfGate); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.SetDatasInfo(b:byte; Port:word); begin Case Port of $63: DoSetDatasInfo(b,1,0); $67: DoSetDatasInfo(b,1,1); $62: DoSetDatasInfo(b,2,0); $66: DoSetDatasInfo(b,2,1); $6B: DoSetDatasInfo(b,4,0); $6F: DoSetDatasInfo(b,4,1); $6A: DoSetDatasInfo(b,5,0); $6E: DoSetDatasInfo(b,5,1); $69: DoSetDatasInfo(b,6,0); $6D: DoSetDatasInfo(b,6,1); $61: DoSetDatasInfo(b,3,0); $65: DoSetDatasInfo(b,3,1); $73: DoSetDatasInfo(b,7,0); $77: DoSetDatasInfo(b,7,1); $72: DoSetDatasInfo(b,8,0); $76: DoSetDatasInfo(b,8,1); $71: DoSetDatasInfo(b,9,0); $75: DoSetDatasInfo(b,9,1); end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.DoSetDatasInfo(bv:byte; Channel:tChannel; LoHiWord:byte); begin with TmpData.DatasInfo[Channel] do begin b[DataInfoCounter.Write[LoHiWord]]:=bv; if DataInfoCounter.Write[LoHiWord]=2*LoHiWord then begin DataInfoCounter.Write[LoHiWord]:=1+2*LoHiWord; end else begin DataInfoCounter.Write[LoHiWord]:=2*LoHiWord; end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.SetCVFReles(b:byte); begin Data.CVFReles:=tCVFReles(b); if (rbZeroOnBase in Data.CVFReles) then MI1201AGM.SetVoltage(5,0) else MI1201AGM.SetVoltage(5,-9); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.Start; begin if TmpData.ReadyFlags=[rfCtrlWord, rfGate, rfTimerCtrlWord] then begin TmpData.ReadyData:=false; InProgress:=true; TimeIntgr:=TmpData.TimeTimer.w; if TimeIntgr=0 then TimeIntgr:=1; MT.Interval:=TimeIntgr; MT.UpdateTimer; end else begin MessageBox(0,'Start','CVF',MB_OK); RunError(201); end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.OnMyTimer(Sender:tObject); begin InProgress:=false; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.GetCVFReles:byte; begin Result:=byte(Data.CVFReles); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.GetReady; begin if not (TmpData.ReadyData) then begin GetSignal; TmpData.ReadyData:=true; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.GetDatasInfo(Port:word):byte; begin Result:=$FF; if not InProgress then begin Case Port of $63:Result:=DoGetDatasInfo(1,0); $67:Result:=DoGetDatasInfo(1,1); $62:Result:=DoGetDatasInfo(2,0); $66:Result:=DoGetDatasInfo(2,1); $6B:Result:=DoGetDatasInfo(4,0); $6F:Result:=DoGetDatasInfo(4,1); $6A:Result:=DoGetDatasInfo(5,0); $6E:Result:=DoGetDatasInfo(5,1); $69:Result:=DoGetDatasInfo(6,0); $6D:Result:=DoGetDatasInfo(6,1); $61:Result:=DoGetDatasInfo(3,0); $65:Result:=DoGetDatasInfo(3,1); $73:Result:=DoGetDatasInfo(7,0); $77:Result:=DoGetDatasInfo(7,1); $72:Result:=DoGetDatasInfo(8,0); $76:Result:=DoGetDatasInfo(8,1); $71:Result:=DoGetDatasInfo(9,0); $75:Result:=DoGetDatasInfo(9,1); end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.DoGetDatasInfo(Channel:tChannel; LoHiword:byte):byte; var f:text; begin if not TmpData.ReadyData then begin GetReady; end; with TmpData.DatasInfo[Channel] do begin Result:=b[DataInfoCounter.Read[LoHiWord]]; if DataInfoCounter.Read[LoHiWord]=2*LoHiWord then begin DataInfoCounter.Read[LoHiWord]:=1+2*LoHiWord; end else begin DataInfoCounter.Read[LoHiWord]:=2*LoHiWord; end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.GetSignal; var i :tChannel; t:cardinal; ty:real; sgnl:extended; begin if (rbInputIsEMU in Data.CVFReles) then begin For i:=1 to 9 do begin sgnl:=Data.Koef[i]*(Abs(MI1201AGM.GetVoltage(5+i))); TmpData.DatasInfo[i].c:=TmpData.DatasInfo[i].c-Round(Data.Koef[i]*(Abs(MI1201AGM.GetVoltage(5+i)++MI1201AGM.GetNoise(TimeIntgr,sgnl))*TmpData.TimeTimer.w)); end; end else begin for i:=1 to 9 do begin TmpData.DatasInfo[i].c:=TmpData.DatasInfo[i].c-round(Data.Koef[i]*Abs(MI1201AGM.GetVoltage(5)*TmpData.TimeTimer.w)); end; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.CheckCtrlWord(Channel:tChannel):boolean; begin case Channel of 1,4,7: Result:=TmpData.CtrlWords[Channel].c=$340034; 2,5,8: Result:=TmpData.CtrlWords[Channel].c=$740074; 3,6,9: Result:=TmpData.CtrlWords[Channel].c=$B400B4; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- procedure tCVF.SetTime(bv:byte); begin with TmpData.TimeTimer do begin b[Counter.Write]:=bv; if Counter.Write=1 then Counter.Write:=0 else Counter.Write:=1; end; end; //----------------------------------------------------------------------------- // Чтение младшего и старшего байта времени интегрирования. // Байты считываются поочередно. //----------------------------------------------------------------------------- function tCVF.GetTime:byte; begin with TmpData.TimeTimer do begin Result:=b[Counter.Read]; if Counter.Read=1 then Counter.Read:=0 else Counter.Read:=1; end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.DataSize:cardinal; begin Result:=SizeOf(Data); end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.SetData(aData:Pointer):boolean; begin Result:=false; try Move(aData^, Data, DataSize); Result:=True; except end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.GetData(aData:Pointer):boolean; begin Result:=false; try Move(Data, aData^, DataSize); Result:=True; except end; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.SubPath:string; begin Result:=cDataSignature; end; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- function tCVF.Progress:byte; begin Result:=byte(InProgress); end; end.