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

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