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

Last change on this file since 18795 was 18612, checked in by tbretz, 8 years ago
God knows why the constructur fails to work with gcc 5, I don't...
File size: 27.9 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 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 PostClose(err!=ba::error::basic_errors::operation_aborted);
489 return;
490 }
491
492 if (!ProcessMessage())
493 {
494 fIsAutoReconnect = true;
495 fReconnectTimeout.expires_from_now(boost::posix_time::seconds(10));
496 fReconnectTimeout.async_wait(boost::bind(&ConnectionFSC::HandleReconnectTimeout,
497 this, dummy::error));
498 PostClose(true);
499 return;
500 }
501
502 StartRead();
503 }
504
505 void ConnectionEstablished()
506 {
507 fNumConsecutiveErrors = 0;
508 fNumConsecutiveMessages = 0;
509 fIsAutoReconnect = false;
510
511 StartRead();
512 }
513
514 void HandleReconnectTimeout(const bs::error_code &)
515 {
516 fIsAutoReconnect = false;
517 }
518
519 void HandleReadTimeout(const bs::error_code &error)
520 {
521 if (error==ba::error::basic_errors::operation_aborted)
522 return;
523
524 if (error)
525 {
526 ostringstream str;
527 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
528 Error(str);
529
530 PostClose();
531 return;
532
533 }
534
535 if (!is_open())
536 {
537 // For example: Here we could schedule a new accept if we
538 // would not want to allow two connections at the same time.
539 return;
540 }
541
542 // Check whether the deadline has passed. We compare the deadline
543 // against the current time since a new asynchronous operation
544 // may have moved the deadline before this actor had a chance
545 // to run.
546 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
547 return;
548
549 Error("Timeout reading data from "+URL());
550
551 PostClose();
552 }
553
554public:
555 ConnectionFSC(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
556 fIsVerbose(false), fIsAutoReconnect(false), fReconnectTimeout(ioservice)
557 {
558 SetLogStream(&imp);
559 }
560
561 void SetVerbose(bool b)
562 {
563 fIsVerbose = b;
564 }
565
566 void SetPositionsSensors(const vector<Interpolator2D::vec> &vec)
567 {
568 fPositionsSensors = vec;
569 }
570
571 void SetPositionsBias(const vector<Interpolator2D::vec> &vec)
572 {
573 fPositionsBias = vec;
574 }
575
576 bool IsOpen() const
577 {
578 return IsConnected() || fIsAutoReconnect;
579 }
580};
581
582// ------------------------------------------------------------------------
583
584#include "DimDescriptionService.h"
585
586class ConnectionDimFSC : public ConnectionFSC
587{
588private:
589
590 vector<double> fLastRms;
591
592 DimDescribedService fDimTemp;
593 DimDescribedService fDimTemp2;
594 DimDescribedService fDimHum;
595 DimDescribedService fDimVolt;
596 DimDescribedService fDimCurrent;
597
598 void Update(DimDescribedService &svc, vector<float> data, float time) const
599 {
600 data.insert(data.begin(), time);
601 svc.Update(data);
602 }
603
604 void UpdateTemp(float time, const vector<float> &temp)
605 {
606 Update(fDimTemp, temp, time);
607
608 vector<double> T;
609 vector<Interpolator2D::vec> xy;
610
611 T.reserve(31);
612 xy.reserve(31);
613
614 double avg = 0;
615 double rms = 0;
616
617 // Create a list of all valid sensors
618 for (int i=0; i<31; i++)
619 if (temp[i]!=0)
620 {
621 T.emplace_back(temp[i]);
622 xy.emplace_back(fPositionsSensors[i]);
623
624 avg += temp[i];
625 rms += temp[i]*temp[i];
626 }
627
628 if (T.size()==0)
629 {
630 Warn("No valid sensor temperatures.");
631 return;
632 }
633
634 avg /= T.size();
635 rms /= T.size();
636 rms -= avg*avg;
637 rms = rms<0 ? 0 : sqrt(rms);
638
639 // Clean broken reports
640 const double cut_val = 0.015;
641 const bool reject = rms>4 || (fabs(fLastRms[0]-fLastRms[1])<=cut_val && fabs(rms-fLastRms[0])>cut_val);
642
643 fLastRms[1] = fLastRms[0];
644 fLastRms[0] = rms;
645
646 if (reject)
647 {
648 Warn("Suspicious temperature values rejecte for BIAS_TEMP.");
649 return;
650 }
651
652 // Create interpolator for the corresponding sensor positions
653 Interpolator2D inter(xy);
654
655 // Calculate weights for the output positions
656 if (!inter.SetOutputGrid(fPositionsBias))
657 {
658 Warn("Temperature values rejecte for BIAS_TEMP (calculation of weights failed).");
659 return;
660 }
661
662 // Interpolate the data
663 T = inter.Interpolate(T);
664
665 avg = 0;
666 rms = 0;
667 for (int i=0; i<320; i++)
668 {
669 avg += T[i];
670 rms += T[i]*T[i];
671 }
672
673 avg /= 320;
674 rms /= 320;
675 rms -= avg*avg;
676 rms = rms<0 ? 0 : sqrt(rms);
677
678 vector<float> out;
679 out.reserve(322);
680 out.assign(T.cbegin(), T.cend());
681 out.emplace_back(avg);
682 out.emplace_back(rms);
683
684 // Update the Dim service with the interpolated positions
685 Update(fDimTemp2, out, time);
686 }
687
688 void UpdateHum(float time, const vector<float> &hum)
689 {
690 Update(fDimHum, hum, time);
691 }
692
693 void UpdateVolt(float time, const vector<float> &volt)
694 {
695 Update(fDimVolt, volt, time);
696 }
697
698 void UpdateCur(float time, const vector<float> &curr)
699 {
700 Update(fDimCurrent, curr, time);
701 }
702
703public:
704 ConnectionDimFSC(ba::io_service& ioservice, MessageImp &imp) :
705 ConnectionFSC(ioservice, imp), fLastRms(2),
706 fDimTemp ("FSC_CONTROL/TEMPERATURE", "F:1;F:31;F:8;F:8;F:4;F:4;F:4",
707 "|t[s]:FSC uptime"
708 "|T_sens[deg C]:Sensor compartment temperatures"
709 "|T_crate[deg C]:Temperatures crate 0 (back/front), 1 (b/f), 2 (b/f), 3 (b/f)"
710 "|T_ps[deg C]:Temp power supplies crate 0 (back/front), 1, 2, 3"
711 "|T_aux[deg C]:Auxiliary power supply temperatures FTM (top/bottom), FSC (t/b)"
712 "|T_back[deg C]:FTM backpanel temperatures FTM (top/bottom), FSC (top/bottom)"
713 "|T_eth[deg C]:Ethernet switches temperatures top (front/back), bottom (f/b)"),
714 fDimTemp2 ("FSC_CONTROL/BIAS_TEMP", "F:1;F:320;F:1;F:1",
715 "|t[s]:FSC uptime"
716 "|T[deg C]:Interpolated temperatures at bias patch positions"
717 "|T_avg[deg C]:Average temperature calculated from all patches"
718 "|T_rms[deg C]:Temperature RMS calculated from all patches"),
719 fDimHum ("FSC_CONTROL/HUMIDITY", "F:1;F:4",
720 "|t[s]:FSC uptime"
721 "|H[%]:Humidity sensors readout"),
722 fDimVolt ("FSC_CONTROL/VOLTAGE",
723 "F:1;F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
724 "|t[s]:FSC uptime"
725 "|FAD_Ud[V]:FAD digital (crate 0-3)"
726 "|FAD_Up[V]:FAD positive (crate 0-3)"
727 "|FAD_Un[V]:FAD negative (crate 0-3)"
728 "|FPA_Ud[V]:FPA digital (crate 0-3)"
729 "|FPA_Up[V]:FPA positive (crate 0-3)"
730 "|FPA_Un[V]:FPA negative (crate 0-3)"
731 "|ETH_U[V]:Ethernet switch (pos/neg)"
732 "|FTM_U[V]:FTM - trigger master (pos/neg)"
733 "|FFC_U[V]:FFC"
734 "|FLP_U[V]:FLP - light pulser"),
735 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",
736 "|t[s]:FSC uptime"
737 "|FAD_Id[A]:FAD digital (crate 0-3)"
738 "|FAD_Ip[A]:FAD positive (crate 0-3)"
739 "|FAD_In[A]:FAD negative (crate 0-3)"
740 "|FPA_Id[A]:FPA digital (crate 0-3)"
741 "|FPA_Ip[A]:FPA positive (crate 0-3)"
742 "|FPA_In[A]:FPA negative (crate 0-3)"
743 "|ETH_I[A]:Ethernet switch (pos/neg)"
744 "|FTM_I[A]:FTM - trigger master (pos/neg)"
745 "|FFC_I[A]:FFC"
746 "|FLP_I[A]:FLP - light pulser")
747 {
748 fLastRms[0] = 1.5;
749 }
750
751 // 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
752};
753
754// ------------------------------------------------------------------------
755
756template <class T, class S>
757class StateMachineFSC : public StateMachineAsio<T>
758{
759private:
760 S fFSC;
761
762 int Disconnect()
763 {
764 // Close all connections
765 fFSC.PostClose(false);
766
767 return T::GetCurrentState();
768 }
769
770 int Reconnect(const EventImp &evt)
771 {
772 // Close all connections to supress the warning in SetEndpoint
773 fFSC.PostClose(false);
774
775 // Now wait until all connection have been closed and
776 // all pending handlers have been processed
777 ba::io_service::poll();
778
779 if (evt.GetBool())
780 fFSC.SetEndpoint(evt.GetString());
781
782 // Now we can reopen the connection
783 fFSC.PostClose(true);
784
785 return T::GetCurrentState();
786 }
787
788 int Execute()
789 {
790 return fFSC.IsOpen() ? State::kConnected : State::kDisconnected;
791 }
792
793 bool CheckEventSize(size_t has, const char *name, size_t size)
794 {
795 if (has==size)
796 return true;
797
798 ostringstream msg;
799 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
800 T::Fatal(msg);
801 return false;
802 }
803
804 int SetVerbosity(const EventImp &evt)
805 {
806 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
807 return T::kSM_FatalError;
808
809 fFSC.SetVerbose(evt.GetBool());
810
811 return T::GetCurrentState();
812 }
813
814public:
815 StateMachineFSC(ostream &out=cout) :
816 StateMachineAsio<T>(out, "FSC_CONTROL"), fFSC(*this, *this)
817 {
818 // State names
819 T::AddStateName(State::kDisconnected, "Disconnected",
820 "FSC board not connected via ethernet.");
821
822 T::AddStateName(State::kConnected, "Connected",
823 "Ethernet connection to FSC established.");
824
825 // Verbosity commands
826 T::AddEvent("SET_VERBOSE", "B:1")
827 (bind(&StateMachineFSC::SetVerbosity, this, placeholders::_1))
828 ("set verbosity state"
829 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
830
831 // Conenction commands
832 T::AddEvent("DISCONNECT", State::kConnected)
833 (bind(&StateMachineFSC::Disconnect, this))
834 ("disconnect from ethernet");
835
836 T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected)
837 (bind(&StateMachineFSC::Reconnect, this, placeholders::_1))
838 ("(Re)connect ethernet connection to FSC, a new address can be given"
839 "|[host][string]:new ethernet address in the form <host:port>");
840
841 fFSC.StartConnect();
842 }
843
844 void SetEndpoint(const string &url)
845 {
846 fFSC.SetEndpoint(url);
847 }
848
849 int EvalOptions(Configuration &conf)
850 {
851 fFSC.SetVerbose(!conf.Get<bool>("quiet"));
852
853 const string fname1 = conf.Get<string>("sensor-pos-file");
854 const auto v1 = Interpolator2D::ReadGrid(fname1);
855 if (v1.size() != 31)
856 {
857 T::Error("Reading sensor positions from "+fname1+"failed ("+to_string(v1.size())+")");
858 return 1;
859 }
860
861 const string fname2 = conf.Get<string>("patch-pos-file");
862 const auto v2 = Interpolator2D::ReadGrid(fname2);
863 if (v2.size() != 320)
864 {
865 T::Error("Reading bias patch positions from "+fname2+"failed ("+to_string(v2.size())+")");
866 return 1;
867 }
868
869 fFSC.SetPositionsSensors(v1);
870 fFSC.SetPositionsBias(v2);
871
872 SetEndpoint(conf.Get<string>("addr"));
873
874 return -1;
875 }
876};
877
878// ------------------------------------------------------------------------
879
880#include "Main.h"
881
882template<class T, class S, class R>
883int RunShell(Configuration &conf)
884{
885 return Main::execute<T, StateMachineFSC<S, R>>(conf);
886}
887
888void SetupConfiguration(Configuration &conf)
889{
890 po::options_description control("FSC control options");
891 control.add_options()
892 ("no-dim", po_bool(), "Disable dim services")
893 ("addr,a", var<string>("localhost:5000"), "Network address of FSC")
894 ("sensor-pos-file", var<string>()->required(), "File with the positions of the 31 temperature sensors")
895 ("patch-pos-file", var<string>()->required(), "File with the positions of the 320 bias patches")
896 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
897 ;
898
899 conf.AddOptions(control);
900}
901
902/*
903 Extract usage clause(s) [if any] for SYNOPSIS.
904 Translators: "Usage" and "or" here are patterns (regular expressions) which
905 are used to match the usage synopsis in program output. An example from cp
906 (GNU coreutils) which contains both strings:
907 Usage: cp [OPTION]... [-T] SOURCE DEST
908 or: cp [OPTION]... SOURCE... DIRECTORY
909 or: cp [OPTION]... -t DIRECTORY SOURCE...
910 */
911void PrintUsage()
912{
913 cout <<
914 "The fscctrl controls the FSC (FACT Slow Control) board.\n"
915 "\n"
916 "The default is that the program is started without user intercation. "
917 "All actions are supposed to arrive as DimCommands. Using the -c "
918 "option, a local shell can be initialized. With h or help a short "
919 "help message about the usuage can be brought to the screen.\n"
920 "\n"
921 "Usage: fscctrl [-c type] [OPTIONS]\n"
922 " or: fscctrl [OPTIONS]\n";
923 cout << endl;
924}
925
926void PrintHelp()
927{
928 Main::PrintHelp<StateMachineFSC<StateMachine, ConnectionFSC>>();
929
930 /* Additional help text which is printed after the configuration
931 options goes here */
932
933 /*
934 cout << "bla bla bla" << endl << endl;
935 cout << endl;
936 cout << "Environment:" << endl;
937 cout << "environment" << endl;
938 cout << endl;
939 cout << "Examples:" << endl;
940 cout << "test exam" << endl;
941 cout << endl;
942 cout << "Files:" << endl;
943 cout << "files" << endl;
944 cout << endl;
945 */
946}
947
948int main(int argc, const char* argv[])
949{
950 Configuration conf(argv[0]);
951 conf.SetPrintUsage(PrintUsage);
952 Main::SetupConfiguration(conf);
953 SetupConfiguration(conf);
954
955 if (!conf.DoParse(argc, argv, PrintHelp))
956 return 127;
957
958 //try
959 {
960 // No console access at all
961 if (!conf.Has("console"))
962 {
963 if (conf.Get<bool>("no-dim"))
964 return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
965 else
966 return RunShell<LocalStream, StateMachineDim, ConnectionDimFSC>(conf);
967 }
968 // Cosole access w/ and w/o Dim
969 if (conf.Get<bool>("no-dim"))
970 {
971 if (conf.Get<int>("console")==0)
972 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
973 else
974 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
975 }
976 else
977 {
978 if (conf.Get<int>("console")==0)
979 return RunShell<LocalShell, StateMachineDim, ConnectionDimFSC>(conf);
980 else
981 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFSC>(conf);
982 }
983 }
984 /*catch (std::exception& e)
985 {
986 cerr << "Exception: " << e.what() << endl;
987 return -1;
988 }*/
989
990 return 0;
991}
Note: See TracBrowser for help on using the repository browser.