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

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