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

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