/******************************************************************************* * Control.cc Control process * T.Barnaby, BEAM Ltd, 2007-02-07 ******************************************************************************* */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <errno.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/mman.h> #include <sys/vfs.h> #include <sys/param.h> #include <sys/time.h> #include <netdb.h> #include <main.h> #include <Control.h> #include <BEntry.h> #include <BDir.h> #include <BString.h> #include <Debug.h> #include <time.h> #include <SigGen.h> #include <TmsLib.h> #include <BFile.h> #define TIME_MS_USE_DATAGET 1 // Convert startTime to orbitNumber for channels after the first DataRequest::DataRequest(DataInfo dataInfo){ dataInfo = dataInfo; } CycleInfo::CycleInfo(UInt32 cycleNumber, BString cycleType){ this->cycleNumber = cycleNumber; this->cycleType = cycleType; } CycleInfoList::CycleInfoList(){ } void CycleInfoList::cycleAdd(UInt32 cycleNumber, BString cycleType){ CycleInfo cycleInfo(cycleNumber, cycleType); olock.lock(); while(olist.number() > numCycles) olist.queueGet(); olist.append(cycleInfo); olock.unlock(); } void CycleInfoList::cycleAddError(UInt32 cycleNumber, BError error){ BIter i; olock.lock(); for(olist.start(i); !olist.isEnd(i); olist.next(i)){ if(olist[i].cycleNumber == cycleNumber){ olist[i].errorList.append(error.copy()); break; } } olock.unlock(); } BList<BError> CycleInfoList::getCycleErrors(UInt32 cycleNumber){ BIter i1, i2; BList<BError> errorList; olock.lock(); for(olist.start(i1); !olist.isEnd(i1); olist.next(i1)){ if(olist[i1].cycleNumber == cycleNumber){ for(olist[i1].errorList.start(i2); !olist[i1].errorList.isEnd(i2); olist[i1].errorList.next(i2)){ errorList.append(olist[i1].errorList[i2].copy()); } break; } } olock.unlock(); return errorList; } ControlTimer::ControlTimer(Control& control) : ocontrol(control){ } void* ControlTimer::function(){ dprintf(DBG_THREADS, "ControlTimerThread: %d\n", gettid()); while(1){ usleep(100000); ocontrol.timer(); } return 0; } Control::Control(int dbFixed) : odataAquire(*this), odebugFixed(dbFixed), ocontrolTimer(*this), otmsControlServer(*this, oboapServer, "tmsControl"), otmsProcessServer(*this, oboapServer, "tmsProcess"), otmsEventServer(*this, oboapServer, "tmsEvent"){ osimulate = 0; ocycleNumberNext = 1; osimulation.timing = 0; osimulation.data = 0; osimulation.setNextCycle = 0; ostartTime = getTime(); ocycleProcessed = 0; onumNextCycleErrors = 0; onumFpgaStateErrors = 0; onumDataGoneErrors = 0; } Control::~Control(){ } BError Control::init(){ BError err; BString s; sched_param sp; dprintf(DBG_CMD, "Control::init\n"); oboapnsHost = config.findValue("TmsServer:"); if(config.findValue("SimulateData:").retInt() == 1) osimulate = 1; else osimulate = 0; if(config.findValue("SimulateNextCycle:").retInt() == 1) osimulation.setNextCycle = 1; else osimulation.setNextCycle = 0; // Set default priority to real-time for all of these threads if(realTime){ // seteuid(0); sp.sched_priority = 25; if(sched_setscheduler(0, SCHED_RR, &sp)) fprintf(stderr, "Warning: unable to set as real-time process\n"); } // Initialise sub systems ocontrolTimer.start(); if(err = oboapServer.init(oboapnsHost, BoapServer::THREADED)){ return err; } #ifdef ZAP if(realTime){ // Set priority back to normal sp.sched_priority = 0; if(sched_setscheduler(0, SCHED_OTHER, &sp)) fprintf(stderr, "Warning: unable to set as normal process\n"); seteuid(getuid()); } #endif err = initCmd(); dprintf(DBG_CMD, "Control::init: End\n"); return err; } void Control::run(){ oboapServer.run(); } void Control::timer(){ static int tick; if(osimulate){ tick++; if(tick == 11){ cycleStartEvent(ocycleNumber.value() + 1); } else if(tick == 12){ tick = 0; } } } BError Control::readCycleParams(){ BError err; BString sptDir = config.findValue("SptDir:"); CycleParamDb cycleParams(sptDir); CycleParam params; BList<BString> fileList; BIter i; // Initialise State/Phase Tables from file based database ocycleParms.clear(); cycleParams.getFileNames(fileList); for(fileList.start(i); !fileList.isEnd(i); fileList.next(i)){ dprintf(DBG_CMD, "Control::readCycleParams: Add CycleType: %s\n", fileList[i].retStr()); if(err = cycleParams.getCycleParams(fileList[i], params)){ wprintf("Cycle Parameters in %s incorrect\n", fileList[i].retStr()); return err; } else { ocycleParms.append(params); } } return err; } BError Control::initCmd(){ BError err; BError err1; unsigned int n; PuServer* puServer; PuChannel chan; BIter i, i1; BString s; dprintf(DBG_CMD, "Control::initCmd\n"); olock.lock(); // Initialise Pickup configuration from configuration file oconfigInfo.puReferences.resize(0); for(n = 1; n <= tmsMaxNumPickups; n++){ s = config.findValue(BString("PickUp") + n + ":"); if(s != ""){ oconfigInfo.puReferences.resize(n); if(sscanf(s, "%hhd,%hhd,%hhd", &chan.moduleNum, &chan.pupeNum, &chan.pupeChan) != 3){ err.set(ErrorConfig, "Pick-Up channel error in configuration file"); eprintf("%s\n", err.getString().retStr()); olock.unlock(); return err; } oconfigInfo.puReferences[n - 1] = chan; } else { break; } } // Remove existing PuServers opuServersLock.wrLock(); for(opuServers.start(i); !opuServers.isEnd(i); ){ delete opuServers[i]; opuServers.del(i); } // Initialise PuModules for(n = 1; n < 9; n++){ if((s = config.findValue(BString("PuServer") + n + ":")) != ""){ dprintf(DBG_CMD, "Control::initCmd: Configure PuServer: %d\n", n); opuServers.append(puServer = new PuServer(*this, n, atoi(s))); if(err1 = puServer->init()){ wprintf("Unable to connect to PuServer: %d\n", n); } else { if(err1 = puServer->initCmd()){ wprintf("Unable to initialise PuServer: %d\n", n); } if(!err1 && (err1 = puServer->configure(oconfigInfo))){ wprintf("Unable to configure PuServer: %d\n", n); } } } } opuServersLock.unlock(); nprintf("Number of PuServers: %d\n", opuServers.number()); // Initialise State/Phase Tables from file based database if(err = readCycleParams()){ olock.unlock(); return err; } if(!osimulate){ for(ocycleParms.start(i1); !ocycleParms.isEnd(i1); ocycleParms.next(i1)){ dprintf(DBG_CMD, "Control::initCmd: Add CycleType: %s\n", ocycleParms[i1].cycleType.retStr()); opuServersLock.rdLock(); for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err1 = opuServers[i]->setControlInfo(ocycleParms[i1])){ wprintf("Module: %d is not available\n", opuServers[i]->getNumber()); } } opuServersLock.unlock(); } } olock.unlock(); // Initialise first cycle s = config.findValue("DefaultCycleType:"); if(s != ""){ setNextCycleInternal(1, s); } olock.lock(); // Clear Stats ostartTime = getTime(); ocycleProcessed = 0; onumNextCycleErrors = 0; onumFpgaStateErrors = 0; onumDataGoneErrors = 0; olock.unlock(); dprintf(DBG_CMD, "Control::initCmd: End\n"); return err; } BError Control::initPuServer(UInt32 number){ BError err; BIter i; BIter i1; opuServersLock.rdLock(); for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(opuServers[i]->getNumber() == number){ err = opuServers[i]->init(); opuServers[i]->configure(oconfigInfo); // Initialise State/Phase Tables from file based database for(ocycleParms.start(i1); !ocycleParms.isEnd(i1); ocycleParms.next(i1)){ dprintf(DBG_CMD, "Control::initPuServer: Add CycleType: %s\n", ocycleParms[i1].cycleType.retStr()); opuServers[i]->setControlInfo(ocycleParms[i1]); } } } opuServersLock.unlock(); return err; } BError Control::setProcessPriority(BUInt32 priority){ BError err; struct sched_param sp; dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__); if(realTime){ sp.sched_priority = 26; if(sched_setscheduler(0, SCHED_RR, &sp)) fprintf(stderr, "Warning: unable to set as real-time process\n"); } return err; } BError Control::configure(ConfigInfo configInfo){ BError err; uint i; BString s; BIter ii; dprintf(DBG_CMD, "Control::configure\n"); // Check parameters if(configInfo.puReferences.size() > tmsMaxNumPickups){ return err.set(ErrorParam, BString("The number of pickups to be configured is greater than: ") + tmsMaxNumPickups); } for(i = 0; i < configInfo.puReferences.size(); i++){ if(configInfo.puReferences[i].moduleNum > 4) return err.set(ErrorParam, BString("The moduleNum parameter is too large")); if(configInfo.puReferences[i].pupeNum > 7) return err.set(ErrorParam, BString("The pupeNum parameter is too large")); if(configInfo.puReferences[i].pupeChan > 3) return err.set(ErrorParam, BString("The pupeChan parameter is too large")); } olock.lock(); oconfigInfo = configInfo; olock.unlock(); // Save configuration to file config.read(); for(i = 0; i < configInfo.puReferences.size(); i++){ s.printf("%d,%d,%d", configInfo.puReferences[i].moduleNum, configInfo.puReferences[i].pupeNum, configInfo.puReferences[i].pupeChan); config.setValue(BString("PickUp") + (i + 1) + ":", s); } // Clear further entries here for(i = configInfo.puReferences.size(); i < tmsMaxNumPickups; i++){ config.deleteEntry(BString("PickUp") + (i + 1) + ":"); } config.write(); olock.lock(); if(!osimulate){ // Inform all Module Controllers opuServersLock.rdLock(); for(opuServers.start(ii); !opuServers.isEnd(ii); opuServers.next(ii)){ if(err = opuServers[ii]->configure(configInfo)){ eprintf("Unable to send configuration to module controller: %s\n", err.getString().retStr()); break; } } opuServersLock.unlock(); } olock.unlock(); return err; } BError Control::getConfiguration(ConfigInfo& configInfo){ BError err; dprintf(DBG_CMD, "Control::getConfiguration: Return: %d\n", oconfigInfo.puReferences.size()); olock.lock(); configInfo = oconfigInfo; olock.unlock(); return err; } BError Control::test(BList<BError>& errors){ BError errRet; BError err; BIter i; BIter i1; BList<BError> errList; dprintf(DBG_CMD, "Control::test\n"); opuServersLock.rdLock(); if(!osimulate){ // Local tests // Disk space if(diskSpace("/") < 1000){ errors.append(BError(1, "TmsServer: Diskspace /: Low")); } else { errors.append(BError(0, "TmsServer: Diskspace /: Ok")); } if(diskSpace("/data") < 1000){ errors.append(BError(1, "TmsServer: Diskspace /data: Low")); } else { errors.append(BError(0, "TmsServer: Diskspace /data: Ok")); } // Memory if(memoryFree() < 200){ errors.append(BError(1, "TmsServer: Memory: Low")); } else { errors.append(BError(0, "TmsServer: Memory: Ok")); } for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err = opuServers[i]->test(errList)){ errors.append(BError(err.getErrorNo(), BString("Module") + opuServers[i]->getNumber() + ": Status: " + err.getString())); } else { errors.append(BError(0, BString("Module") + opuServers[i]->getNumber() + ": Status: Ok")); for(errList.start(i1); !errList.isEnd(i1); errList.next(i1)){ errors.append(errList[i1]); } } } } opuServersLock.unlock(); return errRet; } BError Control::getStatus(BList<NameValue>& statusList){ BError errRet; BError err; BIter i; BIter i1; BList<NameValue> puStatusList; dprintf(DBG_CMD, "Control::getStatus\n"); opuServersLock.rdLock(); if(!osimulate){ for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err = opuServers[i]->getStatus(puStatusList)){ statusList.append(NameValue(BString("Module") + opuServers[i]->getNumber() + "_Running", "0")); } else { for(puStatusList.start(i1); !puStatusList.isEnd(i1); puStatusList.next(i1)){ statusList.append(puStatusList[i1]); } } } } opuServersLock.unlock(); statusList.append(NameValue("TmsServer_Running", "1")); statusList.append(NameValue("TmsServer_CycleNumber", ocycleNumber.value())); statusList.append(NameValue("TmsServer_CycleType", ocycleType)); statusList.append(NameValue("TmsServer_ConnectionsNumber", oboapServer.getConnectionsNumber())); return errRet; } BError Control::getStatistics(BList<NameValue>& statsList){ BError err; BIter i; BIter i1; BList<NameValue> puStatsList; dprintf(DBG_CMD, "Control::getStatistics\n"); opuServersLock.rdLock(); if(!osimulate){ for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ puStatsList.clear(); opuServers[i]->getStatistics(puStatsList); for(puStatsList.start(i1); !puStatsList.isEnd(i1); puStatsList.next(i1)){ statsList.append(puStatsList[i1]); } } } opuServersLock.unlock(); statsList.append(NameValue("TmsServer_UpTime", getTime() - ostartTime)); statsList.append(NameValue("TmsServer_CycleNumProcessed", ocycleProcessed)); statsList.append(NameValue("TmsServer_NextCycleErrors", onumNextCycleErrors)); statsList.append(NameValue("TmsServer_FpgaStateErrors", onumFpgaStateErrors)); statsList.append(NameValue("TmsServer_DataGoneErrors", onumDataGoneErrors)); return err; } BError Control::getPuChannel(UInt32& puChannel, PuChannel& puPhysChannel){ BError err; dprintf(DBG_CMD, "Control::getPuChannel\n"); olock.lock(); if((puChannel < 1) || (puChannel > oconfigInfo.puReferences.size())){ olock.unlock(); return err.set(ErrorParam, "PuChannel out of range"); } puPhysChannel = oconfigInfo.puReferences[puChannel - 1]; olock.unlock(); return err; } BError Control::puServerStarted(UInt32 number){ BError err; dprintf(DBG_CMD, "Control::puServerStarted: %u\n", number); olock.lock(); initPuServer(number); olock.unlock(); return err; } BError Control::setSimulation(Simulation simulation){ BError err; uint32_t chan; BArray<UInt32> data; BFile file; int nb; BIter i; PuChannel puChan; PupeConfig pupeConfig; UInt32 cn; BString ct; BString testSignalFileName = "beam3-437000-8.psd"; BString cycleType = "SimBeam3"; // Read the test signal file if(err = file.open(testSignalFileName, "r")){ if(err = file.open(BString("/usr/tms/data/") + testSignalFileName, "r")){ return err.set(ErrorMisc, BString("Error: Opening file: ") + testSignalFileName); } } data.resize(1024); if((nb = file.read(&data[0], 1024 * sizeof(UInt32))) <= 0){ return err.set(1, BString("Error: Reading 1024 32bit data items from file: ") + testSignalFileName); } data.resize(nb / sizeof(UInt32)); // Setup timing pupeConfig.adcSysclkSync = 0; if(simulation.timing) pupeConfig.internalTimingMask = 0x7f; // All internal event signals else pupeConfig.internalTimingMask = 0x00; // No internal event signals pupeConfig.disableBlr = 0; opuServersLock.rdLock(); for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err = opuServers[i]->getMasterPuChannel(puChan)){ opuServersLock.unlock(); return err; } if(err = setPupeConfig(puChan, pupeConfig)){ return err; } } opuServersLock.unlock(); // Setup data for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ if(err = setTestData(oconfigInfo.puReferences[chan], simulation.data, data)){ return err; } } // Setup setNextCycle osimulation = simulation; if(osimulation.cycleType != "") cycleType = osimulation.cycleType; // Sets the CycleType to match the data if(err = getCycleInfo(cn, ct)){ return err.set(ErrorMisc, BString("Error: Getting Cycle Number: ") + err.getString()); } // Set NextCycle type if(err = setNextCycleInternal(cn + 1, cycleType)){ return err.set(ErrorMisc, BString("Error: Setting Next Cycle: ") + err.getString()); } return err; } BError Control::getSimulation(Simulation& simulation){ BError err; olock.lock(); simulation = osimulation; olock.unlock(); return err; } BError Control::setTestMode(PuChannel puPhysChannel, UInt32 testOutput, UInt32 timingDisableMask){ BError err; opuServersLock.rdLock(); if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->setTestMode(puPhysChannel, testOutput, timingDisableMask); opuServersLock.unlock(); return err; } BError Control::setTimingSignals(PuChannel puPhysChannel, UInt32 timingSignals){ BError err; opuServersLock.rdLock(); if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->setTimingSignals(puPhysChannel, timingSignals); opuServersLock.unlock(); return err; } BError Control::captureDiagnostics(PuChannel puPhysChannel, TestCaptureInfo captureInfo, BArray<UInt64>& data){ BError err; opuServersLock.rdLock(); if(osimulate){ err = getSimCaptureData(captureInfo, data); } else { if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->captureDiagnostics(puPhysChannel, captureInfo, data); } opuServersLock.unlock(); return err; } BError Control::setTestData(PuChannel puPhysChannel, Int32 on, BArray<UInt32> data){ BError err; opuServersLock.rdLock(); if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->setTestData(puPhysChannel, on, data); opuServersLock.unlock(); return err; } BError Control::setPupeConfig(PuChannel puPhysChannel, PupeConfig pupeConfig){ BError err; opuServersLock.rdLock(); if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->setPupeConfig(puPhysChannel, pupeConfig); opuServersLock.unlock(); return err; } BError Control::getPupeConfig(PuChannel puPhysChannel, PupeConfig& pupeConfig){ BError err; opuServersLock.rdLock(); if((puPhysChannel.moduleNum < 1) || (puPhysChannel.moduleNum > opuServers.number())){ opuServersLock.unlock(); return err.set(ErrorParam, BString("PuChannel.moduleNum: ") + puPhysChannel.moduleNum + " is invalid"); } err = opuServers[puPhysChannel.moduleNum - 1]->getPupeConfig(puPhysChannel, pupeConfig); opuServersLock.unlock(); return err; } BError Control::setControlInfo(CycleParam params){ BError err; BIter i; BString sptDir = config.findValue("SptDir:"); CycleParamDb cycleParamFiles(sptDir); int updated = 0; dprintf(DBG_CMD, "Control::setControlInfo\n"); // Add to internal database olock.lock(); for(ocycleParms.start(i); !ocycleParms.isEnd(i); ocycleParms.next(i)){ if((ocycleParms[i].cycleType == params.cycleType) && (ocycleParms[i].channel == params.channel)){ ocycleParms[i] = params; updated = 1; break; } } if(!updated) ocycleParms.append(params); olock.unlock(); opuServersLock.rdLock(); if(!osimulate){ for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err = opuServers[i]->setControlInfo(params)){ opuServersLock.unlock(); return err; } } } opuServersLock.unlock(); // Save to files olock.lock(); err = cycleParamFiles.setCycleParams(params); olock.unlock(); return err; } BError Control::getControlInfo(BString cycleType, UInt32 puChannel, CycleParam& params){ BError err; BIter i; olock.lock(); for(ocycleParms.start(i); !ocycleParms.isEnd(i); ocycleParms.next(i)){ if((ocycleParms[i].cycleType == cycleType) && (ocycleParms[i].channel == puChannel)){ params = ocycleParms[i]; olock.unlock(); return err; } } olock.unlock(); err.set(ErrorMisc, BString("Cycle parameters not found for cycle type: ") + cycleType); return err; } BError Control::delControlInfo(BString cycleType, UInt32 puChannel){ BError err; BString sptDir = config.findValue("SptDir:"); CycleParamDb cycleParamFiles(sptDir); BIter i; dprintf(DBG_CMD, "Control::delControlInfo: %s, %u\n", cycleType.retStr(), puChannel); olock.lock(); for(ocycleParms.start(i); !ocycleParms.isEnd(i); ocycleParms.next(i)){ if((ocycleParms[i].cycleType == cycleType) && (ocycleParms[i].channel == puChannel)){ ocycleParms.del(i); break; } } olock.unlock(); // Deleted. I don't want the .spt file wiped out. - JMB // olock.lock(); // err = cycleParamFiles.deleteCycleParams(cycleType, puChannel); // olock.unlock(); return err; } BError Control::getControlList(BList<CycleParamItem>& itemList){ BError err; BIter i; itemList.clear(); olock.lock(); for(ocycleParms.start(i); !ocycleParms.isEnd(i); ocycleParms.next(i)){ itemList.append(CycleParamItem(ocycleParms[i].cycleType, ocycleParms[i].channel)); } olock.unlock(); return err; } BError Control::setNextCycle(UInt32 cycleNumber, BString cycleType){ if(osimulation.setNextCycle) return BError(ErrorMisc, "System is simulating the setNextCycle call"); else return setNextCycleInternal(cycleNumber, cycleType); } BError Control::setNextCycleInternal(UInt32 cycleNumber, BString cycleType){ BError err; BIter i; int t = 0; double ts, tm[8], te; static double tmax; dprintf(DBG_CMD | DBG_EVENT, "Control::setNextCycleInternal: Num(%d) Type(%s)\n", cycleNumber, cycleType.retStr()); ocycleNumberNext = cycleNumber; ocycleTypeNext = cycleType; opuServersLock.rdLock(); if(!osimulate){ tm[t++] = ts = getTime(); for(opuServers.start(i); !opuServers.isEnd(i); opuServers.next(i)){ if(err = opuServers[i]->setNextCycle(cycleNumber, cycleType)){ opuServersLock.unlock(); dprintf(DBG_CMD | DBG_EVENT, "Control::setNextCycle: Done: Error: %s\n", err.getString().retStr()); return err; } tm[t++] = getTime(); } te = getTime(); if((te - ts) > tmax){ tmax = te - ts; } tm[3] = tm[3] - tm[2]; tm[2] = tm[2] - tm[1]; tm[1] = tm[1] - tm[0]; dprintf(DBG_SETNEXTCYCLE, "Control::setNextCycle: Times: %f,%f,%f = %f MaxTime: %f\n", tm[1],tm[2],tm[3], te - ts, tmax); } opuServersLock.unlock(); dprintf(DBG_CMD | DBG_EVENT, "Control::setNextCycle: Done\n"); return err; } BError Control::getCycleInfo(UInt32& cycleNumber, BString& cycleType){ BError err; dprintf(DBG_CMD, "Control::getCycleInfo\n"); cycleNumber = ocycleNumber.value(); cycleType = ocycleType; return err; } BError Control::getCycleInformation(UInt32 cycleNumber, CycleInformation& cycleInformation){ BError err; PuChannel puPhysChannel(1, 1, 1); dprintf(DBG_CMD, "Control::getCycleInformation\n"); if(err = waitForData(cycleNumber)) return err; opuServersLock.rdLock(); err = opuServers[puPhysChannel.moduleNum - 1]->getCycleInformation(cycleNumber, cycleInformation); opuServersLock.unlock(); return err; } BError Control::getCycleTypeInformation(BString cycleType, CycleTypeInformation& cycleTypeInformation){ BError err; CycleParam params; BUInt32 n; CycleTypeInformationPeriod period; dprintf(DBG_CMD, "Control::getCycleTypeInformation\n"); if(err = getControlInfo(cycleType, 0, params)) return err; cycleTypeInformation.cycleType = cycleType; cycleTypeInformation.info = params.info; for(n = 0; n < params.stateTable.size(); n++){ if(params.stateTable[n].period){ period.cyclePeriod = params.stateTable[n].period; period.harmonic = params.stateTable[n].harmonic; period.numBunches = params.stateTable[n].numBunches; period.bunchMask = params.stateTable[n].bunchMask; cycleTypeInformation.periods.append(period); } } return err; } BError Control::waitForData(BUInt32 cycleNumber){ BError err; Int32 diff; // In the initial state we need to check if we have actually captured the cycle dprintf(DBG_MISC, "Control::waitForData: RequiredCycle: %u CurrentCycle: %u CompletedCycle: %u\n", cycleNumber, ocycleNumber.value(), ocycleCompleteNumber.value()); // First check if we are within the possible cycle range diff = cycleNumber - ocycleCompleteNumber.value(); if(diff < -4) return err.set(ErrorDataGone, BString("TmsServer: Cycle's data has already been overwritten: Current: ") + ocycleCompleteNumber.value() + " Requested: " + cycleNumber); if(diff > 256) return err.set(ErrorDataFuture, BString("TmsServer: Cycle data required is to far in the future: Current: ") + ocycleCompleteNumber.value() + " Requested: " + cycleNumber); // Need Timeout ocycleCompleteNumber.waitMoreThanOrEqual(cycleNumber); return err; } void Control::errorEvent(UInt32 cycleNumber, BError error){ dprintf(DBG_EVENT, "Control::errorEvent: %d %s\n", cycleNumber, error.getString().retStr()); ocycleInfoList.cycleAddError(cycleNumber, error); if(error.getErrorNo() == ErrorStateTable) onumFpgaStateErrors++; oeventServers.errorEvent(cycleNumber, error); } void Control::cycleStartEvent(UInt32 cycleNumber){ UInt32 currentCycleNumber = ocycleNumber.value(); dprintf(DBG_EVENT, "Control::cycleStartEvent: Cycle: %u CurrentCycle: %u NextCycle: %u CompleCycle: %u\n", cycleNumber, currentCycleNumber, ocycleNumberNext, ocycleCompleteNumber.value()); ocycleNumber.setValue(cycleNumber); ocycleType = ocycleTypeNext; ocycleInfoList.cycleAdd(cycleNumber, ocycleTypeNext); if(cycleNumber == currentCycleNumber){ onumNextCycleErrors++; errorEvent(cycleNumber, BError(ErrorCycleNumber, "Cycle Information has not been received")); } oeventServers.cycleStartEvent(cycleNumber); } void Control::cycleStopEvent(UInt32 cycleNumber){ BIter i; BError err; double t1, t2; dprintf(DBG_EVENT, "Control::cycleStopEvent: %u\n", cycleNumber); ocycleCompleteNumber.setValue(cycleNumber); ocycleProcessed++; // Check all requests for(orequestList.start(i); !orequestList.isEnd(i); ){ if(cycleNumber >= orequestList[i].dataInfo.cycleNumber){ oeventServers.dataEvent(orequestList[i].dataInfo); orequestList.del(i); } else { orequestList.next(i); } } oeventServers.cycleStopEvent(cycleNumber); if(osimulation.setNextCycle){ t1 = getTime(); err = setNextCycleInternal(ocycleNumberNext, ocycleTypeNext); t2 = getTime(); dprintf(DBG_SETNEXTCYCLE, "Send setNextCycle: %u current: %u Time: %fms Error: %s\n", ocycleNumberNext, cycleNumber, (t2 - t1) * 1000.0, err.getString().retStr()); ocycleNumberNext++; } } BError Control::getData(DataInfo dataInfo, Data& data){ BError err; BError e; PuChannel puPhysChannel(0, 0, 1); BList<BError> errList; BUInt32 chan; BUInt32 orbitNumber; dprintf(DBG_CMD, "Control::getData\n"); // Setup for error return data.numValues = 0; data.dataType = 0; data.numBunches = 0; data.numChannels = 0; // Check parameters if(dataInfo.channel > oconfigInfo.puReferences.size()) return err.set(ErrorParam, "dataInfo.channel parameter is incorrect"); if(dataInfo.cyclePeriod > CyclePeriodEvent9) return err.set(ErrorParam, "dataInfo.cyclePeriod parameter is incorrect"); if(dataInfo.startTime > 4000) return err.set(ErrorParam, "dataInfo.startTime parameter is to large (max: 4000)"); if(dataInfo.orbitNumber > 1500000) return err.set(ErrorParam, "dataInfo.orbitNumber parameter is to large (max: 1500000)"); if(dataInfo.bunchNumber > 500000) return err.set(ErrorParam, "dataInfo.bunchNumber parameter is to large"); if(dataInfo.numValues > (40 * 8 * 500000)) return err.set(ErrorParam, "dataInfo.numValues parameter is to large (max: 40 * 8 * 500000)"); if(err = waitForData(dataInfo.cycleNumber)) return err; if(osimulate){ err = odataAquire.getData(dataInfo, data); } else { if(dataInfo.channel){ data.errors.resize(1); olock.lock(); puPhysChannel = oconfigInfo.puReferences[dataInfo.channel - 1]; olock.unlock(); opuServersLock.rdLock(); if(puPhysChannel.moduleNum > opuServers.number()){ opuServersLock.unlock(); data.errors[0] = err; return err.set(ErrorMC, BString("Module: ") + puPhysChannel.moduleNum + " is not available"); } err = opuServers[puPhysChannel.moduleNum - 1]->getData(puPhysChannel, dataInfo, data, orbitNumber); // Check if there were any Cycle Errors if(!err){ errList = ocycleInfoList.getCycleErrors(dataInfo.cycleNumber); if(errList.number()){ err = errList.front(); } } if(err.getErrorNo() == ErrorDataGone) onumDataGoneErrors++; opuServersLock.unlock(); data.errors[0] = err; } else { BUInt32 numValues = 0; Data dataSet[oconfigInfo.puReferences.size()]; if(dataInfo.numValues < oconfigInfo.puReferences.size()){ return err.set(ErrorParam, "NumValues to small for request"); } // Get the data from all PUPE channels. This could be improved with multi-threading and // geting the data from separate module controllers at the same time to reduce system latency dataInfo.numValues = dataInfo.numValues / oconfigInfo.puReferences.size(); data.errors.resize(oconfigInfo.puReferences.size()); for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ e = BError(); olock.lock(); puPhysChannel = oconfigInfo.puReferences[chan]; olock.unlock(); opuServersLock.rdLock(); if(puPhysChannel.moduleNum > opuServers.number()){ e.set(ErrorMC, BString("Module: ") + puPhysChannel.moduleNum + " is not available"); } else { e = opuServers[puPhysChannel.moduleNum - 1]->getData(puPhysChannel, dataInfo, dataSet[chan], orbitNumber); #if TIME_MS_USE_DATAGET // If we have set a startTime, use the orbit number for all other channels if(!e && dataInfo.startTime){ // syslog(LOG_ERR, "GetData: Get orbit number for channel: %d at startTime: %d orbitNumber: %d\n", chan, dataInfo.startTime, orbitNumber); dataInfo.orbitNumber = orbitNumber; dataInfo.startTime = 0; } #endif } data.errors[chan] = e; if(e && !err) err = e; opuServersLock.unlock(); } // Check if there were any Cycle Errors if(!err){ errList = ocycleInfoList.getCycleErrors(dataInfo.cycleNumber); if(errList.number()){ err = errList.front(); } for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ data.errors[chan] = err; } } if(err.getErrorNo() == ErrorDataGone) onumDataGoneErrors++; // Now merge the data // Calculate maximum number of values numValues = 0; data.dataType = 0; data.numBunches = 0; for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ if(!data.errors[chan]){ data.dataType = dataSet[chan].dataType; data.numBunches = dataSet[chan].numBunches; if(dataSet[chan].dataValues.size() > numValues) numValues = dataSet[chan].dataValues.size(); } } // Calculate minimum number of values for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ if(!data.errors[chan] && (dataSet[chan].dataValues.size() < numValues)) numValues = dataSet[chan].dataValues.size(); } // Make sure numValues is a multiple of the number of bunches if(data.numBunches) numValues = data.numBunches * (numValues / data.numBunches); data.numValues = numValues * oconfigInfo.puReferences.size(); data.numChannels = oconfigInfo.puReferences.size(); data.dataValues.resize(data.numValues); memset(data.dataValues.data(), 0, data.dataValues.size() * sizeof(DataValue)); // Merge the data for(chan = 0; chan < oconfigInfo.puReferences.size(); chan++){ if(!data.errors[chan]) memcpy(&data.dataValues[chan * numValues], &dataSet[chan].dataValues[0], numValues * sizeof(DataValue)); } } } return err; } BError Control::addEventServer(BString name){ dprintf(DBG_CMD, "Control::addEventServer\n"); return oeventServers.append(name); } BError Control::requestData(DataInfo dataInfo){ BError err; dprintf(DBG_CMD, "Control::requestData\n"); olock.lock(); orequestList.append(dataInfo); olock.unlock(); return err; } BError Control::getSimCaptureData(TestCaptureInfo captureInfo, BArray<UInt64>& data){ BError err; UInt32 num = 1024; UInt32 i; Data d; Sample* samples; SigGenBeam sigBeam; UInt64 v, dds_freq, ds; UInt64 fref, lo1, lo2, blr, gate; UInt64 mean1, mean2, rfSelect1, rfSelect2, selFilter; data.resize(num); samples = new Sample[num]; sigBeam.config(125000000, 437000, 8, 0x3C, 0, 0, 1.0); sigBeam.generate(samples, num); for(i = 0; i < num; i++){ ds = UInt64(int(8191.0 * samples[i]) & 0x3FFF); dds_freq = 300000000 + (i % 16); lo1 = (i & 0x1) ? 1 : 0; lo2 = (i & 0x2) ? 1 : 0; blr = (i & 0x4) ? 1 : 0; gate = (i & 0x8) ? 1 : 0; fref = (i & 0x10) ? 1 : 0; mean1 = (i & 0x20) ? 1 : 0; mean2 = (i & 0x40) ? 1 : 0; rfSelect1 = (i & 0x80) ? 1 : 0; rfSelect2 = (i & 0x100) ? 1 : 0; selFilter = (i & 0x200) ? 1 : 0; v = (gate << 47) | (blr << 46) | (ds << 32) | dds_freq; v |= (selFilter << 55) | (rfSelect2 << 54) | (rfSelect1 << 53) | (fref << 52); v |= (mean2 << 51) | (mean1 << 50) | (lo2 << 49) | (lo1 << 48); data[i] = v; } return err; } #ifdef ZAP diagnostics(31 downto 0) <= dds_freq; diagnostics(47 downto 32) <= GATE_pulse & BLR_pulse & sigma; diagnostics(55 downto 48) <= sel_filter & rf_select2 & rf_select1 & frev_in & phase_table_data(7 downto 6) & LO_pulse2 & LO_pulse1; diagnostics(63 downto 56) <= "0000" & switch_state; #endif BString Control::boapnsHost(){ return oboapnsHost; } uint32_t Control::diskSpace(BString dir){ struct statfs s; uint32_t blocks = 0; if(!statfs(dir, &s)){ blocks = ((uint64_t)s.f_bsize * s.f_bavail) / 1024; } return blocks; } uint32_t Control::memoryFree(){ BEntryFile file("/proc/meminfo"); uint32_t mbytes = 0; BString s; if(!file.read()){ mbytes = file.findValue("MemFree:").retInt() / 1024; mbytes += file.findValue("Buffers:").retInt() / 1024; mbytes += file.findValue("Cached:").retInt() / 1024; } return mbytes; }