{ Контроллер развертки (AК8) 5.105.178 Эмулятор электроники блока управления током э. магнита } unit MI1201AGM_Roll_Emulator; interface USES SysUtils, TimeInterval_Emulator, Peak_Emulator, MassScale_Emulator, MI1201AGM_Hardware_Emulator, MI1201AGM_Controller_Emulator; const cDataSignature='Roll emulator data. '; cRegistrySubPath='Roll'; cValidPorts=[$B1..$B3]; cValidReadPorts=[$B2..$B3]; cValidWritePorts=[$B1..$B3]; cRoll_mks_PerImpuls=16; cRollMaxCounterUpLimit=900000; cRollMaxCounterLoLimit=90000; cRollMaxCounter=750000; cRollMaxCounterNoise=30000; cRollBoundOverload=20000; cRollOverloadMaxTime=20; {ms} cRollCounterMassCoefficient=1.263E-9; type tRollPortNum=0..2; tRollPorts=array[tRollPortNum] of word; tRollPortRegimes=array[tRollPortNum] of tPortOperations; tRollPortComments=array[tRollPortNum] of tPortComment; tRollParameter=( pCounter, pFlags, pAutoTuning ); tRollParameterNames=array[tRollParameter] of string; const cRollPort:tRollPorts=( $B1, $B2, $B3 ); cRollPortRegime:tRollPortRegimes=( [opWrite], [opRead, opWrite], [opRead, opWrite] ); cRollPortComment:tRollPortComments=( ('-','Запись байта в счетчик выдачи импульсов'), ('Сброс контроллера','Выдача импульсов отрицательной (1) или положительной (2) полярности'), ('Байт состояния','Включение (1) или выключение (0) автоподстройки') ); cRollParameterNames:tRollParameterNames=( 'Счетчик импульсов', 'Флаги (байт состояния)', 'Автоподстройка' ); type tDataSignature=array[1..Length(cDataSignature)] of char; tRollCounter=0..cRollMaxCounterUpLimit; tPolarity=(pBad, pNegative, pPositive); tFlag=(fInProgress, fAllowUp, fAllowDown, b3, b4, b5, b6, b7); tFlags=set of tFlag; tInternalFlag=( ifResetRequred, ifLogginOn ); tInternalFlags=set of tInternalFlag; // Данные, сохраняющиеся между измерениями tData=record Signature:tDataSignature; Flags:tFlags; IFlags:tInternalFlags; DeltaCounter:byte; OverLoadTime:tTime_ms; AutoTuning:byte; MaxCounter:tRollCounter; LoBoundOverload:tRollCounter; UpBoundOverload:tRollCounter; MaxCounterNoise:tRollCounter; Counter:tRollCounter; end; tPData=^tData; // Данные, НЕсохраняющиеся между измерениями (запусками программы) tTmpData=record InoperationalCount:cardinal; Direction:0..2; end; tError=( eNotOperational, eInvalidSetAutotuning, eInvalidStartByte, eLimitReached, eInvalidPort, eReadFromInvalidPort, eWriteToInvalidPort ); resourcestring rseNotOperational='не готов'; rseInvalidSetAutotuning='неверный вывод в Автоподстройку'; rseInvalidStartByte='неверное значение байта при запуске'; rseLimitReached='достигнут аппаратный предел'; rseInvalidPort='неверный порт'; rseReadFromInvalidPort='чтение из неверного порта'; rseWriteToInvalidPort='запись в неверный порт'; const cErrorDescriptions:array[tError] of string=( rseNotOperational, rseInvalidSetAutotuning, rseInvalidStartByte, rseLimitReached, rseInvalidPort, rseReadFromInvalidPort, rseWriteToInvalidPort ); type tRollEvent=( evRollNothing, evRollSetAutotuning, evRollOperational, evRollFlags, evRollStartCount, evRollStopCount, evRollLastEvent ); tRoll=class(tController) private prTimer:tTimeIntervalX; prOverloadTimer:tTimeIntervalX; prData:tData; prTmpData:tTmpData; function CheckTimer:boolean; function CheckOverloadTimer:boolean; function Operational:boolean; procedure SetOverload(c:tRollCounter; direction:byte); procedure SetInoperational; procedure StartTimer; function xCheckData(var D:tData):boolean; procedure SetFlags(AFlags:tFlags); procedure SetFlagState(AFlag:tFlag; AState:boolean); procedure SetFlagsByte(AFlags:byte); function GetFlags:byte; function GetAutotuningBool:boolean; procedure SetAutotuningBool(state:boolean); protected // обязательные процедуры function SubPath:string; override; procedure prOutByte(b:Byte; port:word); override; function prInByte(port:word):Byte; override; function CheckData(Data:pointer):boolean; override; function DataSize:integer; override; function SetData(aData:pointer):boolean; override; function GetData(aData:pointer):boolean; override; procedure Notify(AEvent:tRollEvent); overload; function GetPortsCount:cardinal; override; function GetPortOperation(APort:word):tPortOperations; override; function GetPortComment(APort:word; Regime:tPortOperation):string; override; function GetPort(Number:cardinal):word; override; function GetParametersCount:cardinal; override; function GetParameter(i:cardinal):variant; override; function GetParameterName(i:cardinal):string; override; // прочие процедуры public // обязательные процедуры constructor Create(Hardware:tMi1201HardwareEmulator); destructor Destroy; override; procedure ReInit; override; procedure SetDefaultData; override; function ValidPort(APort:word):boolean; function ValidReadPort(APort:word):boolean; function ValidWritePort(APort:word):boolean; // прочие процедуры function Reset:byte; procedure SetCount(c:Byte); procedure SetAutotuning(c:Byte); procedure Start(p:Byte); function GetMass:tMass; // параметры контроллера property Counter:tRollCounter read prData.Counter write prData.Counter; property Flags:byte read GetFlags write SetFlagsByte; property Autotuning:boolean read GetAutotuningBool write SetAutotuningBool; end; implementation function tRoll.GetAutotuningBool:boolean; begin Result:=(prData.Autotuning and 1)=1; end; procedure tRoll.SetAutotuningBool(state:boolean); begin if state then SetAutotuning(1) else SetAutotuning(0); end; function tRoll.GetParametersCount:cardinal; begin Result:=Succ(Ord(High(tRollParameter))); end; function tRoll.GetParameter(i:cardinal):variant; begin if iprData.Flags then begin prData.Flags:=AFlags; Notify(evRollFlags); end; end; procedure tRoll.SetFlagsByte(AFlags:byte); begin SetFlags(tFlags(AFlags)); end; procedure tRoll.SetFlagState(AFlag:tFlag; AState:boolean); begin if AState<>(AFlag in prData.Flags) then begin if AState then Include(prData.Flags,AFlag) else Exclude(prData.Flags,AFlag); Notify(evRollFlags); end; end; procedure tRoll.Notify(AEvent:tRollEvent); begin DoNotify(evCustom, Ord(AEvent)); end; function tRoll.SetData(aData:pointer):boolean; begin Result:=Inherited SetData(aData); if Result then begin Inc(Cardinal(aData),Inherited DataSize); Result:=CheckData(aData); if Result then begin Move(aData^,prData,DataSize); end; end; Notify(evDataRestored); end; function tRoll.GetData(aData:pointer):boolean; begin Result:=Inherited GetData(aData); if Result then begin Inc(Cardinal(aData),Inherited DataSize); Result:=CheckData(aData); if Result then begin Move(prData,aData^,SizeOf(prData)); end; end; end; function tRoll.DataSize:integer; begin Result:=Inherited DataSize + SizeOf(prData); end; function tRoll.SubPath:string; begin Result:=cRegistrySubPath; end; function tRoll.CheckData(Data:pointer):boolean; begin Result:=Inherited CheckData(Data); if Result then begin Inc(Cardinal(Data),Inherited DataSize); Result:=xCheckData(tPData(Data)^); end; end; constructor tRoll.Create(Hardware:tMi1201HardwareEmulator); begin prTimer:=tTimeIntervalX.Create; prOverloadTimer:=tTimeIntervalX.Create; SetFlags([fInProgress..b7]); Inherited; end; destructor tRoll.Destroy; begin Notify(evDestroying); SetFlags([fInProgress..b7]); Inherited; prTimer.Free; prOverloadTimer.Free; Notify(evDestroyed); end; function tRoll.xCheckData(var d:tData):boolean; begin Result:=TRUE; if d.Signature<>cDataSignature then begin d.Signature:=cDataSignature; Result:=FALSE; end; if d.MaxCounterNoise>cRollMaxCounterNoise then begin d.MaxCounterNoise:=cRollMaxCounterNoise; Result:=FALSE; end; if d.LoBoundOverload>100*cRollBoundOverload then begin d.LoBoundOverload:=cRollBoundOverload; Result:=FALSE; end; if d.MaxCounter>cRollMaxCounterUpLimit then begin d.MaxCounter:=cRollMaxCounterUpLimit; Result:=FALSE; end; if d.MaxCounter1 then begin ErrorCode:=Ord(eInvalidSetAutotuning); end; Notify(evRollSetAutotuning); end; procedure tRoll.SetCount(c:Byte); begin prData.DeltaCounter:=c; if not Operational then begin ErrorCode:=Ord(eNotOperational); end; end; procedure tRoll.SetOverload(c:tRollCounter; direction:byte); var t:cardinal; begin t:=((((c*1000) div prData.LoBoundOverload)*cRollOverloadMaxTime) div 1000); if tcRollOverloadMaxTime then t:=cRollOverloadMaxTime; prData.OverLoadTime:=t; if c<>0 then begin case direction of 1: begin SetFlagState(fAllowUp,FALSE); end; 2: begin SetFlagState(fAllowDown,FALSE); end; else begin end; end; prOverloadTimer.Start(t); end; end; procedure tRoll.SetInoperational; begin prTimer.Clear; Include(prData.IFlags,ifResetRequred); SetFlags(prData.Flags+[fInProgress]-[fAllowUp,fAllowDown]); Inc(prTmpData.InoperationalCount); ErrorCode:=Ord(eLimitReached); Notify(evRollOperational); end; procedure tRoll.StartTimer; begin prTimer.Start( (prData.DeltaCounter*cRoll_mks_PerImpuls) div 1000 +prData.OverLoadTime); SetFlagState(fInProgress,TRUE); Notify(evRollStartCount); end; procedure tRoll.Start(p:byte); begin if prTmpData.Direction<>p then begin prTmpData.InoperationalCount:=0; case p of 2: SetFlagState(fAllowUp,TRUE); 1: SetFlagState(fAllowDown,TRUE); end; prTmpData.Direction:=p; end; if (prTmpData.InoperationalCount<10) or Operational then begin case p of 2:begin {-} if prData.Counter(prData.MaxCounter-prData.DeltaCounter) then begin prData.Counter:=prData.MaxCounter; SetInoperational; end else begin Inc(prData.Counter,prData.DeltaCounter); if prData.Counter>prData.UpBoundOverload then begin SetOverload(prData.Counter-prData.UpBoundOverload,p); end else begin SetOverload(0,p); end; StartTimer; end; end; else begin ErrorCode:=Ord(eInvalidStartByte); end; end; end else begin ErrorCode:=Ord(eNotOperational); end; Hardware.Mass:=GetMass; end; function tRoll.GetMass:tMass; var x:extended; begin x:=prData.Counter; Result:=Round(cRollCounterMassCoefficient*Sqr(x)*cMassScale); end; procedure tRoll.prOutByte(b:Byte; port:word); begin case Port of $EDB1: begin { Запись байта в счетчик выдачи импульсов } SetCount(b); end; $EDB2: begin { Выдача импульсов отрицательной (1) или положительной (2) полярности } Start(b); end; $EDB3: begin { Включение (1) или выключение (0) автоподстройки } SetAutotuning(b); end; else if ValidReadPort(port) then begin WriteToInvalidPort:=TRUE; ErrorCode:=Ord(eWriteToInvalidPort); end else begin InvalidPort:=TRUE; ErrorCode:=Ord(eInvalidPort); end; end; end; function tRoll.prInByte(port:word):Byte; begin // port:=port and $FF; Result:=$FF; case Port of $EDB2: begin {Сброс контроллера} Result:=Reset; end; $EDB3: begin {Чтение байта состояния: 0-й бит = 1 - происходит выдача 0-й бит = 0 - выдача закончена ПРИЗНАК ВЕРХНЕГО "АППАРАТНОГО" СТОПА: 1-й бит = 0 - заблокирована выдача положительных импульсов ПРИЗНАК НИЖНЕГО "АППАРАТНОГО" СТОПА: 1-й бит = 1 - развертка 2-й бит = 0 - заблокирована выдача отрицательных импульсов} Result:=Flags; end; else if ValidWritePort(port) then begin ReadFromInvalidPort:=TRUE; ErrorCode:=Ord(eReadFromInvalidPort); end else begin InvalidPort:=TRUE; ErrorCode:=Ord(eInvalidPort); end; end; end; function tRoll.ValidPort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and ((APort and $FF) in cValidPorts); end; function tRoll.ValidReadPort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and ((APort and $FF) in cValidReadPorts); end; function tRoll.ValidWritePort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and((APort and $FF) in cValidWritePorts); end; end. { Контроллер развертки (AК8) 5.105.178 г========T=======T========T=====================================¬ ¦ ¦ ¦ ¦ ¦ ¦ ПОРТ ¦Данные ¦Режим ¦ Назначение ¦ ¦ ¦ ¦ ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ $B1 ¦ байт ¦ запись ¦Запись байта в счетчик выдачи импуль-¦ ¦ ¦ ¦ ¦ сов ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ ¦ ¦ ¦Выдача импульсов отрицательной (1) ¦ ¦ $B2 ¦1 или 2¦ запись ¦или положительной (2) полярности ¦ ¦ ¦ ¦ ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ $B2 ¦ --- ¦ чтение ¦ Сброс контроллера ¦ ¦ ¦ ¦ ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ $B3 ¦1 или 0¦ запись ¦ Включение (1) или выключение (0) ¦ ¦ ¦ ¦ ¦ автоподстройки ¦ ¦ ¦ ¦ ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ $B3 ¦байт ¦ чтение ¦ Чтение байта состояния: ¦ ¦ ¦сост. ¦ ¦ ¦ ¦ ¦ ¦ ¦ 0-й бит = 1 - происходит выдача¦ ¦ ¦ ¦ ¦ 0-й бит = 0 - выдача закончена ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ 1-й бит = 0 - заблокирована вы-¦ ¦ ¦ ¦ ¦ дача положитель- ¦ ¦ ¦ ¦ ¦ ных импульсов ¦ ¦ ¦ ¦ ¦ПРИЗНАК ВЕРХНЕГО "АППАРАТНОГО" СТОПА ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ 1-й бит = 1 - развертка ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ 2-й бит = 0 - заблокирована вы-¦ ¦ ¦ ¦ ¦ дача отрицатель- ¦ ¦ ¦ ¦ ¦ ных импульсов ¦ ¦ ¦ ¦ ¦ПРИЗНАК НИЖНЕГО "АППАРАТНОГО" СТОПА ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ 1-й бит = 1 - развертка ¦ L========¦=======¦========¦=====================================- }