source: branches/fscctrl_safety_limits/src/fscctrl.cc@ 18633

Last change on this file since 18633 was 18344, checked in by dneise, 9 years ago
found the mistake, that lead to an exception without any more information. The 'names' in SetupConfiguration and EvalOPtions must of course be that same, if they are not. One gets an exception ... but not a little bit more ... really awesome.
File size: 40.8 KB
Line 
1#include <functional>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "StateMachineAsio.h"
8#include "Connection.h"
9#include "LocalControl.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13#include "externals/Interpolator2D.h"
14
15#include "tools.h"
16
17#include "HeadersFSC.h"
18
19namespace ba = boost::asio;
20namespace bs = boost::system;
21namespace dummy = ba::placeholders;
22
23using namespace std;
24using namespace FSC;
25
26// ------------------------------------------------------------------------
27
28class ConnectionFSC : public Connection
29{
30 FSC::BinaryOutput_t fMsg; // A single message
31
32 bool fIsVerbose;
33 bool fIsAutoReconnect;
34
35 size_t fNumConsecutiveErrors; // Number of consecutive messages with errors
36 size_t fNumConsecutiveMessages; // Number of consecutive message which are ok
37
38 boost::asio::deadline_timer fReconnectTimeout;
39
40protected:
41 vector<Interpolator2D::vec> fPositionsSensors;
42 vector<Interpolator2D::vec> fPositionsBias;
43
44 double fEthernetSwitchCurrentLimit;
45 double fFFCcurrentLimit;
46 double fFLPcurrentLimit;
47 double fFADdigitalCurrentLimit;
48 double fFADnegativeCurrentLimit;
49 double fFADpositiveCurrentLimit;
50 double fFPAdigitalCurrentLimit;
51 double fFPAnegativeCurrentLimit;
52 double fFPApositiveCurrentLimit;
53
54
55 bool fSecurityLimitsExceeded;
56
57 virtual void UpdateTemp(float, const vector<float> &)
58 {
59 }
60
61 virtual void UpdateHum(float, const vector<float>&)
62 {
63 }
64
65 virtual void UpdateVolt(float, const vector<float>&)
66 {
67 }
68
69 virtual void UpdateCur(float, const vector<float>&)
70 {
71 }
72
73private:
74 //
75 // From: http://de.wikipedia.org/wiki/Pt100
76 //
77 double GetTempPT1000(double R) const
78 {
79 // This is precise within the range 5degC and 25degC
80 // by 3e-3 degC. At 0degC and 30degC it overestimates the
81 // temperature by 0.025 degC. At -10degC it is ~0.9degC
82 // and at 40degC ~0.05degC.
83 const double x = R/1000;
84 return -193.804 + 96.0651*x + 134.673*x*x - 36.9091*x*x*x;
85
86 //for a reasonable range:
87 // R=970 -> -7.6 degC
88 // R=1300 -> 77.6 degC
89
90 //const double R0 = 1000; // 1kOhm
91 //const double a = 3.893e-3;
92 //return (R/R0 - 1)/a;
93 }
94
95 bool CheckChecksum()
96 {
97 const uint16_t volt_checksum = Tools::Fletcher16(fMsg.adc_values, kNumVoltageChannels);
98 const uint16_t resi_checksum = Tools::Fletcher16(fMsg.ad7719_values, kNumResistanceChannels);
99
100 const bool volt_ok = volt_checksum == fMsg.adc_values_checksum;
101 const bool resi_ok = resi_checksum == fMsg.ad7719_values_checksum;
102
103 if (volt_ok && resi_ok)
104 return true;
105
106 fNumConsecutiveErrors++;
107
108 ostringstream out;
109 out << "Checksum error (V:";
110 out << hex << setfill('0');
111
112 if (volt_ok)
113 out << "----|----";
114 else
115 {
116 out << setw(4) << volt_checksum;
117 out << "|";
118 out << setw(4) << fMsg.adc_values_checksum;
119 }
120
121 out << ", R:";
122
123 if (resi_ok)
124 out << "----|----";
125 else
126 {
127 out << setw(4) << resi_checksum;
128 out << "|";
129 out << setw(4) << fMsg.ad7719_values_checksum;
130 }
131
132 out << ", " << dec;
133 out << "Nok=" << fNumConsecutiveMessages << ", ";
134 out << "Nerr=" << fNumConsecutiveErrors << ")";
135
136 Warn(out);
137
138 fNumConsecutiveMessages = 0;
139
140 return false;
141 }
142
143 bool ProcessMessage()
144 {
145 if (fIsVerbose)
146 Out() << "Received one_message of FSC::BinaryOutput_t ... will now process it" << endl;
147
148 if (!CheckChecksum())
149 return false;
150
151 // That looks a bit odd because it copies the values twice for no reason.
152 // This is historical and keeps the following code consistent with the
153 // previous code which was reading ascii data from the fsc
154 vector<float> volt( fMsg.adc_values, fMsg.adc_values + kNumVoltageChannels);
155 vector<float> resist(fMsg.ad7719_values, fMsg.ad7719_values + kNumResistanceChannels);
156
157 const float time = fMsg.time_sec + fMsg.time_ms/1000.;
158
159 // We want to convert the pure ADC values from the FSC board to mV and kOhm respectively
160 // So we do:
161 for (unsigned int i=0; i<volt.size(); i++)
162 volt[i] /= 10;
163
164 for (unsigned int i=0; i<resist.size(); i++)
165 resist[i] *= (6.25 * 1024) / (1 << 25);
166
167 int mapv[] =
168 {
169 0, 16, 24, 8,
170 1, 17, 25, 9,
171 2, 18, 26, 10,
172 //
173 3, 19, 27, 11,
174 4, 20, 28, 12,
175 5, 21, 29, 13,
176 //
177 32, 36, 33, 34, 37, 38,
178 //
179 -1
180 };
181
182 int mapc[] =
183 {
184 40, 56, 64, 48,
185 41, 57, 65, 49,
186 42, 58, 66, 50,
187 //
188 43, 59, 67, 51,
189 44, 60, 68, 52,
190 45, 61, 69, 53,
191 //
192 72, 76, 73, 74, 77, 78,
193 //
194 -1
195 };
196
197
198 int maprh[] =
199 {
200 80, 81, 82, 83, -1
201 };
202
203 int offrh[] =
204 {
205 821, 822, 816, 822,
206 };
207
208 int mapt[] =
209 {
210 // sensor compartment temperatures
211 0, 1, 2, 3, 4, 5, 6, 56, 57, 58, 59, 60,
212 61, 62, 32, 33, 34, 35, 36, 63, 37, 38, 39, 24,
213 25, 26, 27, 28, 29, 30, 31,
214 // crate temperatures (0-3, back/front)
215 12, 13, 52, 53, 44, 46, 20, 21,
216 //crate power supply temperatures (0-3)
217 8, 9, 48, 49, 40, 41, 16, 17,
218 // aux power supplies (FTM-side top/bot, FSC-side top/bot)
219 45, 50, 19, 42,
220 // backpanel (FTM-side top/bot, FSC-side top/bot)
221 11, 51, 18, 43,
222 // switch boxes (top front/back, bottom front/back)
223 15, 14, 47, 10,
224 //
225 -1
226 };
227
228 vector<float> voltages;
229 vector<float> currents;
230 vector<float> humidities;
231 vector<float> temperatures;
232
233 for (int *pv=mapv; *pv>=0; pv++)
234 voltages.push_back(volt[*pv]*0.001);
235
236 for (int *pc=mapc; *pc>=0; pc++)
237 currents.push_back(volt[*pc]*0.005);
238
239 for (int idx=0; idx<4; idx++)
240 {
241 voltages[idx +8] *= -1;
242 voltages[idx+20] *= -1;
243 currents[idx +8] *= -1;
244 currents[idx+20] *= -1;
245 }
246 voltages[12] *= 2;
247 voltages[13] *= 2;
248 voltages[14] *= 2;
249 voltages[15] *= 2;
250
251 voltages[24] *= 2;
252 voltages[25] *= 2;
253
254 voltages[27] *= -1;
255 voltages[29] *= -1;
256
257 currents[27] *= -1;
258 currents[29] *= -1;
259
260 int idx=0;
261 for (int *ph=maprh; *ph>=0; ph++, idx++)
262 humidities.push_back((volt[*ph]-offrh[idx])*0.0313);
263
264 //1019=4.8
265 //1005=1.3
266 //970=-7.6
267 //1300=76
268 for (int *pt=mapt; *pt>=0; pt++)
269 //temperatures.push_back(resist[*pt]>800&&resist[*pt]<2000 ? GetTempPT1000(resist[*pt]) : 0);
270 temperatures.push_back(resist[*pt]>970&&resist[*pt]<1300 ? GetTempPT1000(resist[*pt]) : 0);
271 //temperatures.push_back(resist[*pt]>1019&&resist[*pt]<1300 ? GetTempPT1000(resist[*pt]) : 0);
272
273 // 0 = 3-(3+0)%4
274 // 3 = 3-(3+1)%4
275 // 2 = 3-(3+2)%4
276 // 1 = 3-(3+3)%4
277
278 /*
279 index unit offset scale crate for board:
280 0 mV 0 1 0 FAD 3.3V
281 24 mV 0 1 1 FAD 3.3V
282 16 mV 0 1 2 FAD 3.3V
283 8 mV 0 1 3 FAD 3.3V
284
285 1 mV 0 1 0 FAD 3.3V
286 25 mV 0 1 1 FAD 3.3V
287 17 mV 0 1 2 FAD 3.3V
288 9 mV 0 1 3 FAD 3.3V
289
290 2 mV 0 -1 0 FAD -2.0V
291 26 mV 0 -1 1 FAD -2.0V
292 18 mV 0 -1 2 FAD -2.0V
293 10 mV 0 -1 3 FAD -2.0V
294
295 --
296
297 3 mV 0 1 0 FPA 5.0V
298 27 mV 0 1 1 FPA 5.0V
299 19 mV 0 1 2 FPA 5.0V
300 11 mV 0 1 3 FPA 5.0V
301
302 4 mV 0 1 0 FPA 3.3V
303 28 mV 0 1 1 FPA 3.3V
304 20 mV 0 1 2 FPA 3.3V
305 12 mV 0 1 3 FPA 3.3V
306
307 5 mV 0 -1 0 FPA -3.3V
308 29 mV 0 -1 1 FPA -3.3V
309 21 mV 0 -1 2 FPA -3.3V
310 13 mV 0 -1 3 FPA -3.3V
311
312 --
313
314 32 mV 0 1 bottom ETH 5V
315 36 mV 0 1 top ETH 5V
316
317 33 mV 0 1 bottom FTM 3.3V
318 34 mV 0 -1 bottom FTM -3.3V
319
320 37 mV 0 1 top FFC 3.3V
321 38 mV 0 -1 top FLP -3.3V
322
323 -----
324
325 40 mA 0 5 0 FAD
326 64 mA 0 5 1 FAD
327 56 mA 0 5 2 FAD
328 48 mA 0 5 3 FAD
329
330 41 mA 0 5 0 FAD
331 65 mA 0 5 1 FAD
332 57 mA 0 5 2 FAD
333 49 mA 0 5 3 FAD
334
335 42 mA 0 -5 0 FAD
336 66 mA 0 -5 1 FAD
337 58 mA 0 -5 2 FAD
338 50 mA 0 -5 3 FAD
339
340 --
341
342 43 mA 0 5 0 FPA
343 67 mA 0 5 1 FPA
344 59 mA 0 5 2 FPA
345 51 mA 0 5 3 FPA
346
347 44 mA 0 5 0 FPA
348 68 mA 0 5 1 FPA
349 60 mA 0 5 2 FPA
350 52 mA 0 5 3 FPA
351
352 45 mA 0 -5 0 FPA
353 69 mA 0 -5 1 FPA
354 61 mA 0 -5 2 FPA
355 53 mA 0 -5 3 FPA
356
357 ---
358
359 72 mA 0 5 bottom ETH
360 76 mA 0 5 top ETH
361
362 73 mA 0 5 bottom FTM
363 74 mA 0 -5 bottom FTM
364
365 77 mA 0 5 top FFC
366 78 mA 0 -5 top FLP
367
368 ----
369
370 80 % RH -821 0.0313 FSP000
371 81 % RH -822 0.0313 FSP221
372 82 % RH -816 0.0313 Sector0
373 83 % RH -822 0.0313 Sector2
374 */
375
376 // TEMPERATURES
377 // 31 x Sensor plate
378 // 8 x Crate
379 // 12 x PS
380 // 4 x Backpanel
381 // 4 x Switchbox
382
383
384
385 /*
386 0 ohms FSP 000
387 1 ohms FSP 010
388 2 ohms FSP 023
389 3 ohms FSP 043
390 4 ohms FSP 072
391 5 ohms FSP 080
392 6 ohms FSP 092
393 56 ohms FSP 103
394 57 ohms FSP 111
395 58 ohms FSP 121
396 59 ohms FSP 152
397 60 ohms FSP 163
398 61 ohms FSP 171
399 62 ohms FSP 192
400 32 ohms FSP 200
401 33 ohms FSP 210
402 34 ohms FSP 223
403 35 ohms FSP 233
404 36 ohms FSP 243
405 63 ohms FSP 252
406 37 ohms FSP 280
407 38 ohms FSP 283
408 39 ohms FSP 293
409 24 ohms FSP 311
410 25 ohms FSP 321
411 26 ohms FSP 343
412 27 ohms FSP 352
413 28 ohms FSP 363
414 29 ohms FSP 371
415 30 ohms FSP 381
416 31 ohms FSP 392
417 8 ohms Crate0 ?
418 9 ohms Crate0 ?
419 48 ohms Crate1 ?
420 49 ohms Crate1 ?
421 40 ohms Crate2 ?
422 41 ohms Crate2 ?
423 16 ohms Crate3 ?
424 17 ohms Crate3 ?
425 10 ohms PS Crate 0
426 11 ohms PS Crate 0
427 50 ohms PS Crate 1
428 51 ohms PS Crate 1
429 42 ohms PS Crate 2
430 43 ohms PS Crate 2
431 18 ohms PS Crate 3
432 19 ohms PS Crate 3
433 12 ohms PS Aux0
434 52 ohms PS Aux0
435 20 ohms PS Aux1
436 44 ohms PS Aux1
437 13 ohms Backpanel ?
438 21 ohms Backpanel ?
439 45 ohms Backpanel ?
440 53 ohms Backpanel ?
441 14 ohms Switchbox0 ?
442 15 ohms Switchbox0 ?
443 46 ohms Switchbox1 ?
444 47 ohms Switchbox1 ?
445 7 ohms nc nc
446 22 ohms nc nc
447 23 ohms nc nc
448 54 ohms nc nc
449 55 ohms nc nc
450 */
451
452 CheckCurrentLimits(currents);
453 if (fIsVerbose)
454 {
455 /*
456 for (size_t i=0; i<resist.size(); i++)
457 //if (resist[i]>800 && resist[i]<2000)
458 if (resist[i]>970 && resist[i]<1300)
459 //if (resist[i]>1019 && resist[i]<1300)
460 Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << setprecision(1) << fixed << GetTempPT1000(resist[i]) << endl;
461 else
462 Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << "----" << endl;
463 */
464 PrintTemperaturesNicely(temperatures);
465 PrintVoltagesNicely(voltages, currents);
466 Out() << "\n" << "fSecurityLimitsExceeded:" << fSecurityLimitsExceeded << endl;
467 }
468
469 UpdateTemp(time, temperatures);
470 UpdateVolt(time, voltages);
471 UpdateCur( time, currents);
472 UpdateHum( time, humidities);
473
474 fNumConsecutiveErrors = 0;
475 fNumConsecutiveMessages++;
476
477
478 return true;
479 }
480
481 void PrintTemperaturesNicely(const vector<float> &t)
482 {
483 /*
484 "FSC_CONTROL/TEMPERATURE", "F:1;F:31;F:8;F:8;F:4;F:4;F:4",
485 "|t[s]:FSC uptime"
486 "|T_sens[deg C]:Sensor compartment temperatures"
487 "|T_crate[deg C]:Temperatures crate 0 (back/front), 1 (b/f), 2 (b/f), 3 (b/f)"
488 "|T_ps[deg C]:Temp power supplies crate 0 (back/front), 1, 2, 3"
489 "|T_aux[deg C]:Auxiliary power supply temperatures FTM (top/bottom), FSC (t/b)"
490 "|T_back[deg C]:FTM backpanel temperatures FTM (top/bottom), FSC (top/bottom)"
491 "|T_eth[deg C]:Ethernet switches temperatures top (front/back), bottom (f/b)"),
492 // sensor compartment temperatures
493 0, 1, 2, 3, 4, 5, 6, 56, 57, 58, 59, 60,
494 61, 62, 32, 33, 34, 35, 36, 63, 37, 38, 39, 24,
495 25, 26, 27, 28, 29, 30, 31,
496 // crate temperatures (0-3, back/front)
497 12, 13, 52, 53, 44, 46, 20, 21,
498 //crate power supply temperatures (0-3)
499 8, 9, 48, 49, 40, 41, 16, 17,
500 // aux power supplies (FTM-side top/bot, FSC-side top/bot)
501 45, 50, 19, 42,
502 // backpanel (FTM-side top/bot, FSC-side top/bot)
503 11, 51, 18, 43,
504 // switch boxes (top front/back, bottom front/back)
505 15, 14, 47, 10,
506 */
507 //Out() << "0 1 2 3 4 5 6 7 " << endl;
508 //Out() << "01234567890123456789012345678901234567890123456789012345678901234567890123456789" << endl;
509 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
510 Out() << "T_sens:";
511 for (int i=0; i<31; i++){
512 if (i%16==0){
513 Out() << "\n";
514 }
515 Out() << setw(4) << setprecision(1) << fixed << t[i] << " ";
516 }
517 Out() << endl;
518 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
519
520 Out() << "T_crate: (B:back, F:front)" << endl;
521 Out() << "0: B| F|1: B| F|2: B| F|3: B| F|" << endl;
522 for (int i=31; i<31+8; i++){
523 Out() << setw(4) << setprecision(1) << fixed << t[i] << "|";
524 }
525 Out() << endl;
526 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
527
528 Out() << "T_ps: crate power supplies (B:back, F:front)" << endl;
529 Out() << "0: B| F|1: B| F|2: B| F|3: B| F|" << endl;
530 for (int i=31+8; i<31+8+8; i++){
531 Out() << setw(4) << setprecision(1) << fixed << t[i] << "|";
532 }
533 Out() << endl;
534 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
535 Out() << "T_aux: auxiliary power supplies" << endl;
536 Out() << "FTM top| bot|FSC top| bot|" << endl;
537 for (int i=31+8+8; i<31+8+8+4; i++){
538 Out() << setw(7) << setprecision(1) << fixed << t[i] << "|";
539 }
540 Out() << endl;
541 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
542 Out() << "T_back: backpanel temperatures" << endl;
543 Out() << "FTM top| bot|FSC top| bot|" << endl;
544 for (int i=31+8+8+4; i<31+8+8+4+4; i++){
545 Out() << setw(7) << setprecision(1) << fixed << t[i] << "|";
546 }
547 Out() << endl;
548 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
549 Out() << "T_ethernet: switch boxes" << endl;
550 Out() << "top front| back|bot front| back|" << endl;
551 for (int i=31+8+8+4; i<31+8+8+4+4; i++){
552 Out() << setw(9) << setprecision(1) << fixed << t[i] << "|";
553 }
554 Out() << endl;
555 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
556 }
557
558 void PrintVoltagesNicely(const vector<float> &v, const vector<float> &c)
559 {
560 /*
561
562 F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
563
564 "|FAD_Ud[V]:FAD digital (crate 0-3)"
565 "|FAD_Up[V]:FAD positive (crate 0-3)"
566 "|FAD_Un[V]:FAD negative (crate 0-3)"
567 "|FPA_Ud[V]:FPA digital (crate 0-3)"
568 "|FPA_Up[V]:FPA positive (crate 0-3)"
569 "|FPA_Un[V]:FPA negative (crate 0-3)"
570
571 "|ETH_U[V]:Ethernet switch (pos/neg)"
572 "|FTM_U[V]:FTM - trigger master (pos/neg)"
573 "|FFC_U[V]:FFC"
574 "|FLP_U[V]:FLP - light pulser"),
575 */
576 const char* const voltage_names[] = {
577 "FAD_d | ",
578 "FAD_p | ",
579 "FAD_n | ",
580 "FPA_d | ",
581 "FPA_p | ",
582 "FPA_n | ",
583 "Etherne| ",
584 "FTM | ",
585 "FFC | ",
586 "FLP | ",
587 };
588 const int length_per_group[] = {
589 4, 4, 4, 4, 4, 4, 2, 2, 1, 1,
590 };
591
592 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
593
594 Out() << " | Voltages | Currents" << endl;
595 Out() << "-------| 0 | 1 | 2 | 3 | | 0 | 1 | 2 | 3 |" << endl;
596
597 int pos=0;
598 for (int i=0; i<10; i++)
599 {
600 Out() << voltage_names[i];
601 for (int j=0; j<length_per_group[i]; j++)
602 {
603 Out() << setw(6) << setprecision(2) << fixed << v[pos++] << "| ";
604 }
605 pos -= length_per_group[i];
606 for (int j=0; j<4-length_per_group[i]; j++)
607 {
608 Out() << " ";
609 }
610 Out() << "|";
611 for (int j=0; j<length_per_group[i]; j++)
612 {
613 Out() << setw(6) << setprecision(2) << fixed << c[pos++] << "| ";
614 }
615 Out() << endl;
616 }
617
618 Out() << ". - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -." << endl;
619 }
620
621 bool CheckCurrentLimits(const vector<float> &currents)
622 {
623 /*
624 F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
625 "|FAD_Id[A]:FAD digital (crate 0-3)"
626 "|FAD_Ip[A]:FAD positive (crate 0-3)"
627 "|FAD_In[A]:FAD negative (crate 0-3)"
628 "|FPA_Id[A]:FPA digital (crate 0-3)"
629 "|FPA_Ip[A]:FPA positive (crate 0-3)"
630 "|FPA_In[A]:FPA negative (crate 0-3)"
631 "|ETH_I[A]:Ethernet switch (pos/neg)"
632 "|FTM_I[A]:FTM - trigger master (pos/neg)"
633 "|FFC_I[A]:FFC"
634 "|FLP_I[A]:FLP - light pulser")
635 */
636 fSecurityLimitsExceeded = false;
637
638 const double current_limits[] = {
639 fFADdigitalCurrentLimit,
640 fFADnegativeCurrentLimit,
641 fFADpositiveCurrentLimit,
642 fFPAdigitalCurrentLimit,
643 fFPAnegativeCurrentLimit,
644 fFPApositiveCurrentLimit,
645 fEthernetSwitchCurrentLimit,
646 INFINITY,
647 fFFCcurrentLimit,
648 fFLPcurrentLimit,
649 };
650
651 const int channels_per_group[] = {
652 4, 4, 4, 4, 4, 4, 2, 2, 1, 1,
653 };
654
655 const int groups = 10;
656
657 const char* const group_names[] = {
658 "FAD_digital",
659 "FAD_positive",
660 "FAD_negative",
661 "FPA_digital",
662 "FPA_positive",
663 "FPA_negative",
664 "ethernet_switch",
665 "",
666 "FFC",
667 "FLP",
668 };
669
670 const char* const channel_names[][4] = {
671 {"crate 0", "crate 1", "crate 2", "crate 3"},
672 {"crate 0", "crate 1", "crate 2", "crate 3"},
673 {"crate 0", "crate 1", "crate 2", "crate 3"},
674 {"crate 0", "crate 1", "crate 2", "crate 3"},
675 {"crate 0", "crate 1", "crate 2", "crate 3"},
676 {"crate 0", "crate 1", "crate 2", "crate 3"},
677 {"FTM side", "FSC side"},
678 {""},
679 {"-"},
680 {"-"},
681 };
682
683
684 int offset=0;
685 for (int g=0; g<groups; g++){
686 for (int c=0; c<channels_per_group[g]; c++)
687 {
688 int id = offset+c;
689 if (abs(currents[id]) > abs(current_limits[g])){
690 Out() << "current limit exeeded!! ";
691 Out() << "group: "<< group_names[g];
692 Out() << " channel: "<< channel_names[g][c];
693 Out() << " value: "<< currents[id];
694 Out() << " limit: "<< current_limits[g];
695 Out() << endl;
696 fSecurityLimitsExceeded = true;
697 }
698
699 }
700 offset += channels_per_group[g];
701 }
702 return fSecurityLimitsExceeded;
703 }
704
705 void StartRead()
706 {
707 ba::async_read(*this, ba::buffer(&fMsg, sizeof(FSC::BinaryOutput_t)),
708 boost::bind(&ConnectionFSC::HandleRead, this,
709 dummy::error, dummy::bytes_transferred));
710
711 AsyncWait(fInTimeout, 35000, &Connection::HandleReadTimeout); // 30s
712 }
713
714 void HandleRead(const boost::system::error_code& err, size_t bytes_received)
715 {
716 // Do not schedule a new read if the connection failed.
717 if (bytes_received==0 || err)
718 {
719 if (err==ba::error::eof)
720 return;
721
722 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
723 // 125: Operation canceled
724 if (err && err!=ba::error::eof && // Connection closed by remote host
725 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
726 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
727 {
728 ostringstream str;
729 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
730 Error(str);
731 }
732 PostClose(err!=ba::error::basic_errors::operation_aborted);
733 return;
734 }
735
736 if (!ProcessMessage())
737 {
738 fIsAutoReconnect = true;
739 fReconnectTimeout.expires_from_now(boost::posix_time::seconds(10));
740 fReconnectTimeout.async_wait(boost::bind(&ConnectionFSC::HandleReconnectTimeout,
741 this, dummy::error));
742 PostClose(true);
743 return;
744 }
745
746 StartRead();
747 }
748
749 void ConnectionEstablished()
750 {
751 fNumConsecutiveErrors = 0;
752 fNumConsecutiveMessages = 0;
753 fIsAutoReconnect = false;
754
755 StartRead();
756 }
757
758 void HandleReconnectTimeout(const bs::error_code &)
759 {
760 fIsAutoReconnect = false;
761 }
762
763 void HandleReadTimeout(const bs::error_code &error)
764 {
765 if (error==ba::error::basic_errors::operation_aborted)
766 return;
767
768 if (error)
769 {
770 ostringstream str;
771 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
772 Error(str);
773
774 PostClose();
775 return;
776
777 }
778
779 if (!is_open())
780 {
781 // For example: Here we could schedule a new accept if we
782 // would not want to allow two connections at the same time.
783 return;
784 }
785
786 // Check whether the deadline has passed. We compare the deadline
787 // against the current time since a new asynchronous operation
788 // may have moved the deadline before this actor had a chance
789 // to run.
790 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
791 return;
792
793 Error("Timeout reading data from "+URL());
794
795 PostClose();
796 }
797
798public:
799 ConnectionFSC(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
800 fIsVerbose(false), fIsAutoReconnect(false), fReconnectTimeout(ioservice)
801 {
802 SetLogStream(&imp);
803 }
804
805 void SetVerbose(bool b)
806 {
807 fIsVerbose = b;
808 }
809
810 void SetPositionsSensors(const vector<Interpolator2D::vec> &vec)
811 {
812 fPositionsSensors = vec;
813 }
814
815 void SetEthernetSwitchCurrentLimit(double lim)
816 {
817 fEthernetSwitchCurrentLimit = lim;
818 }
819
820 void SetFFCcurrentLimit(double lim)
821 {
822 fFFCcurrentLimit = lim;
823 }
824
825 void SetFLPcurrentLimit(double lim)
826 {
827 fFLPcurrentLimit = lim;
828 }
829
830 void SetFADdigitalCurrentLimit(double lim)
831 {
832 fFADdigitalCurrentLimit = lim;
833 }
834
835 void SetFADnegativeCurrentLimit(double lim)
836 {
837 fFADnegativeCurrentLimit = lim;
838 }
839
840 void SetFADpositiveCurrentLimit(double lim)
841 {
842 fFADpositiveCurrentLimit = lim;
843 }
844
845 void SetFPAdigitalCurrentLimit(double lim)
846 {
847 fFPAdigitalCurrentLimit = lim;
848 }
849
850 void SetFPAnegativeCurrentLimit(double lim)
851 {
852 fFPAnegativeCurrentLimit = lim;
853 }
854
855 void SetFPApositiveCurrentLimit(double lim)
856 {
857 fFPApositiveCurrentLimit = lim;
858 }
859
860 void SetPositionsBias(const vector<Interpolator2D::vec> &vec)
861 {
862 fPositionsBias = vec;
863 }
864
865 bool IsSecurityLimitExceeded() const
866 {
867 return fSecurityLimitsExceeded;
868 }
869
870 bool IsOpen() const
871 {
872 return IsConnected() || fIsAutoReconnect;
873 }
874};
875
876// ------------------------------------------------------------------------
877
878#include "DimDescriptionService.h"
879
880class ConnectionDimFSC : public ConnectionFSC
881{
882private:
883
884 vector<double> fLastRms;
885
886 DimDescribedService fDimTemp;
887 DimDescribedService fDimTemp2;
888 DimDescribedService fDimHum;
889 DimDescribedService fDimVolt;
890 DimDescribedService fDimCurrent;
891
892 void Update(DimDescribedService &svc, vector<float> data, float time) const
893 {
894 data.insert(data.begin(), time);
895 svc.Update(data);
896 }
897
898 void UpdateTemp(float time, const vector<float> &temp)
899 {
900 Update(fDimTemp, temp, time);
901
902 vector<double> T;
903 vector<Interpolator2D::vec> xy;
904
905 T.reserve(31);
906 xy.reserve(31);
907
908 double avg = 0;
909 double rms = 0;
910
911 // Create a list of all valid sensors
912 for (int i=0; i<31; i++)
913 if (temp[i]!=0)
914 {
915 T.emplace_back(temp[i]);
916 xy.emplace_back(fPositionsSensors[i]);
917
918 avg += temp[i];
919 rms += temp[i]*temp[i];
920 }
921
922 if (T.size()==0)
923 {
924 Warn("No valid sensor temperatures.");
925 return;
926 }
927
928 avg /= T.size();
929 rms /= T.size();
930 rms -= avg*avg;
931 rms = rms<0 ? 0 : sqrt(rms);
932
933 // Clean broken reports
934 const double cut_val = 0.015;
935 const bool reject = rms>4 || (fabs(fLastRms[0]-fLastRms[1])<=cut_val && fabs(rms-fLastRms[0])>cut_val);
936
937 fLastRms[1] = fLastRms[0];
938 fLastRms[0] = rms;
939
940 if (reject)
941 {
942 Warn("Suspicious temperature values rejecte for BIAS_TEMP.");
943 return;
944 }
945
946 // Create interpolator for the corresponding sensor positions
947 Interpolator2D inter(xy);
948
949 // Calculate weights for the output positions
950 if (!inter.SetOutputGrid(fPositionsBias))
951 {
952 Warn("Temperature values rejecte for BIAS_TEMP (calculation of weights failed).");
953 return;
954 }
955
956 // Interpolate the data
957 T = inter.Interpolate(T);
958
959 avg = 0;
960 rms = 0;
961 for (int i=0; i<320; i++)
962 {
963 avg += T[i];
964 rms += T[i]*T[i];
965 }
966
967 avg /= 320;
968 rms /= 320;
969 rms -= avg*avg;
970 rms = rms<0 ? 0 : sqrt(rms);
971
972 vector<float> out;
973 out.reserve(322);
974 out.assign(T.cbegin(), T.cend());
975 out.emplace_back(avg);
976 out.emplace_back(rms);
977
978 // Update the Dim service with the interpolated positions
979 Update(fDimTemp2, out, time);
980 }
981
982 void UpdateHum(float time, const vector<float> &hum)
983 {
984 Update(fDimHum, hum, time);
985 }
986
987 void UpdateVolt(float time, const vector<float> &volt)
988 {
989 Update(fDimVolt, volt, time);
990 }
991
992 void UpdateCur(float time, const vector<float> &curr)
993 {
994 Update(fDimCurrent, curr, time);
995 }
996
997public:
998 ConnectionDimFSC(ba::io_service& ioservice, MessageImp &imp) :
999 ConnectionFSC(ioservice, imp), fLastRms(2),
1000 fDimTemp ("FSC_CONTROL/TEMPERATURE", "F:1;F:31;F:8;F:8;F:4;F:4;F:4",
1001 "|t[s]:FSC uptime"
1002 "|T_sens[deg C]:Sensor compartment temperatures"
1003 "|T_crate[deg C]:Temperatures crate 0 (back/front), 1 (b/f), 2 (b/f), 3 (b/f)"
1004 "|T_ps[deg C]:Temp power supplies crate 0 (back/front), 1, 2, 3"
1005 "|T_aux[deg C]:Auxiliary power supply temperatures FTM (top/bottom), FSC (t/b)"
1006 "|T_back[deg C]:FTM backpanel temperatures FTM (top/bottom), FSC (top/bottom)"
1007 "|T_eth[deg C]:Ethernet switches temperatures top (front/back), bottom (f/b)"),
1008 fDimTemp2 ("FSC_CONTROL/BIAS_TEMP", "F:1;F:320;F:1;F:1",
1009 "|t[s]:FSC uptime"
1010 "|T[deg C]:Interpolated temperatures at bias patch positions"
1011 "|T_avg[deg C]:Average temperature calculated from all patches"
1012 "|T_rms[deg C]:Temperature RMS calculated from all patches"),
1013 fDimHum ("FSC_CONTROL/HUMIDITY", "F:1;F:4",
1014 "|t[s]:FSC uptime"
1015 "|H[%]:Humidity sensors readout"),
1016 fDimVolt ("FSC_CONTROL/VOLTAGE",
1017 "F:1;F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
1018 "|t[s]:FSC uptime"
1019 "|FAD_Ud[V]:FAD digital (crate 0-3)"
1020 "|FAD_Up[V]:FAD positive (crate 0-3)"
1021 "|FAD_Un[V]:FAD negative (crate 0-3)"
1022 "|FPA_Ud[V]:FPA digital (crate 0-3)"
1023 "|FPA_Up[V]:FPA positive (crate 0-3)"
1024 "|FPA_Un[V]:FPA negative (crate 0-3)"
1025 "|ETH_U[V]:Ethernet switch (pos/neg)"
1026 "|FTM_U[V]:FTM - trigger master (pos/neg)"
1027 "|FFC_U[V]:FFC"
1028 "|FLP_U[V]:FLP - light pulser"),
1029 fDimCurrent("FSC_CONTROL/CURRENT", "F:1;F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
1030 "|t[s]:FSC uptime"
1031 "|FAD_Id[A]:FAD digital (crate 0-3)"
1032 "|FAD_Ip[A]:FAD positive (crate 0-3)"
1033 "|FAD_In[A]:FAD negative (crate 0-3)"
1034 "|FPA_Id[A]:FPA digital (crate 0-3)"
1035 "|FPA_Ip[A]:FPA positive (crate 0-3)"
1036 "|FPA_In[A]:FPA negative (crate 0-3)"
1037 "|ETH_I[A]:Ethernet switch (pos/neg)"
1038 "|FTM_I[A]:FTM - trigger master (pos/neg)"
1039 "|FFC_I[A]:FFC"
1040 "|FLP_I[A]:FLP - light pulser")
1041 {
1042 fLastRms[0] = 1.5;
1043 }
1044
1045 // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z
1046};
1047
1048// ------------------------------------------------------------------------
1049
1050template <class T, class S>
1051class StateMachineFSC : public StateMachineAsio<T>
1052{
1053private:
1054 S fFSC;
1055
1056 int Disconnect()
1057 {
1058 // Close all connections
1059 fFSC.PostClose(false);
1060
1061 return T::GetCurrentState();
1062 }
1063
1064 int Reconnect(const EventImp &evt)
1065 {
1066 // Close all connections to supress the warning in SetEndpoint
1067 fFSC.PostClose(false);
1068
1069 // Now wait until all connection have been closed and
1070 // all pending handlers have been processed
1071 ba::io_service::poll();
1072
1073 if (evt.GetBool())
1074 fFSC.SetEndpoint(evt.GetString());
1075
1076 // Now we can reopen the connection
1077 fFSC.PostClose(true);
1078
1079 return T::GetCurrentState();
1080 }
1081
1082 int Execute()
1083 {
1084 if (fFSC.IsSecurityLimitExceeded())
1085 {
1086 return State::kOverCurrent;
1087 }
1088 else if(fFSC.IsOpen())
1089 {
1090 return State::kConnected;
1091 }
1092 else
1093 {
1094 return State::kDisconnected;
1095 }
1096
1097 //return fFSC.IsOpen() ? State::kConnected : State::kDisconnected;
1098 }
1099
1100 bool CheckEventSize(size_t has, const char *name, size_t size)
1101 {
1102 if (has==size)
1103 return true;
1104
1105 ostringstream msg;
1106 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1107 T::Fatal(msg);
1108 return false;
1109 }
1110
1111 int SetVerbosity(const EventImp &evt)
1112 {
1113 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1114 return T::kSM_FatalError;
1115
1116 fFSC.SetVerbose(evt.GetBool());
1117
1118 return T::GetCurrentState();
1119 }
1120
1121public:
1122 StateMachineFSC(ostream &out=cout) :
1123 StateMachineAsio<T>(out, "FSC_CONTROL"), fFSC(*this, *this)
1124 {
1125 // State names
1126 T::AddStateName(State::kDisconnected, "Disconnected",
1127 "FSC board not connected via ethernet.");
1128
1129 T::AddStateName(State::kConnected, "Connected",
1130 "Ethernet connection to FSC established.");
1131
1132 T::AddStateName(State::kHighCurrent, "HighPowerConsumption",
1133 "FSC board measures high power consumption, c.f. FSC current limits in config-file or config-DB.");
1134
1135 T::AddStateName(State::kOverCurrent, "OverCurrent",
1136 "FSC board measures *too* power consumption, c.f. FSC current limits in config-file or config-DB.");
1137
1138 // Verbosity commands
1139 T::AddEvent("SET_VERBOSE", "B:1")
1140 (bind(&StateMachineFSC::SetVerbosity, this, placeholders::_1))
1141 ("set verbosity state"
1142 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1143
1144 // Conenction commands
1145 T::AddEvent("DISCONNECT", State::kConnected)
1146 (bind(&StateMachineFSC::Disconnect, this))
1147 ("disconnect from ethernet");
1148
1149 T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected)
1150 (bind(&StateMachineFSC::Reconnect, this, placeholders::_1))
1151 ("(Re)connect ethernet connection to FSC, a new address can be given"
1152 "|[host][string]:new ethernet address in the form <host:port>");
1153
1154 fFSC.StartConnect();
1155 }
1156
1157 void SetEndpoint(const string &url)
1158 {
1159 fFSC.SetEndpoint(url);
1160 }
1161
1162 int EvalOptions(Configuration &conf)
1163 {
1164 fFSC.SetVerbose(!conf.Get<bool>("quiet"));
1165
1166 const string fname1 = conf.Get<string>("sensor-pos-file");
1167 const auto v1 = Interpolator2D::ReadGrid(fname1);
1168 if (v1.size() != 31)
1169 {
1170 T::Error("Reading sensor positions from "+fname1+"failed ("+to_string(v1.size())+")");
1171 return 1;
1172 }
1173
1174 const string fname2 = conf.Get<string>("patch-pos-file");
1175 const auto v2 = Interpolator2D::ReadGrid(fname2);
1176 if (v2.size() != 320)
1177 {
1178 T::Error("Reading bias patch positions from "+fname2+"failed ("+to_string(v2.size())+")");
1179 return 1;
1180 }
1181
1182 fFSC.SetPositionsSensors(v1);
1183 fFSC.SetPositionsBias(v2);
1184
1185 fFSC.SetEthernetSwitchCurrentLimit( conf.Get<double>("max-current.ethernet-switch") );
1186 fFSC.SetFFCcurrentLimit( conf.Get<double>("max-current.FFC") );
1187 fFSC.SetFLPcurrentLimit( conf.Get<double>("max-current.FLP") );
1188 fFSC.SetFADdigitalCurrentLimit( conf.Get<double>("max-current.FAD-digital") );
1189 fFSC.SetFADnegativeCurrentLimit( conf.Get<double>("max-current.FAD-negative") );
1190 fFSC.SetFADpositiveCurrentLimit( conf.Get<double>("max-current.FAD-positive") );
1191 fFSC.SetFPAdigitalCurrentLimit( conf.Get<double>("max-current.FPA-digital") );
1192 fFSC.SetFPAnegativeCurrentLimit( conf.Get<double>("max-current.FPA-negative") );
1193 fFSC.SetFPApositiveCurrentLimit( conf.Get<double>("max-current.FPA-positive") );
1194
1195 SetEndpoint(conf.Get<string>("addr"));
1196
1197 return -1;
1198 }
1199};
1200
1201// ------------------------------------------------------------------------
1202
1203#include "Main.h"
1204
1205template<class T, class S, class R>
1206int RunShell(Configuration &conf)
1207{
1208 return Main::execute<T, StateMachineFSC<S, R>>(conf);
1209}
1210
1211void SetupConfiguration(Configuration &conf)
1212{
1213 po::options_description control("FTM control options");
1214 control.add_options()
1215 ("no-dim", po_bool(), "Disable dim services")
1216 ("addr,a", var<string>("localhost:5000"), "Network address of FSC")
1217 ("sensor-pos-file", var<string>()->required(), "File with the positions of the 31 temperature sensors")
1218 ("patch-pos-file", var<string>()->required(), "File with the positions of the 320 bias patches")
1219 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1220 ;
1221
1222 po::options_description current_limits("Security current limits");
1223 current_limits.add_options()
1224 ("max-current.ethernet-switch", var<double>(INFINITY), "Maximum current for the Ethernet Switch [A]")
1225 ("max-current.FFC", var<double>(INFINITY), "Maximum current for the FFC [A]")
1226 ("max-current.FLP", var<double>(INFINITY), "Maximum current for the FLP [A]")
1227 ("max-current.FAD-digital", var<double>(INFINITY), "Maximum current for the FAD digital [A]")
1228 ("max-current.FAD-negative", var<double>(INFINITY), "Maximum current for the FAD negative [A]")
1229 ("max-current.FAD-positive", var<double>(INFINITY), "Maximum current for the FAD positive [A]")
1230 ("max-current.FPA-digital", var<double>(INFINITY), "Maximum current for the FPA digital [A]")
1231 ("max-current.FPA-negative", var<double>(INFINITY), "Maximum current for the FPA negative [A]")
1232 ("max-current.FPA-positive", var<double>(INFINITY), "Maximum current for the FPA positive [A]")
1233 ;
1234
1235 conf.AddOptions(control);
1236 conf.AddOptions(current_limits);
1237}
1238
1239/*
1240 Extract usage clause(s) [if any] for SYNOPSIS.
1241 Translators: "Usage" and "or" here are patterns (regular expressions) which
1242 are used to match the usage synopsis in program output. An example from cp
1243 (GNU coreutils) which contains both strings:
1244 Usage: cp [OPTION]... [-T] SOURCE DEST
1245 or: cp [OPTION]... SOURCE... DIRECTORY
1246 or: cp [OPTION]... -t DIRECTORY SOURCE...
1247 */
1248void PrintUsage()
1249{
1250 cout <<
1251 "The fscctrl controls the FSC (FACT Slow Control) board.\n"
1252 "\n"
1253 "The default is that the program is started without user intercation. "
1254 "All actions are supposed to arrive as DimCommands. Using the -c "
1255 "option, a local shell can be initialized. With h or help a short "
1256 "help message about the usuage can be brought to the screen.\n"
1257 "\n"
1258 "Usage: fscctrl [-c type] [OPTIONS]\n"
1259 " or: fscctrl [OPTIONS]\n";
1260 cout << endl;
1261}
1262
1263void PrintHelp()
1264{
1265 Main::PrintHelp<StateMachineFSC<StateMachine, ConnectionFSC>>();
1266
1267 /* Additional help text which is printed after the configuration
1268 options goes here */
1269
1270 /*
1271 cout << "bla bla bla" << endl << endl;
1272 cout << endl;
1273 cout << "Environment:" << endl;
1274 cout << "environment" << endl;
1275 cout << endl;
1276 cout << "Examples:" << endl;
1277 cout << "test exam" << endl;
1278 cout << endl;
1279 cout << "Files:" << endl;
1280 cout << "files" << endl;
1281 cout << endl;
1282 */
1283}
1284
1285int main(int argc, const char* argv[])
1286{
1287 Configuration conf(argv[0]);
1288 conf.SetPrintUsage(PrintUsage);
1289 Main::SetupConfiguration(conf);
1290 SetupConfiguration(conf);
1291
1292 if (!conf.DoParse(argc, argv, PrintHelp))
1293 return 127;
1294
1295 //try
1296 {
1297 // No console access at all
1298 if (!conf.Has("console"))
1299 {
1300 if (conf.Get<bool>("no-dim"))
1301 return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
1302 else
1303 return RunShell<LocalStream, StateMachineDim, ConnectionDimFSC>(conf);
1304 }
1305 // Cosole access w/ and w/o Dim
1306 if (conf.Get<bool>("no-dim"))
1307 {
1308 if (conf.Get<int>("console")==0)
1309 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
1310 else
1311 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
1312 }
1313 else
1314 {
1315 if (conf.Get<int>("console")==0)
1316 return RunShell<LocalShell, StateMachineDim, ConnectionDimFSC>(conf);
1317 else
1318 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFSC>(conf);
1319 }
1320 }
1321 /*catch (std::exception& e)
1322 {
1323 cerr << "Exception: " << e.what() << endl;
1324 return -1;
1325 }*/
1326
1327 return 0;
1328}
Note: See TracBrowser for help on using the repository browser.