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

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