/*******************************************************************************
* 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 <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 <sys/ioctl.h>
#include <linux/watchdog.h>
#define SINGLE_DMA 1 ///< Only allow a single DMA accross the PCI bus at a time in getData
CycleParams::CycleParams(BString cycleType, CycleParam& params){
this->cycleType = cycleType;
this->params.append(params);
}
void ControlTimer::sigFunc(int sig, siginfo_t* sigInfo, void* data){
ControlTimer::timer->tick();
}
ControlTimer* ControlTimer::timer;
ControlTimer::ControlTimer(Control& control) : ocontrol(control){
timer = this;
}
void ControlTimer::tick(){
otick.post();
}
void ControlTimer::sync(){
struct itimerval t;
t.it_interval.tv_sec = 0;
t.it_interval.tv_usec = 100000;
t.it_value = t.it_interval;
setitimer(ITIMER_REAL, &t, NULL);
}
void* ControlTimer::function(){
struct sigaction sigAction;
sigset_t sigm;
dprintf(DBG_THREADS, "ControlTimer Thread: %d\n", gettid());
sigemptyset(&sigm);
sigaddset(&sigm, SIGALRM);
sigprocmask(SIG_UNBLOCK, &sigm, 0);
memset(&sigAction, 0, sizeof(sigAction));
sigAction.sa_sigaction = ControlTimer::sigFunc;
sigAction.sa_flags = SA_SIGINFO;
sigaction(SIGALRM, &sigAction, NULL);
sync();
while(1){
otick.wait();
ocontrol.timer();
}
return 0;
}
Control::Control(int dbFixed) :
odebugFixed(dbFixed),
otimer(*this),
opuControlServer(*this, oboapServer, "puControl"),
opuProcessServer(*this, oboapServer, "puProcess"){
onum = 0;
oinitialised = 0;
omaster = 0;
osimulate = 0;
osimulateTiming = 0;
ocycleNumberNext = 0;
oprocessingCycle = 0;
oserverName = "localhost";
ocycleTick = 12;
ostartTime = getTime();
ocycleProcessed = 0;
owatchdog = -1;
}
Control::~Control(){
}
BString Control::getName(){
return BString("Module") + moduleNum() + ": ";
}
BError Control::mergeError(BError err){
if(err){
err.set(err.getErrorNo(), getName() + err.getString());
}
return err;
}
BError Control::init(int number){
BError err;
BString s;
sched_param sp;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
if(number){
onum = number;
}
else {
if(s = config.findValue("ModuleControllerNumber:"))
onum = s.retInt();
}
if(config.findValue("SimulateFpga:").retInt() == 1)
osimulate = 1;
else
osimulate = 0;
s = config.findValue("SimulateTiming:");
if(s != "")
osimulateTiming = s.retInt();
else
osimulateTiming = 0;
if(s = config.findValue("TmsServer:"))
oserverName = s;
// 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
otimer.start();
// Setup watchdog timer, if available
if(s = config.findValue("Watchdog:")){
int v = s.retInt();
if(v){
if((owatchdog = open("/dev/watchdog", O_RDWR)) >= 0){
ioctl(owatchdog, WDIOC_SETTIMEOUT, &v);
v = 0;
ioctl(owatchdog, WDIOC_SETPRETIMEOUT, &v);
}
}
}
opuControlServer.setName(BString("puControl-") + onum);
opuProcessServer.setName(BString("puProcess-") + onum);
if(err = oboapServer.init(oserverName, BoapServer::THREADED)){
return mergeError(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();
return err;
}
void Control::abort(){
// Disable watchdog
if(owatchdog >= 0){
write(owatchdog, "V", 1);
close(owatchdog);
}
}
BError Control::initCmd(){
BError err;
BIter i;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
olock.lock();
oinitialised = 0;
opupeEnginesLock.wrLock();
for(opupeEngines.start(i); !opupeEngines.isEnd(i); ){
delete opupeEngines[i];
opupeEngines.del(i);
}
opupeEnginesLock.unlock();
if(err = initPupeEngines()){
olock.unlock();
return err;
}
nprintf("%d Pupe Engines initialised\n", opupeEngines.number());
olock.unlock();
// Setup default parameters
setNextCycle(0, "Beam3");
dprintf(DBG_CMD, "%s: End\n", __PRETTY_FUNCTION__);
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;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
oconfigInfoLock.lock();
oconfigInfo = configInfo;
oconfigInfoLock.unlock();
oinitialised = 1;
return err;
}
BError Control::test(BList<BError>& errors){
BError errRet;
BError err;
BIter i;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i)){
if(err = opupeEngines[i]->status()){
errors.append(BError(err.getErrorNo(), getName() + "Pupe" + opupeEngines[i]->getSlot() + ": Status: " + err.getErrorNo() + " " + err.getString()));
}
else {
errors.append(BError(0, getName() + "Pupe" + opupeEngines[i]->getSlot() + ": Status: " + "Ok"));
}
}
opupeEnginesLock.unlock();
return errRet;
}
BError Control::getStatus(BList<NameValue>& statusList){
BError err;
BError e;
int numPupe = 0;
BIter i;
BString s;
int p;
BList<NameValue> l;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
#ifdef ZAP
for(opupeEngines.start(i), p = 1; !opupeEngines.isEnd(i); opupeEngines.next(i), p++){
e = opupeEngines[i]->status();
s = BString(e.getErrorNo()) + ",\"" + e.getString() + "\"";
statusList.append(NameValue(BString("TmsPuServer") + onum + "_Pupe" + p + "_Error", s));
if(!e){
numPupe++;
}
}
#else
for(opupeEngines.start(i), p = 1; !opupeEngines.isEnd(i); opupeEngines.next(i), p++){
e = opupeEngines[i]->status();
if(!e){
numPupe++;
}
opupeEngines[i]->getStatusList(PuChannel(1,1,1), statusList);
// statusList = statusList + l;
}
#endif
opupeEnginesLock.unlock();
olock.lock();
statusList.append(NameValue(BString("Module") + moduleNum() + "_Running", "1"));
statusList.append(NameValue(BString("Module") + moduleNum() + "_NumberPupe", numPupe));
statusList.append(NameValue(BString("Module") + moduleNum() + "_CycleNumber", ocycleNumber));
statusList.append(NameValue(BString("Module") + moduleNum() + "_CycleType", ocycleType));
olock.unlock();
return err;
}
BError Control::getStatistics(BList<NameValue>& statsList){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
statsList.append(NameValue(BString("Module") + moduleNum() + "_UpTime", getTime() - ostartTime));
statsList.append(NameValue(BString("Module") + moduleNum() + "_CycleNumProcessed", ocycleProcessed));
return err;
}
BError Control::getMasterPuChannel(PuChannel& puChannel){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
puChannel.moduleNum = onum;
puChannel.pupeNum = omaster + 1;
puChannel.pupeChan = 1;
return err;
}
BError Control::addEventServer(BString name){
BError err;
dprintf(DBG_CMD, "%s: %s\n", __PRETTY_FUNCTION__, name.retStr());
oeventServers.append(name);
return err;
}
BError Control::delEventServer(BString name){
BError err;
BIter i;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
oeventServers.del(name);
return err;
}
BError Control::setControlInfo(CycleParam params){
BError err;
BIter i;
BIter i1, i2;
int found = 0;
dprintf(DBG_CMD, "Control::setControlInfo: %s\n", params.cycleType.retStr());
ocycleParmsLock.lock();
// Check if there is already an entry for this cycleType
for(ocycleParms.start(i1); !ocycleParms.isEnd(i1); ocycleParms.next(i1)){
if(ocycleParms[i1].cycleType == params.cycleType){
found = 1;
break;
}
}
if(found){
// See if there is an entry for this channel
found = 0;
for(ocycleParms[i1].params.start(i2); !ocycleParms[i1].params.isEnd(i2); ocycleParms[i1].params.next(i2)){
if(ocycleParms[i1].params[i2].channel == params.channel){
found = 1;
break;
}
}
if(found){
ocycleParms[i1].params[i2] = params;
}
else {
if(params.channel == 0){
i = ocycleParms[i1].params.begin();
ocycleParms[i1].params.insert(i, params);
}
else {
ocycleParms[i1].params.append(params);
}
}
}
else {
ocycleParms.append(CycleParams(params.cycleType, params));
}
#ifdef ZAP
printf("CycleTypes:\n");
for(ocycleParms.start(i); !ocycleParms.isEnd(i); ocycleParms.next(i)){
printf("%s\n", ocycleParms[i].cycleType.retStr());
}
#endif
ocycleParmsLock.unlock();
return err;
}
BError Control::setNextCycle(UInt32 cycleNumber, BString cycleType){
BError err;
BIter i;
BIter i1, i2;
PuChannel puChannel;
int found = 0;
int afterCycleStop = 0;
double ts, te;
static double tmax;
dprintf(DBG_SETNEXTCYCLE, "%s %u %s\n", __PRETTY_FUNCTION__, cycleNumber, cycleType.retStr());
ts = getTime();
olock.lock();
if(!oprocessingCycle)
afterCycleStop = 1;
ocycleNumberNext = cycleNumber;
ocycleTypeNext = cycleType;
// Could improve this with a hashed name lookup
ocycleParmsLock.lock();
for(ocycleParms.start(i1); !ocycleParms.isEnd(i1); ocycleParms.next(i1)){
dprintf(DBG_SETNEXTCYCLE, "Control::setNextCycle: CheckCycleType: %s - %s\n", ocycleParms[i1].cycleType.retStr(), cycleType.retStr());
if(ocycleParms[i1].cycleType == cycleType){
found = 1;
for(ocycleParms[i1].params.start(i2); !ocycleParms[i1].params.isEnd(i2); ocycleParms[i1].params.next(i2)){
if(ocycleParms[i1].params[i2].channel == 0){
puChannel = PuChannel(0, 0, 0);
opupeEnginesLock.rdLock();
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i)){
opupeEngines[i]->setNextCycle(puChannel, cycleNumber, cycleType, ocycleParms[i1].params[i2]);
}
opupeEnginesLock.unlock();
}
else {
getPuPhysChannel(ocycleParms[i1].params[i2].channel, puChannel);
opupeEnginesLock.rdLock();
if(puChannel.pupeNum > opupeEngines.number()){
err.set(ErrorParam, getName() + "No Pupe Engine Numbered: " + puChannel.pupeNum);
opupeEnginesLock.unlock();
ocycleParmsLock.unlock();
olock.unlock();
return err;
}
opupeEngines[puChannel.pupeNum - 1]->setNextCycle(puChannel, cycleNumber, cycleType, ocycleParms[i1].params[i2]);
opupeEnginesLock.unlock();
}
}
break;
}
}
ocycleParmsLock.unlock();
olock.unlock();
if(!found)
err.set(ErrorParam, BString("There are no Cycle Parameters for cycle type: ") + cycleType);
if(!err && afterCycleStop){
if(oprocessingCycle){
err.set(ErrorCycleNumber, getName() + "The next cycle has already started");
}
}
dprintf(DBG_SETNEXTCYCLE, "Tick: %d\n", ocycleTick);
// Synchronise Module controllers if in simulation mode
if(osimulate)
ocycleTick = 10;
if(osimulateTiming & TimingSigCycleStart){
// Make sure timing simulation is in sync between multiple TmsPuServers when CYCLE_START is simulated
otimer.sync();
if(ocycleTick == 9){
otimer.tick();
}
else {
ocycleTick = 10;
}
}
te = getTime();
if((te - ts) > tmax){
tmax = te - ts;
}
dprintf(DBG_SETNEXTCYCLE, "Control::setNextCycle: Time: %f MaxTime: %f\n", te - ts, tmax);
dprintf(DBG_SETNEXTCYCLE, "%s: End\n", __PRETTY_FUNCTION__);
return err;
}
BError Control::getStatus(PuChannel puChannel, PuStatus& puStatus){
BError err;
BIter i;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if(puChannel.pupeNum == 0){
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i)){
opupeEngines[i]->getStatus(puChannel, puStatus);
}
}
else {
if(puChannel.pupeNum > opupeEngines.number()){
err.set(ErrorParam, getName() + "No Pupe Engine Numbered: " + opupeEngines.number());
}
else {
opupeEngines[puChannel.pupeNum - 1]->getStatus(puChannel, puStatus);
}
}
opupeEnginesLock.unlock();
return err;
}
BError Control::getCycleInformation(UInt32 cycleNumber, CycleInformation& cycleInformation){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
err = mergeError(opupeEngines[0]->getCycleInformation(cycleNumber, cycleInformation));
opupeEnginesLock.unlock();
return err;
}
BError Control::getData(PuChannel puChannel, DataInfo dataInfo, Data& data, UInt32& orbitNumber){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
// Setup for error return
data.numValues = 0;
data.dataType = 0;
data.numBunches = 0;
data.numChannels = 0;
opupeEnginesLock.rdLock();
#if SINGLE_DMA
opupeLock.lock();
#endif
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
#if SINGLE_DMA
opupeLock.unlock();
#endif
opupeEnginesLock.unlock();
return err.set(ErrorParam, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->getData(puChannel, dataInfo, data, orbitNumber));
#if SINGLE_DMA
opupeLock.unlock();
#endif
opupeEnginesLock.unlock();
return err;
}
BError Control::requestData(PuChannel puChannel, DataInfo dataInfo){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
return err;
}
BError Control::setTestMode(PuChannel puChannel, UInt32 testOutput, UInt32 timingDisableMask){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->setTestMode(puChannel, testOutput, timingDisableMask));
opupeEnginesLock.unlock();
return err;
}
BError Control::setTimingSignals(PuChannel puChannel, UInt32 timingSignals){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->setTimingSignals(puChannel, timingSignals));
opupeEnginesLock.unlock();
return err;
}
BError Control::captureDiagnostics(PuChannel puChannel, TestCaptureInfo captureInfo, BArray<UInt64>& data){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->captureDiagnostics(puChannel, captureInfo, data));
opupeEnginesLock.unlock();
dprintf(DBG_CMD, "%s: End\n", __PRETTY_FUNCTION__);
return err;
}
BError Control::setTestData(PuChannel puChannel, Int32 on, BArray<UInt32> data){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->setTestData(puChannel, on, data));
opupeEnginesLock.unlock();
dprintf(DBG_CMD, "%s: End\n", __PRETTY_FUNCTION__);
return err;
}
BError Control::setPupeConfig(PuChannel puChannel, PupeConfig pupeConfig){
BError err;
dprintf(DBG_CMD, "%s\n", __PRETTY_FUNCTION__);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->setPupeConfig(puChannel, pupeConfig));
osimulateTiming = pupeConfig.internalTimingMask;
opupeEnginesLock.unlock();
return err;
}
BError Control::getPupeConfig(PuChannel puChannel, PupeConfig& pupeConfig){
BError err;
dprintf(DBG_CMD, "Control::getPupeConfig: %d.%d.%d\n", puChannel.moduleNum, puChannel.pupeNum, puChannel.pupeChan);
opupeEnginesLock.rdLock();
if((puChannel.pupeNum < 1) || (puChannel.pupeNum > opupeEngines.number())){
opupeEnginesLock.unlock();
return err.set(ErrorMisc, getName() + "PuChannel: PupeNum out of range");
}
err = mergeError(opupeEngines[puChannel.pupeNum - 1]->getPupeConfig(puChannel, pupeConfig));
opupeEnginesLock.unlock();
return err;
}
void Control::run(){
dprintf(DBG_CMD, "Control::run\n");
oboapServer.run();
}
void Control::timer(){
static uint32_t tick = 0;
static int simEnable = 0;
BError err;
BIter i;
// printf("Control::timer: %d\n", ocycleTick);
if(simEnable){
if(++ocycleTick >= 12)
ocycleTick = 0;
//printf("CycleTick: %d\n", ocycleTick);
if(osimulate){
opupeEnginesLock.rdLock();
if(ocycleTick == 0){
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i))
opupeEngines[i]->cycleStart();
}
else if(ocycleTick == 4){
if(opupeEngines.number())
opupeEngines.front()->fpgaTriggerTimingInputs(TimingSigInjection);
}
else if(ocycleTick == 6){
if(opupeEngines.number())
opupeEngines.front()->fpgaTriggerTimingInputs(TimingSigHChange);
}
else if(ocycleTick == 10){
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i))
opupeEngines[i]->cycleStop();
}
opupeEnginesLock.unlock();
}
else {
opupeEnginesLock.rdLock();
if((osimulateTiming & TimingSigCycleStart) && (ocycleTick == 0)){
if(opupeEngines.number())
opupeEngines[omaster]->fpgaTriggerTimingInputs(TimingSigCycleStart);
}
else if((osimulateTiming & TimingSigInjection) && (ocycleTick == 4)){
if(opupeEngines.number())
opupeEngines[omaster]->fpgaTriggerTimingInputs(TimingSigInjection);
}
else if((osimulateTiming & TimingSigHChange) && (ocycleTick == 6)){
if(opupeEngines.number())
opupeEngines[omaster]->fpgaTriggerTimingInputs(TimingSigHChange);
}
else if((osimulateTiming & TimingSigCycleStop) && (ocycleTick == 10)){
if(opupeEngines.number())
opupeEngines[omaster]->fpgaTriggerTimingInputs(TimingSigCycleStop);
}
opupeEnginesLock.unlock();
}
}
if(tick == 30){
simEnable = 1;
}
// Every 1 seconds do some house keeping
if((tick % 10) == 9){
if(!oinitialised){
TmsControl tmsControl(BString("//") + oserverName + "/tmsControl");
if(err = tmsControl.puServerStarted(onum)){
wprintf("Unable to call puServerStarted on %s: %s\n", oserverName.retStr(), err.getString().retStr());
}
}
// Check ADC Pll Locks
opupeEnginesLock.rdLock();
for(opupeEngines.start(i); !opupeEngines.isEnd(i); opupeEngines.next(i)){
opupeEngines[i]->adcPllLockCheck();
}
opupeEnginesLock.unlock();
// Ping the watchdog
if(owatchdog >= 0){
ioctl(owatchdog, WDIOC_KEEPALIVE, 0);
}
}
// Every 10 seconds do some house keeping
if((tick % 100) == 99){
}
tick++;
}
void Control::cycleStart(UInt32 cycleNumber){
BError err;
dprintf(DBG_CYCLE, "Control::cycleStart\n");
olock.lock();
oprocessingCycle = 1;
ocycleNumber = ocycleNumberNext;
ocycleType = ocycleTypeNext;
#ifdef ZAP
// Make sure timing simulation is in sync with cycle start
otimer.sync();
ocycleTick = 0;
#endif
olock.unlock();
if(onum == 1){
if(err = oeventServers.cycleStartEvent(cycleNumber))
wprintf(getName() + "Error send CycleStart event: " + err.getString() + "\n");
}
}
void Control::cycleError(UInt32 cycleNumber, BError error){
dprintf(DBG_CYCLE, "Control::cycleError\n");
olock.lock();
oeventServers.errorEvent(cycleNumber, error);
eprintf(getName() + "Control::cycleError: Cycle: %d Error: %s\n", cycleNumber, error.getString().retStr());
olock.unlock();
}
void Control::cycleStop(UInt32 cycleNumber){
dprintf(DBG_CYCLE, "Control::cycleStop\n");
olock.lock();
ocycleProcessed++;
oprocessingCycle = 0;
// printf("Control::cycleStop: %u CurrentCycleType: %s NextCycleType: %s\n", cycleNumber, ocycleType.retStr(), ocycleTypeNext.retStr());
olock.unlock();
if(onum == 1){
oeventServers.cycleStopEvent(cycleNumber);
}
}
BError Control::initPupeEngines(){
BError err;
BError e;
int physical = 0;
int slot = 0;
int board;
Pupe* pupe;
BArray<int> devs;
int d = 0;
BString str;
BString s;
int numBoards = 5;
if((s = config.findValue("PupeNumber:")) != ""){
numBoards = config.findValue("PupeNumber:").retInt();
}
if((s = config.findValue("PupeMaster:")) != ""){
omaster = config.findValue("PupeMaster:").retInt() - 1;
}
if(config.findValue("PupePhysicalOn:").retInt() == 1){
str = config.findValue("PupePhysicalDevices:");
while((s = str.pullToken(",")) != ""){
devs.resize(d + 1);
devs[d] = s.retInt();
d++;
}
if(err = opupeGeog.scan(devs))
return err;
physical = 1;
}
opupeEnginesLock.wrLock();
for(slot = 0; slot < numBoards; slot++){
if(!osimulate && physical)
board = opupeGeog.getBoardId(slot);
else
board = slot;
if(board < 0){
wprintf(getName() + "PupeEngine no board in slot: " + slot + "\n");
}
pupe = new Pupe(*this, slot, board);
opupeEngines.append(pupe);
if(e = pupe->init()){
wprintf(getName() + "PupeEngine init error: " + e.getString() + "\n");
}
if(omaster == slot)
pupe->setMaster(1);
else
pupe->setMaster(0);
}
opupeEnginesLock.unlock();
return err;
}
BError Control::getPuChannel(PuChannel puPhysChannel, UInt32& puChannel){
BError err;
unsigned int i;
// Could use a mapping table to speed this up if necessary
oconfigInfoLock.lock();
puChannel = 0;
for(i = 0; i < oconfigInfo.puReferences.size(); i++){
if((puPhysChannel.moduleNum == oconfigInfo.puReferences[i].moduleNum) &&
(puPhysChannel.pupeNum == oconfigInfo.puReferences[i].pupeNum) &&
(puPhysChannel.pupeChan == oconfigInfo.puReferences[i].pupeChan)){
puChannel = i + 1;
oconfigInfoLock.unlock();
return err;
}
}
oconfigInfoLock.unlock();
return err.set(ErrorParam, getName() + "Physical PuChannel not configured");
}
BError Control::getPuPhysChannel(UInt32 puChannel, PuChannel& puPhysChannel){
BError err;
oconfigInfoLock.lock();
if((puChannel < 1) || (puChannel > oconfigInfo.puReferences.size())){
oconfigInfoLock.unlock();
return err.set(ErrorParam, getName() + "Physical PuChannel not configured");
}
puPhysChannel = oconfigInfo.puReferences[puChannel - 1];
oconfigInfoLock.unlock();
return err;
}
int Control::moduleNum(){
return onum;
}