source: trunk/MagicSoft/Cosy/main/MCosy.cc@ 4096

Last change on this file since 4096 was 4076, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 37.9 KB
Line 
1#include "MCosy.h"
2
3#include <iomanip.h>
4#include <fstream.h>
5#include <iostream.h>
6
7#include <TROOT.h>
8#include <TEnv.h>
9#include <TSystem.h>
10#include <TApplication.h>
11#include <TTimer.h>
12
13#include <TH2.h>
14#include <TH3.h>
15#include <TProfile.h>
16#include <TCanvas.h>
17
18#include "MGCosy.h"
19#include "MTime.h"
20#include "MDriveCom.h"
21#include "MStarguider.h"
22#include "SlaStars.h"
23#include "MPointing.h"
24#include "MTracking.h"
25
26#include "slalib/slalib.h" // FIXME: REMOVE
27
28#include "macs.h"
29#include "shaftencoder.h"
30
31ClassImp(MCosy);
32
33typedef struct tm tm_t;
34
35/* +===================================+
36 FIXME: What if fMac3 (Sync) died?
37 +===================================+
38*/
39
40//#define EXPERT
41#undef EXPERT
42
43/*
44ZdAz MCosy::CorrectTarget(const ZdAz &src, const ZdAz &dst)
45{
46 // CorrectTarget [se]
47
48 // src [se]
49 // dst [rad]
50
51 // fAltMax = 70
52 // fAltMin = -105/110
53 // fAzMin = -355
54 // fAzMax = 355
55
56 ZdAz source = src * 360.0/16384.0;
57 ZdAz dest = dst * kRad2Deg;
58
59 if (dest.Zd()>-3 && dest.Zd()<3)
60 dest.Zd(dest.Zd()<0?-3:3);
61
62 if (dest.Zd()>-1e-6 && dest.Zd()<1e-6)
63 return dst*(16384.0/k2Pi);
64
65 const float fZdMin = -67;
66 const float fZdMax = 67;
67 const float fAzMin = -29;
68 const float fAzMax = 423;
69
70 //
71 // This corrects to target for the shortest distance, not for the fastest move!
72 //
73 ZdAz s = source-dest;
74
75 float min = s.Sqr();
76
77 //
78 // Is it enought to search inside one revolution?
79 //
80 ZdAz ret = dest;
81
82 for (int i=-5; i<5+1; i++)
83 {
84 const ZdAz p(i%2 ? -dest.Zd() : dest.Zd(), dest.Az() - i*180);
85
86 //
87 // Range Check
88 //
89 if (p.Zd()<fZdMin || p.Zd()>fZdMax)
90 continue;
91
92 if (p.Az()<fAzMin || p.Az()>fAzMax)
93 continue;
94
95 //
96 // Calculate distance
97 //
98 s = source-p;
99
100 const float dist = s.Sqr();
101
102 if (dist > min)
103 continue;
104
105 //
106 // New shortest distance
107 //
108 ret = p;
109 min = dist;
110 }
111 return ret*(16384.0/360.0);
112}
113*/
114
115// --------------------------------------------------------------------------
116//
117// GetSePos, reads the Shaftencoder positions from the Can-drivers
118// for the shaftencoders. The two shaft encoders at the elevation axis
119// are avaraged. The values are returned as a ZdAz object.
120//
121// If one of the two shaftencoders on the elevation axis is missing
122// the other one's position is returned.
123//
124// The positions are alway up-to-date because the shaftencoders are
125// sending all changes immediatly.
126//
127ZdAz MCosy::GetSePos() const
128{
129 const int pa = fAz->GetPos();
130 if (fZd1->IsZombieNode() && fZd2->IsZombieNode())
131 return ZdAz(0, pa);
132
133 //
134 // Get the values
135 //
136 int p1 = (fZd1->GetPos()+8192)%16384;
137 int p2 = -(fZd2->GetPos()+8192)%16384;
138
139 if (fZd1->IsZombieNode())
140 return ZdAz(p2, pa);
141 if (fZd2->IsZombieNode())
142 return ZdAz(p1, pa);
143
144 //
145 // interpolate shaft encoder positions
146 //
147 float p = (float)(p1+p2)/2;
148
149 return ZdAz(p, pa);
150}
151
152// --------------------------------------------------------------------------
153//
154// reads the Rotary encoder positions from the last request of the Macs.
155//
156// The positions are returned as a ZdAz object. Use RequestRePos to request
157// the current positions first.
158//
159ZdAz MCosy::GetRePos()
160{
161 return ZdAz(fMac2->GetPos(), fMac1->GetPos());
162}
163
164// --------------------------------------------------------------------------
165//
166// reads the Rotary encoder positions from the Macs.
167//
168// The positions are returned as a ZdAz object. The positions are the ones
169// which are send as PDOs to the computer. This is done at a given
170// frequency. Which means, that this positions are not ought to be
171// up-to-date.
172//
173ZdAz MCosy::GetRePosPdo()
174{
175 return ZdAz(fMac2->GetPdoPos(), fMac1->GetPdoPos());
176}
177
178// --------------------------------------------------------------------------
179//
180// check for a break-signal (from the msgqueue) and errors.
181//
182int MCosy::StopWaitingForSDO() const
183{
184 return 0/*Break() || HasError()*/;
185}
186
187// --------------------------------------------------------------------------
188//
189// Waits for a movement to become finished.
190//
191// First waits for all peding Sdos, then waits until both motors are stopped
192// or waiting for SDOs was stopped (either by an error or by Break)
193//
194void MCosy::WaitForEndMovement()
195{
196 // FIXME, what when waiting times out (Zombie)
197 if (!fMac1 || !fMac2)
198 return;
199
200 while ((fMac1->IsPositioning() || fMac2->IsPositioning()) &&
201 !(Break() || HasError() || HasZombie()))
202 usleep(1);
203
204 if (!Break() && !HasError() && !HasZombie())
205 return;
206
207 MTime t(-1);
208 lout << t << " - MCosy::WaitForEndMovement aborted...";
209 if (Break())
210 lout << " Break signal...";
211 if (HasError())
212 lout << " Network has error...";
213 if (HasZombie())
214 lout << " Network has zombie...";
215 lout << endl;
216}
217
218// --------------------------------------------------------------------------
219//
220// Check for an error...
221//
222// This is ment for usage after the Action: All Motors Stop.
223//
224void MCosy::CheckForError()
225{
226 //
227 // Check all Can-Nodes for an Error. If there is no error the motor
228 // status is set to stopped.
229 //
230 if (HasError() || HasZombie())
231 {
232 SetStatus(MDriveCom::kError);
233 return;
234 }
235
236 if (fMac1->IsPositioning() || fMac2->IsPositioning())
237 SetStatus(MDriveCom::kMoving);
238 else
239 SetStatus(MDriveCom::kStopped);
240
241 //
242 // If there is an error, the error status is set to Error.
243 //
244
245 /*
246 FIXME: HANDLINGE ERROR
247
248 //
249 // Now try to handle the error.
250 //
251 fMac1->HandleError();
252 fMac2->HandleError();
253
254 //
255 // If the error couldn't get solved return
256 //
257 if (HasError())
258 return;
259
260 //
261 // Set motor status to stopped
262 //
263 SetStatus(MDriveCom::kStopped);
264 */
265}
266
267Bool_t MCosy::CheckRange(const ZdAz &d) const
268{
269 // d [rad]
270
271 if (d.Zd()<fMin.Zd())
272 {
273 lout << "ERROR: Requested Zenith Angle below negative endswitch." << endl;
274 return kFALSE;
275 }
276
277 if (d.Zd()>fMax.Zd())
278 {
279 lout << "ERROR: Requested Zenith Angle behind positive endswitch." << endl;
280 return kFALSE;
281 }
282
283 if (d.Az()<fMin.Az())
284 {
285 lout << "ERROR: Requested Azimuth Angle below negative endswitch." << endl;
286 return kFALSE;
287 }
288
289 if (d.Az()>fMax.Az())
290 {
291 lout << "ERROR: Requested Azimuth Angle behind positive endswitch." << endl;
292 return kFALSE;
293 }
294
295
296 return kTRUE;
297}
298
299ZdAz MCosy::AlignTrackingPos(ZdAz pointing) const
300{
301 // pointing [rad]
302 // AlignTrackingPos [deg]
303
304 pointing *= kRad2Deg;
305
306 if (pointing.Zd()<0)
307 {
308 pointing.Zd(-pointing.Zd());
309 pointing.Az(pointing.Az()+180);
310 //lout << "ZD=-ZD Az+=180" << endl;
311 }
312
313 const ZdAz se = GetSePos()*TMath::TwoPi()/kResSE; // [rad]
314 const ZdAz unbendedse = fBending.CorrectBack(se)*kRad2Deg; // ist pointing
315
316 //lout << "Unbended: " << unbendedse.Zd() << " " << unbendedse.Az() << endl;
317
318 do
319 {
320 const Double_t d = unbendedse.Az() - pointing.Az();
321 if (d>-180 && d<=180)
322 break;
323
324 //lout << "AZ += " << TMath::Sign(360., d) << endl;
325
326 pointing.Az(pointing.Az()+TMath::Sign(360., d));
327 } while (1);
328
329 return pointing/kRad2Deg;
330/*
331 const Bool_t rc = CheckRange(pointing);
332 za = pointing/kRad2Deg; // [rad]
333
334 if (!rc)
335 lout << "Error: Aligned position out of Range." << endl;
336
337 return rc;*/
338}
339
340Double_t MCosy::Starguider(Double_t mjd, ZdAz &dest) const
341{
342 ifstream fin("pointingpos.txt");
343 if (!fin)
344 return -1;
345
346 Double_t mjd0, zd, az;
347 fin >> mjd0 >> zd >> az;
348
349 mjd0 += 52000;
350
351 if (mjd0+1./24/60 <mjd)
352 return -1;
353
354 ZdAz point=AlignTrackingPos(ZdAz(zd, az)/kRad2Deg);
355 /*
356 if (!AlignTrackingPos(ZdAz(zd, az), point))
357 {
358 cout << "Starguider position couldn't be aligned..." << endl;
359 return -1;
360 }*/
361
362 // FIXME: Check Range missing!
363
364 const ZdAz diff = (dest-point)*kRad2Deg;
365
366 if (diff.Zd()>5 || diff.Az()>5)
367 {
368 cout << "Starguider deviation too large... dZd=" << diff.Zd() <<" dAz="<<diff.Az() << endl;
369 return -1;
370 }
371
372 dest -= point;
373 dest *= -kGearTot/TMath::TwoPi(); // [re]
374
375 cout << "Using Starguider... dZd=" << dest.Zd() << " dAz=" << dest.Az() << endl;
376
377 return (mjd-mjd0) * (24*60*60); // [s]
378}
379
380// --------------------------------------------------------------------------
381//
382// Move the telescope to the given position. The position must be given in
383// a ZdAz object in rad.
384//
385// The first positioning is done absolutely. If we didn't reach the
386// correct psotion we try to correct for this by 10 relative position
387// maneuvers. If this doesn't help positioning failed.
388//
389// As a reference the shaftencoder values are used.
390//
391int MCosy::SetPosition(const ZdAz &dst, Bool_t track) // [rad]
392{
393 MPointing point(this, lout);
394
395//#ifdef EXPERT
396// point.SetAccDec(0.4, 0.4);
397// point.SetVelocity(0.2); // fast: 0.6, slow: 0.2
398//#else
399 point.SetPointAccDec(0.2, 0.1);
400 point.SetPointVelocity(0.1);
401//#endif
402
403 return point.SetPosition(dst, track);
404}
405
406void MCosy::TrackPosition(const RaDec &dst) // ra, dec [rad]
407{
408 MTracking track(this, lout);
409 track.SetOut(fOutRep);
410//#ifdef EXPERT
411// track.SetPointAccDec(0.4, 0.4);
412// track.SetPointVelocity(0.2); // fast: 0.6, slow: 0.2
413//#else
414 track.SetPointAccDec(0.2, 0.1);
415 track.SetPointVelocity(0.1);
416//#endif
417 track.SetTrackAccDec(0.1, 0.1);
418
419 track.TrackPosition(dst);
420}
421
422// --------------------------------------------------------------------------
423//
424// Stops the movement of both motors.
425//
426// Sets the status to stopping. Sets the deceleration to 50% of the maximum.
427// stops. Quits the revolution mode and wait for the end of the movement.
428//
429void MCosy::StopMovement()
430{
431 //
432 // Set status to Stopping
433 //
434 SetStatus(MDriveCom::kStopping);
435
436 //
437 // set deceleration to 50%
438 //
439 cout << "Stopping movement (dec=30%)..." << endl;
440 if (fMac1 && fMac2)
441 {
442#ifdef EXPERT
443 fMac1->SetDeceleration(0.5*fMac1->GetVelRes());
444 fMac2->SetDeceleration(0.5*fMac2->GetVelRes());
445#else
446 fMac1->SetDeceleration(0.3*fMac1->GetVelRes());
447 fMac2->SetDeceleration(0.3*fMac2->GetVelRes());
448#endif
449 fMac1->SetRpmMode(FALSE);
450 fMac2->SetRpmMode(FALSE);
451 }
452
453/*
454 fMac1->SetDeceleration(0.3*fMac1->GetVelRes());
455 fMac2->SetDeceleration(0.3*fMac2->GetVelRes());
456
457 fMac2->SendSDO(0x3000, Macs::string('s','t','o','p'));
458 fMac1->SendSDO(0x3000, Macs::string('s','t','o','p'));
459 fMac2->WaitForSdo(0x3000, 0);
460 fMac1->WaitForSdo(0x3000, 0);
461 fMac1->SetRpmMode(FALSE);
462 fMac2->SetRpmMode(FALSE);
463 */
464
465 //
466 // Wait for the movement to really be finished.
467 //
468#ifdef EXPERT
469 cout << "Waiting for end of movement..." << endl;
470#endif
471 WaitForEndMovement();
472
473 //
474 // Check whether everything works fine.
475 //
476 CheckForError();
477#ifdef EXPERT
478 cout << "Movement stopped." << endl;
479#endif
480}
481
482bool MCosy::CheckNetwork()
483{
484 //return kTRUE;
485 //CheckConnections();
486
487 CheckForError();
488
489 if (HasZombie())
490 {
491 lout << "- Found Zombies in Network..." << endl;
492 if (!RebootZombies())
493 return false;
494 }
495
496 /*
497 FIXME HANDLING ERROR
498 */
499 if (HasError())
500 {
501 fMac1->HandleError();
502 fMac2->HandleError();
503 fMac3->HandleError();
504 if (HasError() || HasZombie())
505 return false;
506 }
507
508 CheckForError();
509 return true;
510}
511
512void *MCosy::Proc(int msg, void *mp)
513{
514 switch (msg)
515 {
516 case WM_WAIT:
517 cout << "Wait for execution of Proc(WM_*, ): done." << endl;
518 return NULL;
519
520 case WM_STOP:
521 //cout << "MCosy::Proc: Stop." << endl;
522 if (!CheckNetwork())
523 return (void*)0xebb0;
524 StopMovement();
525 return NULL;
526/*
527 case WM_PRESET:
528 cout << "WM_Preset: start." << endl;
529 if (!CheckNetwork())
530 return (void*)0xebb0;
531 fZd1->SetPreset();
532 fZd2->SetPreset();
533 fAz->SetPreset();
534 cout << "WM_Preset: done. (return 0xaffe)" << endl;
535 return (void*)0xaffe;
536*/
537 /*
538 case WM_CALIB:
539 {
540 cout << "WM_Calib: start." << endl;
541 if (!CheckNetwork())
542 return (void*)0xebb0;
543
544 SlaStars sla(fObservatory);
545 sla.Now();
546
547 RaDec rd = *((RaDec*)mp);
548
549 //RaDec rd(37.94, 89.2644); // POLARIS
550 //RaDec rd(213.915417, 19.1825); // ARCTURUS
551
552 cout << "Calibrating to: " << rd.Ra()*24/360 << "h " << rd.Dec() << "°" << endl;
553
554 ZdAz za=sla.CalcZdAz(rd*kDeg2Rad)*16384.0/k2Pi;
555
556 cout << "Calc Zd: " << za.Zd() << " Az: " << za.Az() << endl;
557
558 ZdAz sepos = GetSePos();
559 cout << "Got Zd: " << sepos.Zd() << " Az: " << sepos.Az() << endl;
560
561 fZd1->SetPreset(za.Zd());
562 fZd2->SetPreset(-za.Zd());
563 fAz->SetPreset(za.Az());
564
565 cout << "WM_Calib: done. (return 0xaffe)" << endl;
566 }
567 return (void*)0xaffe;
568 */
569 case WM_TPOINT:
570 {
571 //cout << "WM_TPoint: start." << endl;
572 SlaStars sla(fObservatory);
573 sla.Now();
574
575 RaDec rd = *((RaDec*)mp);
576 cout << "TPoint Star: " << rd.Ra()/15 << "h " << rd.Dec() << "°" << endl;
577
578 AltAz za=sla.CalcAltAz(rd*kDeg2Rad)*kRad2Deg;
579
580 if (!fOutTp)
581 {
582 //
583 // open tpoint file
584 //
585 const TString name = GetFileName("tpoint/tpoint_%s.txt");
586 cout << "TPoint-Cosy File ********* " << name << " ********** " << endl;
587
588 fOutTp = new ofstream(name);
589 *fOutTp << "Magic Model TPOINT data file" << endl;
590 *fOutTp << ": ALTAZ" << endl;
591 *fOutTp << "49 48 0 ";
592 *fOutTp << sla.GetTime().Year() << " " << sla.GetTime().Month() << " " << sla.GetTime().Day() << " ";
593 *fOutTp << /*"20 1013.25 300 0.5 0.55 0.0065" <<*/ endl;
594 // temp(°C) pressure(mB) height(m) humidity(1) wavelength(microm) troplapserate(K/m)
595 }
596
597 cout << " Alt/Az: " << za.Alt() << "° " << za.Az() << "°" << endl;
598 *fOutTp << setprecision(7) << za.Az() << " " << za.Alt() << " ";
599
600 ZdAz sepos = GetSePos()*TMath::TwoPi()/kResSE;
601 za.Set(TMath::Pi()/2-sepos.Zd(), sepos.Az());
602 za *= kRad2Deg;
603
604 cout << " SE-Pos: " << za.Alt() << "° " << za.Az() << "°" << endl;
605 *fOutTp << fmod(za.Az()+360, 360) << " " << za.Alt() << " ";
606
607 if (fStarguider)
608 {
609 XY tp = fStarguider->GetCoordinates();
610 *fOutTp << 90-tp.X() << " " << tp.Y() << " ";
611 }
612
613 *fOutTp << rd.Ra()/15 << " " << rd.Dec() << " " << setprecision(11) << sla.GetMjd() << endl;
614
615 //cout << "WM_TPoint: done. (return 0xaffe)" << endl;
616 }
617 return (void*)0xca1b;
618
619 case WM_TRACKPOS:
620 //cout << "WM_TrackPosition: start." << endl;
621 {
622 if (!CheckNetwork())
623 return (void*)0xebb0;
624
625 ZdAz dest = *((ZdAz*)mp) * kDeg2Rad;
626 if (!SetPosition(dest))
627 return (void*)0x1234;
628
629 SlaStars sla(fObservatory);
630 sla.Now();
631
632 RaDec rd = sla.CalcRaDec(dest);
633 TrackPosition(rd);
634 }
635 //cout << "WM_TrackPosition: done. (return 0xabcd)" << endl;
636 return (void*)0xabcd;
637
638 case WM_POSITION:
639 //cout << "WM_Position: start." << endl;
640 {
641 if (!CheckNetwork())
642 return (void*)0xebb0;
643
644 ZdAz dest = *((ZdAz*)mp);
645 SetPosition(dest*kDeg2Rad);
646 }
647 //cout << "WM_Position: done. (return 0x7777)" << endl;
648 return (void*)0x7777;
649
650 case WM_POSITION1:
651 //cout << "WM_Position1: start." << endl;
652 {
653 if (!CheckNetwork())
654 return (void*)0xebb0;
655
656 ZdAz dest = *((ZdAz*)mp);
657 SetPosition(dest*kDeg2Rad, kTRUE);
658 }
659 //cout << "WM_Position: done. (return 0x7777)" << endl;
660 return (void*)0x7777;
661
662 case WM_TESTSE:
663 //cout << "WM_TestSe: start." << endl;
664 fBackground = mp ? kBgdSeTest : kBgdNone;
665 //cout << "WM_TestSe: done. (return 0x1e51)" << endl;
666 return (void*)0x1e51;
667
668 case WM_GEAR:
669 //cout << "WM_Gear: start." << endl;
670 fBackground = mp ? kBgdGear : kBgdNone;
671 //cout << "WM_Gear: done. (return 0xfeaf)" << endl;
672 return (void*)0xfeaf;
673
674 case WM_DISPLAY:
675 //cout << "WM_Display: start." << endl;
676 fTriggerDisplay = kTRUE;
677 //cout << "WM_Disply: done. (return 0xd1e1)" << endl;
678 return (void*)0xd1e1;
679
680 case WM_TRACK:
681 //cout << "WM_Track: START" << endl;
682 {
683 RaDec dest = ((RaDec*)mp)[0];
684 if (fStarguider)
685 fStarguider->SetPointingPosition(((RaDec*)mp)[1]);
686 if (!CheckNetwork())
687 return (void*)0xebb0;
688 TrackPosition(dest*kDeg2Rad);
689 }
690 //cout << "WM_Track: done. (return 0x8888)" << endl;
691 return (void*)0x8888;
692
693 case WM_NEWTRACK:
694 //cout << "WM_NewTrack: START" << endl;
695 fRaDec = *((RaDec*)mp);
696 //cout << "WM_NewTrack: done. (return 0x9999)" << endl;
697 return (void*)0x9999;
698
699 case WM_LOADBENDING:
700 //cout << "WM_LoadBending: START" << endl;
701 fBending.Load("bending.txt");
702 //cout << "WM_LoadBending: done. (return 0xbe0d)" << endl;
703 return (void*)0xbe0d;
704
705 case WM_RESETBENDING:
706 //cout << "WM_ResetBending: START" << endl;
707 fBending.Reset();
708 //cout << "WM_ResetBending: done. (return 0xbe0e)" << endl;
709 return (void*)0xbe0e;
710
711 case WM_HOME:
712 //cout << "WM_Home: START" << endl;
713 if (!CheckNetwork())
714 return (void*)0xebb0;
715 else
716 {
717 cout << "HOME NOT ALLOWED... for Magic." << endl;
718 /*
719 cout << "Going Home..." << endl;
720 TEnv env(".cosyrc");
721
722 SetStatus(MDriveCom::kMoving);
723
724 fMac1->SetHome(250000, env.GetValue("Az_MaxTime2ReachHome[s]", 100));
725 fMac2->SetHome(250000, env.GetValue("Zd_MaxTime2ReachHome[s]", 100));
726
727 lout << "SETHOME DONE" << endl;
728
729 SetStatus(HasError() ? MDriveCom::kError : MDriveCom::kStopped);
730
731 fAz->SetPreset();
732 fZd1->SetPreset();
733 fZd2->SetPreset();
734
735 fMac1->ReqPos();
736 fMac2->ReqPos();
737 fMac3->StopMotor();
738 */
739 }
740 //cout << "WM_Home: done. (return 0x403e)" << endl;
741 return (void*)0x403e;
742
743 case WM_CALCALTAZ:
744 {
745 cout << endl;
746
747 SlaStars sla(fObservatory);
748 sla.Now();
749
750 XY xy = *((XY*)mp);
751 RaDec rd(xy.X()*15., xy.Y()); // [deg]
752
753 ZdAz a1 = sla.CalcZdAz(rd*kDeg2Rad); // [rad]
754
755 cout << "Ra/Dec source: " << xy.X() << "h " << xy.Y() << "°" << endl;
756 cout << "Zd/Az target: " << a1.Zd()*kRad2Deg << "° " << a1.Az()*kRad2Deg << "°" << endl;
757
758 if (fZd1 && fZd2 && fAz)
759 a1 = AlignTrackingPos(a1);
760
761 a1 = fBending(a1);
762 CheckRange(a1);
763 a1 *= kRad2Deg;
764
765 const ZdAz a2 = a1*kResSE/360;
766
767 cout << "Zd/Az bended: " << a1.Zd() << "° " << a1.Az() << "°" << endl;
768 cout << "SE bended: " << a2.Zd() << " " << a2.Az() << endl;
769 }
770 return (void*)0xa17a;
771
772 case WM_ENDSWITCH:
773 {
774 ZdAz pos = GetSePos()*TMath::TwoPi()/kResSE;
775 pos = fBending.SubtractOffsets(pos)*kRad2Deg;
776
777 cout << "Endswitch Position: Zd=" << pos.Zd() << "° Az=";
778 cout << pos.Az() << "°" << endl;
779 }
780
781 return (void*)0x1010;
782
783 case WM_QUIT:
784 cout << "WM_Quit: now." << endl;
785 if (!CheckNetwork())
786 {
787 lout << "ERROR: Cannot shutdown CANbus network." << endl;
788 return (void*)0xebb0;
789 }
790 TerminateApp();
791 cout << "WM_Quit: done." << endl;
792 return (void*)0xaaaa;
793 }
794 cout << "MCosy::Proc: Unknown message 0x" << msg << endl;
795 return (void*)0xffffffff;
796}
797
798void *MTTalk::Thread()
799{
800 fCosy->TalkThread();
801 return NULL;
802}
803
804void MCosy::ReadConfig()
805{
806 cout << "Reading configuration file..." << flush;
807 TEnv env(".cosyrc");
808 cout << "done." << endl;
809
810 cout << "Reading telescope range..." << flush;
811 const Double_t amin = env.GetValue("Az_Min[deg]", -95.0);
812 const Double_t zmin = env.GetValue("Zd_Min[deg]", -75.0);
813 fMin.Set(zmin, amin);
814
815 const Double_t amax = env.GetValue("Az_Max[deg]", 305.0);
816 const Double_t zmax = env.GetValue("Zd_Max[deg]", 98.25);
817 fMax.Set(zmax, amax);
818 cout << "done." << endl;
819
820 cout << " * Min: " << zmin << "deg " << amin << "deg" << endl;
821 cout << " * Max: " << zmax << "deg " << amax << "deg" << endl;
822
823 fMin = fBending.AddOffsets(fMin/kRad2Deg);
824 fMax = fBending.AddOffsets(fMax/kRad2Deg);
825
826 cout << " * Min': " << fMin.Zd()*kRad2Deg << "deg " << fMin.Az()*kRad2Deg << "deg" << endl;
827 cout << " * Max': " << fMax.Zd()*kRad2Deg << "deg " << fMax.Az()*kRad2Deg << "deg" << endl;
828
829 cout << "Reading gear ratios..." << flush;
830 kGear.Y(env.GetValue("Az_GearRatio[U_mot/U_tel]", 1000.0));
831 kGear.X(env.GetValue("Zd_GearRatio[U_mot/U_tel]", 1000.0));
832
833 kResRE.Y(0);
834 if (fMac1 && !fMac1->IsZombieNode())
835 kResRE.Y(fMac1->GetRes());
836 else
837 if (fMac3 && !fMac3->IsZombieNode())
838 kResRE.Y(fMac3->GetRes());
839 else
840 kResRE.Y(env.GetValue("Az_ResRE[re/U_mot]", 1500));
841
842 kResRE.X(0);
843 if (fMac2 && !fMac2->IsZombieNode())
844 kResRE.X(fMac2->GetRes());
845 else
846 kResRE.X(env.GetValue("Zd_ResRE[re/U_mot]", 1500));
847
848 kResSE.X(0);
849 if (fZd1 && !fZd1->IsZombieNode())
850 kResSE.X(fZd1->GetPhysRes());
851 else
852 if (fZd2 && !fZd2->IsZombieNode())
853 kResSE.X(fZd2->GetPhysRes());
854 else
855 kResSE.X(env.GetValue("Zd_ResSE[se/U_mot]", 16384));
856
857 kResSE.Y(0);
858 if (fAz && !fAz->IsZombieNode())
859 kResSE.Y(fAz->GetPhysRes());
860 else
861 kResSE.Y(env.GetValue("Az_ResSE[se/U_mot]", 16384));
862
863 // believing the Macs manual '*4' shouldn't be necessary, but it is.
864 // Because the a RE is 4 quad counts.
865 // Calculating speeds we have to convert back to qc
866 kResRE *= 4;
867 kGearTot = kResRE*kGear;
868
869 cout << "done." << endl;
870
871 cout << " * Setting Gear Ratios:" << endl;
872 cout << " --------------------" << endl;
873 cout << " * X: " << kGear.X() << "*" << kResRE.X()/4 << "/" << kResSE.X() << "=4*" << kGearTot.X() << "/" << kResSE.X() << endl;
874 cout << " * Y: " << kGear.Y() << "*" << kResRE.Y()/4 << "/" << kResSE.Y() << "=4*" << kGearTot.Y() << "/" << kResSE.Y() << endl;
875}
876
877void MCosy::InitSync()
878{
879 if (!fMac3)
880 {
881 lout << "Unable to Init Sync! Mac3 not available." << endl;
882 return;
883 }
884
885 const int res = fMac3->GetVelRes();
886
887 fMac3->SetVelocity(0.3*res);
888 fMac3->SetAcceleration(0.2*res);
889 fMac3->SetDeceleration(0.2*res);
890 fMac3->StartPosSync();
891}
892
893void MCosy::TalkThreadSeTest()
894{
895// if (fZd1->IsZombieNode() || fZd2->IsZombieNode())
896 // return;
897
898 if (fHist)
899 {
900 lout << "You are much too fast... try again." << endl;
901 return;
902 }
903
904 fHist = new TH2F("Diff", "Difference of SE values",
905 201, fMin.Zd(), fMax.Zd(), 41, -10.5, 10.5);
906 fHist->SetXTitle("ZA [\\circ]");
907 fHist->SetYTitle("\\Delta SE");
908
909 Double_t offset = 0;
910
911 int cnt = 0;
912
913 lout << "Starting Shaftencoder Test..." << endl;
914
915 while (fBackground==kBgdSeTest)
916 {
917 fZd1->ResetPosHasChanged();
918 fZd2->ResetPosHasChanged();
919
920 while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() &&
921 fBackground==kBgdSeTest)
922 usleep(1);
923
924 const Double_t pos[3] = {
925 (fZd1->GetPos()+8192)%16384,
926 (fZd2->GetPos()+8192)%16384,
927 fAz->GetPos() };
928
929 //
930 // Estimate Offset from the first ten positions
931 //
932 if (cnt++<10)
933 {
934 offset += pos[0]+pos[1];
935 continue;
936 }
937 if (cnt==11)
938 {
939 offset /= 10;
940 cnt++;
941 }
942
943 Double_t apos = (pos[0]-pos[1])/2 * TMath::TwoPi() / kResSE.X();
944
945 ZdAz bend = fBending.CorrectBack(ZdAz(apos, pos[2]))*kRad2Deg;
946 fHist->Fill(bend.Zd(), pos[0]+pos[1]-offset);
947 }
948
949 lout << "Shaftencoder Test Stopped... displaying Histogram." << endl;
950
951 fBackground=kBgdSeTestDispl;
952}
953
954void MCosy::TalkThreadGear()
955{
956// if (fZd1->IsZombieNode() || fZd2->IsZombieNode())
957 // return;
958
959 if (fHist)
960 {
961 lout << "You are much too fast... try again." << endl;
962 return;
963 }
964
965 fHist = new TH3F("Gear", "Gear Ratio Re/Se",
966 (int)((fMax.Zd()-fMin.Zd())/2.5+1), fMin.Zd(), fMax.Zd(),
967 (int)((fMax.Az()-fMin.Az())/2.5+1), fMin.Az(), fMax.Az(),
968 61, 349.5, 500.5);
969
970 fHist->SetXTitle("Zd [\\circ]");
971 fHist->SetYTitle("Az [\\circ]");
972 fHist->SetZTitle("Re/Se");
973
974 lout << "Starting Gear determination..." << endl;
975
976 ZdAz se0 = GetSePos();
977 ZdAz re0 = GetRePosPdo();
978
979 while (fBackground==kBgdGear)
980 {
981 fZd1->ResetPosHasChanged();
982 fZd2->ResetPosHasChanged();
983 fAz->ResetPosHasChanged();
984
985 while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() &&
986 !fAz->PosHasChanged() && fBackground==kBgdGear)
987 usleep(1);
988
989 ZdAz se = GetSePos();
990 ZdAz re = GetRePosPdo();
991
992 ZdAz dse = se-se0;
993 ZdAz dre = re-re0;
994
995 if (fabs(dse.Zd())*144>kResSE.X()) // Each 2.5deg (144)
996 {
997 se0.Zd(se.Zd());
998 re0.Zd(re.Zd());
999
1000 se -= dse/2;
1001
1002 ZdAz bend = fBending.CorrectBack(se*TMath::TwoPi()/kResSE)*kRad2Deg;
1003 ((TH3*)fHist)->Fill(bend.Zd(), bend.Az(), dre.Zd()/dse.Zd());
1004 }
1005
1006 if (fabs(dse.Az())*144>kResSE.Y()) // Each 2.5deg (144)
1007 {
1008 se0.Az(se.Az());
1009 re0.Az(re.Az());
1010
1011 se -= dse/2;
1012
1013 ZdAz bend = fBending.CorrectBack(se*TMath::TwoPi()/kResSE)*kRad2Deg;
1014 ((TH3*)fHist)->Fill(bend.Az(), bend.Az(), dre.Az()/dse.Az());
1015 }
1016 }
1017 lout << "Gear Test Stopped... displaying Histogram." << endl;
1018
1019 fBackground=kBgdGearDispl;
1020}
1021
1022void MCosy::TalkThread()
1023{
1024 /* ========== FIXME? =============
1025 if (fMac1->IsZombieNode() || fMac2->IsZombieNode())
1026 return;
1027 */
1028
1029 if (fMac1 && fMac2)
1030 {
1031 fMac1->ReqPos();
1032 fMac2->ReqPos();
1033 }
1034
1035 InitSync();
1036
1037 /*** FOR DEMO MODE ***/
1038 if (!fZd1 || !fZd2 || !fAz)
1039 return;
1040 /*** FOR DEMO MODE ***/
1041
1042 //
1043 // Start the Network
1044 //
1045 while (1)
1046 {
1047 //
1048 // wait until a tracking session is started
1049 //
1050 while (fBackground==kBgdNone)
1051 usleep(1);
1052
1053 switch (fBackground)
1054 {
1055 case kBgdNone:
1056 continue;
1057/*#ifndef NEWALGO
1058 case kBgdTracking:
1059 TalkThreadTracking();
1060 continue;
1061#endif*/
1062 case kBgdSeTest:
1063 TalkThreadSeTest();
1064 continue;
1065
1066 case kBgdGear:
1067 TalkThreadGear();
1068 continue;
1069
1070 default:
1071 continue;
1072 }
1073 }
1074}
1075
1076ZdAz MCosy::GetPointingPos() const
1077{
1078 if (fZd1->IsZombieNode() || fZd2->IsZombieNode() || fAz->IsZombieNode())
1079 return ZdAz(0, 0);
1080
1081 // GetPointingPos [deg]
1082 const ZdAz seist = GetSePos()*TMath::TwoPi()/kResSE; // [rad]
1083 return fBending.CorrectBack(seist)*TMath::RadToDeg();
1084}
1085
1086Bool_t MCosy::HandleTimer(TTimer *t)
1087{
1088 const Int_t rc = fMutexGui.TryLock();
1089 if (rc==13)
1090 cout << "MCosy::HandleTimer - mutex is already locked by this thread" << endl;
1091
1092 if (rc)
1093 {
1094 lout << "* GUI update skipped due to locked mutex." << endl;
1095 return kTRUE;
1096 }
1097
1098 //
1099 // Update Gui, foremer MTGui.
1100 //
1101 if (fZd1)
1102 fZd1->DisplayVal();
1103 if (fZd2)
1104 fZd2->DisplayVal();
1105 if (fAz)
1106 fAz->DisplayVal();
1107
1108 Byte_t avail = 0;
1109
1110 avail |= (fMac1 && !fMac1->IsZombieNode()) ? 0x01 : 0;
1111 avail |= (fMac2 && !fMac2->IsZombieNode()) ? 0x02 : 0;
1112 avail |= (fMac3 && !fMac3->IsZombieNode()) ? 0x04 : 0;
1113 avail |= (fZd1 && !fZd1->IsZombieNode()) ? 0x08 : 0;
1114 avail |= (fZd2 && !fZd2->IsZombieNode()) ? 0x10 : 0;
1115 avail |= (fAz && !fAz->IsZombieNode()) ? 0x20 : 0;
1116
1117 if (HasError())
1118 SetStatus(MDriveCom::kError);
1119
1120 ZdAz bendist = GetPointingPos();
1121 fCom->SendReport(fStatus, fRaDec, fZdAzSoll, bendist, fTrackingError);
1122
1123 fWin->UpdateWeather(*fCom);
1124 fWin->Update(bendist, fTrackingError, fVelocity, /*fOffset,*/
1125 fRaDec, fZdAzSoll, fStatus, avail);
1126
1127 lout.UpdateGui();
1128
1129 const Bool_t trigger = fTriggerDisplay;
1130 fTriggerDisplay = kFALSE;
1131
1132 if (fBackground==kBgdSeTestDispl || (trigger&&fBackground==kBgdSeTest))
1133 DisplayHistTestSe(!trigger);
1134
1135 if (fBackground==kBgdGearDispl || (trigger&&fBackground==kBgdGear))
1136 DisplayHistGear(!trigger);
1137
1138 if (fMutexGui.UnLock()==13)
1139 cout << "MCosy::HandleTimer - tried to unlock mutex locked by other thread." << endl;
1140
1141 return kTRUE;
1142}
1143
1144void MCosy::DisplayHistTestSe(Bool_t del)
1145{
1146 lout << "Displaying histogram..." << endl;
1147
1148 TH2F &hist = *(TH2F*)fHist;
1149
1150 if (del)
1151 {
1152 fHist = NULL;
1153 fBackground = kBgdNone;
1154 }
1155
1156 TCanvas *c=new TCanvas("c1", "", 1000, 1000);
1157 c->Divide(1,2);
1158
1159 c->cd(1);
1160 TH2 *h=(TH2*)hist.DrawCopy();
1161
1162 TProfile *p = h->ProfileX("_pfx", -1, 9999, "s");
1163 p->SetLineColor(kBlue);
1164 p->Draw("same");
1165 p->SetBit(kCanDelete);
1166
1167 c->cd(2);
1168
1169 TH1F p2("spread", "Spread of the differences", hist.GetNbinsX(), hist.GetBinLowEdge(1),
1170 hist.GetBinLowEdge(hist.GetNbinsX()+1));
1171 p2.SetXTitle("Zd [\\circ]");
1172 for (int i=0; i<hist.GetNbinsX(); i++)
1173 p2.SetBinError(i, p->GetBinError(i));
1174 p2.SetLineColor(kRed);
1175 p2.SetStats(0);
1176 p2.DrawCopy();
1177
1178 if (del)
1179 delete &hist;
1180}
1181
1182void MCosy::DisplayHistGear(Bool_t del)
1183{
1184 lout << "Displaying histogram..." << endl;
1185
1186 TH3F &hist = *(TH3F*)fHist;
1187
1188 if (del)
1189 {
1190 fHist = NULL;
1191 fBackground = kBgdNone;
1192 }
1193
1194 TCanvas *c=new TCanvas("c1", "", 1000, 1000);
1195 c->Divide(2,2);
1196
1197 // ----------
1198
1199 c->cd(1);
1200 TH2D &h1=*(TH2D*)hist.Project3D("zx"); // Zd
1201 h1.SetTitle(" Gear Ratio Zenith Distance [re/se] ");
1202 h1.SetXTitle("Zd [\\circ]");
1203 h1.Draw();
1204 h1.SetBit(kCanDelete);
1205
1206 TProfile *p1 = h1.ProfileX("_pfx", -1, 9999, "s");
1207 p1->SetLineColor(kBlue);
1208 p1->Draw("same");
1209 p1->SetBit(kCanDelete);
1210
1211 // ----------
1212
1213 c->cd(2);
1214 TH2D &h2=*(TH2D*)hist.Project3D("zy"); // Az
1215 h2.SetTitle(" Gear Ratio Azimuth [re/se] ");
1216 h2.SetXTitle("Zd [\\circ]");
1217 h2.Draw();
1218 h2.SetBit(kCanDelete);
1219
1220 TProfile *p2 = h2.ProfileX("_pfx", -1, 9999, "s");
1221 p2->SetLineColor(kBlue);
1222 p2->Draw("same");
1223 p2->SetBit(kCanDelete);
1224
1225 // ----------
1226
1227 c->cd(3);
1228
1229 TAxis &axe1 = *h1.GetXaxis();
1230
1231 TH1F f1("spreadzd", " Spread Zenith Distance ",
1232 axe1.GetNbins(), axe1.GetXmin(), axe1.GetXmax());
1233 f1.SetXTitle("Zd [\\circ]");
1234 for (int i=0; i<axe1.GetNbins(); i++)
1235 f1.SetBinError(i, p1->GetBinError(i));
1236 f1.SetLineColor(kRed);
1237 f1.SetStats(0);
1238 f1.DrawCopy();
1239
1240 c->cd(4);
1241
1242 // ----------
1243
1244 TAxis &axe2 = *h2.GetXaxis();
1245
1246 TH1F f2("spreadaz", " Spread Azimuth ",
1247 axe2.GetNbins(), axe2.GetXmin(), axe2.GetXmax());
1248 f2.SetXTitle("Az [\\circ]");
1249 for (int i=0; i<axe2.GetNbins(); i++)
1250 f2.SetBinError(i, p2->GetBinError(i));
1251 f2.SetLineColor(kRed);
1252 f2.SetStats(0);
1253 f2.DrawCopy();
1254
1255 // ----------
1256
1257 if (del)
1258 delete &hist;
1259}
1260
1261// --------------------------------------------------------------------------
1262//
1263// Start the work of the application:
1264//
1265// Start the Can-Network.
1266// Start the MCosy::TalkThread thread.
1267// turn on the gui update
1268//
1269void MCosy::Start()
1270{
1271 // Don't call this function twice!
1272 Network::Start();
1273
1274 CheckForError();
1275
1276 ReadConfig();
1277
1278 lout << "- Starting TX Thread." << endl;
1279 fTTalk = new MTTalk(this);
1280
1281 lout << "- Starting GUI update." << endl;
1282 fUpdateGui->TurnOn();
1283}
1284
1285// --------------------------------------------------------------------------
1286//
1287// Start the work of the application:
1288//
1289// Turn of the gui update
1290// stop the MCosy::TalkThread thread.
1291// Stop the network
1292//
1293void MCosy::Stop()
1294{
1295 lout << "- Stopping GUI update." << endl;
1296 fUpdateGui->TurnOff();
1297 lout << "- GUI Update stopped." << endl;
1298
1299 delete fTTalk;
1300 lout << "- TX Thread stopped." << endl;
1301
1302 Network::Stop();
1303}
1304
1305// --------------------------------------------------------------------------
1306//
1307// Disable the synchronization by using a negative CAN Id for id2.
1308//
1309void MCosy::Constructor(Int_t id1, Int_t id2, Int_t id3,
1310 Int_t id4, Int_t id5, Int_t id6)
1311{
1312 //
1313 // Create Nodes
1314 //
1315 lout << "- Setting up network." << endl;
1316
1317 fMac1=new Macs(id1, "Mac/Az", lout);
1318 fMac2=new Macs(id3, "Mac/Zd", lout);
1319 if (id2>=0)
1320 fMac3=new Macs(id2, "Mac/Az-Sync", lout);
1321
1322 fZd1=new ShaftEncoder(id4, "SE/Zd1", lout);
1323 fZd2=new ShaftEncoder(id5, "SE/Zd2", lout);
1324 fAz =new ShaftEncoder(id6, "SE/Az", lout);
1325
1326 fZd1->SetReport(fOutRep);
1327 fZd2->SetReport(fOutRep);
1328 fAz->SetReport(fOutRep);
1329
1330 lout << "- Connecting devices to network." << endl;
1331
1332 //
1333 // Connect the devices to the network
1334 //
1335 SetNode(fMac1);
1336 SetNode(fMac2);
1337 if (id2>=0)
1338 SetNode(fMac3);
1339 SetNode(fZd1);
1340 SetNode(fZd2);
1341 SetNode(fAz);
1342
1343 //
1344 // Create Gui Event timer and Gui
1345 //
1346 lout << "- Initializing GUI Timer." << endl;
1347 fUpdateGui = new TTimer(this, 100); // 100ms
1348
1349 lout << "- Starting GUI." << endl;
1350 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
1351}
1352/*
1353void MCosy::ConstructorSE(Int_t id4, Int_t id5, Int_t id6)
1354{
1355 //
1356 // Create Nodes
1357 //
1358 lout << "- Setting up network." << endl;
1359
1360 fZd1=new ShaftEncoder(id4, "SE/Zd1", lout);
1361 fZd2=new ShaftEncoder(id5, "SE/Zd2", lout);
1362 fAz =new ShaftEncoder(id6, "SE/Az", lout);
1363
1364 lout << "- Connecting devices to network." << endl;
1365
1366 //
1367 // Connect the devices to the network
1368 //
1369 SetNode(fZd1);
1370 SetNode(fZd2);
1371 SetNode(fAz);
1372
1373 //
1374 // Create Gui Event timer and Gui
1375 //
1376 lout << "- Initializing GUI Timer." << endl;
1377 fUpdateGui = new TTimer(this, 100); // 100ms
1378
1379 lout << "- Starting GUI." << endl;
1380 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
1381}
1382
1383void MCosy::ConstructorDemo()
1384{
1385 //
1386 // Create Nodes
1387 //
1388 lout << "- Setting up network." << endl;
1389
1390 //
1391 // Create Gui Event timer and Gui
1392 //
1393 lout << "- Initializing GUI Timer." << endl;
1394 fUpdateGui = new TTimer(this, 100); // 100ms
1395
1396 lout << "- Starting GUI." << endl;
1397 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
1398}
1399*/
1400
1401TString MCosy::GetFileName(const char *fmt)
1402{
1403 // FIXME: Timeout missing
1404 while (1)
1405 {
1406 MTime time(-1);
1407 const TString name = Form(fmt, (const char*)time.GetFileName());
1408 if (gSystem->AccessPathName(name, kFileExists))
1409 return name;
1410 break;
1411
1412 usleep(1000);
1413 }
1414 return "";
1415}
1416
1417MCosy::MCosy(/*int mode,*/ const char *dev, const int baud, MLog &out)
1418: Network(dev, baud, out), fObservatory(MObservatory::kMagic1), fStarguider(NULL), fZd1(0), fZd2(0), fAz(0), fMac1(0), fMac2(0), fMac3(0), fBackground(kBgdNone), fStatus(MDriveCom::kStopped), fOutTp(0), fOutRep(0)
1419{
1420 TEnv env(".cosyrc");
1421 const Int_t id1 = env.GetValue("Az_Id-MAC1", 1); //1
1422 const Int_t id2 = env.GetValue("Az_Id-MAC2", 2); //2
1423 const Int_t id3 = env.GetValue("Zd_Id-MAC", 3); //3
1424 const Int_t id4 = env.GetValue("Zd_Id-SE1", 4); //4
1425 const Int_t id5 = env.GetValue("Zd_Id-SE2", 5); //5
1426 const Int_t id6 = env.GetValue("Az_Id-SE", 6); //6
1427
1428 TString name = GetFileName("rep/cosy_%s.rep");
1429 cout << "Open Repfile: " << name << endl;
1430 fOutRep = new MLog(name, kTRUE);
1431
1432/*
1433 lout << "- Program in ";
1434 switch (mode)
1435 {
1436 case 0:
1437 lout << "<<Standard mode>>" << endl;*/
1438 fBending.Load("bending.txt");
1439 Constructor(id1, id2, id3, id4, id5, id6);/*
1440 break;
1441 case 1:
1442 lout << "<<SE mode>>" << endl;
1443 fBending.Load("bending.txt");
1444 ConstructorSE(id4, id5, id6);
1445 break;
1446 default:
1447 lout << "<<Demo mode>>" << endl;
1448 ConstructorDemo();
1449 }
1450*/
1451 lout.SetOutputGui(fWin->GetLog(), kTRUE);
1452
1453 fZd1->SetDisplay(fWin->GetLabel2());
1454 fZd2->SetDisplay(fWin->GetLabel3());
1455 fAz->SetDisplay(fWin->GetLabel1());
1456
1457 fCom = new MDriveCom(this, *fOutRep);
1458 fCom->Start();
1459}
1460
1461void MCosy::TerminateApp()
1462{
1463 cout << "MCosy::TerminateApp()" << endl;
1464/*
1465 Int_t rc;
1466 TGMessageBox msg(this, gClient->GetRoot(),
1467 "Information",
1468 "Cosy is shutting down the system - this may take wa while!",
1469 kMBIconExclamation,
1470 kMBOK, //kMBClose
1471 &rc, 0);
1472*/
1473
1474 lout.DisableOutputDevice(MLog::eGui);
1475 // FIXME: WHY DOES THIS CRASH THE APPLICATIOn WHILE TRAKING?
1476 // lout.SetOutputGui(NULL, kFALSE);
1477
1478 gApplication->Terminate(0);
1479}
1480
1481MCosy::~MCosy()
1482{
1483 if (fOutTp)
1484 {
1485 *fOutTp << "END" << endl;
1486 delete fOutTp;
1487 }
1488 delete fOutRep;
1489
1490 cout << "Deleting GUI timer." << endl;
1491
1492 delete fUpdateGui;
1493 delete fCom;
1494
1495 cout << "Deleting Nodes." << endl;
1496
1497 fZd1->SetReport(0);
1498 fZd2->SetReport(0);
1499 fAz->SetReport(0);
1500
1501 delete fAz;
1502 delete fZd1;
1503 delete fZd2;
1504 delete fMac1;
1505 delete fMac2;
1506 if (fMac3)
1507 delete fMac3;
1508
1509 cout << "Deleting MGCosy." << endl;
1510
1511 lout.DisableOutputDevice(MLog::eGui);
1512
1513 delete fWin;
1514
1515 cout << "MGCosy destructed." << endl;
1516}
Note: See TracBrowser for help on using the repository browser.