source: trunk/FACT++/scripts/Main.js@ 18381

Last change on this file since 18381 was 18381, checked in by Daniela Dorner, 9 years ago
adapted to new drivectrl
File size: 49.2 KB
Line 
1/**
2 * @fileOverview This file has functions related to documenting JavaScript.
3 * @author <a href="mailto:thomas.bretz@epfl.ch">Thomas Bretz</a>
4 */
5'use strict';
6
7dim.log("Start: "+__FILE__+" ["+__DATE__+"]");
8
9// This should be set in dimctrl.rc as JavaScript.schedule-database.
10// It is sent together with the script to the dimserver.
11// If started directly, it has to be set after the command:
12//
13// .js scripts/Main.js schedule-database=...
14//
15if (!$['schedule-database'])
16 throw new Error("Environment 'schedule-database' not set!");
17
18//dimctrl.defineState(37, "TimeOutBeforeTakingData", "MCP took more than 5minutes to start TakingData");
19
20// ================================================================
21// Code related to the schedule
22// ================================================================
23
24//this is just the class implementation of 'Observation'
25include('scripts/Observation_class.js');
26include('scripts/getSchedule.js');
27
28var observations = [ ];
29
30// Get the observation scheduled for 'now' from the table and
31// return its index
32function getObservation(now)
33{
34 if (now==undefined)
35 now = new Date();
36
37 if (isNaN(now.valueOf()))
38 throw new Error("Date argument in getObservation invalid.");
39
40 observations = getSchedule();
41
42 for (var i=0; i<observations.length; i++)
43 if (now<observations[i].start)
44 return i-1;
45
46 return observations.length-1;
47}
48
49// ================================================================
50// Code to check whether observation is allowed
51// ================================================================
52/*
53function currentEst(source)
54{
55 var moon = new Moon();
56 if (!moon.isUp)
57 return 7.7;
58
59 var dist = Sky.dist(moon, source);
60
61 var alt = 90-moon.toLocal().zd;
62
63 var lc = dist*alt*pow(Moon.disk(), 6)/360/360;
64
65 var cur = 7.7+4942*lc;
66
67 return cur;
68}
69
70function thresholdEst(source) // relative threshold (ratio)
71{
72 // Assumption:
73 // atmosphere is 70km, shower taks place after 60km, earth radius 6400km
74 // just using the cosine law
75 // This fits very well with MC results: See Roger Firpo, p.45
76 // "Study of the MAGIC telescope sensitivity for Large Zenith Angle observations"
77
78 var c = Math.cos(Math.Pi-source.zd);
79 var ratio = (10*sqrt(409600*c*c+9009) + 6400*c - 60)/10;
80
81 // assumption: Energy threshold increases linearily with current
82 // assumption: Energy threshold increases linearily with distance
83
84 return ratio*currentEst(source)/7.7;
85}
86*/
87
88// ================================================================
89// Code to perform the DRS calib sequence
90// ================================================================
91
92var irq;
93
94function doDrsCalibration(where)
95{
96 dim.log("Starting DRS calibration ["+where+"]");
97
98 service_feedback.voltageOff();
99
100 var tm = new Date();
101
102 while (!irq)
103 {
104 dim.send("FAD_CONTROL/START_DRS_CALIBRATION");
105 if (irq || !takeRun("drs-pedestal", 1000)) // 40 / 20s (50Hz)
106 continue;
107
108 if (irq || !takeRun("drs-gain", 1000)) // 40 / 20s (50Hz)
109 continue;
110
111 if (where!="data")
112 {
113 if (irq || !takeRun("drs-pedestal", 1000)) // 40 / 20s (50Hz)
114 continue;
115 }
116
117 break;
118 }
119
120 if (where!="data")
121 {
122 dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
123
124 while (!irq && !takeRun("drs-pedestal", 1000)); // 40 / 20s (50Hz)
125 while (!irq && !takeRun("drs-time", 1000)); // 40 / 20s (50Hz)
126 }
127
128 while (!irq)
129 {
130 dim.send("FAD_CONTROL/RESET_SECONDARY_DRS_BASELINE");
131 if (takeRun("pedestal", 1000)) // 40 / 10s (80Hz)
132 break;
133 }
134
135 dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
136
137 while (!irq && !takeRun("pedestal", 1000)); // 40 / 10s (80Hz)
138 // -----------
139 // 4'40 / 2'00
140
141 if (irq)
142 dim.log("DRS calibration interrupted [%.1fs]".$((new Date()-tm)/1000));
143 else
144 dim.log("DRS calibration done [%.1fs]".$((new Date()-tm)/1000));
145}
146
147// ================================================================
148// Code related to the lid
149// ================================================================
150
151function OpenLid()
152{
153 /*
154 while (Sun.horizon(-13).isUp)
155 {
156 var now = new Date();
157 var minutes_until_sunset = (Sun.horizon(-13).set - now)/60000;
158 console.out(now.toUTCString()+": Sun above FACT-horizon, lid cannot be opened: sleeping 1min, remaining %.1fmin".$(minutes_until_sunset));
159 v8.sleep(60000);
160 }*/
161
162 var isClosed = dim.state("LID_CONTROL").name=="Closed";
163
164 var tm = new Date();
165
166 // Wait for lid to be open
167 if (isClosed)
168 {
169 dim.log("Opening lid");
170 dim.send("LID_CONTROL/OPEN");
171 }
172 dim.wait("LID_CONTROL", "Open", 30000);
173
174 if (isClosed)
175 dim.log("Lid open [%.1fs]".$((new Date()-tm)/1000));
176}
177
178function CloseLid()
179{
180 var isOpen = dim.state("LID_CONTROL").name=="Open";
181
182 var tm = new Date();
183
184 // Wait for lid to be open
185 if (isOpen)
186 {
187 if (dim.state("FTM_CONTROL").name=="TriggerOn")
188 {
189 dim.send("FTM_CONTROL/STOP_TRIGGER");
190 dim.wait("FTM_CONTROL", "Valid", 3000);
191 }
192
193 dim.log("Closing lid.");
194 dim.send("LID_CONTROL/CLOSE");
195 }
196 dim.wait("LID_CONTROL", "Closed", 30000);
197
198 if (isOpen)
199 dim.log("Lid closed [%.1fs]".$((new Date()-tm)/1000));
200}
201
202// ================================================================
203// Interrupt data taking in case of high currents
204// ================================================================
205dim.onchange['FEEDBACK'] = function(state)
206{
207 if ((state.name=="Critical" || state.name=="OnStandby") &&
208 (this.prev!="Critical" && this.prev!="OnStandby"))
209 {
210 console.out("Feedback state changed from "+this.prev+" to "+state.name+" [Main.js]");
211 irq = "RESCHEDULE";
212 }
213 this.prev=state.name;
214}
215
216// ================================================================
217// Code related to switching bias voltage on and off
218// ================================================================
219
220var service_feedback = new Subscription("FEEDBACK/CALIBRATED_CURRENTS");
221
222service_feedback.onchange = function(evt)
223{
224 if (!evt.data)
225 return;
226
227 if (this.ok==undefined)
228 return;
229
230 var Unom = evt.obj['U_nom'];
231 var Uov = evt.obj['U_ov'];
232 if (!Uov)
233 return;
234
235 var cnt = 0;
236 var avg = 0;
237 for (var i=0; i<320; i++)
238 {
239 var dU = Uov[i]-Unom;
240
241 // 0.022 corresponds to 1 DAC count (90V/4096)
242 if (Math.abs(dU)>0.033)
243 cnt++;
244
245 avg += dU;
246 }
247 avg /= 320;
248
249 this.ok = cnt<3;// || (this.last!=undefined && Math.abs(this.last-avg)<0.002);
250
251 console.out(" DeltaUov=%.3f (%.3f) [N(>0.033V)=%d]".$(avg, avg-this.last, cnt));
252
253 this.last = avg;
254}
255
256service_feedback.voltageOff = function()
257{
258 var state = dim.state("BIAS_CONTROL").name;
259
260 if (state=="Disconnected")
261 {
262 console.out(" Voltage off: bias crate disconnected!");
263 return;
264 }
265
266 // check of feedback has to be switched on
267 var isOn = state=="VoltageOn" || state=="Ramping";
268 if (isOn)
269 {
270 dim.log("Switching voltage off.");
271
272 if (dim.state("FTM_CONTROL").name=="TriggerOn")
273 {
274 dim.send("FTM_CONTROL/STOP_TRIGGER");
275 dim.wait("FTM_CONTROL", "Valid", 3000);
276 }
277
278 // Supress the possibility that the bias control is
279 // ramping and will reject the command to switch the
280 // voltage off
281 //dim.send("FEEDBACK/STOP");
282 //dim.wait("FEEDBACK", "Calibrated", 3000);
283
284 // Make sure we are not in Ramping anymore
285 //dim.wait("BIAS_CONTROL", "VoltageOn", 3000);
286
287 // Switch voltage off
288 dim.send("BIAS_CONTROL/SET_ZERO_VOLTAGE");
289 }
290
291 dim.wait("BIAS_CONTROL", "VoltageOff", 60000); // FIXME: 30000?
292 dim.wait("FEEDBACK", "Calibrated", 3000);
293
294 // FEEDBACK stays in CurrentCtrl when Voltage is off but output enabled
295 // dim.wait("FEEDBACK", "CurrentCtrlIdle", 1000);
296
297 if (isOn)
298 dim.log("Voltage off.");
299}
300
301// DN: The name of the method voltageOn() in the context of the method
302// voltageOff() is a little bit misleading, since when voltageOff() returns
303// the caller can be sure the voltage is off, but when voltageOn() return
304// this is not the case, in the sense, that the caller can now take data.
305// instead the caller of voltageOn() *must* call waitForVoltageOn() afterwards
306// in order to safely take good-quality data.
307// This could lead to nasty bugs in the sense, that the second call might
308// be forgotten by somebody
309//
310// so I suggest to rename voltageOn() --> prepareVoltageOn()
311// waitForVoltageOn() stays as it is
312// and one creates a third method called:voltageOn() like this
313/* service_feedback.voltageOn = function()
314 * {
315 * this.prepareVoltageOn();
316 * this.waitForVoltageOn();
317 * }
318 *
319 * */
320// For convenience.
321
322service_feedback.voltageOn = function(ov)
323{
324 if (isNaN(ov))
325 ov = 1.1;
326
327 if (this.ov!=ov && dim.state("FEEDBACK").name=="InProgress") // FIXME: Warning, OnStandby, Critical if (ov<this.ov)
328 {
329 dim.log("Stoping feedback.");
330 if (dim.state("FTM_CONTROL").name=="TriggerOn")
331 {
332 dim.send("FTM_CONTROL/STOP_TRIGGER");
333 dim.wait("FTM_CONTROL", "Valid", 3000);
334 }
335
336 dim.send("FEEDBACK/STOP");
337 dim.wait("FEEDBACK", "Calibrated", 3000);
338
339 // Make sure we are not in Ramping anymore
340 dim.wait("BIAS_CONTROL", "VoltageOn", 3000);
341 }
342
343 var isOff = dim.state("FEEDBACK").name=="Calibrated";
344 if (isOff)
345 {
346 dim.log("Switching voltage to Uov="+ov+"V.");
347
348 dim.send("FEEDBACK/START", ov);
349
350 // FIXME: We could miss "InProgress" if it immediately changes to "Warning"
351 // Maybe a dim.timeout state>8 ?
352 dim.wait("FEEDBACK", "InProgress", 45000);
353
354 this.ov = ov;
355 }
356
357 // Wait until voltage on
358 dim.wait("BIAS_CONTROL", "VoltageOn", 60000); // FIXME: 30000?
359}
360
361service_feedback.waitForVoltageOn = function()
362{
363 // Avoid output if condition is already fulfilled
364 dim.log("Waiting for voltage to be stable.");
365
366 function func()
367 {
368 if (irq || this.ok==true)
369 return true;
370 }
371
372 var now = new Date();
373
374 this.last = undefined;
375 this.ok = false;
376 v8.timeout(4*60000, func, this); // FIMXE: Remove 4!
377 this.ok = undefined;
378
379 if (irq)
380 dim.log("Waiting for stable voltage interrupted.");
381 else
382 dim.log("Voltage stable within limits");
383}
384
385// ================================================================
386// Function to shutdown the system
387// ================================================================
388
389function Shutdown(type)
390{
391 if (!type)
392 type = "default";
393
394 dim.log("Starting shutdown ["+type+"].");
395
396 var now1 = new Date();
397
398 var bias = dim.state("BIAS_CONTROL").name;
399 if (bias=="VoltageOn" || bias=="Ramping")
400 service_feedback.voltageOn(0);
401
402 CloseLid();
403
404 var now2 = new Date();
405
406 dim.send("DRIVE_CONTROL/PARK");
407
408 console.out("","Waiting for telescope to park. This may take a while.");
409
410 // FIXME: This might not work is the drive is already close to park position
411 //dim.wait("DRIVE_CONTROL", "Parking", 3000);
412
413 /*
414 // Check if DRS calibration is necessary
415 var diff = getTimeSinceLastDrsCalib();
416 if (diff>30 || diff==null)
417 {
418 doDrsCalibration("singlepe"); // will turn voltage off
419 if (irq)
420 break;
421 }*/
422
423 //take single pe run if required
424 if (type=="singlepe")
425 {
426 dim.log("Taking single-pe run.");
427
428 // The voltage must be on
429 service_feedback.voltageOn();
430 service_feedback.waitForVoltageOn();
431
432 // Before we can switch to 3000 we have to make the right DRS calibration
433 dim.log("Taking single p.e. run.");
434 while (!irq && !takeRun("single-pe", 10000));
435 }
436
437 //wait until drive is in locked (after it reached park position)
438 dim.wait("DRIVE_CONTROL", "Locked", 150000);
439
440 //unlock drive if task was sleep
441 if (type=="sleep")
442 dim.send("DRIVE_CONTROL/UNLOCK");
443
444
445 // It is unclear what comes next, so we better switch off the voltage
446 service_feedback.voltageOff();
447
448 dim.log("Finishing shutdown.");
449
450 var now3 = new Date();
451
452 dim.send("FTM_CONTROL/STOP_TRIGGER");
453 dim.wait("FTM_CONTROL", "Valid", 3000);
454
455 if (bias!="Disconnected")
456 dim.wait("FEEDBACK", "Calibrated", 3000);
457
458 if (type!="sleep")
459 {
460 dim.send("BIAS_CONTROL/DISCONNECT");
461
462 var pwrctrl_state = dim.state("PWR_CONTROL").name;
463 if (pwrctrl_state=="SystemOn" ||
464 pwrctrl_state=="BiasOff" ||
465 pwrctrl_state=="DriveOn")
466 dim.send("PWR_CONTROL/TOGGLE_DRIVE");
467
468 dim.wait("BIAS_CONTROL", "Disconnected", 3000);
469 dim.wait("PWR_CONTROL", "DriveOff", 6000);
470 }
471
472 var sub = new Subscription("DRIVE_CONTROL/POINTING_POSITION");
473 sub.get(5000); // FIXME: Proper error message in case of failure
474
475 var report = sub.get();
476
477 console.out("");
478 console.out("Shutdown procedure ["+type+"] seems to be finished...");
479 console.out(" "+new Date().toUTCString());
480 console.out(" Telescope at Zd=%.1fdeg Az=%.1fdeg".$(report.obj['Zd'], report.obj['Az']));
481 console.out(" Please check on the web cam that the park position was reached");
482 console.out(" and the telescope is not moving anymore.");
483 console.out(" Please check visually that the lid is really closed and");
484 console.out(" that the biasctrl really switched the voltage off.", "");
485 console.out(" DRIVE_CONTROL: "+dim.state("DRIVE_CONTROL").name);
486 console.out(" FEEDBACK: "+dim.state("FEEDBACK").name);
487 console.out(" FTM_CONTROL: "+dim.state("FTM_CONTROL").name);
488 console.out(" BIAS_CONTROL: "+dim.state("BIAS_CONTROL").name);
489 console.out(" PWR_CONTROL: "+dim.state("PWR_CONTROL").name);
490 console.out("");
491 dim.log("Shutdown: end ["+(now2-now1)/1000+"s, "+(now3-now2)/1000+"s, "+(new Date()-now3)/1000+"s]");
492 console.out("");
493
494 sub.close();
495}
496
497
498// ================================================================
499// Function to set the system to sleep-mode
500// ================================================================
501// FIXME: do not repeat code from shutdown-function
502/*
503function GoToSleep()
504{
505 CloseLid();
506
507 var isArmed = dim.state("DRIVE_CONTROL").name=="Armed";
508 if (!isArmed)
509 {
510 dim.log("Drive not ready to move. -> send STOP");
511 dim.send("DRIVE_CONTROL/STOP");
512 dim.wait("DRIVE_CONTROL", "Armed", 5000);
513 }
514
515 dim.send("DRIVE_CONTROL/MOVE_TO 101 0");//park position
516 var sub = new Subscription("DRIVE_CONTROL/POINTING_POSITION");
517 sub.get(5000); // FIXME: Proper error message in case of failure
518
519 function func()
520 {
521 var report = sub.get();
522
523 var zd = report.obj['Zd'];
524 var az = report.obj['Az'];
525
526 if (zd>100 && Math.abs(az)<1)
527 return true;
528
529 return undefined;
530 }
531
532 try { v8.timeout(150000, func); }
533 catch (e)
534 {
535 var p = sub.get();
536 dim.log('Park position not reached? Telescope at Zd='+p.obj['Zd']+' Az='+p.obj['Az']);
537 }
538 var p2 = sub.get();
539 dim.log('Telescope at Zd=%.1fdeg Az=%.1fdeg'.$(p2.obj['Zd'], p2.obj['Az']));
540 sub.close();
541}
542*/
543
544// ================================================================
545// Check datalogger subscriptions
546// ================================================================
547
548var datalogger_subscriptions = new Subscription("DATA_LOGGER/SUBSCRIPTIONS");
549datalogger_subscriptions.get(3000, false);
550
551datalogger_subscriptions.check = function()
552{
553 var obj = this.get();
554 if (!obj.data)
555 throw new Error("DATA_LOGGER/SUBSCRIPTIONS not available.");
556
557 var expected =
558 [
559 "AGILENT_CONTROL_24V/DATA",
560 "AGILENT_CONTROL_50V/DATA",
561 "AGILENT_CONTROL_80V/DATA",
562 "BIAS_CONTROL/CURRENT",
563 "BIAS_CONTROL/DAC",
564 "BIAS_CONTROL/NOMINAL",
565 "BIAS_CONTROL/VOLTAGE",
566 "DRIVE_CONTROL/POINTING_POSITION",
567 "DRIVE_CONTROL/SOURCE_POSITION",
568 "DRIVE_CONTROL/STATUS",
569 "DRIVE_CONTROL/TRACKING_POSITION",
570 "FAD_CONTROL/CONNECTIONS",
571 "FAD_CONTROL/DAC",
572 "FAD_CONTROL/DNA",
573 "FAD_CONTROL/DRS_RUNS",
574 "FAD_CONTROL/EVENTS",
575 "FAD_CONTROL/FEEDBACK_DATA",
576 "FAD_CONTROL/FILE_FORMAT",
577 "FAD_CONTROL/FIRMWARE_VERSION",
578 "FAD_CONTROL/INCOMPLETE",
579 "FAD_CONTROL/PRESCALER",
580 "FAD_CONTROL/REFERENCE_CLOCK",
581 "FAD_CONTROL/REGION_OF_INTEREST",
582 "FAD_CONTROL/RUNS",
583 "FAD_CONTROL/RUN_NUMBER",
584 "FAD_CONTROL/START_RUN",
585 "FAD_CONTROL/STATISTICS1",
586 "FAD_CONTROL/STATS",
587 "FAD_CONTROL/STATUS",
588 "FAD_CONTROL/TEMPERATURE",
589 "FEEDBACK/CALIBRATED_CURRENTS",
590 "FEEDBACK/CALIBRATION",
591 "FEEDBACK/CALIBRATION_R8",
592 "FEEDBACK/CALIBRATION_STEPS",
593/* "FEEDBACK/REFERENCE",*/
594 "FSC_CONTROL/CURRENT",
595 "FSC_CONTROL/HUMIDITY",
596 "FSC_CONTROL/TEMPERATURE",
597 "FSC_CONTROL/VOLTAGE",
598 "FTM_CONTROL/COUNTER",
599 "FTM_CONTROL/DYNAMIC_DATA",
600 "FTM_CONTROL/ERROR",
601 "FTM_CONTROL/FTU_LIST",
602 "FTM_CONTROL/PASSPORT",
603 "FTM_CONTROL/STATIC_DATA",
604 "FTM_CONTROL/TRIGGER_RATES",
605 "GPS_CONTROL/NEMA",
606 "SQM_CONTROL/DATA",
607 "LID_CONTROL/DATA",
608 "MAGIC_LIDAR/DATA",
609 "MAGIC_WEATHER/DATA",
610 "MCP/CONFIGURATION",
611 "PWR_CONTROL/DATA",
612 "RATE_CONTROL/THRESHOLD",
613 "RATE_SCAN/DATA",
614 "RATE_SCAN/PROCESS_DATA",
615 "TEMPERATURE/DATA",
616 "TIME_CHECK/OFFSET",
617 "TNG_WEATHER/DATA",
618 "TNG_WEATHER/DUST",
619 "PFMINI_CONTROL/DATA",
620 ];
621
622 function map(entry)
623 {
624 if (entry.length==0)
625 return undefined;
626
627 var rc = entry.split(',');
628 if (rc.length!=2)
629 throw new Error("Subscription list entry '"+entry+"' has wrong number of elements.");
630 return rc;
631 }
632
633 var list = obj.data.split('\n').map(map);
634 function check(name)
635 {
636 if (list.every(function(el){return el==undefined || el[0]!=name;}))
637 throw new Error("Subscription to '"+name+"' not available.");
638 }
639
640 expected.forEach(check);
641}
642
643
644
645// ================================================================
646// Crosscheck all states
647// ================================================================
648
649// ----------------------------------------------------------------
650// Do a standard startup to bring the system in into a well
651// defined state
652// ----------------------------------------------------------------
653include('scripts/Startup.js');
654
655// ================================================================
656// Code to monitor clock conditioner
657// ================================================================
658
659var sub_counter = new Subscription("FTM_CONTROL/COUNTER");
660sub_counter.onchange = function(evt)
661{
662 if (evt.qos>0 && evt.qos!=2 && evt.qos&0x100==0)
663 throw new Error("FTM reports: clock conditioner not locked.");
664}
665
666// ================================================================
667// Code related to monitoring the fad system
668// ================================================================
669
670// This code is here, because scripts/Startup.js needs the
671// same subscriptions... to be revised.
672var sub_incomplete = new Subscription("FAD_CONTROL/INCOMPLETE");
673var sub_connections = new Subscription("FAD_CONTROL/CONNECTIONS");
674var sub_startrun = new Subscription("FAD_CONTROL/START_RUN");
675sub_startrun.get(5000);
676
677include('scripts/takeRun.js');
678
679// ----------------------------------------------------------------
680// Check that everything we need is availabel to receive commands
681// (FIXME: Should that go to the general CheckState?)
682// ----------------------------------------------------------------
683//console.out("Checking send.");
684checkSend(["MCP", "DRIVE_CONTROL", "LID_CONTROL", "FAD_CONTROL", "FEEDBACK"]);
685//console.out("Checking send: done");
686
687// ----------------------------------------------------------------
688// Bring feedback into the correct operational state
689// ----------------------------------------------------------------
690//console.out("Feedback init: start.");
691service_feedback.get(5000);
692
693// ----------------------------------------------------------------
694// Connect to the DRS_RUNS service
695// ----------------------------------------------------------------
696//console.out("Drs runs init: start.");
697
698var sub_drsruns = new Subscription("FAD_CONTROL/DRS_RUNS");
699sub_drsruns.get(5000);
700// FIXME: Check if the last DRS calibration was complete?
701
702function getTimeSinceLastDrsCalib()
703{
704 // ----- Time since last DRS Calibration [min] ------
705 var runs = sub_drsruns.get(0);
706 var diff = (new Date()-runs.time)/60000;
707
708 // Warning: 'roi=300' is a number which is not intrisically fixed
709 // but can change depending on the taste of the observers
710 var valid = runs.obj['run'][2]>0 && runs.obj['roi']==300;
711
712 if (valid)
713 dim.log("Last DRS calibration was %.1fmin ago".$(diff));
714 else
715 dim.log("No valid DRS calibration available.");
716
717 return valid ? diff : null;
718}
719
720// ----------------------------------------------------------------
721// Install interrupt handler
722// ----------------------------------------------------------------
723function handleIrq(cmd, args, time, user)
724{
725 console.out("Interrupt received:");
726 console.out(" IRQ: "+cmd);
727 console.out(" Time: "+time);
728 console.out(" User: "+user);
729
730 irq = cmd ? cmd : "stop";
731
732 // This will end a run in progress as if it where correctly stopped
733 if (dim.state("MCP").name=="TakingData")
734 dim.send("MCP/STOP");
735
736 // This will stop a rate scan in progress
737 if (dim.state("RATE_SCAN").name=="InProgress")
738 dim.send("RATE_SCAN/STOP");
739}
740
741dimctrl.setInterruptHandler(handleIrq);
742
743// ----------------------------------------------------------------
744// Make sure we will write files
745// ----------------------------------------------------------------
746dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
747
748// ----------------------------------------------------------------
749// Print some information for the user about the
750// expected first oberservation
751// ----------------------------------------------------------------
752var test = getObservation();
753if (test!=undefined)
754{
755 var n = new Date();
756 if (observations.length>0 && test==-1)
757 dim.log("First observation scheduled for "+observations[0].start.toUTCString()+" [id="+observations[0].id+"]");
758 if (test>=0 && test<observations.length)
759 dim.log("First observation should start immediately ["+observations[test].start.toUTCString()+", id="+observations[test].id+"]");
760 if (observations.length>0 && observations[0].start>n+12*3600*1000)
761 dim.log("No observations scheduled for the next 12 hours!");
762 if (observations.length==0)
763 dim.log("No observations scheduled!");
764}
765
766// ----------------------------------------------------------------
767// Start main loop
768// ----------------------------------------------------------------
769dim.log("Entering main loop.");
770console.out("");
771
772var run = -2; // getObservation never called
773var sub;
774var lastId;
775var nextId;
776var sun = Sun.horizon(-12);
777var system_on; // undefined
778
779function processIrq()
780{
781 if (!irq)
782 return false;
783
784 if (irq.toUpperCase()=="RESCHEDULE")
785 {
786 irq = undefined;
787 return false;
788 }
789
790 if (irq.toUpperCase()=="OFF")
791 {
792 service_feedback.voltageOff();
793 dim.send("FAD_CONTROL/CLOSE_OPEN_FILES");
794 return true;
795 }
796
797 /*
798 if (irq.toUpperCase()=="STOP")
799 {
800 dim.send("FAD_CONTROL/CLOSE_OPEN_FILES");
801 dim.send("MCP/STOP");
802 return true;
803 }*/
804
805 if (irq.toUpperCase()=="SHUTDOWN")
806 {
807 Shutdown();
808 return true;
809 }
810
811 dim.log("IRQ "+irq+" unhandled... stopping script.");
812 return true;
813}
814
815while (!processIrq())
816{
817 // Check if observation position is still valid
818 // If source position has changed, set run=0
819 var idxObs = getObservation();
820 if (idxObs===undefined)
821 break;
822
823 // we are still waiting for the first observation in the schedule
824 if (idxObs==-1)
825 {
826 // flag that the first observation will be in the future
827 run = -1;
828 v8.sleep(1000);
829 continue;
830 }
831
832 // Check if we have to take action do to sun-rise
833 var was_up = sun.isUp;
834 sun = Sun.horizon(-12);
835 if (!was_up && sun.isUp)
836 {
837 console.out("");
838 dim.log("Sun rise detected.... automatic shutdown initiated!");
839 // FIXME: State check?
840 Shutdown();
841 system_on = false;
842 continue;
843 }
844
845 // Current and next observation target
846 var obs = observations[idxObs];
847 var nextObs = observations[idxObs+1];
848
849 // Check if observation target has changed
850 if (lastId!=obs.id) // !Object.isEqual(obs, nextObs)
851 {
852 dim.log("Starting new observation ["+obs.start.toUTCString()+", id="+obs.id+"]");
853
854 // This is the first source, but we do not come from
855 // a scheduled 'START', so we have to check if the
856 // telescop is operational already
857 sub = 0;
858 if (run<0)
859 {
860 //Startup(); // -> Bias On/Off?, Lid open/closed?
861 //CloseLid();
862 }
863
864 // The first observation had a start-time in the past...
865 // In this particular case start with the last entry
866 // in the list of measurements
867 if (run==-2)
868 sub = obs.length-1;
869
870 run = 0;
871 lastId = obs.id;
872 }
873
874 //dim.log("DEBUG: Next observation scheduled for "+nextObs.start.toUTCString()+" [id="+nextObs.id+"]");
875 if (nextObs && nextId!=nextObs.id)
876 {
877 dim.log("Next observation scheduled for "+nextObs.start.toUTCString()+" [id="+nextObs.id+"]");
878 console.out("");
879 nextId = nextObs.id;
880 }
881
882 if (!nextObs && nextId)
883 {
884 dim.log("No further observation scheduled.");
885 console.out("");
886 nextId = undefined;
887 }
888
889 //if (nextObs==undefined && obs[obs.length-1].task!="SHUTDOWN")
890 // throw Error("Last scheduled measurement must be a shutdown.");
891
892 // We are done with all measurement slots for this
893 // observation... wait for next observation
894 if (sub>=obs.length)
895 {
896 v8.sleep(1000);
897 continue;
898 }
899
900 if (system_on===false && obs[sub].task!="STARTUP")
901 {
902 v8.sleep(1000);
903 continue;
904 }
905
906 // Check if sun is still up... only DATA and */
907 if ((obs[sub].task=="DATA" || obs[sub].task=="RATESCAN" || obs[sub].task=="RATESCAN2" ) && sun.isUp)
908 {
909 var now = new Date();
910 var remaining = (sun.set - now)/60000;
911 console.out(now.toUTCString()+" - "+obs[sub].task+": Sun above FACT-horizon: sleeping 1min, remaining %.1fmin".$(remaining));
912 v8.sleep(60000);
913 continue;
914 }
915
916
917 if (obs[sub].task!="IDLE" && (obs[sub].task!="DATA" && run>0))
918 dim.log("New task ["+obs[sub]+"]");
919
920 // FIXME: Maybe print a warning if Drive is on during day time!
921
922 // It is not ideal that we allow the drive to be on during day time, but
923 // otherwise it is difficult to allow e.g. the STARTUP at the beginning of the night
924 var power_states = sun.isUp || !system_on ? [ "DriveOff", "SystemOn" ] : [ "SystemOn" ];
925 var drive_states = sun.isUp || !system_on ? undefined : [ "Initialized", "Tracking", "OnTrack" ];
926
927 // A scheduled task was found, lets check if all servers are
928 // still only and in reasonable states. If this is not the case,
929 // something unexpected must have happend and the script is aborted.
930 //console.out(" Checking states [general]");
931 var table =
932 [
933 [ "TNG_WEATHER" ],
934 [ "MAGIC_WEATHER" ],
935 [ "CHAT" ],
936 [ "SMART_FACT" ],
937 [ "TEMPERATURE" ],
938 [ "DATA_LOGGER", [ "NightlyFileOpen", "WaitForRun", "Logging" ] ],
939 [ "FSC_CONTROL", [ "Connected" ] ],
940 [ "MCP", [ "Idle" ] ],
941 [ "TIME_CHECK", [ "Valid" ] ],
942 [ "PWR_CONTROL", power_states/*[ "SystemOn" ]*/ ],
943 [ "AGILENT_CONTROL_24V", [ "VoltageOn" ] ],
944 [ "AGILENT_CONTROL_50V", [ "VoltageOn" ] ],
945 [ "AGILENT_CONTROL_80V", [ "VoltageOn" ] ],
946 [ "BIAS_CONTROL", [ "VoltageOff", "VoltageOn", "Ramping" ] ],
947 [ "FEEDBACK", [ "Calibrated", "InProgress", "OnStandby", "Warning", "Critical" ] ],
948 [ "LID_CONTROL", [ "Open", "Closed" ] ],
949 [ "DRIVE_CONTROL", drive_states/*[ "Armed", "Tracking", "OnTrack" ]*/ ],
950 [ "FTM_CONTROL", [ "Valid", "TriggerOn" ] ],
951 [ "FAD_CONTROL", [ "Connected", "RunInProgress" ] ],
952 [ "RATE_SCAN", [ "Connected" ] ],
953 [ "RATE_CONTROL", [ "Connected", "GlobalThresholdSet", "InProgress" ] ],
954 [ "GPS_CONTROL", [ "Locked" ] ],
955 [ "SQM_CONTROL", [ "Disconnected", "Connected", "Valid" ] ],
956 [ "PFMINI_CONTROL", [ "Disconnected", "Connected", "Receiving" ] ],
957 ];
958
959
960 if (!checkStates(table))
961 {
962 throw new Error("Something unexpected has happened. One of the servers "+
963 "is in a state in which it should not be. Please,"+
964 "try to find out what happened...");
965 }
966
967 datalogger_subscriptions.check();
968
969 // If this is an observation which needs the voltage to be swicthed on
970 // skip that if the voltage is not stable
971 /*
972 if (obs[sub].task=="DATA" || obs[sub].task=="RATESCAN")
973 {
974 var state = dim.state("FEEDBACK").name;
975 if (state=="Warning" || state=="Critical" || state=="OnStandby")
976 {
977 v8.sleep(1000);
978 continue;
979 }
980 }*/
981
982
983 // Check if obs.task is one of the one-time-tasks
984 switch (obs[sub].task)
985 {
986 case "IDLE":
987 v8.sleep(5000);
988 continue;
989
990 case "SLEEP":
991 Shutdown("sleep"); //GoToSleep();
992
993 sub++;
994 dim.log("Task finished [SLEEP].");
995 console.out("");
996 continue;
997
998 case "STARTUP":
999 CloseLid();
1000
1001 doDrsCalibration("startup"); // will switch the voltage off
1002
1003 if (irq)
1004 break;
1005
1006 service_feedback.voltageOn();
1007 service_feedback.waitForVoltageOn();
1008
1009 // Before we can switch to 3000 we have to make the right DRS calibration
1010 dim.log("Taking single p.e. run.");
1011 while (!irq && !takeRun("single-pe", 10000));
1012
1013 // It is unclear what comes next, so we better switch off the voltage
1014 service_feedback.voltageOff();
1015
1016 system_on = true;
1017 dim.log("Task finished [STARTUP]");
1018 console.out("");
1019 break;
1020
1021 case "SHUTDOWN":
1022 Shutdown("singlepe");
1023 system_on = false;
1024
1025 // FIXME: Avoid new observations after a shutdown until
1026 // the next startup (set run back to -2?)
1027 sub++;
1028 dim.log("Task finished [SHUTDOWN]");
1029 console.out("");
1030 //console.out(" Waiting for next startup.", "");
1031 continue;
1032
1033 case "DRSCALIB":
1034 doDrsCalibration("drscalib"); // will switch the voltage off
1035 dim.log("Task finished [DRSCALIB]");
1036 console.out("");
1037 break;
1038
1039 case "SINGLEPE":
1040 // The lid must be closes
1041 CloseLid();
1042
1043 // Check if DRS calibration is necessary
1044 var diff = getTimeSinceLastDrsCalib();
1045 if (diff>30 || diff==null)
1046 {
1047 doDrsCalibration("singlepe"); // will turn voltage off
1048 if (irq)
1049 break;
1050 }
1051
1052 // The voltage must be on
1053 service_feedback.voltageOn();
1054 service_feedback.waitForVoltageOn();
1055
1056 // Before we can switch to 3000 we have to make the right DRS calibration
1057 dim.log("Taking single p.e. run.");
1058 while (!irq && !takeRun("single-pe", 10000));
1059
1060 // It is unclear what comes next, so we better switch off the voltage
1061 service_feedback.voltageOff();
1062 dim.log("Task finished [SINGLE-PE]");
1063 console.out("");
1064 break;
1065
1066 case "OVTEST":
1067 var locked = dim.state("DRIVE_CONTROL").name=="Locked";
1068 if (!locked)
1069 dim.send("DRIVE_CONTROL/PARK");
1070
1071 dim.send("FEEDBACK/STOP");
1072
1073 // The lid must be closed
1074 CloseLid();
1075
1076 if (!locked)
1077 {
1078 //console.out("Waiting for telescope to park. This may take a while.");
1079 dim.wait("DRIVE_CONTROL", "Locked", 3000);
1080 dim.send("DRIVE_CONTROL/UNLOCK");
1081 }
1082
1083 // Check if DRS calibration is necessary
1084 var diff = getTimeSinceLastDrsCalib();
1085 if (diff>30 || diff==null)
1086 {
1087 doDrsCalibration("ovtest"); // will turn voltage off
1088 if (irq)
1089 break;
1090 }
1091
1092 // The voltage must be on
1093 service_feedback.voltageOn(0.4);
1094 service_feedback.waitForVoltageOn();
1095
1096 dim.log("Taking single p.e. run (0.4V)");
1097 while (!irq && !takeRun("single-pe", 10000));
1098
1099 for (var i=5; i<18 && !irq; i++)
1100 {
1101 dim.send("FEEDBACK/STOP");
1102 dim.wait("FEEDBACK", "Calibrated", 3000);
1103 dim.wait("BIAS_CONTROL", "VoltageOn", 3000);
1104 dim.send("FEEDBACK/START", i*0.1);
1105 dim.wait("FEEDBACK", "InProgress", 45000);
1106 dim.wait("BIAS_CONTROL", "VoltageOn", 60000); // FIXME: 30000?
1107 service_feedback.waitForVoltageOn();
1108 dim.log("Taking single p.e. run ("+(i*0.1)+"V)");
1109 while (!irq && !takeRun("single-pe", 10000));
1110 }
1111
1112 // It is unclear what comes next, so we better switch off the voltage
1113 service_feedback.voltageOff();
1114 dim.log("Task finished [OVTEST]");
1115 console.out("");
1116 break;
1117
1118 case "RATESCAN":
1119 var tm1 = new Date();
1120
1121 // This is a workaround to make sure that we really catch
1122 // the new OnTrack state later and not the old one
1123 dim.send("DRIVE_CONTROL/STOP");
1124 dim.wait("DRIVE_CONTROL", "Initialized", 15000);
1125
1126 // The lid must be open
1127 OpenLid();
1128
1129 // Switch the voltage to a reduced level (Ubd)
1130 service_feedback.voltageOn(0);
1131
1132 if (obs[sub].source != undefined)
1133 {
1134 dim.log("Pointing telescope to '"+obs[sub].source+"'.");
1135 dim.send("DRIVE_CONTROL/TRACK_ON", obs[sub].source);
1136 }
1137 else
1138 {
1139 dim.log("Pointing telescope to ra="+obs[sub].ra+" dec="+obs[sub].dec);
1140 dim.send("DRIVE_CONTROL/TRACK", obs[sub].ra, obs[sub].dec);
1141 }
1142
1143 dim.wait("DRIVE_CONTROL", "OnTrack", 150000); // 110s for turning and 30s for stabilizing
1144
1145 // Now tracking stable, switch voltage to nominal level and wait
1146 // for stability.
1147 service_feedback.voltageOn();
1148 service_feedback.waitForVoltageOn();
1149
1150 if (!irq)
1151 {
1152 dim.log("Starting calibration.");
1153
1154 // Calibration (2% of 20')
1155 while (!irq)
1156 {
1157 if (irq || !takeRun("pedestal", 1000)) // 80 Hz -> 10s
1158 continue;
1159 if (irq || !takeRun("light-pulser-ext", 1000)) // 80 Hz -> 10s
1160 continue;
1161 break;
1162 }
1163
1164 var tm2 = new Date();
1165
1166 dim.log("Starting ratescan.");
1167
1168 //set reference to whole camera (in case it was changed)
1169 dim.send("RATE_SCAN/SET_REFERENCE_CAMERA");
1170 // Start rate scan
1171 dim.send("RATE_SCAN/START_THRESHOLD_SCAN", 50, 1000, -10, "default");
1172
1173 // Lets wait if the ratescan really starts... this might take a few
1174 // seconds because RATE_SCAN configures the ftm and is waiting for
1175 // it to be configured.
1176 dim.wait("RATE_SCAN", "InProgress", 10000);
1177 dim.wait("RATE_SCAN", "Connected", 2700000);
1178
1179 // Here one could implement a watchdog for the feedback as well, but what is the difference
1180 // whether finally one has to find out if the feedback was in the correct state
1181 // or the ratescan was interrupted?
1182
1183 // this line is actually some kind of hack.
1184 // after the Ratescan, no data is written to disk. I don't know why, but it happens all the time
1185 // So I decided to put this line here as a kind of patchwork....
1186 //dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
1187
1188 dim.log("Ratescan done [%.1fs, %.1fs]".$((tm2-tm1)/1000, (new Date()-tm2)/1000));
1189 }
1190
1191 dim.log("Task finished [RATESCAN]");
1192 console.out("");
1193 break; // case "RATESCAN"
1194
1195 case "RATESCAN2":
1196 var tm1 = new Date();
1197
1198 // This is a workaround to make sure that we really catch
1199 // the new OnTrack state later and not the old one
1200 dim.send("DRIVE_CONTROL/STOP");
1201 dim.wait("DRIVE_CONTROL", "Initialized", 15000);
1202
1203 if (obs[sub].rstype=="dark-bias-off")
1204 service_feedback.voltageOff();
1205 else
1206 {
1207 // Switch the voltage to a reduced level (Ubd)
1208 var bias = dim.state("BIAS_CONTROL").name;
1209 if (bias=="VoltageOn" || bias=="Ramping")
1210 service_feedback.voltageOn(0);
1211 }
1212
1213 // Open the lid if required
1214 if (!obs[sub].lidclosed)
1215 OpenLid();
1216 else
1217 CloseLid();
1218
1219 // track source/position or move to position
1220 if (obs[sub].lidclosed)
1221 {
1222 dim.log("Moving telescope to zd="+obs[sub].zd+" az="+obs[sub].az);
1223 dim.send("DRIVE_CONTROL/MOVE_TO", obs[sub].zd, obs[sub].az);
1224 v8.sleep(3000);
1225 dim.wait("DRIVE_CONTROL", "Initialized", 150000); // 110s for turning and 30s for stabilizing
1226 }
1227 else
1228 {
1229 if (obs[sub].source != undefined)
1230 {
1231 dim.log("Pointing telescope to '"+obs[sub].source+"'.");
1232 dim.send("DRIVE_CONTROL/TRACK_ON", obs[sub].source);
1233 }
1234 else
1235 {
1236 dim.log("Pointing telescope to ra="+obs[sub].ra+" dec="+obs[sub].dec);
1237 dim.send("DRIVE_CONTROL/TRACK", obs[sub].ra, obs[sub].dec);
1238 }
1239
1240 dim.wait("DRIVE_CONTROL", "OnTrack", 150000); // 110s for turning and 30s for stabilizing
1241 }
1242
1243 // Now tracking stable, switch voltage to nominal level and wait
1244 // for stability.
1245 if (obs[sub].rstype!="dark-bias-off")
1246 {
1247 service_feedback.voltageOn();
1248 service_feedback.waitForVoltageOn();
1249 }
1250
1251 if (!irq)
1252 {
1253 var tm2 = new Date();
1254
1255 dim.log("Starting ratescan 2/1 ["+obs[sub].rstype+"]");
1256
1257 //set reference to whole camera (in case it was changed)
1258 dim.send("RATE_SCAN/SET_REFERENCE_CAMERA");
1259 // Start rate scan
1260 dim.send("RATE_SCAN/START_THRESHOLD_SCAN", 50, 300, 20, obs[sub].rstype);
1261
1262 // Lets wait if the ratescan really starts... this might take a few
1263 // seconds because RATE_SCAN configures the ftm and is waiting for
1264 // it to be configured.
1265 dim.wait("RATE_SCAN", "InProgress", 10000);
1266 //FIXME: discuss what best value is here
1267 dim.wait("RATE_SCAN", "Connected", 2700000);//45min
1268 //dim.wait("RATE_SCAN", "Connected", 1200000);//3.3h
1269
1270 // Here one could implement a watchdog for the feedback as well, but what is the difference
1271 // whether finally one has to find out if the feedback was in the correct state
1272 // or the ratescan was interrupted?
1273
1274 // this line is actually some kind of hack.
1275 // after the Ratescan, no data is written to disk. I don't know why, but it happens all the time
1276 // So I decided to put this line here as a kind of patchwork....
1277 //dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
1278
1279 dim.log("Ratescan 2/1 done [%.1fs, %.1fs]".$((tm2-tm1)/1000, (new Date()-tm2)/1000));
1280 }
1281
1282 if (!irq)
1283 {
1284 var tm2 = new Date();
1285
1286 dim.log("Starting ratescan 2/2 ["+obs[sub].rstype+"]");
1287
1288 // Start rate scan
1289 dim.send("RATE_SCAN/START_THRESHOLD_SCAN", 300, 1000, 100, obs[sub].rstype);
1290
1291 // Lets wait if the ratescan really starts... this might take a few
1292 // seconds because RATE_SCAN configures the ftm and is waiting for
1293 // it to be configured.
1294 dim.wait("RATE_SCAN", "InProgress", 10000);
1295 dim.wait("RATE_SCAN", "Connected", 2700000);
1296
1297 // Here one could implement a watchdog for the feedback as well, but what is the difference
1298 // whether finally one has to find out if the feedback was in the correct state
1299 // or the ratescan was interrupted?
1300
1301 // this line is actually some kind of hack.
1302 // after the Ratescan, no data is written to disk. I don't know why, but it happens all the time
1303 // So I decided to put this line here as a kind of patchwork....
1304 //dim.send("FAD_CONTROL/SET_FILE_FORMAT", 6);
1305
1306 dim.log("Ratescan 2/2 done [%.1fs, %.1fs]".$((tm2-tm1)/1000, (new Date()-tm2)/1000));
1307 }
1308
1309 dim.log("Task finished [RATESCAN2]");
1310 console.out("");
1311 break; // case "RATESCAN2"
1312
1313 case "CUSTOM":
1314
1315 // This is a workaround to make sure that we really catch
1316 // the new OnTrack state later and not the old one
1317 dim.send("DRIVE_CONTROL/STOP");
1318 dim.wait("DRIVE_CONTROL", "Initialized", 15000);
1319
1320 // Ramp bias if needed
1321 if (!obs[sub].biason)
1322 service_feedback.voltageOff();
1323 else
1324 {
1325 // Switch the voltage to a reduced level (Ubd)
1326 var bias = dim.state("BIAS_CONTROL").name;
1327 if (bias=="VoltageOn" || bias=="Ramping")
1328 service_feedback.voltageOn(0);
1329 }
1330 // Close lid
1331 CloseLid();
1332
1333 // Move to position (zd/az)
1334 dim.log("Moving telescope to zd="+obs[sub].zd+" az="+obs[sub].az);
1335 dim.send("DRIVE_CONTROL/MOVE_TO", obs[sub].zd, obs[sub].az);
1336 v8.sleep(3000);
1337 dim.wait("DRIVE_CONTROL", "Initialized", 150000); // 110s for turning and 30s for stabilizing
1338
1339 // Now tracking stable, switch voltage to nominal level and wait
1340 // for stability.
1341 if (obs[sub].biason)
1342 {
1343 service_feedback.voltageOn();
1344 service_feedback.waitForVoltageOn();
1345 }
1346
1347 if (!irq)
1348 {
1349 dim.log("Taking custom run with time "+obs[sub].time+"s, threshold="+obs[sub].threshold+", biason="+obs[sub].biason);
1350
1351 var customRun = function()
1352 {
1353 v8.sleep(500);//wait that configuration is set
1354 dim.wait("FTM_CONTROL", "TriggerOn", 15000);
1355 dim.send("FAD_CONTROL/SEND_SINGLE_TRIGGER");
1356 dim.send("RATE_CONTROL/STOP");
1357 dim.send("FTM_CONTROL/STOP_TRIGGER");
1358 dim.wait("FTM_CONTROL", "Valid", 3000);
1359 dim.send("FTM_CONTROL/ENABLE_TRIGGER", true);
1360 dim.send("FTM_CONTROL/SET_TIME_MARKER_DELAY", 123);
1361 dim.send("FTM_CONTROL/SET_THRESHOLD", -1, obs[sub].threshold);
1362 v8.sleep(500);//wait that configuration is set
1363 dim.send("FTM_CONTROL/START_TRIGGER");
1364 dim.wait("FTM_CONTROL", "TriggerOn", 15000);
1365 }
1366
1367 takeRun(customRun, -1, obs[sub].time);
1368 }
1369 dim.log("Task finished [CUSTOM].");
1370 dim.log("");
1371 break; // case "CUSTOM"
1372
1373 case "DATA":
1374
1375 // ========================== case "DATA" ============================
1376 /*
1377 if (Sun.horizon("FACT").isUp)
1378 {
1379 console.out(" SHUTDOWN","");
1380 Shutdown();
1381 console.out(" Exit forced due to broken schedule", "");
1382 exit();
1383 }
1384 */
1385
1386 // Calculate remaining time for this observation in minutes
1387 var remaining = nextObs==undefined ? 0 : (nextObs.start-new Date())/60000;
1388 //dim.log("DEBUG: remaining: "+remaining+" nextObs="+nextObs+" start="+nextObs.start);
1389
1390 // ------------------------------------------------------------
1391
1392 dim.log("Run count "+run+" [remaining "+parseInt(remaining)+"min]");
1393
1394 // ----- Time since last DRS Calibration [min] ------
1395 var diff = getTimeSinceLastDrsCalib();
1396
1397 // Changine pointing position and take calibration...
1398 // ...every four runs (every ~20min)
1399 // ...if at least ten minutes of observation time are left
1400 // ...if this is the first run on the source
1401 var point = (run%4==0 && remaining>10) || run==0;
1402
1403 // Take DRS Calib...
1404 // ...every four runs (every ~20min)
1405 // ...at last every two hours
1406 // ...when DRS temperature has changed by more than 2deg (?)
1407 // ...when more than 15min of observation are left
1408 // ...no drs calibration was done yet
1409 var drscal = (run%4==0 && (remaining>15 && diff>70)) || diff==null;
1410
1411 if (point)
1412 {
1413 // Switch the voltage to a reduced voltage level
1414 service_feedback.voltageOn(0);
1415
1416 // Change wobble position every four runs,
1417 // start with alternating wobble positions each day
1418 var wobble = (parseInt(run/4) + parseInt(new Date()/1000/3600/24-0.5))%2+1;
1419
1420 //console.out(" Move telescope to '"+source+"' "+offset+" "+wobble);
1421 dim.log("Pointing telescope to '"+obs[sub].source+"' [wobble="+wobble+"]");
1422
1423 // This is a workaround to make sure that we really catch
1424 // the new OnTrack state later and not the old one
1425 dim.send("DRIVE_CONTROL/STOP");
1426 dim.wait("DRIVE_CONTROL", "Initialized", 15000);
1427
1428 //dim.send("DRIVE_CONTROL/MOON");
1429 dim.send("DRIVE_CONTROL/TRACK_WOBBLE", wobble, obs[sub].source);
1430
1431 // Do we have to check if the telescope is really moving?
1432 // We can cross-check the SOURCE service later
1433 }
1434
1435 if (drscal)
1436 {
1437 doDrsCalibration("data"); // will turn voltage off
1438
1439 // Now we switch on the voltage and a significant amount of
1440 // time has been passed, so do the check again.
1441 sun = Sun.horizon(-12);
1442 if (!was_up && sun.isUp)
1443 {
1444 dim.log("Sun rise detected....");
1445 continue;
1446 }
1447 }
1448
1449 if (irq)
1450 continue;
1451
1452 OpenLid();
1453
1454 // This is now th right time to wait for th drive to be stable
1455 dim.wait("DRIVE_CONTROL", "OnTrack", 150000); // 110s for turning and 30s for stabilizing
1456
1457 // Now check the voltage... (do not start a lot of stuff just to do nothing)
1458 var state = dim.state("FEEDBACK").name;
1459 if (state=="Warning" || state=="Critical" || state=="OnStandby")
1460 {
1461 v8.sleep(60000);
1462 continue;
1463 }
1464
1465 // Now we are 'OnTrack', so we can ramp to nominal voltage
1466 // and wait for the feedback to get stable
1467 service_feedback.voltageOn();
1468 service_feedback.waitForVoltageOn();
1469
1470 // If pointing had changed, do calibration
1471 if (!irq && point)
1472 {
1473 dim.log("Starting calibration.");
1474
1475 // Calibration (2% of 20')
1476 while (!irq)
1477 {
1478 if (irq || !takeRun("pedestal", 1000)) // 80 Hz -> 10s
1479 continue;
1480// if (irq || !takeRun("light-pulser-ext", 1000)) // 80 Hz -> 10s
1481// continue;
1482 break;
1483 }
1484 }
1485
1486 //console.out(" Taking data: start [5min]");
1487
1488 // FIXME: What do we do if during calibration something has happened
1489 // e.g. drive went to ERROR? Maybe we have to check all states again?
1490
1491 var twilight = Sun.horizon(-16).isUp;
1492
1493 if (twilight)
1494 {
1495 for (var i=0; i<5 && !irq; i++)
1496 takeRun("data", -1, 60); // Take data (1min)
1497 }
1498 else
1499 {
1500 var len = 300;
1501 while (!irq && len>15)
1502 {
1503 var time = new Date();
1504 if (takeRun("data", -1, len)) // Take data (5min)
1505 break;
1506
1507 len -= parseInt((new Date()-time)/1000);
1508 }
1509 }
1510
1511 //console.out(" Taking data: done");
1512 run++;
1513
1514 continue; // case "DATA"
1515 }
1516
1517 if (nextObs!=undefined && sub==obs.length-1)
1518 dim.log("Next observation will start at "+nextObs.start.toUTCString()+" [id="+nextObs.id+"]");
1519
1520 sub++;
1521}
1522
1523sub_drsruns.close();
1524
1525dim.log("Left main loop [irq="+irq+"]");
1526
1527// ================================================================
1528// Comments and ToDo goes here
1529// ================================================================
1530
1531// error handline : http://www.sitepoint.com/exceptional-exception-handling-in-javascript/
1532// classes: http://www.phpied.com/3-ways-to-define-a-javascript-class/
Note: See TracBrowser for help on using the repository browser.