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

Last change on this file since 16050 was 16049, checked in by tbretz, 11 years ago
Moved some code around data taking (automatic reconnect etc) to takeRun.js so that it can also be used from CheckUnderflow.js
File size: 32.2 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
92function doDrsCalibration(where)
93{
94 console.out(" Take DRS calibration ["+where+"]");
95
96 service_feedback.voltageOff();
97
98 var tm = new Date();
99
100 while (1)
101 {
102 dim.send("FAD_CONTROL/START_DRS_CALIBRATION");
103 if (!takeRun("drs-pedestal", 1000)) // 40 / 20s (50Hz)
104 continue;
105
106 if (!takeRun("drs-gain", 1000)) // 40 / 20s (50Hz)
107 continue;
108
109 if (!takeRun("drs-pedestal", 1000)) // 40 / 20s (50Hz)
110 continue;
111
112 break;
113 }
114
115 dim.send("FAD_CONTROL/SET_FILE_FORMAT", 2);
116
117 while (!takeRun("drs-pedestal", 1000)); // 40 / 20s (50Hz)
118 while (!takeRun("drs-time", 1000)); // 40 / 20s (50Hz)
119
120 while (1)
121 {
122 dim.send("FAD_CONTROL/RESET_SECONDARY_DRS_BASELINE");
123 if (takeRun("pedestal", 1000)) // 40 / 10s (80Hz)
124 break;
125 }
126
127 dim.send("FAD_CONTROL/SET_FILE_FORMAT", 2);
128
129 while (!takeRun("pedestal", 1000)); // 40 / 10s (80Hz)
130
131 // -----------
132 // 4'40 / 2'00
133
134 console.out(" DRS calibration done [%.1f]".$((new Date()-tm)/1000));
135}
136
137// ================================================================
138// Code related to the lid
139// ================================================================
140
141function OpenLid()
142{
143 /*
144 while (Sun.horizon(-13).isUp)
145 {
146 var now = new Date();
147 var minutes_until_sunset = (Sun.horizon(-13).set - now)/60000;
148 console.out(now.toUTCString()+": Sun above FACT-horizon, lid cannot be opened: sleeping 1min, remaining %.1fmin".$(minutes_until_sunset));
149 v8.sleep(60000);
150 }*/
151
152 var isClosed = dim.state("LID_CONTROL").name=="Closed";
153
154 var tm = new Date();
155
156 // Wait for lid to be open
157 if (isClosed)
158 {
159 console.out(" Open lid: start");
160 dim.send("LID_CONTROL/OPEN");
161 }
162 dim.wait("LID_CONTROL", "Open", 30000);
163
164 if (isClosed)
165 console.out(" Open lid: done [%.1fs]".$((new Date()-tm)/1000));
166}
167
168function CloseLid()
169{
170 var isOpen = dim.state("LID_CONTROL").name=="Open";
171
172 var tm = new Date();
173
174 // Wait for lid to be open
175 if (isOpen)
176 {
177 console.out(" Close lid: start");
178 dim.send("LID_CONTROL/CLOSE");
179 }
180 dim.wait("LID_CONTROL", "Closed", 30000);
181
182 if (isOpen)
183 console.out(" Close lid: end [%.1fs]".$((new Date()-tm)/1000));
184}
185
186// ================================================================
187// Code related to switching bias voltage on and off
188// ================================================================
189
190var service_feedback = new Subscription("FEEDBACK/DEVIATION");
191
192service_feedback.onchange = function(evt)
193{
194 if (this.cnt && evt.counter>this.cnt+12)
195 return;
196
197 this.voltageStep = null;
198 if (!evt.data)
199 return;
200
201 var delta = evt.obj['DeltaBias'];
202
203 // It seems this can happen when the feedback was newly started. Why?
204 // What is the correct solution?
205 if (!delta)
206 return;
207
208 var avg = 0;
209 for (var i=0; i<320; i++)
210 avg += delta[i];
211 avg /= 320;
212
213 if (this.previous)
214 this.voltageStep = Math.abs(avg-this.previous);
215
216 this.previous = avg;
217
218 console.out(" DeltaV="+this.voltageStep);
219}
220
221// DN: Why is voltageOff() implemented as
222// a method of a Subscription to a specific Service
223// I naively would think of voltageOff() as an unbound function.
224// I seems to me it has to be a method of a Subscription object, in order
225// to use the update counting method. But does it have to be
226// a Subscription to FEEDBACK/DEVIATION, or could it work with other services as well?
227service_feedback.voltageOff = function()
228{
229 var state = dim.state("BIAS_CONTROL").name;
230
231 if (state=="Disconnected")
232 {
233 console.out(" Voltage off: bias crate disconnected!");
234 return;
235 }
236
237 // check of feedback has to be switched on
238 var isOn = state=="VoltageOn" || state=="Ramping";
239 if (isOn)
240 {
241 console.out(" Voltage off: start");
242
243 // Supress the possibility that the bias control is
244 // ramping and will reject the command to switch the
245 // voltage off
246 var isControl = dim.state("FEEDBACK").name=="CurrentControl";
247 if (isControl)
248 {
249 console.out(" Suspending feedback.");
250 dim.send("FEEDBACK/ENABLE_OUTPUT", false);
251 dim.wait("FEEDBACK", "CurrentCtrlIdle", 3000);
252 }
253
254 // Switch voltage off
255 console.out(" Voltage on: switch off");
256 dim.send("BIAS_CONTROL/SET_ZERO_VOLTAGE");
257
258 // If the feedback was enabled, re-enable it
259 if (isControl)
260 {
261 console.out(" Resuming feedback.");
262 dim.send("FEEDBACK/ENABLE_OUTPUT", true);
263 dim.wait("FEEDBACK", "CurrentControl", 3000);
264 }
265 }
266
267 dim.wait("BIAS_CONTROL", "VoltageOff", 5000);
268
269 // FEEDBACK stays in CurrentCtrl when Voltage is off but output enabled
270 // dim.wait("FEEDBACK", "CurrentCtrlIdle", 1000);
271
272 if (isOn)
273 console.out(" Voltage off: end");
274}
275
276// DN: The name of the method voltageOn() in the context of the method
277// voltageOff() is a little bit misleading, since when voltageOff() returns
278// the caller can be sure the voltage is off, but when voltageOn() return
279// this is not the case, in the sense, that the caller can now take data.
280// instead the caller of voltageOn() *must* call waitForVoltageOn() afterwards
281// in order to safely take good-quality data.
282// This could lead to nasty bugs in the sense, that the second call might
283// be forgotten by somebody
284//
285// so I suggest to rename voltageOn() --> prepareVoltageOn()
286// waitForVoltageOn() stays as it is
287// and one creates a third method called:voltageOn() like this
288/* service_feedback.voltageOn = function()
289 * {
290 * this.prepareVoltageOn();
291 * this.waitForVoltageOn();
292 * }
293 *
294 * */
295// For convenience.
296
297service_feedback.voltageOn = function()
298{
299 //if (Sun.horizon("FACT").isUp)
300 // throw new Error("Sun is above FACT-horizon, voltage cannot be switched on.");
301
302 var isOff = dim.state("BIAS_CONTROL").name=="VoltageOff";
303 if (isOff)
304 {
305 console.out(" Voltage on: switch on");
306 //console.out(JSON.stringify(dim.state("BIAS_CONTROL")));
307
308 dim.send("BIAS_CONTROL/SET_GLOBAL_DAC", 1);
309 }
310
311 // Wait until voltage on
312 dim.wait("BIAS_CONTROL", "VoltageOn", 5000);
313
314 // From now on the feedback waits for a valid report from the FSC
315 // and than switchs to CurrentControl
316 dim.wait("FEEDBACK", "CurrentControl", 60000);
317
318 if (isOff)
319 {
320 console.out(" Voltage on: cnt="+this.cnt);
321
322 this.previous = undefined;
323 this.cnt = this.get().counter;
324 this.voltageStep = undefined;
325 }
326}
327
328service_feedback.waitForVoltageOn = function()
329{
330 // waiting 45sec for the current control to stabilize...
331 // v8.sleep(45000);
332
333 // ----- Wait for at least three updates -----
334 // The feedback is started as if the camera where at 0deg
335 // Then after the first temp update, the temperature will be set to the
336 // correct value (this has already happened)
337 // So we only have to wait for the current to get stable.
338 // This should happen after three to five current updates.
339 // So we want one recent temperature update
340 // and three recent current updates
341
342 // Avoid output if condition is already fulfilled
343 if (this.cnt && this.get().counter>this.cnt+10)
344 return;
345
346 // FIXME: timeout missing
347 console.out(" Feedback wait: start");
348
349 function func(service)
350 {
351 if ((service.cnt!=undefined && service.get().counter>service.cnt+10) ||
352 (service.voltageStep && service.voltageStep<0.02))
353 return true;
354 }
355
356 var now = new Date();
357 //v8.timeout(5*60000, func, this);
358 while ((this.cnt==undefined || this.get().counter<=this.cnt+10) && (!this.voltageStep || this.voltageStep>0.02))
359 v8.sleep(100);
360
361 console.out(" Feedback wait: end [dV=%.3f, cnt=%d, %.2fs]".$(this.voltageStep, this.get().counter, (new Date()-now)/1000));
362}
363
364// ================================================================
365// Function to shutdown the system
366// ================================================================
367
368function Shutdown()
369{
370 console.out("Shutdown: start");
371
372 service_feedback.voltageOff();
373 CloseLid();
374 dim.send("DRIVE_CONTROL/PARK");
375
376 console.out("Waiting for telescope to park. This may take a while.");
377
378 // FIXME: This might not work is the drive is already close to park position
379 dim.wait("DRIVE_CONTROL", "Locked", 3000);
380
381 var sub = new Subscription("DRIVE_CONTROL/POINTING_POSITION");
382 sub.get(5000); // FIXME: Proper error message in case of failure
383
384 function func()
385 {
386 var report = sub.get();
387
388 var zd = report.obj['Zd'];
389 var az = report.obj['Az'];
390
391 if (zd>100 && Math.abs(az)<1)
392 return true;
393
394 return undefined;
395 }
396
397 var now = new Date();
398 v8.timeout(150000, func);
399
400 //dim.send("FEEDBACK/STOP");
401 dim.send("FEEDBACK/ENABLE_OUTPUT", false);
402 dim.send("FTM_CONTROL/STOP_TRIGGER");
403 dim.send("BIAS_CONTROL/DISCONNECT");
404
405 dim.wait("FTM_CONTROL", "Idle", 3000);
406 dim.wait("BIAS_CONTROL", "Disconnected", 3000);
407 dim.wait("FEEDBACK", "Connected", 3000);
408
409 var report = sub.get();
410
411 console.out("");
412 console.out("Shutdown procedure seems to be finished...");
413 console.out(" "+new Date().toUTCString());
414 console.out(" Telescope at Zd=%.1fdeg Az=%.1fdeg".$(report.obj['Zd'], report.obj['Az']));
415 console.out(" Please make sure the park position was reached");
416 console.out(" and the telescope is not moving anymore.");
417 console.out(" Please check that the lid is closed and the voltage switched off.", "");
418 console.out(" DRIVE_CONTROL: "+dim.state("DRIVE_CONTROL").name);
419 console.out(" FEEDBACK: "+dim.state("FEEDBACK").name);
420 console.out(" FTM_CONTROL: "+dim.state("FTM_CONTROL").name);
421 console.out(" BIAS_CONTROL: "+dim.state("BIAS_CONTROL").name);
422 console.out("");
423 console.out("Shutdown: end ["+(new Date()-now)/1000+"s]");
424
425 sub.close();
426}
427
428// ================================================================
429// Check datalogger subscriptions
430// ================================================================
431
432var datalogger_subscriptions = new Subscription("DATA_LOGGER/SUBSCRIPTIONS");
433datalogger_subscriptions.get(3000, false);
434
435datalogger_subscriptions.check = function()
436{
437 var obj = this.get();
438 if (!obj.data)
439 throw new Error("DATA_LOGGER/SUBSCRIPTIONS not available.");
440
441 var expected =
442 [
443 "BIAS_CONTROL/CURRENT",
444 "BIAS_CONTROL/DAC",
445 "BIAS_CONTROL/NOMINAL",
446 "BIAS_CONTROL/VOLTAGE",
447 "DRIVE_CONTROL/POINTING_POSITION",
448 "DRIVE_CONTROL/SOURCE_POSITION",
449 "DRIVE_CONTROL/STATUS",
450 "DRIVE_CONTROL/TRACKING_POSITION",
451 "FAD_CONTROL/CONNECTIONS",
452 "FAD_CONTROL/DAC",
453 "FAD_CONTROL/DNA",
454 "FAD_CONTROL/DRS_RUNS",
455 "FAD_CONTROL/EVENTS",
456 "FAD_CONTROL/FEEDBACK_DATA",
457 "FAD_CONTROL/FILE_FORMAT",
458 "FAD_CONTROL/FIRMWARE_VERSION",
459 "FAD_CONTROL/INCOMPLETE",
460 "FAD_CONTROL/PRESCALER",
461 "FAD_CONTROL/REFERENCE_CLOCK",
462 "FAD_CONTROL/REGION_OF_INTEREST",
463 "FAD_CONTROL/RUNS",
464 "FAD_CONTROL/RUN_NUMBER",
465 "FAD_CONTROL/START_RUN",
466 "FAD_CONTROL/STATISTICS1",
467 // "FAD_CONTROL/STATISTICS2",
468 "FAD_CONTROL/STATS",
469 "FAD_CONTROL/STATUS",
470 "FAD_CONTROL/TEMPERATURE",
471 "FEEDBACK/CALIBRATED_CURRENTS",
472 "FEEDBACK/CALIBRATION",
473 "FEEDBACK/DEVIATION",
474 "FEEDBACK/REFERENCE",
475 "FSC_CONTROL/CURRENT",
476 "FSC_CONTROL/HUMIDITY",
477 "FSC_CONTROL/TEMPERATURE",
478 "FSC_CONTROL/VOLTAGE",
479 "FTM_CONTROL/COUNTER",
480 "FTM_CONTROL/DYNAMIC_DATA",
481 "FTM_CONTROL/ERROR",
482 "FTM_CONTROL/FTU_LIST",
483 "FTM_CONTROL/PASSPORT",
484 "FTM_CONTROL/STATIC_DATA",
485 "FTM_CONTROL/TRIGGER_RATES",
486 "LID_CONTROL/DATA",
487 "MAGIC_LIDAR/DATA",
488 "MAGIC_WEATHER/DATA",
489 "MCP/CONFIGURATION",
490 "PWR_CONTROL/DATA",
491 "RATE_CONTROL/THRESHOLD",
492 "RATE_SCAN/DATA",
493 "RATE_SCAN/PROCESS_DATA",
494 "TEMPERATURE/DATA",
495 "TIME_CHECK/OFFSET",
496 "TNG_WEATHER/DATA",
497 "TNG_WEATHER/DUST",
498 ];
499
500 function map(entry)
501 {
502 if (entry.length==0)
503 return undefined;
504
505 var rc = entry.split(',');
506 if (rc.length!=2)
507 throw new Error("Subscription list entry '"+entry+"' has wrong number of elements.");
508 return rc;
509 }
510
511 var list = obj.data.split('\n').map(map);
512
513 function check(name)
514 {
515 if (list.every(function(el){return el==undefined || el[0]!=name;}))
516 throw new Error("Subscription to '"+name+"' not available.");
517 }
518
519 expected.forEach(check);
520}
521
522
523
524// ================================================================
525// Crosscheck all states
526// ================================================================
527
528// ----------------------------------------------------------------
529// Do a standard startup to bring the system in into a well
530// defined state
531// ----------------------------------------------------------------
532include('scripts/Startup.js');
533
534// ================================================================
535// Code related to monitoring the fad system
536// ================================================================
537
538// This code is here, because scripts/Startup.js needs the
539// same subscriptions... to be revised.
540var sub_incomplete = new Subscription("FAD_CONTROL/INCOMPLETE");
541var sub_connections = new Subscription("FAD_CONTROL/CONNECTIONS");
542var sub_startrun = new Subscription("FAD_CONTROL/START_RUN");
543sub_startrun.get(5000);
544
545include('scripts/takeRun.js');
546
547// ----------------------------------------------------------------
548// Check that everything we need is availabel to receive commands
549// (FIXME: Should that go to the general CheckState?)
550// ----------------------------------------------------------------
551console.out("Checking send.");
552checkSend(["MCP", "DRIVE_CONTROL", "LID_CONTROL", "FAD_CONTROL", "FEEDBACK"]);
553console.out("Checking send: done");
554
555// ----------------------------------------------------------------
556// Bring feedback into the correct operational state
557// ----------------------------------------------------------------
558console.out("Feedback init: start.");
559service_feedback.get(5000);
560
561dim.send("FEEDBACK/ENABLE_OUTPUT", true);
562dim.send("FEEDBACK/START_CURRENT_CONTROL", 0.);
563
564v8.timeout(3000, function() { var n = dim.state("FEEDBACK").name; if (n=="CurrentCtrlIdle" || n=="CurrentControl") return true; });
565
566// ----------------------------------------------------------------
567// Connect to the DRS_RUNS service
568// ----------------------------------------------------------------
569console.out("Drs runs init: start.");
570
571var sub_drsruns = new Subscription("FAD_CONTROL/DRS_RUNS");
572sub_drsruns.get(5000);
573// FIXME: Check if the last DRS calibration was complete?
574
575function getTimeSinceLastDrsCalib()
576{
577 // ----- Time since last DRS Calibration [min] ------
578 var runs = sub_drsruns.get(0);
579 var diff = (new Date()-runs.time)/60000;
580
581 // Warning: 'roi=300' is a number which is not intrisically fixed
582 // but can change depending on the taste of the observers
583 var valid = runs.obj['run'][2]>0 && runs.obj['roi']==300;
584
585 if (valid)
586 console.out(" Last DRS calib: %.1fmin ago".$(diff));
587 else
588 console.out(" No valid drs calibration available");
589
590 return valid ? diff : null;
591}
592
593// ----------------------------------------------------------------
594// Make sure we will write files
595// ----------------------------------------------------------------
596dim.send("FAD_CONTROL/SET_FILE_FORMAT", 2);
597
598// ----------------------------------------------------------------
599// Print some information for the user about the
600// expected first oberservation
601// ----------------------------------------------------------------
602var test = getObservation();
603if (test!=undefined)
604{
605 var n = new Date();
606 if (observations.length>0 && test==-1)
607 console.out(n.toUTCString()+": First observation scheduled for "+observations[0].start.toUTCString());
608 if (test>=0 && test<observations.length)
609 console.out(n.toUTCString()+": First observation should start immediately.");
610 if (observations.length>0 && observations[0].start>n+12*3600*1000)
611 console.out(n.toUTCString()+": No observations scheduled for the next 12 hours!");
612 if (observations.length==0)
613 console.out(n.toUTCString()+": No observations scheduled!");
614}
615
616// ----------------------------------------------------------------
617// Start main loop
618// ----------------------------------------------------------------
619console.out("Start main loop.");
620
621var run = -2; // getObservation never called
622var sub;
623var lastId;
624var sun = Sun.horizon(-12);
625var system_on; // undefined
626
627while (1)
628{
629 // Check if observation position is still valid
630 // If source position has changed, set run=0
631 var idxObs = getObservation();
632 if (idxObs===undefined)
633 break;
634
635 // we are still waiting for the first observation in the schedule
636 if (idxObs==-1)
637 {
638 // flag that the first observation will be in the future
639 run = -1;
640 v8.sleep(1000);
641 continue;
642 }
643
644 // Check if we have to take action do to sun-rise
645 var was_up = sun.isUp;
646 sun = Sun.horizon(-12);
647 if (!was_up && sun.isUp)
648 {
649 console.out("", "Sun rise detected.... automatic shutdown initiated!");
650 // FIXME: State check?
651 Shutdown();
652 system_on = false;
653 continue;
654 }
655
656 // Current and next observation target
657 var obs = observations[idxObs];
658 var nextObs = observations[idxObs+1];
659
660 // Check if observation target has changed
661 if (lastId!=obs.id) // !Object.isEqual(obs, nextObs)
662 {
663 console.out("--- "+obs.id+" ---");
664 console.out("Current time: "+new Date().toUTCString());
665 console.out("Current observation: "+obs.start.toUTCString());
666 if (nextObs!=undefined)
667 console.out("Next observation: "+nextObs.start.toUTCString());
668 console.out("");
669
670 // This is the first source, but we do not come from
671 // a scheduled 'START', so we have to check if the
672 // telescop is operational already
673 sub = 0;
674 if (run<0)
675 {
676 //Startup(); // -> Bias On/Off?, Lid open/closed?
677 //CloseLid();
678 }
679
680 // The first observation had a start-time in the past...
681 // In this particular case start with the last entry
682 // in the list of measurements
683 if (run==-2)
684 sub = obs.length-1;
685
686 run = 0;
687 }
688 lastId = obs.id;
689
690 if (nextObs==undefined && obs[obs.length-1].task!="SHUTDOWN")
691 throw Error("Last scheduled measurement must be a shutdown.");
692
693 // We are done with all measurement slots for this
694 // observation... wait for next observation
695 if (sub>=obs.length)
696 {
697 v8.sleep(1000);
698 continue;
699 }
700
701 if (system_on===false && obs[sub].task!="STARTUP")
702 {
703 v8.sleep(1000);
704 continue;
705 }
706
707 // Check if sun is still up... only DATA and RATESCAN must be suppressed
708 if ((obs[sub].task=="DATA" || obs[sub].task=="RATESCAN") && sun.isUp)
709 {
710 var now = new Date();
711 var remaining = (sun.set - now)/60000;
712 console.out(now.toUTCString()+" - "+obs[sub].task+": Sun above FACT-horizon: sleeping 1min, remaining %.1fmin".$(remaining));
713 v8.sleep(60000);
714 continue;
715 }
716
717 console.out("\n"+(new Date()).toUTCString()+": Current measurement: "+obs[sub]);
718
719 // FIXME: Maybe print a warning if Drive is on during day time!
720
721 // It is not ideal that we allow the drive to be on during day time, but
722 // otherwise it is difficult to allow e.g. the STARTUP at the beginning of the night
723 var power_states = sun.isUp || system_on===false ? [ "DriveOff", "SystemOn" ] : [ "SystemOn" ];
724 var drive_states = sun.isUp || system_on===false ? undefined : [ "Armed", "Tracking", "OnTrack" ];
725
726 // A scheduled task was found, lets check if all servers are
727 // still only and in reasonable states. If this is not the case,
728 // something unexpected must have happend and the script is aborted.
729 //console.out(" Checking states [general]");
730 var table =
731 [
732 [ "TNG_WEATHER" ],
733 [ "MAGIC_WEATHER" ],
734 [ "CHAT" ],
735 [ "SMART_FACT" ],
736 [ "TEMPERATURE" ],
737 [ "DATA_LOGGER", [ "NightlyFileOpen", "WaitForRun", "Logging" ] ],
738 [ "FSC_CONTROL", [ "Connected" ] ],
739 [ "MCP", [ "Idle" ] ],
740 [ "TIME_CHECK", [ "Valid" ] ],
741 [ "PWR_CONTROL", power_states/*[ "SystemOn" ]*/ ],
742// [ "AGILENT_CONTROL", [ "VoltageOn" ] ],
743 [ "BIAS_CONTROL", [ "VoltageOff", "VoltageOn", "Ramping" ] ],
744 [ "FEEDBACK", [ "CurrentControl", "CurrentCtrlIdle" ] ],
745 [ "LID_CONTROL", [ "Open", "Closed" ] ],
746 [ "DRIVE_CONTROL", drive_states/*[ "Armed", "Tracking", "OnTrack" ]*/ ],
747 [ "FTM_CONTROL", [ "Idle", "TriggerOn" ] ],
748 [ "FAD_CONTROL", [ "Connected", "WritingData" ] ],
749 [ "RATE_SCAN", [ "Connected" ] ],
750 [ "RATE_CONTROL", [ "Connected", "GlobalThresholdSet", "InProgress" ] ],
751 ];
752
753
754 if (!checkStates(table))
755 {
756 throw new Error("Something unexpected has happened. One of the servers "+
757 "is in a state in which it should not be. Please,"+
758 "try to find out what happened...");
759 }
760
761 datalogger_subscriptions.check();
762
763 // Check if obs.task is one of the one-time-tasks
764 switch (obs[sub].task)
765 {
766 case "STARTUP":
767 console.out(" STARTUP", "");
768 CloseLid();
769
770 doDrsCalibration("startup"); // will switch the voltage off
771
772 service_feedback.voltageOn();
773 service_feedback.waitForVoltageOn();
774
775 // Before we can switch to 3000 we have to make the right DRS calibration
776 console.out(" Take single p.e. run.");
777 while (!takeRun("pedestal", 5000));
778
779 // It is unclear what comes next, so we better switch off the voltage
780 service_feedback.voltageOff();
781 system_on = true;
782 break;
783
784 case "SHUTDOWN":
785 console.out(" SHUTDOWN", "");
786 Shutdown();
787 system_on = false;
788
789 // FIXME: Avoid new observations after a shutdown until
790 // the next startup (set run back to -2?)
791 console.out(" Waiting for next startup.", "");
792 sub++;
793 continue;
794
795 case "IDLE":
796 v8.sleep(1000);
797 continue;
798
799 case "DRSCALIB":
800 console.out(" DRSCALIB", "");
801 doDrsCalibration("drscalib"); // will switch the voltage off
802 break;
803
804 case "SINGLEPE":
805 console.out(" SINGLE-PE", "");
806
807 // The lid must be closes
808 CloseLid();
809
810 // Check if DRS calibration is necessary
811 var diff = getTimeSinceLastDrsCalib();
812 if (diff>30 || diff==null)
813 doDrsCalibration("singlepe"); // will turn voltage off
814
815 // The voltage must be on
816 service_feedback.voltageOn();
817 service_feedback.waitForVoltageOn();
818
819 // Before we can switch to 3000 we have to make the right DRS calibration
820 console.out(" Take single p.e. run.");
821 while (!takeRun("pedestal", 5000));
822
823 // It is unclear what comes next, so we better switch off the voltage
824 service_feedback.voltageOff();
825 break;
826
827 case "RATESCAN":
828 console.out(" RATESCAN", "");
829
830 var tm1 = new Date();
831
832 // This is a workaround to make sure that we really catch
833 // the new state and not the old one
834 dim.send("DRIVE_CONTROL/STOP");
835 dim.wait("DRIVE_CONTROL", "Armed", 5000);
836
837 // The lid must be open
838 OpenLid();
839
840 // The voltage must be switched on
841 service_feedback.voltageOn();
842
843 if (obs.source != undefined)
844 dim.send("DRIVE_CONTROL/TRACK_ON", obs[sub].source);
845 else
846 dim.send("DRIVE_CONTROL/TRACK", obs[sub].ra, obs[sub].dec);
847
848 dim.wait("DRIVE_CONTROL", "OnTrack", 150000); // 110s for turning and 30s for stabilizing
849
850 service_feedback.waitForVoltageOn();
851
852 var tm2 = new Date();
853
854 // Start rate scan
855 dim.send("RATE_SCAN/START_THRESHOLD_SCAN", 50, 1000, -10);
856
857 // Lets wait if the ratescan really starts... this might take a few
858 // seconds because RATE_SCAN configures the ftm and is waiting for
859 // it to be configured.
860 dim.wait("RATE_SCAN", "InProgress", 10000);
861 dim.wait("RATE_SCAN", "Connected", 2700000);
862
863 // this line is actually some kind of hack.
864 // after the Ratescan, no data is written to disk. I don't know why, but it happens all the time
865 // So I decided to put this line here as a kind of patchwork....
866 //dim.send("FAD_CONTROL/SET_FILE_FORMAT", 2);
867
868 console.out(" Ratescan done [%.1fs, %.1fs]".$((tm2-tm1)/1000, (new Date()-tm2)/1000));
869 break; // case "RATESCAN"
870
871 case "DATA":
872
873 // ========================== case "DATA" ============================
874 /*
875 if (Sun.horizon("FACT").isUp)
876 {
877 console.out(" SHUTDOWN","");
878 Shutdown();
879 console.out(" Exit forced due to broken schedule", "");
880 exit();
881 }
882 */
883 // Calculate remaining time for this observation in minutes
884 var remaining = nextObs==undefined ? 0 : (nextObs.start-new Date())/60000;
885
886 // ------------------------------------------------------------
887
888 console.out(" Run #"+run+" (remaining "+parseInt(remaining)+"min)");
889
890 // ----- Time since last DRS Calibration [min] ------
891 var diff = getTimeSinceLastDrsCalib();
892
893 // Changine pointing position and take calibration...
894 // ...every four runs (every ~20min)
895 // ...if at least ten minutes of observation time are left
896 // ...if this is the first run on the source
897 var point = (run%4==0 && remaining>10) || run==0;
898
899 // Take DRS Calib...
900 // ...every four runs (every ~20min)
901 // ...at last every two hours
902 // ...when DRS temperature has changed by more than 2deg (?)
903 // ...when more than 15min of observation are left
904 // ...no drs calibration was done yet
905 var drscal = (run%4==0 && (remaining>15 && diff>70)) || diff==null;
906
907 if (point)
908 {
909 // Change wobble position every four runs,
910 // start with alternating wobble positions each day
911 var wobble = (parseInt(run/4) + parseInt(new Date()/1000/3600/24-0.5))%2+1;
912
913 //console.out(" Move telescope to '"+source+"' "+offset+" "+wobble);
914 console.out(" Move telescope to '"+obs[sub].source+"' ["+wobble+"]");
915
916 //var offset = observations[obs][2];
917 //var wobble = observations[obs][3 + parseInt(run/4)%2];
918
919 //dim.send("DRIVE_CONTROL/TRACK_SOURCE", offset, wobble, source);
920
921 dim.send("DRIVE_CONTROL/TRACK_WOBBLE", wobble, obs[sub].source);
922
923 // Do we have to check if the telescope is really moving?
924 // We can cross-check the SOURCE service later
925 }
926
927 if (drscal)
928 doDrsCalibration("data"); // will turn voltage off
929
930 OpenLid();
931
932 // voltage must be switched on after the lid is open for the
933 // feedback to adapt the voltage properly to the night-sky
934 // background light level.
935 service_feedback.voltageOn();
936
937 // This is now th right time to wait for th drive to be stable
938 dim.wait("DRIVE_CONTROL", "OnTrack", 150000); // 110s for turning and 30s for stabilizing
939
940 // Now we have to be prepared for data-taking:
941 // make sure voltage is on
942 service_feedback.waitForVoltageOn();
943
944 // If pointing had changed, do calibration
945 if (point)
946 {
947 console.out(" Calibration.");
948
949 // Calibration (2% of 20')
950 while (1)
951 {
952 if (!takeRun("pedestal", 1000)) // 80 Hz -> 10s
953 continue;
954 if (!takeRun("light-pulser-ext", 1000)) // 80 Hz -> 10s
955 continue;
956 break;
957 }
958 }
959
960 console.out(" Taking data: start [5min]");
961
962 var len = 300;
963 while (len>15)
964 {
965 var time = new Date();
966 if (takeRun("data", -1, len)) // Take data (5min)
967 break;
968
969 len -= parseInt((new Date()-time)/1000);
970 }
971
972 console.out(" Taking data: done");
973 run++;
974
975 continue; // case "DATA"
976 }
977
978 if (nextObs!=undefined && sub==obs.length-1)
979 console.out(" Waiting for next observation scheduled for "+nextObs.start.toUTCString(),"");
980
981 sub++;
982}
983
984sub_drsruns.close();
985
986// ================================================================
987// Comments and ToDo goes here
988// ================================================================
989
990// error handline : http://www.sitepoint.com/exceptional-exception-handling-in-javascript/
991// classes: http://www.phpied.com/3-ways-to-define-a-javascript-class/
992//
993// Arguments: TakeFirstDrsCalib
994// To be determined: How to stop the script without foreceful interruption?
Note: See TracBrowser for help on using the repository browser.