source: trunk/FACT++/src/fscctrl.cc@ 20085

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