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

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