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

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