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

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