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

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