source: trunk/FACT++/src/miniftmctrl.cc@ 20086

Last change on this file since 20086 was 20059, checked in by tbretz, 4 years ago
Added from famous git repository and updated to be used in a FACT context - maybe more changes to come.
File size: 42.2 KB
Line 
1#include <boost/array.hpp>
2
3#include <string>
4#include <queue>
5
6#include "FACT.h"
7#include "Dim.h"
8#include "Event.h"
9#include "StateMachineDim.h"
10#include "StateMachineAsio.h"
11#include "Connection.h"
12#include "LocalControl.h"
13#include "Configuration.h"
14#include "Console.h"
15
16#include "tools.h"
17
18#include "HeadersMiniFTM.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std;
25
26class ConnectionMiniFTM : public Connection
27{
28public:
29 static bool fIsFACT;
30
31private:
32 bool fIsVerbose;
33 bool fDebugRx;
34
35 uint32_t fInterval;
36 uint16_t fTimerFreq;
37
38 boost::asio::deadline_timer fRxTimeout;
39 boost::asio::deadline_timer fTempTimer;
40
41 vector<uint8_t> fBuffer;
42
43 bool fIsInitializing;
44
45 MiniFTM::Config fConf;
46 MiniFTM::Temp fTemp;
47
48 virtual void UpdateConfiguration(const MiniFTM::Config &)
49 {
50 }
51
52 virtual void UpdateTemperatures(uint8_t, const MiniFTM::Temp &)
53 {
54 }
55
56 virtual void UpdateTrigger(uint8_t, const uint64_t &)
57 {
58 }
59
60 queue<MiniFTM::BusData> fQueue;
61
62 void HandleReadTimeout(const bs::error_code &error)
63 {
64 if (error==ba::error::basic_errors::operation_aborted)
65 return;
66
67 if (error)
68 {
69 ostringstream str;
70 str << "Read timeout: " << error.message() << " (" << error << ")";
71 Error(str);
72
73 PostClose();
74 return;
75
76 }
77
78 if (!is_open())
79 {
80 // For example: Here we could schedule a new accept if we
81 // would not want to allow two connections at the same time.
82 return;
83 }
84
85 // Check whether the deadline has passed. We compare the deadline
86 // against the current time since a new asynchronous operation
87 // may have moved the deadline before this actor had a chance
88 // to run.
89 //if (fRxTimeout.expires_at() > ba::deadline_timer::traits_type::now())
90 // return;
91
92 Error("Timeout ("+to_simple_string(fRxTimeout.expires_from_now())+") reading data.");
93 PostClose();
94 }
95
96 void TriggerTempTimer()
97 {
98 if (fInterval==0)
99 return;
100
101 fTempTimer.expires_from_now(boost::posix_time::milliseconds(fInterval));
102 fTempTimer.async_wait(boost::bind(&ConnectionMiniFTM::HandleTempTimer, this, dummy::error));
103 }
104
105 void HandleTempTimer(const bs::error_code &error)
106 {
107 if (error==ba::error::basic_errors::operation_aborted)
108 return;
109
110 if (error)
111 {
112 ostringstream str;
113 str << "Temp timer: " << error.message() << " (" << error << ")";
114 Error(str);
115
116 PostClose();
117 return;
118
119 }
120
121 if (!is_open())
122 return;
123
124 SendRead(MiniFTM::kADCs);
125 TriggerTempTimer();
126 }
127
128
129 void HandleReceivedData(const boost::system::error_code& err, size_t bytes_received, int)
130 {
131 // Do not schedule a new read if the connection failed.
132 if (bytes_received!=1024 || err)
133 {
134 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
135 // 125: Operation canceled
136 if (err && err!=ba::error::eof && // Connection closed by remote host
137 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
138 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
139 {
140 ostringstream str;
141 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
142 Error(str);
143 }
144 PostClose(err!=ba::error::basic_errors::operation_aborted);
145 return;
146 }
147
148 // Keep time of (async) data reception
149 const Time time;
150
151 MiniFTM::BusData &data = *reinterpret_cast<MiniFTM::BusData*>(fBuffer.data());
152
153 // Print raw message in verbose mode
154 if (fDebugRx)
155 Out() << "RX|" << data << endl;
156
157 // Some sanity checks
158 if (data.fStartBits!=0xffff || data.fStopBits!=0xffff)
159 {
160 Error(Tools::Form("Frame bytes mismatch (%04x|%04x)",
161 data.fStartBits, data.fStopBits));
162 PostClose();
163 return;
164 }
165
166 if (!data.isCrcValid())
167 {
168 Error(Tools::Form("Checksum mismatch (Received: %d, Expected: %d)", data.fCrc, data.calcCrc()));
169 PostClose();
170 return;
171 }
172
173 if (data.fReadWrite==MiniFTM::kCmdError)
174 {
175 ostringstream msg;
176 msg << "MiniFTM returned an error: ";
177 switch (data.fData)
178 {
179 case MiniFTM::kErrFrameStart: msg << "Start bytes wrong"; break;
180 case MiniFTM::kErrFrameStop: msg << "Stop bytes wrong"; break;
181 case MiniFTM::kErrFrameCrc: msg << "Checksum error"; break;
182 case MiniFTM::kErrUnknownCmd: msg << "Command unknown"; break;
183 case MiniFTM::kErrForbiddenCmd: msg << "Command not allowed"; break;
184 default: msg << "Unknwon error"; break;
185 }
186 msg << Tools::Form(" [%04x]", data.fData);
187 Error(msg);
188 PostClose();
189 return;
190 }
191
192 if (fQueue.empty() && data.fReadWrite!=MiniFTM::kCmdADM)
193 {
194 Error(Tools::Form("Unexpected answer [%02x|%04x] received.", data.fReadWrite, data.fCommand));
195 PostClose();
196 return;
197 }
198
199 if (!fQueue.empty() && data.fReadWrite!=MiniFTM::kCmdADM && fQueue.front().id() != data.id())
200 {
201 Error(Tools::Form("Command mismatch (Received: %06x, Expected: %06x)", data.id(), fQueue.front().id()));
202 PostClose();
203 return;
204 }
205
206 // Requested Message received -> cancel timeout
207 if (!fQueue.empty() && data.fReadWrite!=MiniFTM::kCmdADM)
208 fRxTimeout.cancel();
209
210 switch (data.fCommand)
211 {
212 case MiniFTM::kRegProductId:
213 fConf.fProductId = data.fData;
214 UpdateConfiguration(fConf);
215 Info(Tools::Form("Product ID = 0x%x", data.fData));
216 // FIXME: Check for validity
217 break;
218
219 case MiniFTM::kRegFirmwareId:
220 fConf.fFirmwareId = data.fData;
221 UpdateConfiguration(fConf);
222 Info(Tools::Form("Firmware = 0x%x", data.fData));
223 // FIXME: Check for validity
224 break;
225
226 case MiniFTM::kClockEnable:
227 fConf.fClockState = data.fCommand>>8;
228 UpdateConfiguration(fConf);
229 Info("Clock enabled.");
230 break;
231
232 case MiniFTM::kClockDisable:
233 fConf.fClockState = data.fCommand>>8;
234 UpdateConfiguration(fConf);
235 Info("Clock disabled.");
236 break;
237
238 case MiniFTM::kClockShutdown:
239 fConf.fClockState = data.fCommand>>8;
240 UpdateConfiguration(fConf);
241 Info("Clock shut down.");
242 break;
243
244 case MiniFTM::kClockFrequency:
245 {
246 const uint16_t dac = (data.fData>>2) &0x3ff;
247 const uint16_t oct = (data.fData>>12)&0xf;
248
249 const double freq = pow(2, oct)*2078/(2-dac/1024.)/1000;
250
251 fConf.fClockFrequency64 = data.fData;
252 fConf.fClockFrequencyD = freq;
253
254 UpdateConfiguration(fConf);
255
256 Info(Tools::Form("Clock frequency = %.2f kHz [dac=%d; oct=%d]", freq, dac, oct));
257 }
258 break;
259
260 case MiniFTM::kTriggerFixedRate:
261 fConf.fTriggerState = data.fCommand>>8;
262 UpdateConfiguration(fConf);
263 Info("Fixed rate trigger turned on ["+to_string(fConf.fTriggerState)+"]");
264 break;
265
266 case MiniFTM::kTriggerExternal:
267 fConf.fTriggerState = data.fCommand>>8;
268 UpdateConfiguration(fConf);
269 Info("External trigger turned on ["+to_string(fConf.fTriggerState)+"]");
270 break;
271
272 case MiniFTM::kTriggerRandom:
273 fConf.fTriggerState = data.fCommand>>8;
274 UpdateConfiguration(fConf);
275 Info("Random trigger turned on ["+to_string(fConf.fTriggerState)+"]");
276 break;
277
278 case MiniFTM::kTriggerShutdown:
279 fConf.fTriggerState = data.fCommand>>8;
280 UpdateConfiguration(fConf);
281 Info("Trigger turned off ["+to_string(fConf.fTriggerState)+"]");
282 break;
283
284 case MiniFTM::kTriggerRS485On:
285 fConf.fRS485OnOff = data.fCommand>>8;
286 UpdateConfiguration(fConf);
287 Info("RS485 communication turned on.");
288 break;
289
290 case MiniFTM::kTriggerRS485Off:
291 fConf.fRS485OnOff = data.fCommand>>8;
292 UpdateConfiguration(fConf);
293 Info("RS485 communication turned off.");
294 break;
295
296 case MiniFTM::kTriggerFrequency:
297 {
298 const double freq = fTimerFreq/(data.fData+1.); // old: 2*4150.
299
300 fConf.fTriggerFrequency64 = data.fData;
301 fConf.fTriggerFrequencyD = freq;
302
303 UpdateConfiguration(fConf);
304
305 Info(Tools::Form("Trigger frequency = %.2f Hz (%d)", freq, data.fData));
306 break;
307 }
308
309 case MiniFTM::kFadReset:
310 Info("FAD reset.");
311 break;
312
313 case MiniFTM::kFadResetCycles:
314 Info(Tools::Form("FAD Reset Length = %ld cycles", data.fData));
315 break;
316
317 case MiniFTM::kFadResetActiveHi:
318 Info(Tools::Form("FAD Reset is Active %s (%x)", (data.fData?"HI":"LO"), data.fData));
319 break;
320
321 case MiniFTM::kADC1:
322 {
323 fTemp.SetADC1(data.fData);
324 UpdateTemperatures(1, fTemp);
325 Info(Tools::Form("ADC1 = %.1f degC (%04x)", fTemp.fTemp1, fTemp.fADC1));
326 break;
327 }
328
329 case MiniFTM::kADC2:
330 {
331 fTemp.SetADC2(data.fData);
332 UpdateTemperatures(2, fTemp);
333 Info(Tools::Form("ADC2 = %.1f degC (%0x4)", fTemp.fTemp2, fTemp.fADC2));
334 break;
335 }
336
337 case MiniFTM::kADCs:
338 {
339 fTemp.SetADC1(data.fData&0xffff);
340 fTemp.SetADC2(data.fData>>16);
341
342 UpdateTemperatures(3, fTemp);
343
344 // if (fIsVerbose)
345 Info(Tools::Form("ADC1/2 = %.1f / %.1f degC (%04x/%04x)",
346 fTemp.fTemp1, fTemp.fTemp2, fTemp.fADC1, fTemp.fADC2));
347 break;
348 }
349
350 case MiniFTM::kRS485Data:
351 fConf.fRS485Data = data.fData;
352 UpdateConfiguration(fConf);
353 Info(Tools::Form("RS485 data = %016lx", data.fData));
354 break;
355
356 case MiniFTM::kSingleTrigger:
357 Info("Single trigger.");
358 break;
359
360 case MiniFTM::kTriggerCounter:
361 if (fIsVerbose)
362 Info("Trigger counter: "+to_string(data.fData&0xffff)+" (busy="+to_string(data.fData>>32)+")");
363 UpdateTrigger(0, data.fData);
364 break;
365
366 case MiniFTM::kConfiguration:
367 {
368 Info("RS485 communication "+string(data.fData&1?"on":"off"));
369
370 ostringstream out;
371 switch (data.fData&0x06)
372 {
373 case 0x02:
374 fConf.fTriggerState = data.fData&0x8?MiniFTM::kRandom:MiniFTM::kFixedRate;
375 out << (data.fData&0x8?"random":"fixed rate");
376 break;
377 case 0x04:
378 fConf.fTriggerState = MiniFTM::kExternal;
379 out << "external";
380 break;
381
382 case 0x06:
383 fConf.fTriggerState = MiniFTM::kShutdown;
384 out << (data.fData&0x10?"off/hi":"off/lo");
385 break;
386 }
387 Info("Trigger status: "+out.str());
388
389 fConf.fRS485OnOff = data.fData&1;
390 fConf.fConfiguration = data.fData;
391 UpdateConfiguration(fConf);
392 }
393 break;
394
395 case MiniFTM::kRegError:
396 //fDimData.SetErrorReg(data.fData[0]);
397 //UpdateData(time, data.id(), fDimData);
398 if (data.fData)
399 {
400 // Automatically acknowledge the error (Good idea?)
401 SendWrite(MiniFTM::kRegError);
402 Error("MiniFTM reported internal error "+to_string(data.fData)+".");
403 }
404 else
405 Info(data.fReadWrite==MiniFTM::kCmdRead?"No internal error reported by MiniFTM.":"Internal error reported by MiniFTM cleared.");
406 break;
407
408 case MiniFTM::kEnableADM:
409 Info(string("Automatic data sending mode (ADM) ")+(data.fData?"enabled":"disabled"));
410 //fDimConf.set(PSU::kBitADM, data[0]);
411 //UpdateConfig(time, data.id(), fDimConf);
412 break;
413
414 default:
415 Error(Tools::Form("Unknown command byte received (%d)", data.fCommand));
416 PostClose();
417 return;
418 }
419
420 // Start reading of next package
421 AsyncRead(ba::buffer(fBuffer));
422
423 // If this was an automatic package no further handling should be done
424 if (data.fReadWrite==MiniFTM::kCmdADM)
425 return;
426
427 // Remove the request for which we just processed the answer from
428 // the queue. This could have a check for an empty queue, but an
429 // empty queue here should never happen!
430 fQueue.pop();
431
432 // If this is the answer to the last sent initialization request
433 // Initialization is done
434 if (fQueue.empty() && fIsInitializing)
435 {
436 TriggerTempTimer();
437 PrintConfig();
438 fIsInitializing = false;
439 return;
440 }
441
442 // send next request if queue not empty
443 PostCommandFromQueue();
444 }
445
446 void PostCommandFromQueue()
447 {
448 if (fQueue.empty())
449 return;
450
451 const MiniFTM::BusData &dat = fQueue.front();
452
453 PostMessage(&dat, sizeof(dat));
454 if (GetDebugTx())
455 Out() << "TX|" << dat << endl;
456
457 AsyncWait(fRxTimeout, 1000, &Connection::HandleReadTimeout);
458 }
459
460public:
461 void SendCommand(uint8_t rw, uint16_t cmd, uint64_t d0=0)
462 {
463 fQueue.emplace(rw, cmd, d0);
464 if (fQueue.size()==1)
465 PostCommandFromQueue();
466 }
467
468 void SendWrite(uint16_t cmd, uint64_t val=0)
469 {
470 SendCommand(MiniFTM::kCmdWrite, cmd, val);
471 }
472
473 void SendRead(uint16_t cmd, uint64_t val=0)
474 {
475 SendCommand(MiniFTM::kCmdRead, cmd, val);
476 }
477
478 // This is called when a connection was established
479 void ConnectionEstablished()
480 {
481 Info("Connection established to "+URL()+"...");
482
483 fQueue = queue<MiniFTM::BusData>();
484
485 SendRead(MiniFTM::kRegProductId);
486 SendRead(MiniFTM::kRegFirmwareId);
487 SendRead(MiniFTM::kRegError);
488
489 SendRead(MiniFTM::kClockFrequency);
490
491 SendWrite(MiniFTM::kClockEnable);
492 SendRead(MiniFTM::kClockFrequency);
493
494 SendWrite(MiniFTM::kTriggerShutdown);
495 SendRead(MiniFTM::kTriggerFrequency);
496
497 //SendWrite(MiniFTM::kTriggerRS485On); // Done when trigger is truned on
498
499 SendRead(MiniFTM::kFadResetCycles);
500 SendRead(MiniFTM::kFadResetActiveHi);
501
502 SendRead(MiniFTM::kConfiguration);
503 SendRead(MiniFTM::kADCs);
504
505 SendWrite(MiniFTM::kEnableADM, true);
506
507 fIsInitializing = true;
508
509 AsyncRead(ba::buffer(fBuffer));
510 }
511
512public:
513 ConnectionMiniFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
514 fIsVerbose(true), fDebugRx(false),
515 fRxTimeout(ioservice), fTempTimer(ioservice),
516 fBuffer(1024), fIsInitializing(false)
517 {
518 SetLogStream(&imp);
519 }
520
521 void SetVerbose(bool b)
522 {
523 fIsVerbose = b;
524 }
525
526 void SetDebugRx(bool b)
527 {
528 fDebugRx = b;
529 Connection::SetVerbose(b);
530 }
531
532 void SetDebugTx(bool b)
533 {
534 Connection::SetDebugTx(b);
535 }
536
537 int GetState() const
538 {
539 if (!IsConnected())
540 return MiniFTM::State::kDisconnected;
541
542 if (fIsInitializing)
543 return MiniFTM::State::kConnected;
544
545 return MiniFTM::State::kValid;
546 }
547
548 size_t GetQueueSize() const
549 {
550 return fQueue.size();
551 }
552
553 uint8_t GetTriggerState() const
554 {
555 return fConf.fTriggerState;
556 }
557
558 uint8_t IsTriggerOn() const
559 {
560 return fConf.fTriggerState!=MiniFTM::kShutdown;
561 }
562
563 void PrintConfig()
564 {
565 Out() << fConf;
566 }
567
568 void SetInterval(uint32_t i)
569 {
570 fTempTimer.cancel();
571 fInterval = i;
572 if (IsConnected() && !fIsInitializing)
573 TriggerTempTimer();
574 }
575
576 void SetTimerFreq(uint16_t i)
577 {
578 fTimerFreq = i;
579 }
580};
581
582bool ConnectionMiniFTM::fIsFACT = true;
583
584// ------------------------------------------------------------------------
585
586#include "DimDescriptionService.h"
587
588class ConnectionDimMiniFTM : public ConnectionMiniFTM
589{
590private:
591 DimDescribedService fDimConfig;
592 DimDescribedService fDimTemp;
593 DimDescribedService fDimTrigger;
594
595public:
596 ConnectionDimMiniFTM(ba::io_service& ioservice, MessageImp &imp) :
597 ConnectionMiniFTM(ioservice, imp),
598 fDimConfig(fIsFACT?"MINIFTM_CONTROL/CONFIGURATION":"FTM_CONTROL/CONFIGURATION",
599 "X:1;X:1;C:1;X:1;D:1;C:1;C:1;X:1;D:1;X:1;X:1",
600 "|firmware[uint64]:Firmware ID"
601 "|product[uint64]:Product ID"
602 "|clk_state[uint8]:Clock state"
603 "|clk_freq_raw[uint64]:Clock frequency (raw)"
604 "|clk_freq[Hz]:Clock frequency"
605 "|trg_mode[uint8]:Trigger Mode"
606 "|rs485_state[uint8]:RS485 state"
607 "|trg_freq_raw[uint64]:Trigger frequency (raw)"
608 "|trg_freq[Hz]:Trigger frequency"
609 "|configuration[uint64]:Trigger and RS485 configuration bits"
610 "|rs485_data[uint64]:RS485 data"),
611 fDimTemp(fIsFACT?"MINIFTM_CONTROL/TEMPERATURES":"FTM_CONTROL/TEMPERATURES",
612 "S:2;F:2",
613 "|adc[uint16]:ADC counts"
614 "|temp[degC]:Corresponding temperatures"),
615 fDimTrigger(fIsFACT?"MINIFTM_CONTROL/TRIGGER_COUNTER":"FTM_CONTROL/TRIGGER_COUNTER",
616 "S:1;S:1",
617 "|counter[uint32]:Trigger counter (incoming and internal)"
618 "|busy[uint32]:Counter of suppressed triggers")
619 {
620 }
621
622 void UpdateConfiguration(const MiniFTM::Config &conf)
623 {
624 //fDim.setQuality(status.GetVal());
625 fDimConfig.setData(conf);
626 fDimConfig.Update();
627 }
628
629 void UpdateTemperatures(uint8_t qos, const MiniFTM::Temp &temp)
630 {
631 fDimTemp.setQuality(qos);
632 fDimTemp.setData(temp);
633 fDimTemp.Update();
634 }
635
636 void UpdateTrigger(uint8_t qos, const uint64_t &data)
637 {
638 fDimTrigger.setQuality(qos);
639 fDimTrigger.setData(data);
640 fDimTrigger.Update();
641 }
642};
643
644// ------------------------------------------------------------------------
645
646template <class T, class S>
647class StateMachineMiniFTM : public StateMachineAsio<T>
648{
649private:
650 S fFTM;
651 Time fLastCommand;
652
653 bool CheckEventSize(size_t has, const char *name, size_t size)
654 {
655 if (has==size)
656 return true;
657
658 ostringstream msg;
659 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
660 T::Fatal(msg);
661 return false;
662 }
663
664 int SetVerbosity(const EventImp &evt)
665 {
666 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
667 return T::kSM_FatalError;
668
669 fFTM.SetVerbose(evt.GetBool());
670
671 return T::GetCurrentState();
672 }
673
674 int SetDebugRx(const EventImp &evt)
675 {
676 if (!CheckEventSize(evt.GetSize(), "SetDebugRx", 1))
677 return T::kSM_FatalError;
678
679 fFTM.SetDebugRx(evt.GetBool());
680
681 return T::GetCurrentState();
682 }
683
684 int SetDebugTx(const EventImp &evt)
685 {
686 if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1))
687 return T::kSM_FatalError;
688
689 fFTM.SetDebugTx(evt.GetBool());
690
691 return T::GetCurrentState();
692 }
693
694 int Disconnect()
695 {
696 // Close all connections
697 fFTM.PostClose(false);
698
699 /*
700 // Now wait until all connection have been closed and
701 // all pending handlers have been processed
702 poll();
703 */
704
705 return T::GetCurrentState();
706 }
707
708 int Reconnect(const EventImp &evt)
709 {
710 // Close all connections to supress the warning in SetEndpoint
711 fFTM.PostClose(false);
712
713 // Now wait until all connection have been closed and
714 // all pending handlers have been processed
715 ba::io_service::poll();
716
717 if (evt.GetBool())
718 fFTM.SetEndpoint(evt.GetString());
719
720 // Now we can reopen the connection
721 fFTM.PostClose(true);
722
723 return T::GetCurrentState();
724 }
725
726 int PrintConfig()
727 {
728 fFTM.PrintConfig();
729 return T::GetCurrentState();
730 }
731
732 uint16_t fTriggerMode; // Kommand to be sent to turn the trigger on
733
734 int Configure(const EventImp &evt)
735 {
736 const string name = evt.GetText();
737
738 auto it = fRunTypes.find(name);
739 if (it==fRunTypes.end())
740 {
741 T::Info("Configure - Run-type '"+name+"' not found... trying 'default'.");
742
743 it = fRunTypes.find("default");
744 if (it==fRunTypes.end())
745 {
746 T::Error("Configure - Run-type 'default' not found.");
747 return T::GetCurrentState();
748 }
749 }
750
751 Dim::SendCommand("FTU_CONTROL/ENABLE_PRESCALING", uint8_t(0));
752
753 fFTM.SendWrite(MiniFTM::kTriggerShutdown);
754 fFTM.SendWrite(MiniFTM::kTriggerRS485On);
755 fFTM.SendWrite(MiniFTM::kTriggerFrequency, it->second.fTriggerRate);
756 fFTM.SendWrite(MiniFTM::kRS485Data);
757
758 fTriggerMode = MiniFTM::kTriggerShutdown;
759 if (it->second.fTriggerType=="fixedrate")
760 fTriggerMode = MiniFTM::kTriggerFixedRate;
761 if (it->second.fTriggerType=="external")
762 fTriggerMode = MiniFTM::kTriggerExternal;
763 if (it->second.fTriggerType=="random")
764 fTriggerMode = MiniFTM::kTriggerRandom;
765
766 return MiniFTM::State::kConfiguring;
767 }
768
769 int ResetConfig()
770 {
771 return fFTM.GetState();
772 }
773
774 int StartTrigger()
775 {
776 fFTM.SendWrite(fTriggerMode);
777 return T::GetCurrentState();//MiniFTM::State::kTriggerOn;
778 }
779
780 int ReadRegister(uint16_t cmd)
781 {
782 fFTM.SendRead(cmd);
783
784 return T::GetCurrentState();
785 }
786
787 int WriteRegister(uint16_t cmd)
788 {
789 fFTM.SendWrite(cmd);
790
791 return T::GetCurrentState();
792 }
793
794 int WriteRegister64(const EventImp &evt, uint16_t cmd)
795 {
796 if (!CheckEventSize(evt.GetSize(), "WriteRegister64", 8))
797 return T::kSM_FatalError;
798
799 fFTM.SendWrite(cmd, evt.Get<uint64_t>());
800
801 return T::GetCurrentState();
802 }
803
804 int ShutdownTrigger(const EventImp &evt)
805 {
806 if (!CheckEventSize(evt.GetSize(), "ReadRegister", 1))
807 return T::kSM_FatalError;
808
809 fFTM.SendWrite(MiniFTM::kTriggerShutdown, evt.GetBool());
810
811 return T::GetCurrentState();
812 }
813
814 int SetClockFrequency(const EventImp &evt)
815 {
816 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 4))
817 return T::kSM_FatalError;
818
819 const uint16_t m = evt.Get<uint16_t>(0);
820 const uint16_t e = evt.Get<uint16_t>(2);
821
822 if (m>0x3ff)
823 {
824 T::Warn("Clock frequency matinsse exceeds allowed range (10 bit)... ignored.");
825 return T::GetCurrentState();
826 }
827
828 if (e>0xf)
829 {
830 T::Warn("Clock frequency exponent exceeds allowed range (4 bit)... ignored.");
831 return T::GetCurrentState();
832 }
833
834 fFTM.SendWrite(MiniFTM::kClockFrequency, (e<<12)|(m<<2));
835
836 return T::GetCurrentState();
837 }
838
839 int SetTriggerFrequency(const EventImp &evt)
840 {
841 if (!CheckEventSize(evt.GetSize(), "SetTriggerFrequency", 4))
842 return T::kSM_FatalError;
843
844 if (evt.GetUInt()<5)
845 {
846 T::Warn("Trigger frequency too high... ignored.");
847 return T::GetCurrentState();
848 }
849 if (evt.GetUInt()>0xffff)
850 {
851 T::Warn("Trigger frequency exceeds allowed range (16 bit)... ignored.");
852 return T::GetCurrentState();
853 }
854
855 fFTM.SendWrite(MiniFTM::kTriggerFrequency, evt.GetUInt());
856
857 return T::GetCurrentState();
858 }
859/*
860 int SetRS485Mode(const EventImp &evt)
861 {
862 if (!CheckEventSize(evt.GetSize(), "SetRS485Mode", 8))
863 return T::kSM_FatalError;
864
865 const uint8_t *ptr = evt.Ptr<uint8_t>();
866
867 uint64_t data = 0;
868 data |= uint64_t(ptr[0])<<40; // baud (word2)
869 data |= uint64_t(ptr[1])<<32; // baud (word2)
870 data |= uint64_t(ptr[2])<<24; // baud (word3)
871 data |= uint64_t(ptr[3])<<16; // baud (word3)
872 data |= uint64_t(ptr[4]&1)<<(40+15); // PEN
873 data |= uint64_t(ptr[5]&1)<<(40+14); // PAR
874 data |= uint64_t(ptr[6]&1)<<(40+13); // SPB
875 data |= uint64_t(ptr[7]&1)<<(40+11); // MSB
876
877 fFTM.SendWrite(MiniFTM::kRS485Mode, data);
878
879 return T::GetCurrentState();
880 }
881*/
882 int SetInterval(const EventImp &evt)
883 {
884 if (!CheckEventSize(evt.GetSize(), "SetInterval", 8))
885 return T::kSM_FatalError;
886
887 if (evt.GetUXtra()>0xffffffff)
888 {
889 T::Warn("Interval out of allowed range [32 bit]... ignored.");
890 return T::GetCurrentState();
891 }
892
893 fFTM.SetInterval(evt.GetUXtra());
894
895 return T::GetCurrentState();
896 }
897
898 int Execute()
899 {
900 if (fFTM.GetState()<MiniFTM::State::kValid)
901 return fFTM.GetState();
902
903 switch (T::GetCurrentState())
904 {
905 case MiniFTM::State::kConfiguring:
906 return fFTM.GetQueueSize()==0 ? MiniFTM::State::kConfigured : MiniFTM::State::kConfiguring;
907
908 case MiniFTM::State::kConfigured:
909 return fFTM.IsTriggerOn() ? MiniFTM::State::kTriggerOn : MiniFTM::State::kConfigured;
910
911 case MiniFTM::State::kTriggerOn:
912 return fFTM.IsTriggerOn() ? MiniFTM::State::kTriggerOn : MiniFTM::State::kValid;
913 }
914
915 return fFTM.GetState();
916 }
917
918public:
919 StateMachineMiniFTM(ostream &out=cout) :
920 StateMachineAsio<T>(out, ConnectionMiniFTM::fIsFACT?"MINIFTM_CONTROL":"FTM_CONTROL"),
921 fFTM(*this, *this)
922 {
923 // State names
924 T::AddStateName(MiniFTM::State::kDisconnected, "Disconnected",
925 "No ethernet connection established");
926
927 T::AddStateName(MiniFTM::State::kConnected, "Connected",
928 "Connection established, requesting configuration");
929
930 T::AddStateName(MiniFTM::State::kValid, "Valid",
931 "Connection established, valid configuration received");
932
933 T::AddStateName(MiniFTM::State::kConfiguring, "Configuring",
934 "Configuring FTM for data taking");
935
936 T::AddStateName(MiniFTM::State::kConfigured, "Configured",
937 "Ready for data taking, ready to enable trigger");
938
939 T::AddStateName(MiniFTM::State::kTriggerOn, "TriggerOn",
940 "Trigger enabled");
941
942
943 // Verbosity commands
944 T::AddEvent("SET_VERBOSE", "B:1")
945 (bind(&StateMachineMiniFTM::SetVerbosity, this, placeholders::_1))
946 ("Set verbosity state"
947 "|verbosity[bool]:disable or enable verbosity for interpreted data (yes/no)");
948
949 T::AddEvent("SET_DEBUG_RX", "B:1")
950 (bind(&StateMachineMiniFTM::SetDebugRx, this, placeholders::_1))
951 ("Set debux-rx state"
952 "|debug[bool]:dump received message to console (yes/no)");
953
954 T::AddEvent("SET_DEBUG_TX", "B:1")
955 (bind(&StateMachineMiniFTM::SetDebugTx, this, placeholders::_1))
956 ("Set debux-tx state"
957 "|debug[bool]:dump outgoing message to console (yes/no)");
958
959
960 // Device control
961 T::AddEvent("READ_PRODUCT_ID", MiniFTM::State::kValid)
962 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kRegProductId))
963 ("Read product identification");
964
965 T::AddEvent("READ_FIRMWARE_ID", MiniFTM::State::kValid)
966 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kRegFirmwareId))
967 ("Read firmware version");
968
969 T::AddEvent("READ_CLOCK_STATE", MiniFTM::State::kValid)
970 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kClockState))
971 ("Read clock state");
972
973 T::AddEvent("READ_CLOCK_FREQUENCY", MiniFTM::State::kValid)
974 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kClockFrequency))
975 ("Read clock frequency");
976
977 //T::AddEvent("READ_TRIGGER_MODE", MiniFTM::State::kValid)
978 // (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kTriggerState))
979 // ("Read trigger mode");
980
981 T::AddEvent("READ_TRIGGER_FREQUENCY", MiniFTM::State::kValid)
982 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kTriggerFrequency))
983 ("Read trigger frequency");
984
985 T::AddEvent("READ_CONFIGURATION", MiniFTM::State::kValid)
986 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kConfiguration))
987 ("Read some configuration bits");
988
989 T::AddEvent("RESET_FAD", MiniFTM::State::kValid)
990 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kFadReset))
991 ("Send FAD reset");
992
993 T::AddEvent("READ_ADC1", MiniFTM::State::kValid)
994 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kADC1))
995 ("Read ADC1 (Temp1)");
996
997 T::AddEvent("READ_ADC2", MiniFTM::State::kValid)
998 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kADC2))
999 ("Read ADC2 (Temp2)");
1000
1001 T::AddEvent("READ_TEMPERATURES", MiniFTM::State::kValid)
1002 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kADCs))
1003 ("Read both temperatures (ADCs)");
1004
1005
1006 T::AddEvent("READ_FAD_RESET_CYCLES", MiniFTM::State::kValid)
1007 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kFadResetCycles))
1008 ("Read number of cycles of FAD reset");
1009
1010 T::AddEvent("READ_FAD_RESET_ACTIVE_HI", MiniFTM::State::kValid)
1011 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kFadResetActiveHi))
1012 ("Set when FAD reset is active hi");
1013
1014
1015
1016 T::AddEvent("SET_CLOCK_FREQUENCY", "S:1;S:1", MiniFTM::State::kValid)
1017 (bind(&StateMachineMiniFTM::SetClockFrequency, this, placeholders::_1))
1018 ("Set clock frequency 2^oct*2078Hz/(2-dac/1024)"
1019 "|dac[uint16]:Value DAC (10 bit)"
1020 "|oct[uint16]:Value OCT (4 bit)");
1021
1022 T::AddEvent("SET_TRIGGER_FREQUENCY", "I:1", MiniFTM::State::kValid)
1023 (bind(&StateMachineMiniFTM::SetTriggerFrequency, this, placeholders::_1))
1024 ("Set trigger frequency"
1025 "|dac[Hz]:Clock frequency (16 bit): DAC = 2*4150Hz/f - 1");
1026
1027
1028
1029 T::AddEvent("ENABLE_CLOCK", MiniFTM::State::kValid)
1030 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kClockEnable))
1031 ("Enable clock");
1032
1033 T::AddEvent("DISABLE_CLOCK", MiniFTM::State::kValid)
1034 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kClockDisable))
1035 ("Disable clock");
1036
1037 T::AddEvent("SHUTDOWN_CLOCK", MiniFTM::State::kValid)
1038 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kClockShutdown))
1039 ("Shutdown clock");
1040
1041
1042 T::AddEvent("ENABLE_FIXED_RATE_TRIGGER", MiniFTM::State::kValid)
1043 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerFixedRate))
1044 ("Enable fixed rate trigger");
1045
1046 T::AddEvent("ENABLE_EXTERNAL_TRIGGER", MiniFTM::State::kValid)
1047 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerExternal))
1048 ("Enable external trigger");
1049
1050 T::AddEvent("ENABLE_RANDOM_TRIGGER", MiniFTM::State::kValid)
1051 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerRandom))
1052 ("Enable random trigger");
1053
1054 T::AddEvent("SHUTDOWN_TRIGGER", "B:1", MiniFTM::State::kValid)
1055 (bind(&StateMachineMiniFTM::ShutdownTrigger, this, placeholders::_1))
1056 ("Shutdown trigger"
1057 "|hilo[bool]:Set hi or lo state after shutdown");
1058
1059
1060/*
1061 T::AddEvent("SET_RS485_MODE", "S:2;B:4", MiniFTM::State::kValid)
1062 (bind(&StateMachineMiniFTM::SetRS485Mode, this, placeholders::_1))
1063 ("Set the RS485 mode"
1064 "|BAUD0[uint16]:Baud rate (word 2)"
1065 "|BAUD1[uint16]:Baud rate (word 3)"
1066 "|PEN[bool]:Parity enabled (0: disabled, 1: enabled)"
1067 "|PAR[bool]:Parity even (0: odd, 1: even)"
1068 "|SPB[bool]:Stop bits (0: one, 1: two)"
1069 "|MSB[bool]:Most Significant Bit First (MSB) (0: LSB, 1: MSB)");
1070*/
1071
1072 T::AddEvent("ENABLE_RS485", MiniFTM::State::kValid)
1073 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerRS485On))
1074 ("Enable RS485 communication.");
1075
1076 T::AddEvent("DISABLE_RS485", MiniFTM::State::kValid)
1077 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerRS485Off))
1078 ("Disable RS485 communication.");
1079
1080
1081
1082 T::AddEvent("READ_RS485_DATA", MiniFTM::State::kValid)
1083 (bind(&StateMachineMiniFTM::ReadRegister, this, MiniFTM::kRS485Data))
1084 ("Read RS485 data");
1085
1086 T::AddEvent("SET_RS485_DATA", "X:1", MiniFTM::State::kValid)
1087 (bind(&StateMachineMiniFTM::WriteRegister64, this, placeholders::_1, MiniFTM::kRS485Data))
1088 ("Set RS485 data");
1089
1090
1091
1092 T::AddEvent("SET_FAD_RESET_CYCLES", "X:1", MiniFTM::State::kValid)
1093 (bind(&StateMachineMiniFTM::WriteRegister64, this, placeholders::_1, MiniFTM::kFadResetCycles))
1094 ("Set number of Cycles of FAD reset"
1095 "|cycles[uint16]:Number of cycles (min: 10, 16 bit)");
1096
1097
1098 T::AddEvent("SET_FAD_RESET_ACTIVE_HI", "X:1", MiniFTM::State::kValid)
1099 (bind(&StateMachineMiniFTM::WriteRegister64, this, placeholders::_1, MiniFTM::kFadResetActiveHi))
1100 ("Set whether FAD reset is active hi"
1101 "|hi[bool]:Active hi");
1102
1103
1104
1105 T::AddEvent("SINGLE_TRIGGER", MiniFTM::State::kValid)
1106 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kSingleTrigger))
1107 ("Issue single trigger");
1108
1109
1110
1111 T::AddEvent("ERROR", MiniFTM::State::kValid)
1112 (bind(&StateMachineMiniFTM::WriteRegister, this, 0x9999))
1113 ("Send an errorneous command (debugging purpose)");
1114
1115
1116
1117 T::AddEvent("PRINT_CONFIGURATION")
1118 (bind(&StateMachineMiniFTM::PrintConfig, this))
1119 ("Print the current configuration as available in memory");
1120
1121
1122 // A new configure will first stop the FTM this means
1123 // we can allow it in idle _and_ taking data
1124 T::AddEvent("CONFIGURE", "C", MiniFTM::State::kValid, MiniFTM::State::kTriggerOn)
1125 (bind(&StateMachineMiniFTM::Configure, this, placeholders::_1))
1126 ("Configure a new run");
1127
1128 T::AddEvent("RESET_CONFIGURE", MiniFTM::State::kConfigured)
1129 (bind(&StateMachineMiniFTM::ResetConfig, this))
1130 ("Reset states during a configuration or in case of configuration error");
1131
1132 T::AddEvent("START_TRIGGER", MiniFTM::State::kConfigured)
1133 (bind(&StateMachineMiniFTM::StartTrigger, this))
1134 ("Start trigger as configured by CONFIGURE");
1135
1136 T::AddEvent("STOP_TRIGGER", MiniFTM::State::kTriggerOn)
1137 (bind(&StateMachineMiniFTM::WriteRegister, this, MiniFTM::kTriggerShutdown))
1138 ("Disable all triggers");
1139
1140
1141
1142 T::AddEvent("SET_INTERVAL", "X:1", MiniFTM::State::kValid)
1143 (bind(&StateMachineMiniFTM::SetInterval, this, placeholders::_1))
1144 ("Set temperature request interval"
1145 "|dt[uint32]:Interval in ms (0=off)");
1146
1147
1148
1149 // Conenction commands
1150 T::AddEvent("DISCONNECT", MiniFTM::State::kConnected, MiniFTM::State::kValid)
1151 (bind(&StateMachineMiniFTM::Disconnect, this))
1152 ("Disconnect from ethernet");
1153
1154 T::AddEvent("RECONNECT", "O", MiniFTM::State::kDisconnected, MiniFTM::State::kConnected, MiniFTM::State::kValid)
1155 (bind(&StateMachineMiniFTM::Reconnect, this, placeholders::_1))
1156 ("(Re)connect ethernet connection, a new address can be given"
1157 "|[host][string]:new ethernet address in the form <host:port>");
1158 }
1159
1160 map<string, MiniFTM::RunType> fRunTypes;
1161
1162 template<typename _t>
1163 bool GetConfig(Configuration &conf, const string &name, const string &sub, _t &rc)
1164 {
1165 if (conf.HasDef(name, sub))
1166 {
1167 rc = conf.GetDef<_t>(name, sub);
1168 return true;
1169 }
1170
1171 T::Error("Neither "+name+"default nor "+name+sub+" found.");
1172 return false;
1173 }
1174
1175 int EvalOptions(Configuration &conf)
1176 {
1177 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1178 fFTM.SetDebugTx(conf.Get<bool>("debug-tx"));
1179 fFTM.SetDebugRx(conf.Get<bool>("debug-rx"));
1180 fFTM.SetEndpoint(conf.Get<string>("addr"));
1181 fFTM.SetInterval(conf.Get<uint32_t>("interval"));
1182 fFTM.SetTimerFreq(conf.Get<uint16_t>("timer-frequency"));
1183
1184 // ---------- Setup run types ---------
1185 const vector<string> types = conf.Vec<string>("run-type");
1186 if (types.empty())
1187 T::Warn("No run-types defined.");
1188 else
1189 T::Message("Defining run-types");
1190
1191 for (auto it=types.begin(); it!=types.end(); it++)
1192 {
1193 T::Message(" -> "+ *it);
1194
1195 if (fRunTypes.count(*it)>0)
1196 {
1197 T::Error("Run-type "+*it+" defined twice.");
1198 return 1;
1199 }
1200
1201 MiniFTM::RunType &c = fRunTypes[*it];
1202 if (!GetConfig(conf, "trigger-rate.", *it, c.fTriggerRate) ||
1203 !GetConfig(conf, "trigger-type.", *it, c.fTriggerType))
1204 return 2;
1205 }
1206
1207 // -----------------------------------
1208
1209 fFTM.StartConnect();
1210
1211 return -1;
1212 }
1213};
1214
1215// ------------------------------------------------------------------------
1216
1217#include "Main.h"
1218
1219
1220template<class T, class S, class R>
1221int RunShell(Configuration &conf)
1222{
1223#if BOOST_VERSION < 104600
1224 const string fname = boost::filesystem::path(conf.GetName()).filename();
1225#else
1226 const string fname = boost::filesystem::path(conf.GetName()).filename().string();
1227#endif
1228
1229 ConnectionMiniFTM::fIsFACT = fname!="ftmctrl";
1230
1231 return Main::execute<T, StateMachineMiniFTM<S, R>>(conf);
1232}
1233
1234void SetupConfiguration(Configuration &conf)
1235{
1236 po::options_description control("Interlock control");
1237 control.add_options()
1238 ("no-dim,d", po_switch(), "Disable dim services")
1239 ("addr,a", var<string>(""), "Network address of the lid controling Arduino including port")
1240 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1241 ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
1242 ("debug-rx", po_bool(), "Enable debugging for received data.")
1243 ("interval", var<uint32_t>(15000), "Interval in which temperatures are requested [ms]")
1244 ("timer-frequency", var<uint16_t>(32768), "Frequency of internal timer module [Hz]")
1245 ;
1246
1247 po::options_description runtype("Run type configuration");
1248 runtype.add_options()
1249 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
1250 ("trigger-type.*", var<string>(), "Calibration type ('fixedrate', 'random', 'external', 'off')")
1251 ("trigger-rate.*", var<uint16_t>(), "Target rate for calibration by rate")
1252 ;
1253
1254 conf.AddOptions(control);
1255 conf.AddOptions(runtype);
1256}
1257
1258/*
1259 Extract usage clause(s) [if any] for SYNOPSIS.
1260 Translators: "Usage" and "or" here are patterns (regular expressions) which
1261 are used to match the usage synopsis in program output. An example from cp
1262 (GNU coreutils) which contains both strings:
1263 Usage: cp [OPTION]... [-T] SOURCE DEST
1264 or: cp [OPTION]... SOURCE... DIRECTORY
1265 or: cp [OPTION]... -t DIRECTORY SOURCE...
1266 */
1267void PrintUsage()
1268{
1269 cout <<
1270 "The ftmctrl is a hardware interface to the MiniFTM board built for FAMOUS"
1271 "\n"
1272 "The default is that the program is started with user intercation. "
1273 "All actions are supposed to arrive as DimCommands. Using the -c "
1274 "option, a local shell can be initialized. With h or help a short "
1275 "help message about the usuage can be brought to the screen.\n"
1276 "\n"
1277 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1278 " or: ftmctrl [OPTIONS]\n";
1279 cout << endl;
1280}
1281
1282void PrintHelp()
1283{
1284 Main::PrintHelp<StateMachineMiniFTM<StateMachine, ConnectionMiniFTM>>();
1285
1286 /* Additional help text which is printed after the configuration
1287 options goes here */
1288
1289 /*
1290 cout << "bla bla bla" << endl << endl;
1291 cout << endl;
1292 cout << "Environment:" << endl;
1293 cout << "environment" << endl;
1294 cout << endl;
1295 cout << "Examples:" << endl;
1296 cout << "test exam" << endl;
1297 cout << endl;
1298 cout << "Files:" << endl;
1299 cout << "files" << endl;
1300 cout << endl;
1301 */
1302}
1303
1304int main(int argc, const char* argv[])
1305{
1306 Configuration conf(argv[0]);
1307 conf.SetPrintUsage(PrintUsage);
1308 Main::SetupConfiguration(conf);
1309 SetupConfiguration(conf);
1310
1311 if (!conf.DoParse(argc, argv, PrintHelp))
1312 return 127;
1313
1314 // No console access at all
1315 if (!conf.Has("console"))
1316 {
1317 if (conf.Get<bool>("no-dim"))
1318 return RunShell<LocalStream, StateMachine, ConnectionMiniFTM>(conf);
1319 else
1320 return RunShell<LocalStream, StateMachineDim, ConnectionDimMiniFTM>(conf);
1321 }
1322 // Cosole access w/ and w/o Dim
1323 if (conf.Get<bool>("no-dim"))
1324 {
1325 if (conf.Get<int>("console")==0)
1326 return RunShell<LocalShell, StateMachine, ConnectionMiniFTM>(conf);
1327 else
1328 return RunShell<LocalConsole, StateMachine, ConnectionMiniFTM>(conf);
1329 }
1330 else
1331 {
1332 if (conf.Get<int>("console")==0)
1333 return RunShell<LocalShell, StateMachineDim, ConnectionDimMiniFTM>(conf);
1334 else
1335 return RunShell<LocalConsole, StateMachineDim, ConnectionDimMiniFTM>(conf);
1336 }
1337
1338 return 0;
1339}
Note: See TracBrowser for help on using the repository browser.