00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "roc/ReadoutApplication.h"
00015
00016 #include <time.h>
00017
00018 #include "dabc/Parameter.h"
00019 #include "dabc/Command.h"
00020 #include "dabc/timing.h"
00021 #include "dabc/CommandsSet.h"
00022 #include "dabc/Device.h"
00023 #include "dabc/Port.h"
00024 #include "dabc/Module.h"
00025 #include "dabc/ConnectionRequest.h"
00026 #include "dabc/Url.h"
00027
00028 #include "mbs/MbsTypeDefs.h"
00029 #include "mbs/Factory.h"
00030
00031 #include "roc/defines_roc.h"
00032 #include "roc/UdpBoard.h"
00033 #include "roc/UdpDevice.h"
00034 #include "roc/Commands.h"
00035 #include "roc/CombinerModule.h"
00036
00037 const char* nameRocComb = "RocComb";
00038 const char* nameRocCalibr = "RocCalibr";
00039 const char* nameSusiboComb = "SusiboComb";
00040 const char* nameTRBComb = "TRBComb";
00041 const char* nameTRBTrans = "TRBTrans";
00042 const char* nameSuperComb = "SuperComb";
00043
00044 roc::ReadoutApplication::ReadoutApplication() :
00045 dabc::Application(roc::xmlReadoutAppClass),
00046 fRocBrds()
00047 {
00048 CreatePar(roc::xmlIgnoreMissingEpoch).DfltBool(false);
00049
00050 CreatePar(roc::xmlRawReadout).DfltBool(true);
00051
00052 CreatePar(roc::xmlSyncNumber).DfltInt(0);
00053
00054 CreatePar(roc::xmlSyncScaleDown).DfltInt(-1);
00055
00056 CreatePar(roc::xmlNumRocs).DfltInt(3);
00057
00058 for (int nr = 0; nr < NumRocs(); nr++) {
00059 CreatePar(FORMAT(("%s%d", xmlRocIp, nr)));
00060 CreatePar(FORMAT(("%s%d", xmlRocFebs, nr)));
00061 }
00062 CreatePar(roc::xmlMeasureADC).DfltBool(false);
00063 CreatePar(roc::xmlUseDLM).DfltBool(true);
00064
00065 CreatePar(roc::xmlEpicsStreamNode).DfltStr("");
00066 CreatePar(roc::xmlEpicsTransportNode).DfltStr("");
00067
00068 CreatePar(roc::xmlNumMbs).DfltInt(0);
00069 for (int n = 0; n < NumMbs(); n++) {
00070 CreatePar(FORMAT(("%s%d", roc::xmlMbsAddr, n))).DfltStr("");
00071 CreatePar(FORMAT(("%s%d", roc::xmlSyncSubeventId, n))).DfltInt(0);
00072 }
00073
00074 CreatePar(roc::xmlNumSusibo).DfltInt(0);
00075 for (int n = 0; n < NumSusibo(); n++)
00076 CreatePar(FORMAT(("%s%d", roc::xmlSusiboAddr, n))).DfltInt(0);
00077
00078 CreatePar(roc::xmlNumSlaves).DfltInt(0);
00079 for (int n = 0; n < NumSlaves(); n++) {
00080 CreatePar(FORMAT(("%s%d", roc::xmlSlaveAddr, n))).DfltStr("");
00081 CreatePar(FORMAT(("Slave%s%d", roc::xmlSyncSubeventId, n))).DfltInt(0);
00082 }
00083
00084 CreatePar(roc::xmlNumTRBs).DfltInt(0);
00085 for (int n = 0; n < NumTRBs(); n++)
00086 CreatePar(FORMAT(("%s%d", roc::xmlTRBAddr, n))).DfltStr("");
00087
00088 CreatePar("EventsInBuffer").DfltInt(1);
00089 CreatePar("HitDelay").DfltInt(200);
00090 CreatePar("PollingTimeout").DfltDouble(0.01);
00091
00092 CreatePar(dabc::xmlBufferSize).DfltInt(8192);
00093 CreatePar(dabc::xmlNumBuffers).DfltInt(100);
00094 CreatePar(dabc::xmlFlushTimeout).DfltDouble(1.);
00095 CreatePar(dabc::xmlFlushTimeout).DfltDouble(1.);
00096
00097 CreatePar(mbs::xmlServerKind).DfltStr(mbs::ServerKindToStr(mbs::StreamServer));
00098 CreatePar(mbs::xmlCombineCompleteOnly).DfltBool(false);
00099
00100 CreatePar(xmlRawFile).DfltStr("");
00101 CreatePar(mbs::xmlSizeLimit).DfltInt(0);
00102
00103 CreatePar(roc::xmlSpillRoc).DfltInt(-1);
00104 CreatePar(roc::xmlSpillAux).DfltInt(-1);
00105 CreatePar(roc::xmlCalibrationPeriod).DfltDouble(-1.);
00106 CreatePar(roc::xmlCalibrationLength).DfltDouble(0.5);
00107
00108 CreatePar(roc::xmlGet4ResetPeriod).DfltDouble(-1.);
00109 CreatePar(roc::xmlGet4ResetLimit).DfltDouble(-1.);
00110
00111 fMasterNode = Cfg("IsMaster").AsBool(true);
00112
00113 if (fMasterNode) {
00114 CreatePar("FilePath").DfltStr("./");
00115 CreatePar("RunPrefix").DfltStr("");
00116
00117 CreatePar("RunNumber").DfltStr("-1");
00118 CreatePar("RunInfo", "info").SetStr("NoRun");
00119
00120 CreateCmdDef("StartRun");
00121 CreateCmdDef("StopRun");
00122 CreateCmdDef("SetPrefix").AddArg("Prefix", "string", true, "te_");
00123 CreateCmdDef("SetRunNumber").AddArg("RunNumber", "string", true, "1");
00124
00125
00126
00127 CreateCmdDef("SetPrefixTest");
00128 CreateCmdDef("SetPrefixBeam");
00129 CreateCmdDef("SetPrefixCosmics");
00130 CreateCmdDef("IncRunNumber");
00131 CreateCmdDef("DecRunNumber");
00132 CreateCmdDef("ResetRunNumber");
00133 }
00134
00135 fRawReadout = false;
00136 fSuperCombiner = false;
00137 fDoMeasureADC = false;
00138 fCheckSlavesConn = false;
00139 fFirstSlavePort = -1;
00140
00141 fFileOutPort.clear();
00142 fServerOutPort.clear();
00143
00144 DOUT3(("!!!! Readout application %s created !!!!", GetName()));
00145
00146 if (NumSlaves()>0)
00147
00148 RegisterForParameterEvent(dabc::ConnectionObject::ObjectName());
00149
00150 }
00151
00152 roc::ReadoutApplication::~ReadoutApplication()
00153 {
00154 DOUT3(("!!!! Readout application %s destructor !!!!", GetName()));
00155 }
00156
00157 std::string roc::ReadoutApplication::DataServerKind() const
00158 {
00159 return Par(mbs::xmlServerKind).AsStdStr();
00160 }
00161
00162 std::string roc::ReadoutApplication::RocAddr(int nreadout) const
00163 {
00164 if ((nreadout < 0) || (nreadout >= NumRocs())) return "";
00165 return Par(FORMAT(("%s%d", xmlRocIp, nreadout))).AsStdStr();
00166 }
00167
00168 std::string roc::ReadoutApplication::TRBAddr(int index) const
00169 {
00170 if ((index < 0) || (index >= NumTRBs())) return "";
00171 return Par(FORMAT(("%s%d", roc::xmlTRBAddr, index))).AsStdStr();
00172 }
00173
00174 int roc::ReadoutApplication::SusiboAddr(int index) const
00175 {
00176 if ((index < 0) || (index >= NumSusibo()))
00177 return 0;
00178 return Par(FORMAT(("%s%d", roc::xmlSusiboAddr, index))).AsInt();
00179 }
00180
00181 std::string roc::ReadoutApplication::SlaveAddr(int index) const
00182 {
00183 if ((index < 0) || (index >= NumSlaves()))
00184 return "";
00185 return Par(FORMAT(("%s%d", xmlSlaveAddr, index))).AsStdStr();
00186 }
00187
00188 std::string roc::ReadoutApplication::MbsAddr(int index) const
00189 {
00190 if ((index < 0) || (index >= NumMbs()))
00191 return "";
00192 return Par(FORMAT(("%s%d", roc::xmlMbsAddr, index))).AsStdStr();
00193 }
00194
00195 int roc::ReadoutApplication::NumOpticRocs()
00196 {
00197 int cnt(0);
00198 for (int n = 0; n < NumRocs(); n++)
00199 if (roc::Board::IsOpticAddress(RocAddr(n).c_str()) != 0) cnt++;
00200 return cnt;
00201 }
00202
00203
00204 int roc::ReadoutApplication::NumUdpRocs()
00205 {
00206 int cnt(0);
00207 for (int n = 0; n < NumRocs(); n++)
00208 if (roc::Board::IsOpticAddress(RocAddr(n).c_str()) == 0) cnt++;
00209 return cnt;
00210 }
00211
00212
00213 bool roc::ReadoutApplication::CreateRawOpticInput(const std::string& portname, const std::string& rocaddr, bool isfirstoptic, int numoptics)
00214 {
00215 DOUT2(("Creating raw optic readout for board %s", rocaddr.c_str()));
00216
00217 std::string opticdevname = "AbbDev";
00218 std::string opticthrdname = "AbbDevThrd";
00219
00220 if (isfirstoptic) {
00221
00222
00223 dabc::CmdCreateDevice cmd2(roc::typeAbbDevice, opticdevname.c_str(), opticthrdname.c_str());
00224
00225
00226 if (!dabc::mgr.Execute(cmd2)) {
00227 EOUT(("Cannot create AbbDevice"));
00228 return false;
00229 }
00230
00231
00232 dabc::CmdCreateTransport cmd4(portname, opticdevname.c_str(), opticthrdname.c_str());
00233
00234 cmd4.SetStr(roc::xmlBoardAddr, rocaddr);
00235
00236
00237
00238
00239 cmd4.SetBool("WithMbsHeader", true);
00240 cmd4.SetBool("ManyRocs", numoptics > 1);
00241
00242 if (!dabc::mgr.Execute(cmd4)) {
00243 EOUT(("Cannot connect splitter module to ABB device"));
00244 return false;
00245 }
00246
00247 DOUT0(("Raw optic transport for board %s created!", rocaddr.c_str()));
00248
00249 } else {
00250
00251 dabc::Command cmd9("AddExtraBoard");
00252 cmd9.SetStr(roc::xmlBoardAddr, rocaddr);
00253 cmd9.SetReceiver(opticdevname.c_str());
00254 if (!dabc::mgr.Execute(cmd9)) {
00255 EOUT(("Cannot assign explicit ROC path %s to the AbbDevice", rocaddr.c_str()));
00256 return false;
00257 }
00258
00259 DOUT0(("Addition board %s for raw optic transport appended!", rocaddr.c_str()));
00260 }
00261
00262 return true;
00263 }
00264
00265 bool roc::ReadoutApplication::CreateRawUdpInput(const std::string& portname, const std::string& rocaddr, int rocindx)
00266 {
00267 DOUT0(("Creating raw Ethernet readout for board %s", rocaddr.c_str()));
00268
00269 std::string devname = dabc::format("Roc%udev", rocindx);
00270 std::string thrdname = "RocReadoutThrd";
00271
00272 dabc::CmdCreateDevice cmd6(roc::typeUdpDevice, devname.c_str(),
00273 thrdname.c_str());
00274 cmd6.SetStr(roc::xmlBoardAddr, rocaddr);
00275 cmd6.SetStr(roc::xmlRole, base::roleToString(base::roleDAQ));
00276
00277 if (!dabc::mgr.Execute(cmd6)) {
00278 EOUT(("Cannot create device %s for roc %s", devname.c_str(), rocaddr.c_str()));
00279 return false;
00280 }
00281
00282 dabc::CmdCreateTransport cmd7(portname.c_str(), devname.c_str(), thrdname.c_str());
00283 cmd7.SetStr(roc::xmlBoardAddr, rocaddr);
00284 cmd7.SetBool("WithMbsHeader", true);
00285
00286 if (!dabc::mgr.Execute(cmd7)) {
00287 EOUT(("Cannot connect readout module to device %s", devname.c_str()));
00288 return false;
00289 }
00290
00291 DOUT0(("Raw Ethernet readout created"));
00292
00293 return true;
00294 }
00295
00296
00297
00298 bool roc::ReadoutApplication::CreateRocCombiner(const char* modulename,
00299 bool bnetmode, const char* inppoolname, const char* outpoolname,
00300 unsigned buffersize, int numoutputs, bool skiperrordata,
00301 roc::BoardsVector& brds)
00302 {
00303 int numoptic(0);
00304 for (unsigned n = 0; n < brds.size(); n++)
00305 if (roc::Board::IsOpticAddress(brds[n].rocname.c_str()) != 0)
00306 numoptic++;
00307
00308 dabc::CmdCreateModule cmd1("roc::CombinerModule", modulename, "RocCombThrd");
00309 cmd1.SetBool(roc::xmlBnetMode, bnetmode);
00310 cmd1.SetStr(dabc::xmlInputPoolName, inppoolname);
00311 cmd1.SetStr(dabc::xmlOutputPoolName, outpoolname);
00312 cmd1.SetInt(dabc::xmlBufferSize, buffersize);
00313 cmd1.SetInt(dabc::xmlNumInputs, brds.size());
00314 cmd1.SetInt(dabc::xmlNumOutputs, numoutputs);
00315 cmd1.SetBool(roc::xmlSkipErrorData, skiperrordata);
00316
00317 bool res = dabc::mgr.Execute(cmd1);
00318 DOUT3(("Create ROC combiner module = %s", DBOOL(res)));
00319 if (!res) return false;
00320
00321 std::string devname, devtype, thrdname, opticdevname, opticthrdname;
00322
00323 if (numoptic > 0) {
00324
00325
00326 opticdevname = "AbbDev";
00327 opticthrdname = "AbbDevThrd";
00328
00329 dabc::CmdCreateDevice cmd2(roc::typeAbbDevice, opticdevname.c_str(),
00330 opticthrdname.c_str());
00331
00332
00333 if (!dabc::mgr.Execute(cmd2)) {
00334 EOUT(("Cannot create AbbDevice"));
00335 return false;
00336 }
00337
00338 brds.addDLMDev(opticdevname);
00339
00340 if (numoptic > 1) {
00341 DOUT0(("Create optical splitter module"));
00342
00343 dabc::CmdCreateModule cmd3("roc::SplitterModule", "Splitter",
00344 "RocCombThrd");
00345 cmd3.SetInt(dabc::xmlBufferSize, buffersize);
00346 cmd3.SetStr(dabc::xmlPoolName, inppoolname);
00347 cmd3.SetInt(dabc::xmlNumOutputs, numoptic);
00348 if (!dabc::mgr.Execute(cmd3)) {
00349 EOUT(("Cannot create optic Splitter module"));
00350 return false;
00351 }
00352
00353 dabc::CmdCreateTransport cmd4("Splitter/Input", opticdevname.c_str(),
00354 opticthrdname.c_str());
00355 cmd4.SetStr(roc::xmlBoardAddr, "none");
00356
00357 if (!dabc::mgr.Execute(cmd4)) {
00358 EOUT(("Cannot connect splitter module to ABB device"));
00359 return false;
00360 }
00361 }
00362 }
00363
00364 int splitterid(0);
00365
00366 for (unsigned n = 0; n < brds.size(); n++) {
00367
00368 DOUT3(("Start configure ROC%u", n));
00369
00370 std::string rocaddr = brds[n].rocname;
00371 std::string portname = dabc::format("%s/Input%u", modulename, n);
00372
00373 bool isoptic = roc::Board::IsOpticAddress(rocaddr.c_str()) != 0;
00374
00375 int infoid = -1;
00376
00377 if (isoptic) {
00378
00379 devname = opticdevname;
00380
00381 dabc::Command cmd5;
00382
00383 if (numoptic == 1) {
00384 cmd5 = dabc::CmdCreateTransport(portname.c_str(),
00385 opticdevname.c_str(), opticthrdname.c_str());
00386 cmd5.SetStr(roc::xmlBoardAddr, rocaddr);
00387 } else {
00388 cmd5 = dabc::CmdConnectPorts(dabc::format("Splitter/Output%d", splitterid).c_str(),
00389 portname.c_str());
00390 infoid = splitterid;
00391 splitterid++;
00392 }
00393
00394 if (!dabc::mgr.Execute(cmd5)) {
00395 EOUT(("Cannot provide connection for ROC %s", rocaddr.c_str()));
00396 return false;
00397 }
00398 } else {
00399
00400 devname = dabc::format("Roc%udev", n);
00401 thrdname = "RocReadoutThrd";
00402
00403
00404 brds.addDLMDev(devname);
00405
00406 dabc::CmdCreateDevice cmd6(roc::typeUdpDevice, devname.c_str(),
00407 thrdname.c_str());
00408 cmd6.SetStr(roc::xmlBoardAddr, rocaddr);
00409 cmd6.SetStr(roc::xmlRole, base::roleToString(base::roleDAQ));
00410
00411 if (!dabc::mgr.Execute(cmd6)) {
00412 EOUT(("Cannot create device %s for roc %s", devname.c_str(), rocaddr.c_str()));
00413 return false;
00414 }
00415
00416 dabc::CmdCreateTransport cmd7(portname.c_str(), devname.c_str(),
00417 thrdname.c_str());
00418 cmd7.SetStr(roc::xmlBoardAddr, rocaddr);
00419
00420 if (!dabc::mgr.Execute(cmd7)) {
00421 EOUT(("Cannot connect readout module to device %s", devname.c_str()));
00422 return false;
00423 }
00424 }
00425
00426 roc::CmdGetBoardPtr cmd8;
00427 cmd8.SetStr(roc::xmlBoardAddr, rocaddr);
00428 cmd8.SetReceiver(devname.c_str());
00429 roc::Board* brd = 0;
00430 if (dabc::mgr.Execute(cmd8))
00431 brd = (roc::Board*) cmd8.GetPtr(roc::CmdGetBoardPtr::Board());
00432
00433 if (brd == 0) {
00434 EOUT(("Cannot get board pointer from device %s", devname.c_str()));
00435 return false;
00436 }
00437
00438 brds.setBoard(n, brd, devname);
00439
00440 if (infoid >= 0) {
00441 dabc::Command cmd9("AddExtraBoard");
00442 cmd9.SetStr(roc::xmlBoardAddr, rocaddr);
00443 cmd9.SetReceiver(opticdevname.c_str());
00444 if (!dabc::mgr.Execute(cmd9)) {
00445 EOUT(("Cannot assign explicit ROC path %s to the AbbDevice", rocaddr.c_str()));
00446 return false;
00447 }
00448
00449
00450 dabc::Command cmd10("AddROC");
00451 cmd10.SetInt("ROCID", brd->rocNumber());
00452 cmd10.SetReceiver("Splitter");
00453 if (!dabc::mgr.Execute(cmd10)) {
00454 EOUT(("Cannot ADD ROCID %d to splitter", brd->rocNumber()));
00455 return false;
00456 }
00457 }
00458
00459 dabc::Command cmd11("ConfigureInput");
00460
00461 cmd11.SetInt("Input", n);
00462 cmd11.SetBool("IsUdp", brd->getTransportKind() == roc::kind_UDP);
00463 cmd11.SetInt("ROCID", brd->rocNumber());
00464 cmd11.SetInt("Format", brd->getMsgFormat());
00465 cmd11.SetReceiver(modulename);
00466 if (!dabc::mgr.Execute(cmd11)) {
00467 EOUT(("Cannot configure input %u of combiner module!!!", n));
00468 return false;
00469 }
00470
00471 DOUT2(("Did configure input%d as ROC%u addr:%s", n, brd->rocNumber(), rocaddr.c_str()));
00472 }
00473
00474 return true;
00475 }
00476
00477 bool roc::ReadoutApplication::CreateAppModules()
00478 {
00479 fCalibrState = calNONE;
00480 fFileOutPort.clear();
00481
00482 DOUT2(("CreateAppModules starts..."));
00483
00484 fRawReadout = Par(roc::xmlRawReadout).AsBool(true);
00485
00486 bool res = false;
00487
00488 dabc::lgr()->SetLogLimit(10000000);
00489
00490 unsigned bufsize = Par(dabc::xmlBufferSize).AsInt(8192);
00491
00492
00493 if (DoRawReadout()) bufsize+=100;
00494
00495 DOUT2(("Create ROC POOL %d x %d", bufsize, Par(dabc::xmlNumBuffers).AsInt(100)));
00496
00497 dabc::mgr.CreateMemoryPool(roc::xmlRocPool, bufsize, Par(dabc::xmlNumBuffers).AsInt(100));
00498
00499 bool isepics = !EpicsStreamNode().empty() || !EpicsTransportNode().empty();
00500
00501 int num_super_inputs = 0;
00502 int nsuperinp = 0;
00503
00504
00505 int num_optic_rocs = NumOpticRocs();
00506 int num_udp_rocs = NumUdpRocs();
00507
00508 if (DoRawReadout()) {
00509 num_super_inputs = NumMbs() + NumSlaves() + num_udp_rocs + (num_optic_rocs>0 ? 1 : 0) +
00510 NumSusibo() + (NumTRBs()>0 ? 1 : 0) + (isepics ? 1 : 0);
00511
00512 fSuperCombiner = true;
00513 } else {
00514 fDoMeasureADC = (NumRocs() > 0) && Par(roc::xmlMeasureADC).AsBool(false);
00515 num_super_inputs = NumMbs() + NumSlaves() + (NumRocs() > 0 ? 1 : 0)
00516 + (NumSusibo() > 0 ? 1 : 0) + (NumTRBs() > 0 ? 1 : 0) + (isepics ? 1 : 0);
00517 fSuperCombiner = (num_super_inputs > 1) || ((num_super_inputs==1) && (NumRocs()==0));
00518
00519 if (NumMbs() > 2) {
00520 EOUT(("For a moment maximum two MBS input are supported in synchronized readout"));
00521 exit(345);
00522 }
00523
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533 if (DoSuperCombiner()) {
00534
00535 if (DoRawReadout()) {
00536 dabc::CmdCreateModule cmd4("dabc::MultiplexerModule", nameSuperComb, "SuperCombThrd");
00537 cmd4.SetStr(dabc::xmlPoolName, roc::xmlRocPool);
00538 cmd4.SetInt(dabc::xmlNumInputs, num_super_inputs);
00539 cmd4.SetInt(dabc::xmlNumOutputs, 2);
00540 cmd4.SetStr("DataRateName","RawData");
00541 res = dabc::mgr.Execute(cmd4);
00542 DOUT3(("Create RAW super combiner module = %s", DBOOL(res)));
00543 if (!res) return false;
00544
00545 fServerOutPort = dabc::format("%s/Output0", nameSuperComb);
00546 fFileOutPort = dabc::format("%s/Output1", nameSuperComb);
00547
00548 } else {
00549 dabc::CmdCreateModule cmd4("mbs::CombinerModule", nameSuperComb, "SuperCombThrd");
00550 cmd4.SetStr(dabc::xmlPoolName, roc::xmlRocPool);
00551 cmd4.SetInt(dabc::xmlNumInputs, num_super_inputs);
00552 cmd4.SetBool(mbs::xmlNormalOutput, false);
00553 cmd4.SetBool(mbs::xmlFileOutput, true);
00554 cmd4.SetBool(mbs::xmlServerOutput, DataServerKind().length() > 0);
00555 cmd4.SetBool(mbs::xmlCombineCompleteOnly,
00556 Par(mbs::xmlCombineCompleteOnly).AsBool(false));
00557 cmd4.SetStr(mbs::xmlCombinerRatesPrefix, "Super");
00558
00559 cmd4.SetInt(mbs::xmlEvidMask, 0xffffff);
00560
00561 res = dabc::mgr.Execute(cmd4);
00562 DOUT3(("Create super combiner module = %s", DBOOL(res)));
00563 if (!res) return false;
00564
00565 fServerOutPort = dabc::format("%s/%s", nameSuperComb, mbs::portServerOutput);
00566 fFileOutPort = dabc::format("%s/%s", nameSuperComb, mbs::portFileOutput);
00567
00568 }
00569 }
00570
00571
00572 for (int nmbs = 0; nmbs < NumMbs(); nmbs++) {
00573 dabc::CmdCreateTransport cmd5(
00574 FORMAT(("%s/Input%d", nameSuperComb, nsuperinp)),
00575 mbs::typeClientTransport, "MbsReadoutThrd");
00576 cmd5.SetStr(mbs::xmlServerName, MbsAddr(nmbs));
00577 cmd5.SetStr(mbs::xmlServerKind,
00578 mbs::ServerKindToStr(mbs::TransportServer));
00579 res = dabc::mgr.Execute(cmd5);
00580 DOUT1(("Created MBS client transport for node %s : result is %s", MbsAddr(nmbs).c_str(), DBOOL(res)));
00581 if (!res) return false;
00582
00583 if (!DoRawReadout()) {
00584 dabc::Command cmd6("ConfigureInput");
00585 cmd6.SetInt("Port", nsuperinp);
00586 cmd6.SetBool("RealMbs", true);
00587 cmd6.SetBool("RealEvntNum", false);
00588 cmd6.SetUInt("EvntSrcFullId",
00589 Par(FORMAT(("%s%d", roc::xmlSyncSubeventId, nmbs))).AsInt(0));
00590 cmd6.SetUInt("EvntSrcShift", 0);
00591 cmd6.SetStr("RateName", "MbsData");
00592 cmd6.SetReceiver(nameSuperComb);
00593 res = dabc::mgr.Execute(cmd6);
00594 DOUT1(("Configure special MBS case as supercombiner input %d : result is %s", nsuperinp, DBOOL(res)));
00595 if (!res) return false;
00596 }
00597
00598 nsuperinp++;
00599 }
00600
00601
00602
00603 for (int nslave = 0; nslave < NumSlaves(); nslave++) {
00604
00605 if (!ConnectSlave(nslave, nsuperinp)) return false;
00606
00607 if (fFirstSlavePort<0) fFirstSlavePort = nsuperinp;
00608
00609 nsuperinp++;
00610 }
00611
00612
00613
00614
00615 if (NumRocs() > 0) {
00616
00617 fRocBrds.returnBoards();
00618
00619 if (DoRawReadout()) {
00620 bool isfirstoptic(true);
00621
00622 for (int nroc = 0; nroc < NumRocs(); nroc++) {
00623 std::string portname = dabc::format("%s/Input%d", nameSuperComb, nsuperinp);
00624
00625 if (roc::Board::IsOpticAddress(RocAddr(nroc).c_str()) != 0) {
00626 res = CreateRawOpticInput(portname, RocAddr(nroc), isfirstoptic, num_optic_rocs);
00627 if (!res) return false;
00628
00629 if (isfirstoptic) nsuperinp++;
00630
00631 isfirstoptic = false;
00632 } else {
00633
00634 res = CreateRawUdpInput(portname, RocAddr(nroc), nroc);
00635 if (!res) return false;
00636 nsuperinp++;
00637 }
00638
00639
00640 }
00641
00642 } else {
00643 for (int n = 0; n < NumRocs(); n++)
00644 fRocBrds.addRoc(RocAddr(n),
00645 Par(FORMAT(("%s%d", xmlRocFebs, n))).AsStdStr());
00646
00647 res = CreateRocCombiner(nameRocComb,
00648 false,
00649 roc::xmlRocPool,
00650 roc::xmlRocPool,
00651 Par(dabc::xmlBufferSize).AsInt(16 * 1024),
00652 2,
00653 fSuperCombiner,
00654 fRocBrds);
00655
00656 if (res && fDoMeasureADC)
00657 for (unsigned n = 0; n < fRocBrds.size(); n++)
00658 for (int nfeb = 0; nfeb < 2; nfeb++)
00659 for (int nadc = 0; nadc < fRocBrds.numAdc(n, nfeb); nadc++) {
00660 std::string parname = dabc::format("ROC%u_FEB%d_ADC%d",
00661 fRocBrds[n].brd->rocNumber(), nfeb, nadc);
00662 CreatePar(parname);
00663 }
00664
00665 if (!res) return false;
00666
00667
00668 if (DoSuperCombiner()) {
00669
00670 dabc::Command cmd7("ConfigureInput");
00671 cmd7.SetInt("Port", nsuperinp);
00672 cmd7.SetBool("RealMbs", false);
00673 cmd7.SetBool("RealEvntNum", true);
00674 cmd7.SetReceiver(nameSuperComb);
00675 res = dabc::mgr.Execute(cmd7);
00676 DOUT1(("Configure ROC as supercombiner input %d : result is %s", nsuperinp, DBOOL(res)));
00677 if (!res) return false;
00678
00679 dabc::mgr.Connect(dabc::format("%s/Output0", nameRocComb),
00680 dabc::format("%s/Input%d", nameSuperComb, nsuperinp));
00681
00682 nsuperinp++;
00683 } else {
00684 fServerOutPort = dabc::format("%s/Output0", nameRocComb);
00685 fFileOutPort = dabc::format("%s/Output1", nameRocComb);
00686 }
00687 }
00688
00689
00690 }
00691
00692 if (NumSusibo() > 0) {
00693
00694 if (!DoRawReadout()) {
00695 dabc::CmdCreateModule cmd41("mbs::CombinerModule", nameSusiboComb, "SusiboCombThrd");
00696 cmd41.SetStr(dabc::xmlPoolName, roc::xmlRocPool);
00697 cmd41.SetInt(dabc::xmlNumInputs, NumSusibo());
00698 cmd41.SetBool(mbs::xmlNormalOutput, true);
00699 cmd41.SetBool(mbs::xmlFileOutput, true);
00700 cmd41.SetBool(mbs::xmlServerOutput, true);
00701 cmd41.SetBool(mbs::xmlCombineCompleteOnly, false);
00702 cmd41.SetInt(mbs::xmlEvidMask, 0xffffff);
00703 cmd41.SetStr(mbs::xmlCombinerRatesPrefix, "Spadic");
00704 res = dabc::mgr.Execute(cmd41);
00705 DOUT3(("Create susibo combiner module = %s", DBOOL(res)));
00706 if (!res) return false;
00707 }
00708
00709 for (int n = 0; n < NumSusibo(); n++) {
00710
00711 std::string portname = dabc::format("%s/Input%d", nameSusiboComb, n);
00712
00713 if (DoRawReadout()) portname = dabc::format("%s/Input%d", nameSuperComb, nsuperinp++);
00714
00715 dabc::CmdCreateTransport cmd42(portname, "spadic::SusiboInput");
00716
00717 cmd42.SetStr("SusiboAddr-", FORMAT(("SusiboInput%d", n)));
00718 cmd42.SetInt("SusiboID-", SusiboAddr(n));
00719 cmd42.SetInt("EventsInBuffer", Par("EventsInBuffer").AsInt(1));
00720 cmd42.SetInt("HitDelay", Par("HitDelay").AsInt(200));
00721 cmd42.SetDouble("PollingTimeout", Par("PollingTimeout").AsDouble(0.01));
00722
00723 cmd42.SetInt("SusiboMbsFormat", true);
00724
00725 res = dabc::mgr.Execute(cmd42);
00726 if (res==0) return false;
00727 }
00728
00729 if (!DoRawReadout()) {
00730 dabc::mgr.Connect(dabc::format("%s/%s", nameSusiboComb, mbs::portOutput),
00731 dabc::format("%s/Input%d", nameSuperComb, nsuperinp));
00732
00733 dabc::Command cmd71("ConfigureInput");
00734 cmd71.SetInt("Port", nsuperinp);
00735 cmd71.SetBool("RealMbs", false);
00736 cmd71.SetBool("RealEvntNum", true);
00737 cmd71.SetBool("Optional", true);
00738 cmd71.SetReceiver(nameSuperComb);
00739 res = dabc::mgr.Execute(cmd71);
00740 DOUT1(("Configure Susibo as supercombiner input %d : result is %s", nsuperinp, DBOOL(res)));
00741 if (!res) return false;
00742
00743 nsuperinp++;
00744 }
00745 }
00746
00747 if (NumTRBs() > 0) {
00748
00749 dabc::CmdCreateModule cmd3("hadaq::CombinerModule", nameTRBComb, "TRBCombThrd");
00750 cmd3.SetStr(dabc::xmlPoolName, roc::xmlRocPool);
00751 cmd3.SetInt(dabc::xmlNumInputs, NumTRBs());
00752 cmd3.SetBool(mbs::xmlNormalOutput, true);
00753 cmd3.SetInt(dabc::xmlBufferSize, (int) bufsize*0.7);
00754
00755
00756 res = dabc::mgr.Execute(cmd3);
00757 DOUT0(("Create TRB combiner module = %s", DBOOL(res)));
00758 if (res==0) return false;
00759
00760 for (int n=0;n<NumTRBs();n++) {
00761 dabc::CmdCreateTransport cmd31(FORMAT(("%s/Input%d", nameTRBComb, n)), "hadaq::UdpInput", "HadaqUdpThrd");
00762 cmd31.SetStr("HadaqUdpPort", TRBAddr(n));
00763 cmd31.SetInt(dabc::xmlBufferSize, bufsize);
00764 cmd31.SetInt("HadaqUdpBuffer", bufsize);
00765 res = dabc::mgr.Execute(cmd31);
00766 DOUT0(("Create input %d addr %s TRB combiner module = %s", n, TRBAddr(n).c_str(), DBOOL(res)));
00767 if (res==0) return false;
00768 }
00769
00770 dabc::CmdCreateModule cmd32("hadaq::MbsTransmitterModule", nameTRBTrans, "TRBOnlineThrd");
00771 cmd32.SetStr(dabc::xmlPoolName, roc::xmlRocPool);
00772 cmd32.SetInt(dabc::xmlBufferSize, bufsize);
00773 res = dabc::mgr.Execute(cmd32);
00774 DOUT0(("Create TRB transmitter module = %s", DBOOL(res)));
00775 if (res==0) return false;
00776 dabc::mgr.Connect(dabc::format("%s/%s", nameTRBComb, mbs::portOutput),
00777 dabc::format("%s/%s", nameTRBTrans, mbs::portInput));
00778
00779
00780 dabc::mgr.Connect(dabc::format("%s/%s", nameTRBTrans, mbs::portOutput),
00781 dabc::format("%s/Input%d", nameSuperComb, nsuperinp));
00782
00783 if (!DoRawReadout()) {
00784 dabc::Command cmd72("ConfigureInput");
00785 cmd72.SetInt("Port", nsuperinp);
00786 cmd72.SetBool("RealMbs", false);
00787 cmd72.SetBool("RealEvntNum", true);
00788 cmd72.SetBool("Optional", true);
00789 cmd72.SetReceiver(nameSuperComb);
00790 res = dabc::mgr.Execute(cmd72);
00791 DOUT1(("Configure TRB as supercombiner input %d : result is %s", nsuperinp, DBOOL(res)));
00792 if (!res) return false;
00793 }
00794
00795 nsuperinp++;
00796 }
00797
00798 if (isepics) {
00799 dabc::CmdCreateTransport cmd8(
00800 FORMAT(("%s/Input%d", nameSuperComb, nsuperinp)),
00801 mbs::typeClientTransport, "MbsReadoutThrd");
00802 if (!EpicsStreamNode().empty()) {
00803 cmd8.SetStr(mbs::xmlServerName, EpicsStreamNode());
00804 cmd8.SetStr(mbs::xmlServerKind, mbs::ServerKindToStr(mbs::StreamServer));
00805 } else {
00806 cmd8.SetStr(mbs::xmlServerName, EpicsTransportNode());
00807 cmd8.SetStr(mbs::xmlServerKind, mbs::ServerKindToStr(mbs::TransportServer));
00808 }
00809 cmd8.SetDouble(dabc::xmlConnTimeout, 5.);
00810 res = dabc::mgr.Execute(cmd8);
00811 DOUT0(("Created EPICS client transport result is %s", DBOOL(res)));
00812 if (!res) return false;
00813
00814 dabc::Command cmd9("ConfigureInput");
00815 cmd9.SetInt("Port", nsuperinp);
00816 cmd9.SetBool("RealMbs", false);
00817 cmd9.SetBool("RealEvntNum", false);
00818 cmd9.SetBool("NoEvntNum", true);
00819 cmd9.SetReceiver(nameSuperComb);
00820 res = dabc::mgr.Execute(cmd9);
00821
00822 DOUT1(("Configure special EPICS case as supercombiner input %d : result is %s", nsuperinp, DBOOL(res)));
00823 if (!res) return false;
00824
00825 nsuperinp++;
00826 }
00827
00828 if (!OutputFileName().empty() && !fFileOutPort.empty()) {
00829 if (!StartFile(OutputFileName())) return false;
00830 }
00831
00832 if (!DataServerKind().empty() && !fServerOutPort.empty()) {
00833
00835
00836 dabc::CmdCreateTransport cmd13(fServerOutPort.c_str(),
00837 mbs::typeServerTransport, "MbsServerThrd");
00838
00839 cmd13.SetStr(mbs::xmlServerKind, DataServerKind());
00840
00841
00842
00843
00844 res = dabc::mgr.Execute(cmd13);
00845 DOUT0(("Connected module port %s to Mbs server res = %s", fServerOutPort.c_str(), DBOOL(res)));
00846 if (!res) return false;
00847 }
00848
00849 return true;
00850 }
00851
00852 bool roc::ReadoutApplication::StartFile(const std::string& filename)
00853 {
00854 if (fFileOutPort.empty()) {
00855 EOUT(("Cannot create file output - no appropriate port specified"));
00856 return false;
00857 }
00858
00859 dabc::CmdCreateTransport cmd11(fFileOutPort, mbs::typeLmdOutput);
00860
00861 cmd11.SetStr(mbs::xmlFileName, filename);
00862
00863 if (fMasterNode) {
00864 cmd11.SetStr("InfoPar", "RunInfo");
00865 } else {
00866 CreatePar("FileInfo","info").SetSynchron(true, 2., false).SetStr("nofile");
00867 cmd11.SetStr("InfoPar", "FileInfo");
00868 }
00869
00870 bool res = dabc::mgr.Execute(cmd11);
00871 DOUT1(("Create lmd file %s for %s, res = %s", filename.c_str(), fFileOutPort.c_str(), DBOOL(res)));
00872 return res;
00873 }
00874
00875 bool roc::ReadoutApplication::StopFile()
00876 {
00877 if (fFileOutPort.find(nameSuperComb)!=0) {
00878 EOUT(("File port connected not to the super combiner!!!"));
00879 dabc::PortRef port = dabc::mgr.FindPort(fFileOutPort);
00880 if (!port.null()) port()->Disconnect();
00881 }
00882
00883 return dabc::mgr.FindModule(nameSuperComb).Execute(mbs::comStopFile);
00884
00885
00886
00887
00888
00889 }
00890
00891 bool roc::ReadoutApplication::ConnectSlave(int nslave, int ninp)
00892 {
00893 dabc::CmdCreateTransport cmd21(
00894 FORMAT(("%s/Input%d", nameSuperComb, ninp)),
00895 mbs::typeClientTransport, "SlaveReadoutThrd");
00896 cmd21.SetStr(mbs::xmlServerName, SlaveAddr(nslave));
00897 cmd21.SetStr(mbs::xmlServerKind,
00898 mbs::ServerKindToStr(mbs::TransportServer));
00899 cmd21.SetDouble(dabc::xmlConnTimeout, 5.);
00900 bool res = dabc::mgr.Execute(cmd21);
00901
00902 int slavesubevid = Par(FORMAT(("Slave%s%d", roc::xmlSyncSubeventId, nslave))).AsInt(0);
00903
00904 DOUT1(("Created client transport for slave %s syncid %d: result is %s",
00905 SlaveAddr(nslave).c_str(), slavesubevid, DBOOL(res)));
00906
00907 if (!res) {
00908 DOUT0(("=============================================="));
00909 DOUT0((" ++++++++++ SLAVE %d WAS NOT CONNECTED +++++++++", nslave));
00910 DOUT0(("=============================================="));
00911 if (slavesubevid!=1) return false;
00912 }
00913
00914 if (DoRawReadout()) return true;
00915
00916 if (slavesubevid==0) {
00917 DOUT1(("Configure slave %d input as normal MBS input", nslave));
00918 } else
00919 if (slavesubevid==1) {
00920 DOUT1(("Configure slave %d input as optional MBS input - can be used for FASP", nslave));
00921 dabc::Command cmd22("ConfigureInput");
00922 cmd22.SetInt("Port", ninp);
00923 cmd22.SetBool("RealMbs", false);
00924 cmd22.SetBool("RealEvntNum", true);
00925 cmd22.SetBool("Optional", true);
00926 cmd22.SetReceiver(nameSuperComb);
00927 res = dabc::mgr.Execute(cmd22);
00928 DOUT1(("Configure client for slave %d as optional supercombiner input %d : result is %s",
00929 nslave, ninp, DBOOL(res)));
00930 } else {
00931 DOUT1(("Configure slave %d input as ubnormal MBS input with event number in subeventid 0x%x ", nslave, slavesubevid));
00932
00933 dabc::Command cmd22("ConfigureInput");
00934 cmd22.SetInt("Port", ninp);
00935 cmd22.SetBool("RealMbs", false);
00936 cmd22.SetBool("RealEvntNum", false);
00937 cmd22.SetUInt("EvntSrcFullId", slavesubevid);
00938 cmd22.SetUInt("EvntSrcShift", 0);
00939 cmd22.SetStr("RateName", "SlaveData");
00940
00941 cmd22.SetReceiver(nameSuperComb);
00942 res = dabc::mgr.Execute(cmd22);
00943 DOUT1(("Configure client for slave %d as supercombiner input %d : result is %s",
00944 nslave, ninp, DBOOL(res)));
00945 }
00946 return res;
00947 }
00948
00949
00950 bool roc::ReadoutApplication::AfterAppModulesStopped()
00951 {
00952 if (fCalibrState == calON)
00953 SwitchCalibrationMode(false);
00954 return true;
00955 }
00956
00957 bool roc::ReadoutApplication::BeforeAppModulesDestroyed()
00958 {
00959 fRocBrds.returnBoards();
00960
00961 return dabc::Application::BeforeAppModulesDestroyed();
00962 }
00963
00964 bool roc::ReadoutApplication::IsModulesRunning()
00965 {
00966 if (!DoRawReadout()) {
00967
00968 if ((NumRocs() > 0) && !dabc::mgr.FindModule(nameRocComb).IsRunning())
00969 return false;
00970
00971 if ((NumSusibo() > 0) && !dabc::mgr.FindModule(nameSusiboComb).IsRunning())
00972 return false;
00973
00974 if ((NumTRBs() > 0) &&
00975 (!dabc::mgr.FindModule(nameTRBComb).IsRunning() || !dabc::mgr.FindModule(nameTRBTrans).IsRunning()))
00976 return false;
00977 }
00978
00979 if (DoSuperCombiner() && !dabc::mgr.FindModule(nameSuperComb).IsRunning())
00980 return false;
00981
00982 return true;
00983 }
00984
00985 int roc::ReadoutApplication::ExecuteCommand(dabc::Command cmd)
00986 {
00987 if (cmd.IsName(roc::CmdCalibration::CmdName())) {
00988 bool flag = cmd.GetBool(roc::CmdCalibration::FlagName(), true);
00989 return cmd_bool(SwitchCalibrationMode(flag));
00990 } else if (cmd.IsName("StartRun")) {
00991 std::string fname = Par("FilePath").AsStdStr();
00992 fname+=Par("RunPrefix").AsStdStr();
00993 int number = Par("RunNumber").AsInt(-1);
00994 if (number >= 0)
00995 fname += dabc::format("run%d.lmd", number);
00996 if (StartFile(fname)) {
00997 Par("RunInfo").SetStr(std::string("Start file ")+fname);
00998 return dabc::cmd_true;
00999 }
01000 Par("RunInfo").SetStr(std::string("Fail open file ")+fname);
01001 return dabc::cmd_false;
01002 } else if (cmd.IsName("StopRun")) {
01003
01004 bool res = StopFile();
01005 int number = Par("RunNumber").AsInt(-1);
01006 if (number >= 0)
01007 Par("RunNumber").SetInt(number + 1);
01008 Par("RunInfo").SetStr("NoRun");
01009 return cmd_bool(res);
01010 } else if (cmd.IsName("SetPrefix")) {
01011
01012 std::string prename = Cfg("Prefix", cmd).AsStdStr();
01013 Par("RunPrefix").SetStr(prename);
01014 DOUT1(("Setting Prefix to %s", prename.c_str()));
01015 return dabc::cmd_true;
01016 } else if (cmd.IsName("SetRunNumber")) {
01017 int number = Cfg("RunNumber", cmd).AsInt();
01018 Par("RunNumber").SetInt(number);
01019 DOUT1(("Setting Run number to %d", number));
01020 return dabc::cmd_true;
01021 } else if (cmd.IsName("SetPrefixTest")) {
01022 std::string prename = "Te_";
01023 Par("RunPrefix").SetStr(prename);
01024 DOUT1(("Setting Prefix to %s", prename.c_str()));
01025 return dabc::cmd_true;
01026 } else if (cmd.IsName("SetPrefixBeam")) {
01027 std::string prename = "Be_";
01028 Par("RunPrefix").SetStr(prename);
01029 DOUT1(("Setting Prefix to %s", prename.c_str()));
01030 return dabc::cmd_true;
01031 } else if (cmd.IsName("SetPrefixCosmics")) {
01032 std::string prename = "Co_";
01033 Par("RunPrefix").SetStr(prename);
01034 DOUT1(("Setting Prefix to %s", prename.c_str()));
01035 return dabc::cmd_true;
01036 } else if (cmd.IsName("IncRunNumber")) {
01037 int number = Par("RunNumber").AsInt(-1);
01038 if (number >= 0)
01039 Par("RunNumber").SetInt(number + 1);
01040 return dabc::cmd_true;
01041 } else if (cmd.IsName("DecRunNumber")) {
01042 int number = Par("RunNumber").AsInt(-1);
01043 if (number >= 0) {
01044 number -= 1;
01045 if (number < 0)
01046 number = 0;
01047 Par("RunNumber").SetInt(number);
01048 return dabc::cmd_true;
01049 }
01050 } else if (cmd.IsName("ResetRunNumber")) {
01051 Par("RunNumber").SetInt(0);
01052 return dabc::cmd_true;
01053 } else if (cmd.IsName("ResetAllGet4")) {
01054 fRocBrds.ResetAllGet4();
01055 return dabc::cmd_true;
01056 } else if (cmd.IsName("ezca::OnUpdate")) {
01057 int id = cmd.GetInt("EpicsFlagRec");
01058 fRocBrds.produceSystemMessage(id+1000);
01059 DOUT0(("Has EZCA command rec = %d", id));
01060 return dabc::cmd_true;
01061 }
01062
01063 return dabc::Application::ExecuteCommand(cmd);
01064 }
01065
01066 bool roc::ReadoutApplication::SwitchCalibrationMode(bool on)
01067 {
01068 if ((fCalibrState == calON) && on)
01069 return true;
01070
01071 if ((fCalibrState == calOFF) && !on)
01072 return true;
01073
01074 DOUT0(("SwitchCalibration %s %5.2f", DBOOL(on), dabc::Now().AsDouble()));
01075
01076 if (on && fDoMeasureADC) {
01077 roc::MessagesVector* vect = fRocBrds.readoutExtraMessages();
01078
01079 if (vect != 0) {
01080
01081 for (unsigned n = 0; n < vect->size(); n++)
01082 if (vect->at(n).isSysMsg()
01083 && vect->at(n).getSysMesType() == roc::SYSMSG_ADC) {
01084 uint32_t val = vect->at(n).getSysMesData();
01085
01086 std::string parname = dabc::format("ROC%u_FEB%d_ADC%d",
01087 vect->at(n).getRocNumber(), val >> 31, (val >> 24) & 0x7f);
01088
01089 Par(parname).SetInt(val & 0xffffff);
01090
01091
01092
01093 }
01094
01095 roc::CmdMessagesVector cmd(vect);
01096 cmd.SetReceiver(nameRocComb);
01097 dabc::mgr.Submit(cmd);
01098 }
01099 }
01100
01101 fRocBrds.autoped_switch(on);
01102
01103
01104
01105
01106 fCalibrState = on ? calON : calOFF;
01107
01108 return true;
01109 }
01110
01111 void roc::ReadoutApplication::ProcessParameterEvent(const dabc::ParameterEvent& evnt)
01112 {
01113
01114
01115 DOUT0(("Get change event for connection %s value %s", evnt.ParName().c_str(), evnt.ParValue().c_str()));
01116
01117 if (evnt.ParValue() == dabc::ConnectionObject::GetStateName(dabc::ConnectionObject::sBroken)) {
01118 DOUT0(("Activate reconnection timeout for slaves"));
01119 fCheckSlavesConn = true;
01120 ActivateTimeout(3);
01121 }
01122 }
01123
01124 double roc::ReadoutApplication::ProcessTimeout(double last_diff)
01125 {
01126 double res = dabc::Application::ProcessTimeout(last_diff);
01127
01128
01129 if (fCheckSlavesConn) {
01130
01131 DOUT0(("!!! Check reconnection for slaves !!!"));
01132
01133 dabc::ModuleRef m = dabc::mgr.FindModule(nameSuperComb);
01134 if (m.null()) { EOUT(("Did not found super combiner !!!")); return res; }
01135
01136 bool tryagain = false;
01137
01138 for (int nslave = 0; nslave < NumSlaves(); nslave++) {
01139
01140 if (m.IsInputConnected(nslave)) continue;
01141
01142 if (!ConnectSlave(nslave, fFirstSlavePort+nslave)) tryagain = true;
01143 }
01144
01145 if (tryagain) {
01146 if ((res<0) || (res>3)) res = 3;
01147 } else
01148 fCheckSlavesConn = false;
01149 }
01150
01151 return res;
01152 }
01153