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

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