/*******************************************************************************
* 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>
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();
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;
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");
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);
// 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]);
}
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;
}