File: DETECUSE\detecuse.cpp
1 /*
2 $Header: /vol/baal-vol3/projekt98/quellen/XCTL_32/DETECUSE/detecuse.cpp,v 1.40 2004/08/16 13:55:14 reinecke Exp $
3
4 Projekt : XCTL
5 Subsystem : Detektoren
6 Autor : Jan Picard <picard@informatik.hu-berlin.de> 2001-2002
7 Institut fuer Informatik,
8 Humboldt-Universitaet Berlin
9 Inhalt : Code fuer das Interface des Detektoren-Subsystems
10 */
11
12 #include "utils\u_utils.h"
13 #include "winresrc\rc_def.h" // Ressourcen-IDs
14 #include <string.h>
15
16 // TCurve
17 //#include "datavisa\datavisa.h"
18
19 #include "detecuse\detecuse.h"
20 #include "detecuse\detecmes.h"
21 #include "detecuse\detecgui.h"
22
23 #include "utils\CheckMemory.h" //DUMPMEM
24
25 //--||--\\--||--//--||--\\--||--//--||--\\--||--//--||--\\--||--//--||--\\--||--
26
27 // #############################################################################
28 // Implementationsdetails fuer TDetectorManager
29 //
30 // Da BC45 den STL-Datentyp vector<TDetector*> nicht unterstuetzt,
31 // hier eine Implementation als verkettete Liste.
32 // Diese Details sind absichtlich ausserhalb der Klassendeklaration von
33 // TDetectorManager realisiert, damit diese Implementation nach Umstieg auf VC++
34 // geaendert werden kann.
35 // #############################################################################
36
37 //! Verkettete Liste von Zeigern auf TDetector-Objekte
38 class TDListNode
39 {
40 public:
41 TDListNode();
42 ~TDListNode();
43
44 //! fuegt einen TDetector-Zeiger zum Container hinzu
45 void push_back(TDetector*);
46
47 //! gibt den im entsprechenden Knoten gespeicherten TDetector-Zeiger zurueck
48 TDetector* node()
49 {
50 return m_detector;
51 };
52
53 //! gibt den naechsten Knoten der verketteten Liste zurueck
54 TDListNode* next()
55 {
56 return m_next;
57 };
58
59 //! gibt die Laenge der Liste zurueck
60 int size()
61 {
62 return m_size;
63 };
64
65 private:
66
67 //! der in diesem Knoten gespeicherte Detektor
68 TDetector* m_detector;
69
70 //! Zeiger auf den naechsten Knoten der Liste
71 TDListNode* m_next;
72
73 //! Laenge der Liste
74 int m_size;
75 };
76
77 TDListNode::TDListNode()
78 {
79 m_next= 0;
80 m_detector= 0;
81 m_size= 0;
82 }
83
84 TDListNode::~TDListNode()
85 {
86 // rekursive Destruktion
87 _FREEOBJ(m_next);
88
89 _FREEOBJ(m_detector);
90 }
91
92 void TDListNode::push_back(TDetector* param)
93 {
94 if ( m_detector == 0 )
95 m_detector= param;
96 else
97 {
98 if (m_next == 0)
99 m_next= new TDListNode();
100
101 m_next->push_back(param);
102 }
103 m_size++;
104 }
105
106 static TDListNode* DetectorContainer;
107
108 //******************************************************************************
109 //########### Methoden zum Verwalten der Detektoren ############################
110 //******************************************************************************
111
112 TDetectorManager::TDetectorManager()
113 {
114 SetInfo("Erstellen der Detektoren-Liste");
115
116 DetectorContainer= new TDListNode();
117
118 int id= 0;
119 char Ident[20];
120 char buf[127];
121
122 // Alle "deviceX"-Abschnitte der hardware.ini abarbeiten,
123 // fuer jeden gueltigen Abschnitt wird ein TDetector-Objekt erstellt
124 do
125 {
126 sprintf( Ident, "Device%d", id );
127 GetPrivateProfileString( Ident, "Type", "", buf, MaxString, GetHWFile() );
128
129 // Der kuerzeste Typ ist "PSD", jeder kuerzere Wert ist entweder falsch
130 // oder gar nicht deklariert ( buf == "" )
131 if ( strlen(buf) < 3)
132 break;
133
134 CreateDetector(buf, id);
135 id++;
136 }
137 while (1);
138
139 if (DetectorContainer->node() == 0)
140 {
141 MessageBox(0, "Es wurde kein nutzbarer Detektor gefunden.\n"
142 "Das Programm wird jetzt beendet",
143 "Kritischer Fehler", MBFAILURE);
144
145 _FREEOBJ(DetectorContainer); //hp
146 exit(4);
147 }
148
149 ActiveDetector= DetectorContainer->node();
150 }
151
152 TDetectorManager::~TDetectorManager( void )
153 {
154 _FREEOBJ(DetectorContainer);
155 };
156
157 TDetectorManager& TDetectorManager::DetectorManager()
158 {
159 // die Singleton-Instanz
160 static TDetectorManager theDetectorManager;
161
162 return theDetectorManager;
163 }
164
165 void TDetectorManager::CreateDetector(const char* type, int id)
166 {
167 TDetector* newDetector;
168
169 char szDetectorType[MaxString];
170 strcpy(szDetectorType, type);
171 strupr(szDetectorType);
172
173 if ( strcmp( szDetectorType, "GENERIC" ) == 0)
174 newDetector= new TGenericDetector(id);
175 else
176 if ( strcmp( szDetectorType, "STOE-PSD" ) == 0)
177 newDetector= new TStoePsd(id);
178 else
179 if ( strcmp( szDetectorType, "RADICON" ) == 0)
180 newDetector= new TRadicon(id);
181 else
182 if ( strcmp( szDetectorType, "BRAUN-PSD" ) == 0)
183 newDetector= new TBraunPsd(id);
184 else
185 if ( strcmp( szDetectorType, "PSD" ) == 0)
186 newDetector= new TOneDimTestDetector(id);
187 else
188 if ( strcmp( szDetectorType, "TEST" ) == 0)
189 newDetector= new Testdev(id);
190 else
191 newDetector= new TZeroDimSimpleTestDetector(id);
192
193 char buf[127];
194 sprintf( buf, "Initialisieren des Detektors %s",
195 newDetector->GetCharacteristic() );
196 SetInfo( buf );
197
198 // Versuch, den Detektor zu initalisieren. Gibt Initialize() FALSE
199 // zurueck, ist der Detektor nicht nutzbar. Das Detektor-Objekt
200 // wird zerstoert und nicht in den DetectorContainer eingefuegt.
201 if (newDetector->Initialize())
202 DetectorContainer->push_back(newDetector);
203 else
204 {
205 sprintf( buf, "Detektor %s konnte nicht initialisiert werden.",
206 newDetector->GetCharacteristic() );
207 MessageBox( GetFocus( ), buf, "Detector-Fehler", MBSTOP );
208
209 _FREEOBJ(newDetector);
210 }
211 }
212
213 BOOL TDetectorManager::DimAvailable(int dimension) const
214 {
215 // Da sich die Liste der nutzbaren Detektoren nicht nach der Erstellung
216 // nicht mehr aendert, kann das Ergebnis zwischengespeichert werden.
217 static BOOL bDim[3]= { FALSE, FALSE, FALSE };
218 static BOOL bIsCached= FALSE;
219
220 if ( ( dimension < 0 ) || ( dimension > 2) )
221 return FALSE;
222
223 if ( bIsCached == FALSE )
224 {
225 TDListNode* DCIterator= DetectorContainer;
226
227 // Iterieren ueber den Container und Ermitteln, ob von jeder Dimension
228 // mindestens ein Detektor nutzbar ist.
229 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
230 {
231 bDim[DCIterator->node()->GetDimension()]= TRUE;
232 DCIterator= DCIterator->next();
233 }
234
235 bIsCached= TRUE;
236 }
237
238 return bDim[dimension];
239 }
240
241 BOOL TDetectorManager::IsValidId(int n) const
242 {
243 return ( ( n >= 0 ) && ( n <= DetectorContainer->size()) );
244 }
245
246 TDetector* TDetectorManager::GetDetector( void ) const
247 {
248 return ActiveDetector;
249 }
250
251 TDetector* TDetectorManager::GetDetector( int n, int nFilterDimension ) const
252 {
253 if (! IsValidId(n) )
254 return ActiveDetector;
255
256 TDListNode* DCIterator= DetectorContainer;
257 TDetector* theDetector;
258 int nCounter= 0;
259
260 // nur wenn die Dimension gefiltert wird
261 if ( nFilterDimension == 0 || nFilterDimension == 1 )
262 {
263 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
264 {
265 theDetector= DCIterator->node();
266 if ( theDetector->GetDimension() == nFilterDimension )
267 {
268 // nur wenn es der nte Detektor der gesuchten Dimension ist
269 if ( nCounter == n )
270 return theDetector;
271
272 nCounter++;
273 }
274 DCIterator= DCIterator->next();
275 }
276 // nicht gefunden
277 return ActiveDetector;
278 }
279
280 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
281 {
282 // den nten Detektor zurueckgeben
283 if ( nCounter == n )
284 return DCIterator->node();
285 nCounter++;
286
287 DCIterator= DCIterator->next();
288 }
289
290 return ActiveDetector;
291 }
292
293 BOOL TDetectorManager::SetDetector( int n, int nFilterDimension )
294 {
295 if (! IsValidId(n) )
296 return FALSE;
297
298 TDListNode* DCIterator= DetectorContainer;
299 TDetector* theDetector;
300 int nCounter= 0;
301
302 // nur wenn die Dimension gefiltert wird
303 if ( nFilterDimension == 0 || nFilterDimension == 1 )
304 {
305 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
306 {
307 theDetector= DCIterator->node();
308 if ( theDetector->GetDimension() == nFilterDimension )
309 {
310 // nur wenn es der nte Detektor der gesuchten Dimension ist
311 if ( nCounter == n )
312 {
313 ActiveDetector= theDetector;
314 return TRUE;
315 }
316
317 nCounter++;
318 }
319 DCIterator= DCIterator->next();
320 }
321 return FALSE;
322 }
323
324 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
325 {
326 // den nten Detektor aktivieren
327 if ( nCounter == n )
328 {
329 ActiveDetector= DCIterator->node();
330 return TRUE;
331 }
332 nCounter++;
333 DCIterator= DCIterator->next();
334 }
335
336 return FALSE;
337 }
338
339 BOOL TDetectorManager::SetDetector( const TDetector* newDetector )
340 {
341 TDListNode* DCIterator= DetectorContainer;
342 TDetector* theDetector;
343
344 // nur wenn dieser Detektor in unserer Liste vorkommt
345 // eigentlich eine Vorsichtsmassnahmen
346 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
347 {
348 theDetector= DCIterator->node();
349 if ( theDetector == newDetector )
350 {
351 ActiveDetector= theDetector;
352 return TRUE;
353 }
354 DCIterator= DCIterator->next();
355 }
356 return FALSE;
357 }
358
359 void TDetectorManager::FillDetectorComboBox( HWND comboBox, int nFilterDimension) const
360 {
361 TDListNode* DCIterator= DetectorContainer;
362 TDetector* theDetector;
363
364 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
365 {
366 theDetector= DCIterator->node();
367 switch (nFilterDimension)
368 {
369 case 0:
370 case 1:
371 case 2:
372 if ( theDetector->GetDimension() == nFilterDimension )
373 ComboBox_AddString( comboBox, theDetector->GetCharacteristic() );
374 break;
375
376 default:
377 ComboBox_AddString( comboBox, theDetector->GetCharacteristic() );
378 break;
379 }
380 DCIterator= DCIterator->next();
381 }
382 }
383
384 int TDetectorManager::GetIdByDescription( LPCSTR detectorname ) const
385 {
386 int nCounter= 0;
387
388 TDListNode* DCIterator= DetectorContainer;
389
390 while ( ( DCIterator != 0 ) && ( DCIterator->node() != 0 ) )
391 {
392 if ( strcmp( DCIterator->node()->GetCharacteristic(), detectorname ) == 0 )
393 return nCounter;
394
395 nCounter++;
396 DCIterator= DCIterator->next();
397 }
398 return -1;
399 }
400
401 //******************************************************************************
402 // TDetector
403 //******************************************************************************
404
405 TDetector::TDetector(int id)
406 {
407 nId= id;
408 exposure= TExposureSettings( 0.7f, 20000 );
409 fIntensity= 1.0f;
410 fSigma= 0.1f;
411 bDataValid= FALSE;
412 bActive= FALSE;
413 hWndFrame= GetFrameHandle();
414 hControlWnd= NULL;
415 hCounterWnd= NULL;
416 uAskTime= 300;
417
418 LoadDetectorSettings();
419 }
420
421 TDetector::~TDetector( )
422 {
423 SaveDetectorSettings();
424 }
425
426 void TDetector::LoadDetectorSettings()
427 {
428 char buf[ MaxString ];
429
430 GetPrivateProfileString( "Name", "Counter", szCharacteristic);
431
432 GetPrivateProfileString( "Debug", "0", buf);
433 bDebug= ( atoi( buf ) != 0 );
434
435 GetPrivateProfileString( "ExposureTime", "4.0", buf);
436 exposure.SetExposureTime( atof( buf ));
437
438 GetPrivateProfileString( "ExposureCounts", "10000", buf);
439 exposure.SetExposureCounts( atol( buf ));
440 }
441
442 void TDetector::SaveDetectorSettings() const
443 {
444 char buf[ MaxString ];
445
446 sprintf( buf, "%.2f", exposure.GetExposureTime() );
447 WritePrivateProfileString( "ExposureTime", buf);
448 sprintf( buf, "%ld", exposure.GetExposureCounts() );
449 WritePrivateProfileString( "ExposureCounts", buf);
450 }
451
452 BOOL TDetector::SetExposureSettings (const TExposureSettings& newExposureSettings)
453 {
454 exposure= newExposureSettings;
455
456 return SetParameters();
457 }
458
459 BOOL TDetector::Initialize( void )
460 {
461 PushSettings( );
462 return TRUE;
463 }
464
465 void TDetector::UpdateViews(BOOL bDisplayOnly) const
466 {
467 if ( GetCounterWnd() )
468 // Display benachrichtigen
469 PostMessage( GetCounterWnd(), WM_COMMAND, cm_CounterSet, nId );
470
471 if ( bDisplayOnly )
472 return;
473
474 if ( GetControlWnd() )
475 // Daten-Empfaenger benachrichtigen
476 PostMessage( GetControlWnd(), WM_COMMAND, cm_CounterSet, nId );
477 }
478
479 BOOL TDetector::SetParameters( void )
480 {
481 // Wenn keine Messung lief, einfach Parameter setzen
482 if ( bActive == FALSE )
483 return _SetParameters();
484
485 // Sonst Messung erst beenden, Parameter setzen und Messung wieder starten
486 MeasureStop();
487 BOOL bRetCode= _SetParameters();
488 MeasureStart();
489 return bRetCode;
490 }
491
492 TDetector::PushSettings( void )
493 {
494 Settings.exposure= exposure;
495 return TRUE;
496 }
497
498 TDetector::PopSettings( void )
499 {
500 exposure= Settings.exposure;
501
502 SetParameters( );
503
504 return TRUE;
505 }
506
507 //! Einfache Refaktorisierung (Methode extrahieren)
508 //! Laedt den Wert fuer einen angegebenen Schluessel aus der hardware.ini
509 //! und schreibt bei Bedarf einen Default-Wert zurueck.
510 DWORD TDetector::GetPrivateProfileString(LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, UINT iMaxLen ) const
511 {
512 char Ident[20];
513 sprintf( Ident, "Device%d", GetId() );
514
515 DWORD ret= ::GetPrivateProfileString(
516 Ident, lpKeyName, lpDefault, lpReturnedString, iMaxLen, GetHWFile() );
517
518 if ( CreateIniDefaults() )
519 ::WritePrivateProfileString( Ident, lpKeyName, lpReturnedString, GetHWFile());
520
521 return ret;
522 }
523
524 DWORD
525 TDetector::WritePrivateProfileString( LPCSTR lpKeyName, LPCSTR lpString) const
526 {
527 char Ident[20];
528 sprintf( Ident, "Device%d", GetId() );
529
530 return ::WritePrivateProfileString( Ident, lpKeyName, lpString, GetHWFile());
531 }
532
533 float TDetector::CalculateSigma(float intensity, float factor)
534 {
535 if ( intensity == 0.0 )
536 return 1.0;
537
538 return factor * sqrt(intensity) / intensity;
539 }
540
541 double TDetector::MillisecondsToSeconds( DWORD milliseconds )
542 {
543 double integerPart= ( (double)milliseconds ) / 1000.0;
544 double fractionalPart= ( (double)(milliseconds % 1000) ) / 1000.0;
545 return ( integerPart + fractionalPart );
546 }
547
548 //############################################################################
549 // TZeroDimDetector
550 //############################################################################
551
552 // time event handling
553 int nEventsToCall;
554 int nEvent;
555 int nEventsCalled;
556 float fEventIntensity;
557 HWND hEventControlWnd;
558 BOOL bEventDataValid;
559
560 TZeroDimDetector::TZeroDimDetector(int id) : TDetector(id)
561 {
562 bSound= FALSE;
563 LoadDetectorSettings();
564 }
565
566 TZeroDimDetector::~TZeroDimDetector()
567 {
568 SaveDetectorSettings();
569 }
570
571 void TZeroDimDetector::SetSound(BOOL bSoundParam)
572 {
573 bSound= bSoundParam;
574 }
575
576 void TZeroDimDetector::LoadDetectorSettings()
577 {
578 char buf[ MaxString ];
579
580 GetPrivateProfileString( "Sound", "1", buf);
581 bSound= atoi( buf );
582 }
583
584 void TZeroDimDetector::SaveDetectorSettings() const
585 {
586 char buf[ MaxString ];
587
588 sprintf( buf, "%d", bSound );
589 WritePrivateProfileString( "Sound", buf);
590 }
591
592 BOOL TZeroDimDetector::Initialize( void )
593 {
594 return TDetector::Initialize();
595 }
596
597 int TZeroDimDetector::MeasureStart( void )
598 {
599 if (bActive)
600 MeasureStop( );
601
602 if ( bDebug )
603 SetInfo( "MStart" );
604
605 if ( ! GetControlWnd() && ! GetCounterWnd() )
606 return R_Failure;
607
608 uAskTime= TRange<UINT>(500, 7000).ForceIntoRange(
609 GetExposureSettings().GetExposureTime() * 1100 );
610
611 SetTimer( hWndFrame, DetectorTimerIdStart + GetId(), uAskTime, NULL );
612 bDataValid= FALSE;
613 bActive= TRUE;
614 return R_MeasOk;
615 }
616
617 int TZeroDimDetector::MeasureStop( void )
618 {
619 if ( !bActive )
620 return R_MeasOk;
621
622 KillTimer( hWndFrame, DetectorTimerIdStart + GetId() );
623
624 if ( bDebug && bActive )
625 SetInfo( "MStop" );
626
627 bActive= FALSE;
628
629 return R_MeasOk;
630 }
631
632 int TZeroDimDetector::GetIntegral( float &data )
633 {
634 data= 0.0;
635
636 if ( !bDataValid )
637 return R_Failure;
638
639 data= fIntensity;
640
641 fSigma= CalculateSigma ( fIntensity );
642
643 return R_OK;
644 }
645
646 //! Methode wird periodisch aufgerufen (Initialisierung in InitializeEvent)
647 //! realisiert Intensitaetsmessung waehrend dem zeitintervall zwischen zwei
648 //! Aufrufen der Methode (fuer kontinuierlichen Scan)
649 //! anschliessend wird das Scanfenster benachrichtigt
650 //! (cm_CounterSet waehrend messung; cm_SteeringReady bei letzter Messung)
651 //! hier nur Simulation
652 CALLBACK TZeroDimDetector::EventHandler( UINT, UINT, DWORD, DWORD, DWORD )
653 {
654 double angx;
655
656 nEventsCalled++;
657 // mlGetDistance(angx);
658 angx= ( nEventsCalled - nEventsToCall / 2 ) * 0.246;
659 angx= angx * angx / 11.3;
660 fEventIntensity= 32000 / ( 1 + 1.8 * angx * angx ) + ( rand( ) % 80 ) + 270;
661
662 //! Messwert gueltig
663 bEventDataValid= TRUE;
664 PostMessage( hEventControlWnd, WM_COMMAND, cm_CounterSet, nEventsCalled );
665
666 if ( nEventsCalled == nEventsToCall )
667 {
668 timeKillEvent( nEvent );
669 PostMessage( hEventControlWnd, WM_COMMAND, cm_SteeringReady, 0l );
670 // bEventDataValid= FALSE;
671 }
672
673 return R_OK;
674 }
675
676 //! macht dem Detektor das Fenster bekannt, an das er innerhalb von EventHandler
677 //! seine Nachrichten schicken soll
678 //! (fuer kontinuierlichen Scan)
679 void TZeroDimDetector::SetEventHost( HWND hwnd)
680 {
681 hEventControlWnd= hwnd;
682 }
683
684 //! loescht Detektor-Event
685 //! sorgt, dafuer dass Eventhandler nicht mehr aufgerufen wird
686 //! (fuer kontinuierlichen Scan)
687 void TZeroDimDetector::KillEvent(void)
688 {
689 timeKillEvent( nEvent );
690 }
691
692 //! liefert die durch EventHandler gemessene Intensitaet im Parameter zurueck
693 //! Rueckkehrcode TRUE
694 //! nur einmal Auslesen eines Wertes erlaubt
695 //! bei wiederholtem Ausleseversuch 0 in Parameter und
696 //! Rueckkehrcode FALSE
697 //! (fuer kontinuierlichen Scan)
698 BOOL TZeroDimDetector::GetEventIntensity( float &data)
699 {
700 data= 0;
701
702 if (!bEventDataValid)
703 return FALSE;
704
705 data= fEventIntensity;
706
707 bEventDataValid= FALSE;
708
709 return TRUE;
710 }
711
712 //! initialisiert ein periodisches Aufrufen der Methode EventHandler
713 //! 2. Parameter gibt Anzahl der Aufrufe an
714 //! Aufrufintervall entspricht der Messzeit
715 //! Rueckkehrcode FALSE wenn Aufrufintervall < 0.1 sek.
716 //! sonst TRUE (wenn erfolgreich)
717 //! (fuer kontinuierlichen Scan)
718 BOOL TZeroDimDetector::InitializeEvent( HWND hwnd, int ec )
719 {
720 int EventTime= 1000.0 * exposure.GetExposureTime();
721
722 SetControlWnd(hwnd);
723 nEventsCalled= 0;
724 nEventsToCall= ec;
725 // check calltime
726
727 if ( EventTime <= 100 )
728 {
729 MessageBox( GetFocus( ), "Meßzeit wurde zu klein gewählt !", "InitializeEvent", MBINFO );
730 return FALSE;
731 }
732
733 if ( NULL != GetControlWnd() )
734 nEvent= timeSetEvent( EventTime, 1, ( LPTIMECALLBACK ) TZeroDimDetector::EventHandler, 0, TIME_PERIODIC );
735
736 bDataValid= FALSE;
737
738 return TRUE;
739 }
740
741 //############################################################################
742 // TOneDimDetector
743 //############################################################################
744 TOneDimDetector::TOneDimDetector(int id) : TDetector(id), hCountBuf(0)
745 {
746 SetDataType( PsdPositionData );
747 bSoftOverflow= bHardOverflow= bSignalGrowUp= bHVControl= FALSE;
748 m_Axis= (EAxisType)0;
749
750 strcpy(szUnit, "");
751 LoadDetectorSettings();
752 }
753
754 TOneDimDetector::~TOneDimDetector( )
755 {
756 //21.08.2004 MEMCORRECT if (hCountBuf) HeapFree(GetProcessHeap(),0,hCountBuf); hCountBuf= 0;
757 _FREELIST(hCountBuf);
758
759 SaveDetectorSettings();
760 }
761
762 void TOneDimDetector::LoadDetectorSettings()
763 {
764 char buf[ MaxString ];
765
766 GetPrivateProfileString( "EnergyScale", "2", buf);
767 SetEnergyScale( (UINT)atoi(buf) );
768
769 GetPrivateProfileString( "PositionScale", "1", buf);
770 SetPositionScale( (UINT)atoi(buf) );
771
772 GetPrivateProfileString( "OverflowIntensity", "50000.0", buf);
773 OverflowIntensity= atof( buf );
774
775 GetPrivateProfileString( "SignalGrowUp", "0", buf);
776 bSignalGrowUp= ( atoi( buf ) != 0 );
777
778 GetPrivateProfileString( "HVRegelung", "0", buf);
779 bHVControl= ( atoi( buf ) != 0 );
780
781 GetPrivateProfileString( "ReadLeftFirst", "1", buf);
782 bReadLeftFirst= ( atoi ( buf ) != 0 );
783
784 GetPrivateProfileString( "Unit", "Sekunden", szUnit, _MAXLENUNIT);
785 eUnit= UnitEnum( szUnit );
786
787 GetPrivateProfileString( "AngleStep", "1.0", buf);
788 fAngleStep= atof( buf ); // in Motoreinheit und für Scale=0 lesen; d.h. nicht SetAngleStep benutzen -
789
790 GetPrivateProfileString( "Digits", "5", buf ); // Nachkommastellen für die Kanalbreite in arcsec
791 nDigits= atoi( buf );
792
793 GetPrivateProfileString( "MaxChannels", "4096", buf);
794 nMaxChannels= atoi( buf );
795
796 // First- und LastChannel direkt einlesen, später bei SetChannelRange ggf. korrigieren
797 GetPrivateProfileString( "FirstChannel", "0", buf);
798 int firstCh= atoi( buf );
799
800 GetPrivateProfileString( "LastChannel", "4095", buf);
801 int lastCh= atoi( buf );
802
803 // benötigt <uPositionScale>, <nMaxChannels> und <eDataType>==PsdPositionData
804 SetChannelRange( firstCh, lastCh );
805
806 // benötigt First und LastChannel
807 GetPrivateProfileString( "AddedChannels", "4", buf);
808 SetAddedChannels( atoi( buf ) );
809
810 GetPrivateProfileString( "SteeringAxis", "0", buf);
811 m_Axis= mlParsingAxis(buf); // ggf. (TAxisType)0
812 }
813
814 void TOneDimDetector::SaveDetectorSettings() const
815 {
816 char aBuf[ MaxString ];
817 char aFormat[ MaxString ];
818
819 sprintf( aBuf, "%u", uEnergyScale );
820 WritePrivateProfileString( "EnergyScale", aBuf);
821
822 sprintf( aBuf, "%u", uPositionScale );
823 WritePrivateProfileString( "PositionScale", aBuf);
824
825 sprintf( aBuf, "%d", ( bHVControl ? 1 : 0 ) );
826 WritePrivateProfileString( "HVRegelung", aBuf);
827
828 WritePrivateProfileString( "Unit", szUnit);
829
830 sprintf( aBuf, "%d", nMaxChannels);
831 WritePrivateProfileString( "MaxChannels", aBuf);
832
833 sprintf( aBuf, "%d", GetFirstChannel() ); // umrechnen auf Scale
834 WritePrivateProfileString( "FirstChannel", aBuf);
835
836 sprintf( aBuf, "%d", GetLastChannel() ); // umrechnen auf Scale
837 WritePrivateProfileString( "LastChannel", aBuf );
838
839 sprintf( aBuf, "%d", nAddedChannels );
840 WritePrivateProfileString( "AddedChannels", aBuf);
841
842 sprintf( aBuf, "%f", OverflowIntensity );
843 WritePrivateProfileString( "OverflowIntensity", aBuf);
844
845 sprintf( aBuf, "%d", ( bSignalGrowUp ? 1 : 0 ) );
846 WritePrivateProfileString( "SignalGrowUp", aBuf);
847
848 sprintf( aBuf, "%d", ( bReadLeftFirst ? 1 : 0 ) );
849 WritePrivateProfileString( "ReadLeftFirst", aBuf);
850
851 sprintf( aBuf, "%d", nDigits );
852 WritePrivateProfileString( "Digits", aBuf); // Nachkommastellen der Kanalbreite in arcsec speichern
853
854 sprintf(aFormat, "%s%d%s", "%.", nDigits, "f"); // Anzahl der Nachkommastellen beachten
855 sprintf( aBuf, aFormat, fAngleStep ); // in Motoreinheit und für Scale=0 speichern; d.h. nicht GetAngleStep benutzen
856 WritePrivateProfileString( "AngleStep", aBuf);
857
858 WritePrivateProfileString( "MJ_Channel", "0"); // 10.12.2002 Kulllmann, Reinecker Kanal-Offset löschen
859 }
860
861 BOOL TOneDimDetector::Initialize( void )
862 {
863 TDetector::Initialize( );
864
865 if ( GetWidth() == 0.0 )
866 {
867 MessageBox( GetFocus( ), "Psd ist nicht kalibriert !", "Meldung", MBSTOP );
868 fAngleStep= 1.0;
869 SetAddedChannels( 4 );
870 }
871
872 // allocate memory
873 //21.08.2004 MEMCORRECT hCountBuf= (HGLOBAL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,GetBufferSize() * sizeof(DWORD));
874 hCountBuf= new char[ GetBufferSize() * sizeof(DWORD) ];
875
876 //hp initial hardware check
877 if (PsdInit() != R_OK)
878 return(false);
879
880 PushSettings( );
881
882 return TRUE;
883 }
884
885 BOOL TOneDimDetector::RunSpecificParametersDlg( HWND aParentWnd )
886 {
887 //! neu Kullmann+Reinecker: TheModeless durch PsdParamDlg ersetzt; extern entfernt
888 static TModelessDlg *PsdParamDlg= 0;
889
890 if ( (!PsdParamDlg) || (!PsdParamDlg->GetHandle()) )
891 { //! GetHandle() ist wichtig für den Fall, dass sich das Dialogfenster selbst zerstört hat !!!
892 PsdParamDlg= new TPsdParametersDlg(&PsdParamDlg);
893 if ( PsdParamDlg ) PsdParamDlg->Initialize( dlGetInstance(), aParentWnd );
894 return TRUE;
895 }
896 else
897 {
898 _FREEOBJ(PsdParamDlg);
899 return FALSE;
900 }
901 }
902
903 void TOneDimDetector::SetAddedChannels(int nParam)
904 {
905 nAddedChannels= TRange<int>(1, GetChannelNumber()).ForceIntoRange(nParam);
906 }
907
908 int TOneDimDetector::GetFirstChannel() const
909 {
910 if ( eDataType == PsdEnergyData )
911 return 0; // volle Kanalbreite benutzen
912 else
913 // FirstChannel auf Scale umrechnen
914 return max( 0, min(GetScaledMaxChannels(uPositionScale)-1, nFirstChannel >> uPositionScale) );
915 };
916
917 int TOneDimDetector::GetLastChannel() const
918 {
919 if ( eDataType == PsdEnergyData )
920 return GetScaledMaxChannels(uEnergyScale)-1; // volle Kanalbreite benutzen
921 else
922 // LastChannel auf Scale umrechnen
923 return max( 0, min(GetScaledMaxChannels(uPositionScale)-1, nLastChannel >> uPositionScale) );
924 };
925
926 void TOneDimDetector::SetChannelRange(int first, int last)
927 {
928 if ( eDataType == PsdEnergyData ) return; // First- und LastChannel nicht verändern (sind bei PsdEnergyData allein abhängig von nMaxChannels und EnergyScale)
929
930 // nochrechnen auf <MaxChannels>-Kanäle - siehe PsdReadOut
931 TRange<int> limit(0, nMaxChannels-1);
932 first= limit.ForceIntoRange(first << uPositionScale);
933 last= limit.ForceIntoRange(last << uPositionScale);
934
935 nFirstChannel= min(first, last);
936 nLastChannel= max(first, last);
937 }
938
939 UINT TOneDimDetector::GetMaximumChannel( void ) const
940 {
941 if ( bReadLeftFirst )
942 return uMaximumChannel;
943
944 return ( GetChannelNumber() - uMaximumChannel );
945 }
946
947 // NEU: Berücksichtigt alle Messwerte und überträgt diese in die Kurve
948 int TOneDimDetector::FillInCurve( TCurve &curve, EUnitType aMotorUnit )
949 {
950 // Vorbedingungen
951 if ( bHardOverflow )
952 return R_HardOverflow;
953
954 UINT addC= max(1, nAddedChannels);
955
956 LPDWORD lpdwCountBuf= (LPDWORD)hCountBuf;
957
958 curve.New( );
959 // 07.05.2004 curve.FastOpen( );
960
961 double dAngle= 0.0;
962 double intens= 0.0;
963 double dWidth= CalcValueInUnit( aMotorUnit, GetAngleStep() ); // GetAngleStep - unabhängig von <AddedChannels>
964 for ( int idx= 0;idx<GetChannelNumber(); idx++ ) {
965 int index;
966 if ( bReadLeftFirst )
967 index= idx;
968 else // Lesereihenfolge umdrehen (hinten anfangen und dann nach vorn)
969 index= (GetChannelNumber()-1) - idx;
970
971 intens+= (float)lpdwCountBuf[index]; // <intens> zuerst inkrementieren
972 if ( (idx+1) % addC==0 ) { // Kanalgruppe vollständig
973 // Zwischenspeichern in floats, da curve.PAdd Referenzen verlangt
974 float x= dAngle;
975 float y= intens;
976 float z= idx;
977 curve.PAdd( x, y, z ); // 07.05.2004 FastP...
978 intens= 0; // neue Kanalgruppe beginnt
979 }
980 dAngle += dWidth; // <dAngle> als letztes inkrementieren
981 }
982
983 // 07.05.2004 curve.FastClose( );
984
985 //! neu akk
986 fIntensity= dwIntegratedCounts; //fIntensity= dwIntegratedCounts / dRealTime;
987 fSigma= CalculateSigma( fIntensity );
988
989 // Ist ein "weicher" Overflow aufgetreten ?
990 if ( fIntensity >= OverflowIntensity )
991 {
992 bSoftOverflow= TRUE;
993 return R_SoftOverflow;
994 }
995
996 return R_OK;
997 }
998
999 /*10.07.2004 // ALT: Nicht alle Messwerte werden berücksichtigt, es fehlt IMMER der letzte Wert.
1000 int TOneDimDetector::FillInCurve( TCurve &curve, EUnitType aMotorUnit )
1001 {
1002 // Vorbedingungen
1003 if ( bHardOverflow )
1004 return R_HardOverflow;
1005
1006 UINT addC= max(1, nAddedChannels);
1007
1008 LPDWORD lpdwCountBuf= (LPDWORD)hCountBuf;
1009
1010 curve.New( );
1011 // 07.05.2004 curve.FastOpen( );
1012
1013 double dAngle= 0.0;
1014 double intens= 0.0;
1015 double dWidth= CalcValueInUnit( aMotorUnit, GetWidth()); // GetWidth - berücksichtigt <AddedChannels>
1016 for ( int idx= 0;idx < (GetChannelNumber() - addC); idx += addC )
1017 {
1018 intens= 0.0;
1019
1020 for ( int i= 0; i < addC; i++ )
1021 {
1022 int index;
1023 // Summe pro Kanalgruppe ermitteln
1024 index= idx + i;
1025 if ( !bReadLeftFirst )
1026 index= ( GetChannelNumber() - 1 ) - index;
1027
1028 intens += ( float ) lpdwCountBuf[index];
1029 }
1030
1031 // Zwischenspeichern in floats, da curve.PAdd Referenzen verlangt
1032 float x= dAngle;
1033 float y= intens;
1034 float z= idx;
1035 curve.PAdd( x, y, z ); // 07.05.2004 FastP...
1036
1037 dAngle += dWidth;
1038 }
1039
1040 // 07.05.2004 curve.FastClose( );
1041
1042 //! neu akk
1043 fIntensity= dwIntegratedCounts; //fIntensity= dwIntegratedCounts / dRealTime;
1044 fSigma= CalculateSigma( fIntensity );
1045
1046 // Ist ein "weicher" Overflow aufgetreten ?
1047 if ( fIntensity >= OverflowIntensity )
1048 {
1049 bSoftOverflow= TRUE;
1050 return R_SoftOverflow;
1051 }
1052
1053 return R_OK;
1054 }*/
1055
1056 int TOneDimDetector::GetIntegral( float &integral )
1057 {
1058 integral= 0.0;
1059
1060 if ( bHardOverflow )
1061 return R_HardOverflow;
1062
1063 integral= fIntensity= dwIntegratedCounts;
1064 fSigma= CalculateSigma( fIntensity );
1065
1066 // Ist ein "weicher" Overflow aufgetreten ?
1067 if ( fIntensity >= OverflowIntensity )
1068 {
1069 bSoftOverflow= TRUE;
1070 return R_SoftOverflow;
1071 }
1072
1073 return R_OK;
1074 }
1075
1076 int TOneDimDetector::MeasureStart( void )
1077 {
1078 if (bActive)
1079 MeasureStop( );
1080
1081 if ( !GetControlWnd() && !GetCounterWnd() )
1082 return R_Failure;
1083
1084 bSoftOverflow= FALSE;
1085 bHardOverflow= FALSE;
1086 bFirstReadOut= TRUE;
1087
1088 if ( R_Failure == PsdStart( ) )
1089 return R_Failure;
1090
1091 uAskTime= TRange<UINT>(500, 2000).ForceIntoRange(
1092 GetExposureSettings().GetExposureTime() * 1020 );
1093
1094 // Start-Zeit merken
1095 dwStartTime= timeGetTime( );
1096
1097 SetTimer( hWndFrame, DetectorTimerIdStart + GetId( ), uAskTime, NULL );
1098
1099 bActive= TRUE;
1100 bDataValid= FALSE;
1101
1102 return R_MeasOk;
1103 }
1104
1105 int TOneDimDetector::MeasureStop( void )
1106 {
1107 if ( !bActive )
1108 return R_MeasOk;
1109
1110 KillTimer( hWndFrame, DetectorTimerIdStart + GetId( ) );
1111
1112 bDataValid= FALSE;
1113
1114 PsdStop( );
1115
1116 bActive= FALSE;
1117
1118 return R_MeasOk;
1119 }
1120
1121 int TOneDimDetector::PollDetector( void )
1122 {
1123 char buf[ MaxString ];
1124 int retval= R_MeasOk;
1125
1126 KillTimer( hWndFrame, DetectorTimerIdStart + GetId( ) );
1127
1128 if ( !bActive )
1129 return R_Failure;
1130
1131 bActive= FALSE;
1132
1133 dwElapsedTime= timeGetTime( ) - dwStartTime;
1134
1135 if ( MillisecondsToSeconds( dwElapsedTime ) < GetExposureSettings().GetExposureTime() )
1136 {
1137 retval= R_MeasInProcess;
1138 bActive= TRUE;
1139
1140 if ( !bSignalGrowUp )
1141 {
1142 //*** Kein stufenweiser Signalaufbau
1143 SetTimer( hWndFrame, DetectorTimerIdStart + GetId( ), uAskTime, NULL );
1144 return R_MeasInProcess;
1145 }
1146
1147 //*** Stufenweiser Signalaufbau
1148 //FEHLER? Akkumuierter Signalaufbau von TStoePSD::PollDetector übernehmen!
1149 if ( PsdReadOut( IntermediateRead ) == R_Failure )
1150 return R_Failure;
1151
1152 dRealTime= MillisecondsToSeconds( dwElapsedTime );
1153
1154 bFirstReadOut= FALSE;
1155
1156 long lWaitTime= GetExposureSettings().GetExposureTime() * 1020 - dwElapsedTime;
1157
1158 uAskTime= TRange<UINT>(500, 2000).ForceIntoRange( lWaitTime );
1159
1160 SetTimer( hWndFrame, DetectorTimerIdStart + GetId( ), uAskTime, NULL );
1161
1162 goto SendNotify;
1163 }
1164
1165 if ( PsdStop( ) == R_Failure )
1166 return R_Failure;
1167
1168 dRealTime= MillisecondsToSeconds( dwElapsedTime );
1169
1170 if ( PsdReadOut( FinalRead ) == R_Failure )
1171 return R_Failure;
1172
1173 bDataValid= TRUE;
1174
1175 SendNotify: //*** Benachrichtigen der entsprechenden Fenster ***
1176
1177 if ( dRealTime == 0.0 )
1178 {
1179 SetInfo( "dRealTime == 0.0 Fehler Psd" );
1180 DelayTime( 300 );
1181 dRealTime= 1.0;
1182 PsdStop( );
1183 bDataValid= FALSE;
1184 return R_Failure;
1185 }
1186
1187 if ( bHardOverflow )
1188 {
1189 strcpy( buf, "Überlauf Psd ( Hochspannung ? )" );
1190 MessageBeep( 0 );
1191 retval= R_HardOverflow;
1192 }
1193
1194 UpdateViews();
1195
1196 return retval;
1197 }
1198
1199 void TOneDimDetector::SetAngleRange( float )
1200 {
1201 //JP!!!!
1202 return;
1203 }
1204
1205 BOOL TOneDimDetector::PushSettings( void )
1206 {
1207 TDetector::PushSettings( );
1208 Settings.nAddedChannels= nAddedChannels;
1209 return TRUE;
1210 }
1211
1212 BOOL TOneDimDetector::PopSettings( void )
1213 {
1214 TDetector::PopSettings( );
1215 nAddedChannels= Settings.nAddedChannels;
1216 return TRUE;
1217 }
1218
1219 float TOneDimDetector::GetAngleStep() const
1220 {
1221 // auf Scale umrechnen; ">>" geht nicht, da <fValParam> float ist
1222 return fAngleStep * pow(2, uPositionScale); // Kanalbreite nur bei Positionspektrum (Energiespektrum hat nur Kanaldarstellung)
1223 };
1224 void TOneDimDetector::SetAngleStep( float stp )
1225 {
1226 // nochrechnen auf <MaxChannels>-Kanäle: "<<" geht nicht, da <stp> float ist
1227 fAngleStep= stp / pow(2, uPositionScale); // Kanalbreite nur bei Positionspektrum (Energiespektrum hat nur Kanaldarstellung)
1228 };
1229
1230 float TOneDimDetector::GetWidth() const
1231 {
1232 return nAddedChannels * GetAngleStep();
1233 }
1234
1235 float TOneDimDetector::GetAngleRange() const
1236 {
1237 return GetChannelNumber() * GetAngleStep();
1238 }
1239
1240 UINT TOneDimDetector::GetAngleStepDigits( void ) const
1241 {
1242 return nDigits;
1243 }
1244
1245 void TOneDimDetector::SetAngleStepDigits(UINT aDigits)
1246 {
1247 nDigits = aDigits;
1248 }
1249
1250 void TOneDimDetector::CheckMaximumChannel(UINT channel, DWORD counts)
1251 {
1252 // Kanal mit Maximum ermitteln
1253 if ( dwMaxCounts < counts )
1254 {
1255 uMaximumChannel= channel;
1256 dwMaxCounts= counts;
1257 }
1258 }
1259
1260 UINT TOneDimDetector::SetEnergyScale(UINT aEnergyScale)
1261 {
1262 UINT result= uEnergyScale;
1263 uEnergyScale= max( 0x0, min(0x3, aEnergyScale) );
1264 return result;
1265 }
1266
1267 UINT TOneDimDetector::SetPositionScale(UINT aPositionScale)
1268 {
1269 UINT result= uPositionScale;
1270 uPositionScale= max( 0x0, min(0x3, aPositionScale) );
1271 return result;
1272 };
1273
1274 //##############################################################################
1275 // TExposureSettings
1276 //##############################################################################
1277
1278 TExposureSettings::TExposureSettings(
1279 float exposureTime, DWORD exposureCounts)
1280 : CountBounds(10, 300000L), TimeBounds(0.1f, 500.0f)
1281 {
1282 SetExposureTime( exposureTime );
1283 SetExposureCounts( exposureCounts );
1284 }
1285
1286 void TExposureSettings::SetExposureTime(float exposureTime)
1287 {
1288 fExposureTime= TimeBounds.ForceIntoRange( exposureTime );
1289 }
1290
1291 void TExposureSettings::SetExposureCounts( DWORD exposureCounts )
1292 {
1293 dwExposureCounts= CountBounds.ForceIntoRange( exposureCounts );
1294 }
1295
1296 //##############################################################################
1297 // TDetectorGUI
1298 //##############################################################################
1299
1300 void TDetectorGUI::RunPsdCalibrateDialog(HWND hwnd, TCurve &curve)
1301 {
1302 TModalDlg *dlg= new TCalibratePsdDlg( curve );
1303 if ( dlg ) dlg->ExecuteDialog( hwnd );
1304 _FREEOBJ(dlg);
1305 }
1306
1307 void TDetectorGUI::RunCommonDevParamDialog( HWND hwnd )
1308 {
1309 TModalDlg* dlg= new TCommonDevParamDlg();
1310 if ( dlg ) dlg->ExecuteDialog( hwnd );
1311 _FREEOBJ(dlg);
1312 }
1313