{ Контроллер счетчика ионов 5.105.182 (АК-7) } {--------------------------------------------------------------------------- The control units for mass-spectrometer MI1201-AGM (c) Copyright Aleksandrov O.E., 1998 Модуль управления масс-спектрометром МИ1201-АГМ (c) Собственность Александрова О.Е., 1998 Molecular Physics department 620002, Екатеринбург, К-2 USTU, Ekaterinsburg, K-2, 620002 УГТУ, RUSSIA Кафедра молекулярной физики phone 75-48-39 тел. 75-48-39 E-mail: aleks@dpt.ustu.ru ----------------------------------------------------------------------------} Unit c_Count; {$X+} INTERFACE USES c_Ctrl, c_Ctrl1, c_Bus, MItypes; const {Значения параметров по-умолчанию } cDefaultDivCoeff=1000; { 1000 соответствует миллисекундам } cDefaultIntegrationTime=100; { [мс] для для коэфф. деления =1000 } cDefaultTimeOut={500} 1000; { [мс] } cStartWaitMaxTimeout=300; { [мс] макс. время ожидания запуска счета } cDefaultResetCtrl=True; { аппаратный сброс и инициализаци контроллера в начале каждого измерения } type { Коды ошибок } tErrorCodes=({$I C_ErrCds.Inc}, ecFailReset, ecFailResetTrigger, ecFailStart, ecFailRead, ecFailReady, ecInvalid_Time_DivCoeff_Combination, ecBadControllerState); tFlag=(fResetCtrl, fDoInitialResetCtrl); tFlags=set of tFlag; tTmpFlag=(fStarted, fResetCtrlOnce); tTmpFlags=set of tTmpFlag; tTime=1..$FFFF; tDivCoeff=1..$FFFF; tPort=(rwReady_PreCount, rwByte2_Gate, rwByte1_Start, owResetTrigger, owTimerCntrlWord, owTimerIntegrationTime, owDivisionCoefficient, rwBytes3_4); tPortsArray=array[0..Ord(High(tPort))+1] of Byte; const cUnreadablePorts=[]; type tPorts=record case byte of 0:(rwReady_PreCount, rwByte2_Gate, rwByte1_Start, owResetTrigger, owTimerCntrlWord, owTimerIntegrationTime, owDivisionCoefficient, rwBytes3_4:word); 1:(Ports:array[tPort] of word); end; tData=record Ports:tPorts; Flags:tFlags; DivCoeff:tDivCoeff; IntegrationTime:tTime; { время интегрирования с которым БУДЕТ запущено измерение} LastData:tSignalData; PortsData:tPortsArray; end; tTmpData=record BusPtr:c_Bus.tCtrlPtr; Flags:tTmpFlags; StartTime:longint; IntegrationTime:tTime; { время интегрирования с которым было запущено последнее измерение} LazyWaitTimeInterval:word; { время интегрирования, которое было установлено при последнем запуске } end; { флаги состояния контроллера } tCtrlFlag=(fBusy, f1, f2, f3, f4, f5, f6, f7); tCtrlFlags= set of tCtrlFlag; tCtrl=object(c_Ctrl1.tCtrl) function Name:tName; virtual; { НЕисполняемые функции (без ввода/вывода в порты)} constructor InitDefault(var Bus:c_Bus.tCtrl); constructor Init(var Bus:c_Bus.tCtrl; Ports:tPorts); destructor Done; procedure DivCoeff(x:tDivCoeff); { коэффициент деления: 1 счетчика соответствует (1 сек)/DivCoeff} procedure IntegrationTime(x:tTime); { время счета в миллисекундах. Всегда и независимо от DivCoeff. Перевод в необходимые единицы при запуске измерения. Если перевод невозможен - возбуждается ошибка.} procedure ResetCtrl(x:boolean); function CurDivCoeff:tDivCoeff; { возвр. текущий коэфф. деления для таймера } function CurIntegrationTime:tTime; { возвр. текущее время интегрирования [мс] } function CurResetCtrl:boolean; { возвр. текущее состояние для аппаратного сброса и инициализации в начале каждого измерения (TRUE - применяется сброс) } function CurCount:tSignalData; { возвр. данные последнего измерения } procedure SetErrorCode(ec:tErrorCode); virtual; function ErrorMessage(en:tErrorCode):string; virtual; procedure SetNoError; virtual; { Сохранение/восстановление состояния контроллера } function DataSize:word; // procedure Save(var DataPtr:pointer); // procedure exRestore(var DataPtr:pointer); function Restore(var DataPtr:pointer):boolean; function Save(var DataPtr:pointer):boolean; { Исполняемые функции (ввод/вывод в порты)} procedure exInit; virtual; // procedure exReInit; virtual; function exGetData:tSignalData; { запуск, ожидание окончания счета и возвращает результат измерения } function exStart:boolean; { запуск } function exReady:boolean; { возвращает TRUE если счет закончен } function exWaitReady:boolean; function exRead:tSignalData; { ожидание окончания счета и возвращает результат измерения } function exJustRead:tSignalData; { возвращает текущее значение счетчика} procedure exDetectCtrl(var x:tCtrlAlive); virtual; private prData:tData; prTmpData:tTmpData; procedure exInitialReset; function exWait:boolean; function exLazyWait:boolean; procedure DelayWait; function exReset:boolean; function exResetTrigger:boolean; procedure exDone; virtual; procedure exDoStart; {Процедуры сохранения значений в портах} procedure exReadPortsData(var PD:tPortsArray); procedure exSavePortsData; function exIsNotChangedPortsData:boolean; procedure ClearPortsData; {Время ожидания запуска счета} function StartWaitTimeout:word; { Вспомогательные функции определния наличия питания, см. exIsPowerON} function PortsNumber:word; virtual; function exReadSafePorts(var PortsValues:tPortValuesArray; Count:word):boolean; virtual; end; function ValidCombination(DC:tDivCoeff; IT:tTime):boolean; IMPLEMENTATION USES Windows, MI1201ioctl, {$IFDef LogPortIO} SysUtils, PortsIOLog,{$EndIF Def LogPortIO} xStrings, DataSave, MiscFunc, PortsIO; const cCtrlAlive=2; { число портов <>$FF для "живого" контроллера, используется для детектирования наличия } { ВОТ ГАДЫ!, нет чтобы сказать что для счетчика ионов адреса портов указаны абсолютные, а не относительно базового $ED00. Слагаемое $1300 сделано чтобы общую схему вычисления адреса порта не нарушать: ($PortShift+$1300+$ED00) and $FFFF = $PortShift} cDefaultPorts:tPorts=( rwReady_PreCount: $121; rwByte2_Gate: $122; rwByte1_Start: $123; owResetTrigger: $120; owTimerCntrlWord: $124; owTimerIntegrationTime:$125; owDivisionCoefficient: $126; rwBytes3_4: $127 ); function DCandIT2Counter(DC:tDivCoeff; IT:tTime):word; var x:longint; begin DCandIT2Counter:=0; if DC>0 then begin x:=(Longint(IT)*1000) div DC; if x<=$FFFF then DCandIT2Counter:=x; end; end; function ValidCombination(DC:tDivCoeff; IT:tTime):boolean; begin ValidCombination:=DCandIT2Counter(dc,it)<>0; end; {------------------------------------------------------------------------} { Инициализация (без ввода/вывода в порты)} constructor tCtrl.Init(var Bus:c_Bus.tCtrl; Ports:tPorts); begin Inherited Init; prTmpData.BusPtr:=@Bus; prTmpData.IntegrationTime:=1; prTmpData.LazyWaitTimeInterval:=cLazyWaitTimeIntervalMax; prData.Ports:=Ports; prData.Flags:=[fDoInitialResetCtrl]; prData.LastData:=0; DivCoeff(cDefaultDivCoeff); IntegrationTime(cDefaultIntegrationTime); TimeOut(cDefaultTimeOut); ResetCtrl(cDefaultResetCtrl); ClearPortsData; If (Bus.Error) and (NoError) then begin SetErrorCode(tErrorCode(ecBadBus)); end; end; constructor tCtrl.InitDefault(var Bus:c_Bus.tCtrl); begin Init(Bus, cDefaultPorts); end; destructor tCtrl.Done; begin if NotInitialized then Exit; Inherited Done end; function tCtrl.Name; begin Name:='IonCounter'; end; (*procedure tCtrl.exRestore; begin Inherited exRestore(DataPtr); RestoreData(DataPtr, prData, SizeOf(prData)); Include(prTmpData.Flags, fResetCtrlOnce); OperationTimeReset(0); end;*) (*procedure tCtrl.Save; begin exSavePortsData; Inherited Save(DataPtr); StoreData(DataPtr, prData, SizeOf(prData)); end;*) function tCtrl.Restore(var DataPtr:pointer):boolean; begin if Inherited Restore(DataPtr) then Restore:=RestoreDataEx(DataPtr, prData, SizeOf(prData)) else Restore:=FALSE; Include(prTmpData.Flags, fResetCtrlOnce); end; function tCtrl.Save(var DataPtr:pointer):boolean; begin if Inherited Save(DataPtr) then Save:=StoreDataEx(DataPtr, prData, SizeOf(prData)) else Save:=FALSE; end; function tCtrl.DataSize:word; begin DataSize:=Inherited DataSize + DataSave.SizeOfData(SizeOf(prData)); end; {------------------------------------------------------------------------} { Установка параметров (без ввода/вывода в порты)} procedure tCtrl.DivCoeff(x:tDivCoeff); begin prData.DivCoeff:=x; Include(prTmpData.Flags, fResetCtrlOnce); end; procedure tCtrl.IntegrationTime(x:tTime); begin if x>cLazyWaitTimeIntervalMax then prTmpData.LazyWaitTimeInterval:=cLazyWaitTimeIntervalMax else prTmpData.LazyWaitTimeInterval:=cLazyWaitTimeIntervalMin; if prData.IntegrationTime<>x then begin prData.IntegrationTime:=x; Include(prTmpData.Flags, fResetCtrlOnce); end; end; procedure tCtrl.ResetCtrl(x:boolean); begin if x then Include(prData.Flags, fResetCtrl) else Exclude(prData.Flags, fResetCtrl); end; function tCtrl.CurCount:tSignalData; begin CurCount:=prData.LastData; end; {------------------------------------------------------------------------} { Чтение текущих значений параметров (без ввода/вывода в порты)} function tCtrl.CurDivCoeff:tDivCoeff; begin CurDivCoeff:=prData.DivCoeff; end; function tCtrl.CurIntegrationTime:tTime; begin CurIntegrationTime:=prData.IntegrationTime; end; function tCtrl.CurResetCtrl:boolean; begin CurResetCtrl:=(fResetCtrl in prData.Flags); end; procedure tCtrl.SetErrorCode(ec:tErrorCode); begin if ec<>0 then Include(prData.Flags, fDoInitialResetCtrl); Inherited SetErrorCode(ec); end; procedure tCtrl.SetNoError; begin Inherited SetNoError; prTmpData.BusPtr^.SetErrorCode(0); end; function ErrorMessage(en:tErrorCode):string; begin case tErrorCodes(en) of ecFailReset: ErrorMessage:='Ошибка установки праметров контроллера'; ecFailResetTrigger: ErrorMessage:='Ошибка аппаратного сброса контроллера'; ecFailStart: ErrorMessage:='Ошибка запуска счета'; ecTimeOut: ErrorMessage:='Истекло время ожидания готовности'; ecFailRead: ErrorMessage:='Ошибка чтения данных'; ecFailReady: ErrorMessage:='Ошибка чтения состояния счета'; ecInvalid_Time_DivCoeff_Combination: ErrorMessage:='Недопустимое сочетание времени интегрирования и коэффициента деления'; ecBadControllerState: ErrorMessage:='Ошибочное состояние контроллера'; else ErrorMessage:='Неизвестная ошибка'; end; end; function tCtrl.ErrorMessage(en:tErrorCode):string; const cIonCounter=' (Счетчик)'; begin case tErrorCodes(en) of ecOK, ecAbort, ecNotInitialized: ErrorMessage:=Inherited ErrorMessage(en)+cIonCounter; else ErrorMessage:=Inherited ErrorMessage(en)+cIonCounter; end; end; {------------------------------------------------------------------------} { Исполняемые функции (ввод/вывод в порты)} procedure tCtrl.exInit; var t:word; begin Inherited exInit; if IsExInitDone then begin t:=CurIntegrationTime; IntegrationTime(1); exDoStart; exStart; exGetData; SetExInitDone(NoError); IntegrationTime(t); end; OperationTimeReset(0); end; function tCtrl.exGetData:tSignalData; begin exStart; exGetData:=exRead; OperationTimeReset(0); end; procedure tCtrl.exDoStart; type tStartCmd=packed record Count:ULONG; // число операций в буфере Gate:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; Count2:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; Start:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; end; tStartResult=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; end; var StartResult:tStartResult; const StartCmd:tStartCmd=( Count:0; { установить Gate } Gate:( Header:(OpCode:(ULong:Ord(mfocWrite))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Data:(ULong:0); ); { досчитать 2 импульса } Count2:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; Data:(ULong:(0)); ); { запустить } Start:( Header:(OpCode:(ULong:Ord(mfocWrite))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Data:(ULong:0); ); ); begin with StartCmd do begin if Count=0 then begin Count:=3; { установить Gate } Gate.Port.Number:=prData.Ports.rwByte2_Gate; { досчитать 2 импульса } Count2.Port.Number:=prData.Ports.rwReady_PreCount; { запустить } Start.Port.Number:=prData.Ports.rwByte1_Start; end; end; prTmpData.BusPtr^.exMultifunctionIO( StartCmd, SizeOf(StartCmd), StartResult, SizeOf(StartResult)); end; (* procedure tCtrl.exDoStart; // const h0000:word=0; type tStartCmd=packed record Count:ULONG; // число операций в буфере Gate:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; Count2:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; Start:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; end; tStartResult=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; end; var StartCmd:tStartCmd; StartResult:tStartResult; begin with StartCmd do begin Count:=3; { установить Gate } Gate.Header.OpCode.ULong:=Ord(mfocWrite); Gate.Port.Number:=prData.Ports.rwByte2_Gate; Gate.Port.PortType:=Ord(PORT_UCHAR); Gate.Data.UChar:=0; { досчитать 2 импульса } Count2.Header.OpCode.ULong:=Ord(mfocWriteBuffer); Count2.Port.Number:=prData.Ports.rwReady_PreCount; Count2.Port.PortType:=Ord(PORT_UCHAR); Count2.Count:=2; Count2.Data.ULong[0]:=0; { запустить } Start.Header.OpCode.ULong:=Ord(mfocWrite); Start.Port.Number:=prData.Ports.rwByte1_Start; Start.Port.PortType:=Ord(PORT_UCHAR); Start.Data.UChar:=0; end; prTmpData.BusPtr^.exMultifunctionIO( StartCmd, SizeOf(StartCmd), StartResult, SizeOf(StartResult)); // with prData.Ports do begin { PortsIO.OutByte(0, $122); PortsIO.OutByte(0, $121); PortsIO.OutByte(0, $121); PortsIO.OutByte(0, $123);} // prTmpData.BusPtr^.exOutByteX(rwByte2_Gate, 0); { установить Gate } // prTmpData.BusPtr^.exOutBytesX(rwReady_PreCount, h0000, 2); { досчитать 2 импульса } // prTmpData.BusPtr^.exOutByteX(rwByte1_Start, 0); { запустить счет } // end; end; *) function tCtrl.StartWaitTimeout:word; begin if cStartWaitMaxTimeout>prTmpData.IntegrationTime then begin StartWaitTimeout:=prTmpData.IntegrationTime; end else begin StartWaitTimeout:=cStartWaitMaxTimeout; end; end; function tCtrl.exStart:boolean; const cStart=(1 shl Ord(fBusy)); type tStartCmd=packed record Count:ULONG; // число операций в буфере WaitReady:tGENPORT_MULTIFUNCTION_IO_WAIT_INPUT; Write1:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; WriteBuff1:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteAndWait1:tGENPORT_MULTIFUNCTION_IO_WRITE_AND_WAIT_INPUT; end; tStartResult=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; WaitReadyResult:tGENPORT_MULTIFUNCTION_IO_WAIT_OUTPUT; WriteAndWaitResult1:tGENPORT_MULTIFUNCTION_IO_WRITE_AND_WAIT_OUTPUT; end; var StartResult:tStartResult; const StartCmd:tStartCmd=( Count:0; { дождаться готовности } WaitReady:( Header:(OpCode:(ULong:Ord(mfocWait))); WaitData:( Port:(PortType:Ord(PORT_UCHAR)); TimeOut:0; // Время ожидания в мс TimeResolution:1; // Интервал опроса порта в мс Mask:(1 shl Ord(fBusy)); // Маска Patt:0; // Образец ControlFlags:0; // Флаги (битовые) управления ожиданием ); ); { установить Gate } Write1:( Header:(OpCode:(ULong:Ord(mfocWrite))); Port:(PortType:Ord(PORT_UCHAR)); Data:(UChar:0); ); { досчитать 2 импульса } WriteBuff1:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; Data:(ULong:(0)); ); { запустить и ждать старта } WriteAndWait1:( Header:(OpCode:(ULong:Ord(mfocWriteAndWait))); Data:( WriteData:( Port:(Number:0; PortType:Ord(PORT_UCHAR)); Data:(ULong:0); ); WaitData:( Port:(Number:0; PortType:Ord(PORT_UCHAR)); TimeOut:0; TimeResolution:0; Mask:cStart; Patt:cStart; ControlFlags: (1 shl Ord(wcfWaitOnDISPATCH_Level)); ); ); ); ); begin OperationTimeReSet(2*CurTimeOut); exReset; with prTmpData.BusPtr^ do begin with StartCmd do begin if Count=0 then begin Count:=4; { дождаться готовности } WaitReady.WaitData.Port.Number:=prData.Ports.rwReady_PreCount; { установить Gate } Write1.Port.Number:=prData.Ports.rwByte2_Gate; { досчитать 2 импульса } WriteBuff1.Port.Number:=prData.Ports.rwReady_PreCount; { запустить и ждать старта } WriteAndWait1.Data.WriteData.Port.Number:=prData.Ports.rwByte1_Start; WriteAndWait1.Data.WaitData.Port.Number:=prData.Ports.rwReady_PreCount; end; { дождаться готовности } WaitReady.WaitData.TimeOut:=CurTimeout; { запустить и ждать старта } WriteAndWait1.Data.WaitData.TimeOut:=StartWaitTimeout; end; if ( prTmpData.BusPtr^.exMultifunctionIO(StartCmd, SizeOf(StartCmd), StartResult, SizeOf(StartResult))<>0) then begin SetErrorCode(tErrorCode(ecFailStart)) end else if not StartResult.WaitReadyResult.Event then begin SetErrorCode(tErrorCode(ecTimeOut)); end else begin MarkTime; OperationTimeReSet(prTmpData.IntegrationTime+CurTimeOut); if not StartResult.WriteAndWaitResult1.Event and (prTmpData.IntegrationTime>1000) then begin SetErrorCode(tErrorCode(ecFailStart)); end; end; end; exStart:=NoError; end; (* function tCtrl.exStart:boolean; const cStart=(1 shl Ord(fBusy)); // const h0000:word=0; type tStartCmd=packed record Count:ULONG; // число операций в буфере Write1:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; WriteBuff1:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteAndWait1:tGENPORT_MULTIFUNCTION_IO_WRITE_AND_WAIT_INPUT; end; tStartResult=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; WriteAndWaitResult1:tGENPORT_MULTIFUNCTION_IO_WRITE_AND_WAIT_OUTPUT; end; var StartCmd:tStartCmd; StartResult:tStartResult; begin {$IfDef LogPortIO} PortsIOLog.LogStrLn('-----------StartCount'); {$EndIf Def LogPortIO} { PortsIO.OutByte(0, $120); PortsIO.OutByte(52, $124); PortsIO.OutByte(116, $124); PortsIO.OutByte(178, $124); PortsIO.OutByte((1000 mod 256), $126); PortsIO.OutByte((1000 div 256), $126); PortsIO.OutByte((prData.IntegrationTime mod 256), $125); PortsIO.OutByte((prData.IntegrationTime div 256), $125); PortsIO.OutByte(255, $127); PortsIO.OutByte(255, $127); PortsIO.OutByte(0, $120); PortsIO.OutByte(0, $122); PortsIO.OutByte(0, $121); PortsIO.OutByte(0, $121); PortsIO.OutByte(0, $123); prTmpData.IntegrationTime:=prData.IntegrationTime;} OperationTimeReSet(2*CurTimeOut); exReset; If exWait then with prTmpData.BusPtr^ do begin with StartCmd do begin Count:=3; { установить Gate } Write1.Header.OpCode.ULong:=Ord(mfocWrite); Write1.Port.Number:=prData.Ports.rwByte2_Gate; Write1.Port.PortType:=Ord(PORT_UCHAR); Write1.Data.UChar:=0; { досчитать 2 импульса } WriteBuff1.Header.OpCode.ULong:=Ord(mfocWriteBuffer); WriteBuff1.Port.Number:=prData.Ports.rwReady_PreCount; WriteBuff1.Port.PortType:=Ord(PORT_UCHAR); WriteBuff1.Count:=2; WriteBuff1.Data.ULong[0]:=0; { запустить и ждать старта } WriteAndWait1.Header.OpCode.ULong:=Ord(mfocWriteAndWait); WriteAndWait1.Data.WriteData.Port.Number:=prData.Ports.rwByte1_Start; WriteAndWait1.Data.WriteData.Port.PortType:=Ord(PORT_UCHAR); WriteAndWait1.Data.WriteData.Data.ULong:=0; WriteAndWait1.Data.WaitData.Port.Number:=prData.Ports.rwReady_PreCount; WriteAndWait1.Data.WaitData.Port.PortType:=Ord(PORT_UCHAR); WriteAndWait1.Data.WaitData.TimeOut:=StartWaitTimeout; WriteAndWait1.Data.WaitData.TimeResolution:=0; WriteAndWait1.Data.WaitData.Mask:=cStart; WriteAndWait1.Data.WaitData.Patt:=cStart; WriteAndWait1.Data.WaitData.ControlFlags:= (1 shl Ord(wcfWaitOnDISPATCH_Level)) {or (1 shl Ord(wcfUseQueryPerformanceCounter))}; end; // prTmpData.BusPtr^.exOutByteX(prData.Ports.rwByte2_Gate, 0); { установить Gate } // prTmpData.BusPtr^.exOutBytesX(prData.Ports.rwReady_PreCount, h0000, 2); { досчитать 2 импульса } MarkTime; // if ( prTmpData.BusPtr^.exOutByteAndWaitX( // prData.Ports.rwByte1_Start, 0, // prData.Ports.rwReady_PreCount, cStart, cStart, StartWaitTimeout // )<>0 // ) then begin if ( prTmpData.BusPtr^.exMultifunctionIO( StartCmd, SizeOf(StartCmd), StartResult, SizeOf(StartResult) )<>0 ) then begin SetErrorCode(tErrorCode(ecFailStart)) end else if not StartResult.WriteAndWaitResult1.Event then begin if (prTmpData.IntegrationTime>300) then SetErrorCode(tErrorCode(ecFailStart)); end else begin OperationTimeReSet(prTmpData.IntegrationTime+CurTimeOut); end; end; // prTmpData.BusPtr^.exOutByteX(prData.Ports.rwByte1_Start, 0); { запустить счет } // if (prTmpData.IntegrationTime>=500) and // (prTmpData.BusPtr^.exWaitX(prData.Ports.rwReady_PreCount, cStart, cStart, CurTimeOut)<>0) then begin // SetErrorCode(tErrorCode(ecFailStart)); // end else begin // OperationTimeReSet(prTmpData.IntegrationTime+CurTimeOut); // end; exStart:=NoError; end; *) function tCtrl.exReady:boolean; begin exReady:=FALSE; If NoError then begin if not (fBusy in tCtrlFlags(prTmpData.BusPtr^.exInByteX(prData.Ports.rwReady_PreCount))) then begin if (prTmpData.BusPtr^.NoError) then begin OperationTimeReset(0); exReady:=TRUE; end else begin SetErrorCode(tErrorCode(ecFailReady)); end; end; end; end; function tCtrl.exWaitReady:boolean; begin exWaitReady:=exLazyWait; end; function tCtrl.exRead:tSignalData; var Data:tSignalData; begin If exLazyWait then begin Data:=exJustRead; prData.LastData:=Data; exRead:=Data; end else begin exRead:=0; end; OperationTimeReset(0); end; function tCtrl.exJustRead:tSignalData; { возвращает текущее значение счетчика} var dw:tDWord; type tCmd=packed record Count:ULONG; // число операций в буфере ReadB1:tGENPORT_MULTIFUNCTION_IO_READ_INPUT; ReadB2:tGENPORT_MULTIFUNCTION_IO_READ_INPUT; ReadW2:tGENPORT_MULTIFUNCTION_IO_READ_BUFFER_INPUT; end; tResultData=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; ReadB1:tGENPORT_MULTIFUNCTION_IO_READ_OUTPUT; ReadB2:tGENPORT_MULTIFUNCTION_IO_READ_OUTPUT; ReadW2:tGENPORT_MULTIFUNCTION_IO_READ_BUFFER_OUTPUT; end; var ResultData:tResultData; const Cmd:tCmd=( Count:0; {1) чтение байта 1 } ReadB1:( Header:(OpCode:(ULong:Ord(mfocRead))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); ); {2) чтение байта 2 } ReadB2:( Header:(OpCode:(ULong:Ord(mfocRead))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); ); {3) чтение слова 2 } ReadW2:( Header:(OpCode:(ULong:Ord(mfocReadBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; ); ); begin exJustRead:=0; If NoError then begin with Cmd do begin if Count=0 then begin Count:=3; {1) чтение байта 1 } ReadB1.Port.Number:=prData.Ports.rwByte1_Start; {2) чтение байта 2 } ReadB2.Port.Number:=prData.Ports.rwByte2_Gate; {3) чтение слова 2 } ReadW2.Port.Number:=prData.Ports.rwBytes3_4; end; end; if prTmpData.BusPtr^.exMultifunctionIO(Cmd, SizeOf(Cmd), ResultData, SizeOf(ResultData))=0 then begin dw.b1:=ResultData.ReadB1.Data.UChar; dw.b2:=ResultData.ReadB2.Data.UChar; dw.w2:=not ResultData.ReadW2.Data.UShort[0]; exJustRead:=tSignalData(dw); end else begin Self.SetErrorCode(tErrorCode(ecFailRead)); end; end; end; (* function tCtrl.exJustRead:tSignalData; { возвращает текущее значение счетчика} var dw:tDWord; begin exJustRead:=0; If NoError then begin dw.b1:=prTmpData.BusPtr^.exInByteX(prData.Ports.rwByte1_Start); dw.b2:=prTmpData.BusPtr^.exInByteX(prData.Ports.rwByte2_Gate); prTmpData.BusPtr^.exInBytesX(prData.Ports.rwBytes3_4, dw.w2, 2); dw.w2:=not dw.w2; if prTmpData.BusPtr^.NoError then begin exJustRead:=tSignalData(dw); end else begin Self.SetErrorCode(tErrorCode(ecFailRead)); end; end; end; *) { * PRIVATE секция } procedure tCtrl.exInitialReset; begin CheckExInitDone; if (fDoInitialResetCtrl in prData.Flags) then exReset; end; procedure tCtrl.DelayWait; var t:longint; const cDt=10; begin If NoError then begin t:=IntelliTimeOut(prTmpData.IntegrationTime,0); Dec(t,cDt); if t>0 then prTmpData.BusPtr^.Delay(t); end; end; function tCtrl.exWait:boolean; var t,t0:tTiks; begin If NoError then begin t:=IntelliTimeOut(tTiks(prTmpData.IntegrationTime)+CurTimeOut,CurTimeOut); t0:=OperationTime; OperationTimeSet(t); exWait:=TRUE; if prTmpData.BusPtr^.exLazyWaitX_NTE( prData.Ports.rwReady_PreCount, (1 shl Ord(fBusy)), 0, t,cLazyWaitTimeIntervalMin )<>0 then begin SetErrorCode(tErrorCode(ecTimeOut)); exWait:=FALSE; end else begin OperationTimeReset(t0); end; end else begin exWait:=FALSE; end; end; function tCtrl.exLazyWait:boolean; var t,t0:tTiks; begin If not exReady then begin DelayWait; t:=prTmpData.IntegrationTime+CurTimeOut; t0:=OperationTime; OperationTimeSet(t); if (prTmpData.BusPtr^.exLazyWaitX_NTE(prData.Ports.rwReady_PreCount, (1 shl Ord(fBusy)), 0, t, prTmpData.LazyWaitTimeInterval)=0) then begin exLazyWait:=TRUE; OperationTimeReSet(t0); end else begin SetErrorCode(tErrorCode(ecTimeOut)); exLazyWait:=FALSE; end; end else begin exLazyWait:=TRUE; end; end; function tCtrl.exResetTrigger:boolean; begin If NoError then begin exResetTrigger:=TRUE; prTmpData.BusPtr^.exOutByteX(prData.Ports.owResetTrigger, 0); if prTmpData.BusPtr^.Error then begin Self.SetErrorCode(tErrorCode(ecFailResetTrigger)); exResetTrigger:=FALSE; end; end else begin exResetTrigger:=FALSE; end; end; function tCtrl.exReset:boolean; type tCmd=packed record Count:ULONG; // число операций в буфере WriteCtlWord:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteTimeOut:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteDivCoeff:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteInitCounter:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteResetTrigger:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; end; tResultData=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; end; var ResultData:tResultData; x:longint; lIntegrationTime:word; const Cmd:tCmd=( Count:0; {1) запись управляющего слова таймера } WriteCtlWord:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:3; Data:(ULong:($3474B2)); { управляющие слово таймеров для счетчика ионов} ); {2) запись времени интегрирования таймера} WriteTimeOut:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; ); {3) запись коэффициента деления таймера } WriteDivCoeff:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; ); {4) инициализация счетчика таймера } WriteInitCounter:( Header:(OpCode:(ULong:Ord(mfocWriteBuffer))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Count:2; Data:(ULong:($FFFF)); { байты для записи в счетчики при инициализации } ); {5) сброс триггера } WriteResetTrigger:( Header:(OpCode:(ULong:Ord(mfocWrite))); Port:(Number:0; PortType:Ord(PORT_UCHAR)); Data:(ULong:0); ); ); begin exReset:=FALSE; If ( (prData.Flags*[fDoInitialResetCtrl, fResetCtrl]<>[]) or (fResetCtrlOnce in prTmpData.Flags)) then begin { считывание локально текущего времени, для обеспечения реентерабельности и многопотоковости } lIntegrationTime:=prData.IntegrationTime; { перевод времени из миллисекунд в соответствии с коэффициентом деления } x:=DCandIT2Counter(prData.DivCoeff, lIntegrationTime); if (0<>x) then begin with Cmd do begin if Count=0 then begin Count:=5; {1) запись управляющего слова таймера } WriteCtlWord.Port.Number:=prData.Ports.owTimerCntrlWord; {2) запись времени интегрирования таймера} WriteTimeOut.Port.Number:=prData.Ports.owTimerIntegrationTime; {3) запись коэффициента деления таймера } WriteDivCoeff.Port.Number:=prData.Ports.owDivisionCoefficient; {4) инициализация счетчика таймера } WriteInitCounter.Port.Number:=prData.Ports.rwBytes3_4; {5) сброс триггера } WriteResetTrigger.Port.Number:=prData.Ports.owResetTrigger; end; {2) запись времени интегрирования таймера} WriteTimeOut.Data.ULong[0]:=x; {3) запись коэффициента деления таймера } WriteDivCoeff.Data.ULong[0]:=prData.DivCoeff; end; { Установка параметров контроллера } if prTmpData.BusPtr^.exMultifunctionIO(Cmd, SizeOf(Cmd), ResultData, SizeOf(ResultData))=0 then begin { запоминание установленного времени интегрирования, для обеспечения реентерабельности и многопотоковости } prTmpData.IntegrationTime:=lIntegrationTime; Exclude(prTmpData.Flags, fResetCtrlOnce); Exclude(prData.Flags, fDoInitialResetCtrl); exReset:=TRUE; end else begin Self.SetErrorCode(tErrorCode(ecFailReset)); end; end else begin SetErrorCode(tErrorCode(ecInvalid_Time_DivCoeff_Combination)); end; end else begin exReset:=exResetTrigger; end; end; (*function tCtrl.exReset:boolean; const h3474B2:array[1..3] of Byte=($34, $74, $B2); { управляющие слова таймеров для счетчика ионов} hFFFF:word=$FFFF; { байты для записи в счетчики при инициализации } type tStartCmd=packed record Count:ULONG; // число операций в буфере WriteCtlWord:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteTimeOut:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteDivCoeff:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteInitCounter:tGENPORT_MULTIFUNCTION_IO_WRITE_BUFFER_INPUT; WriteResetTrigger:tGENPORT_MULTIFUNCTION_IO_WRITE_INPUT; end; tStartResult=packed record Header:tGENPORT_MULTIFUNCTION_IO_OUTPUT_HEADER; end; var StartCmd:tStartCmd; StartResult:tStartResult; var x:longint; lIntegrationTime, TimeCount:word; begin exReset:=FALSE; {$IFNdef DBG} временное исправление {$EndIF} if fResetCtrlOnce in prTmpData.Flags then begin MarkTime; end; If exResetTrigger and ((fDoInitialResetCtrl in prData.Flags) or (fResetCtrl in prData.Flags) or (fResetCtrlOnce in prTmpData.Flags)) then begin with prData.Ports do begin { считывание локально текущего времени, для обеспечения реентерабельности и многопотоковости } lIntegrationTime:=prData.IntegrationTime; { перевод времени из миллисекунд в соответствии с коэффициентом деления } x:=DCandIT2Counter(prData.DivCoeff, lIntegrationTime); if (0<>x) then with prTmpData.BusPtr^ do begin TimeCount:=x; with StartCmd do begin Count:=5; {1 запись управляющего слова таймера } WriteCtlWord.Header.OpCode.ULong:=Ord(mfocWriteBuffer); WriteCtlWord.Port.Number:=prData.Ports.owTimerCntrlWord; WriteCtlWord.Port.PortType:=Ord(PORT_UCHAR); WriteCtlWord.Count:=3; WriteCtlWord.Data.ULong[0]:=$3474B2; {2 запись времени интегрирования таймера} WriteTimeOut.Header.OpCode.ULong:=Ord(mfocWriteBuffer); WriteTimeOut.Port.Number:=prData.Ports.owTimerIntegrationTime; WriteTimeOut.Port.PortType:=Ord(PORT_UCHAR); WriteTimeOut.Count:=2; WriteTimeOut.Data.ULong[0]:=TimeCount; {3 запись коэффициента деления таймера } WriteDivCoeff.Header.OpCode.ULong:=Ord(mfocWriteBuffer); WriteDivCoeff.Port.Number:=prData.Ports.owDivisionCoefficient; WriteDivCoeff.Port.PortType:=Ord(PORT_UCHAR); WriteDivCoeff.Count:=2; WriteDivCoeff.Data.ULong[0]:=prData.DivCoeff; {4 инициализация счетчика таймера } WriteInitCounter.Header.OpCode.ULong:=Ord(mfocWriteBuffer); WriteInitCounter.Port.Number:=prData.Ports.rwBytes3_4; WriteInitCounter.Port.PortType:=Ord(PORT_UCHAR); WriteInitCounter.Count:=2; WriteInitCounter.Data.ULong[0]:=$FFFF; {5 сброс триггера } WriteResetTrigger.Header.OpCode.ULong:=Ord(mfocWrite); WriteResetTrigger.Port.Number:=prData.Ports.owResetTrigger; WriteResetTrigger.Port.PortType:=Ord(PORT_UCHAR); WriteResetTrigger.Data.UChar:=0; end; prTmpData.BusPtr^.exMultifunctionIO( StartCmd, SizeOf(StartCmd), StartResult, SizeOf(StartResult) ); { Установка параметров контроллера } // PortsIO.OutByte(52, $124); // PortsIO.OutByte(116, $124); // PortsIO.OutByte(178, $124); // exOutBytesX(owTimerCntrlWord, h3474B2, 3); {запись управляющего слова таймера } // PortsIO.OutByte((TimeCount mod 256), $125); // PortsIO.OutByte((TimeCount div 256), $125); // exOutBytesX(owTimerIntegrationTime, TimeCount, 2); {запись времени интегрирования таймера} // if prTmpData.BusPtr^.NoError then begin { запоминание установленного времени интегрирования, для обеспечения реентерабельности и многопотоковости } // prTmpData.IntegrationTime:=lIntegrationTime; // end; // PortsIO.OutByte((1000 mod 256), $126); // PortsIO.OutByte((1000 div 256), $126); // exOutBytesX(owDivisionCoefficient, prData.DivCoeff, 2); {запись коэффициента деления таймера } // PortsIO.OutByte(255, $127); // PortsIO.OutByte(255, $127); // exOutBytesX(rwBytes3_4, hFFFF, 2); {инициализация счетчика таймера } // if exResetTrigger then begin if prTmpData.BusPtr^.NoError then begin { запоминание установленного времени интегрирования, для обеспечения реентерабельности и многопотоковости } prTmpData.IntegrationTime:=lIntegrationTime; Exclude(prTmpData.Flags, fResetCtrlOnce); Exclude(prData.Flags, fDoInitialResetCtrl); exReset:=TRUE; end else begin Self.SetErrorCode(tErrorCode(ecFailReset)); end; end else begin SetErrorCode(tErrorCode(ecInvalid_Time_DivCoeff_Combination)); end; end; MarkTime; end; end;*) procedure tCtrl.exDone; begin if IsExDoneDone then Exit; if not CheckExInitDone then Exit; SetNoError; exReset; SetExInitDone(FALSE); SetExDoneDone(NoError); Inherited exDone; end; procedure tCtrl.exDetectCtrl(var x:tCtrlAlive); var c:word; begin c:=prTmpData.BusPtr^.exScanNotFFportsX(prData.Ports, (SizeOf(prData.Ports) shr 1)); case c of cCtrlAlive:x:=aYes; 0: x:=aNo; else if c>=(cCtrlAlive shr 1) then x:=aMayBeYes else x:=aMayBeNo; end; end; procedure tCtrl.exReadPortsData; var i:tPort; begin ClearPortsDataX(PD); if NoError then begin for i:=Low(tPort) to High(tPort) do begin if not (i in cUnreadablePorts) then begin PD[Ord(i)]:=prTmpData.BusPtr^.exInByteX(prData.Ports.Ports[i]); if prTmpData.BusPtr^.Error then begin SetErrorCode(Ord(ecFailReadPortsData)); break; end; end; end; end; if NoError then begin i:=High(i); if not (i in cUnreadablePorts) then begin PD[Ord(i)]:=prTmpData.BusPtr^.exInByte(prData.Ports.Ports[i]); if prTmpData.BusPtr^.Error then begin SetErrorCode(Ord(ecFailReadPortsData)); end; end; end; end; procedure tCtrl.exSavePortsData; begin exReadPortsData(prData.PortsData); end; procedure tCtrl.ClearPortsData; begin ClearPortsDataX(prData.PortsData); end; function tCtrl.exIsNotChangedPortsData:boolean; var PD:tPortsArray; begin exReadPortsData(pd); exIsNotChangedPortsData:=Equal(PD,prData.PortsData,SizeOf(PD)); end; function tCtrl.PortsNumber:word; begin PortsNumber:=Succ(Ord(High(tPort)))+1; end; function tCtrl.exReadSafePorts(var PortsValues:tPortValuesArray; Count:word):boolean; var i:tPort; begin if NoError and (Count=PortsNumber) then begin for i:=Low(tPort) to High(tPort) do begin if not (i in cUnreadablePorts) then begin PortsValues[Ord(i)]:=prTmpData.BusPtr^.exInByteX(prData.Ports.Ports[i]); if prTmpData.BusPtr^.Error then begin SetErrorCode(Ord(ecFailReadPortsData)); break; end; end; end; end; if NoError then begin i:=High(i); if not (i in cUnreadablePorts) then begin PortsValues[Succ(Ord(i))]:=prTmpData.BusPtr^.exInByte(prData.Ports.Ports[i]); if prTmpData.BusPtr^.Error then begin SetErrorCode(Ord(ecFailReadPortsData)); end; end; end; exReadSafePorts:=NoError; end; END.