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

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