//OpenSCADA system file: tdaqs.cpp /*************************************************************************** * Copyright (C) 2003-2018 by Roman Savochenko, * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include "tsys.h" #include "tmess.h" #include "tcontroller.h" #include "tmodule.h" #include "tvalue.h" #include "tdaqs.h" using namespace OSCADA; //************************************************* //* TDAQS * //************************************************* TDAQS::TDAQS( ) : TSubSYS(SDAQ_ID,_("Data acquisition"),true), mElErr("Error"), mRdStLevel(0), mRdRestConnTm(30), mRdTaskPer(1), mRdRestDtTm(1), mRdPrcTm(0), prcStRd(false), endrunRd(false) { mTmpLib = grpAdd("tmplb_"); //> Templates lib db structure mElLib.fldAdd(new TFld("ID",_("Identifier"),TFld::String,TCfg::Key,OBJ_ID_SZ)); mElLib.fldAdd(new TFld("NAME",_("Name"),TFld::String,TFld::TransltText,OBJ_NM_SZ)); mElLib.fldAdd(new TFld("DESCR",_("Description"),TFld::String,TFld::FullText|TFld::TransltText,"1000")); mElLib.fldAdd(new TFld("DB",_("Data base"),TFld::String,TFld::NoFlag,"30")); //> Template DB structure mElTmpl.fldAdd(new TFld("ID",_("Identifier"),TFld::String,TCfg::Key,OBJ_ID_SZ)); mElTmpl.fldAdd(new TFld("NAME",_("Name"),TFld::String,TFld::TransltText,OBJ_NM_SZ)); mElTmpl.fldAdd(new TFld("DESCR",_("Description"),TFld::String,TFld::FullText|TFld::TransltText,"1000")); mElTmpl.fldAdd(new TFld("MAXCALCTM",_("Maximum calculate time, seconds"),TFld::Integer,TFld::NoFlag,"4","10","0;3600")); mElTmpl.fldAdd(new TFld("PROGRAM",_("Program"),TFld::String,TFld::TransltText,"1000000")); //> Parameter template IO DB structure mElTmplIO.fldAdd(new TFld("TMPL_ID",_("Template identifier"),TFld::String,TCfg::Key,OBJ_ID_SZ)); mElTmplIO.fldAdd(new TFld("ID",_("Identifier"),TFld::String,TCfg::Key,OBJ_ID_SZ)); mElTmplIO.fldAdd(new TFld("NAME",_("Name"),TFld::String,TFld::TransltText,OBJ_NM_SZ)); mElTmplIO.fldAdd(new TFld("TYPE",_("Value type"),TFld::Integer,TFld::NoFlag,"1")); mElTmplIO.fldAdd(new TFld("FLAGS",_("Flags"),TFld::Integer,TFld::NoFlag,"4")); mElTmplIO.fldAdd(new TFld("VALUE",_("Value"),TFld::String,TFld::TransltText,"50")); mElTmplIO.fldAdd(new TFld("POS",_("Real position"),TFld::Integer,TFld::NoFlag,"4")); //Error attributes mElErr.fldAdd(new TFld("err",_("Error"),TFld::String,TFld::NoWrite|TVal::DirRead)); } TDAQS::~TDAQS( ) { if(prcStRd) subStop(); nodeDelAll(); } string TDAQS::objName( ) { return TSubSYS::objName()+":TDAQS"; } void TDAQS::rdStList( vector &ls ) { ResAlloc res(mRdRes, false); ls.clear(); for( map::iterator sti = mSt.begin(); sti != mSt.end(); sti++ ) ls.push_back(sti->first); } void TDAQS::rdActCntrList( vector &ls, bool isRun ) { AutoHD cntr; ls.clear(); vector mls, cls; modList(mls); for(unsigned iM = 0; iM < mls.size(); iM++) { if(!at(mls[iM]).at().redntAllow()) continue; at(mls[iM]).at().list(cls); for(unsigned iC = 0; iC < cls.size(); iC++) { cntr = at(mls[iM]).at().at(cls[iC]); if(cntr.at().startStat() && (!isRun || !cntr.at().redntUse())) ls.push_back(cntr.at().workId()); } } } void TDAQS::ctrListPrmAttr( XMLNode *opt, const string &l_prm, bool toPrm, char sep, const string &pref ) { int c_lv = 0; string c_path = "", c_el; vector ls; opt->childAdd("el")->setText(pref+c_path); AutoHD DAQnd = this; const char *c_grp = "mod_"; for(int c_off = 0; (sep && (c_el=TSYS::strSepParse(l_prm,0,sep,&c_off)).size()) || (!sep && (c_el=TSYS::pathLev(l_prm,0,true,&c_off)).size()); ++c_lv) { c_path += sep ? (c_lv?sep+c_el:c_el) : "/"+c_el; DAQnd = DAQnd.at().nodeAt(c_grp+c_el, 0, sep, 0, true); if(DAQnd.freeStat()) break; opt->childAdd("el")->setText(pref+c_path); c_grp = (c_lv == 0) ? "cntr_" : "prm_"; } if(sep && c_lv) c_path += sep; if(!DAQnd.freeStat()) { DAQnd.at().chldList(DAQnd.at().grpId(c_grp), ls, true); for(unsigned i_l = 0; i_l < ls.size(); i_l++) opt->childAdd("el")->setText(pref+c_path+(sep?ls[i_l]:("/"+ls[i_l]))); //Get attributes if(!toPrm && strcmp(c_grp,"prm_") == 0) { DAQnd.at().chldList(DAQnd.at().grpId("a_"), ls, true); if(ls.size()) opt->childAdd("el")->setText(_("=== Attributes ===")); for(unsigned i_l = 0; i_l < ls.size(); i_l++) opt->childAdd("el")->setText(pref+c_path+(sep?ls[i_l]:("/"+ls[i_l]))); } } } void TDAQS::load_( ) { //Load parameters from command line map itReg; vector > full; //Load templates libraries of parameter try { //>> Search and create new libraries TConfig cEl(&elLib()); //cEl.cfgViewAll(false); vector dbLs; //>> Search into DB SYS->db().at().dbList(dbLs, true); dbLs.push_back(DB_CFG); for(unsigned iDB = 0; iDB < dbLs.size(); iDB++) for(int libCnt = 0; SYS->db().at().dataSeek(dbLs[iDB]+"."+tmplLibTable(),nodePath()+"tmplib",libCnt++,cEl,false,&full); ) { string l_id = cEl.cfg("ID").getS(); if(!tmplLibPresent(l_id)) tmplLibReg(new TPrmTmplLib(l_id.c_str(),"",(dbLs[iDB]==SYS->workDB())?"*.*":dbLs[iDB])); tmplLibAt(l_id).at().load(&cEl); itReg[l_id] = true; } // Check for remove items removed from DB if(!SYS->selDB().empty()) { tmplLibList(dbLs); for(unsigned i_it = 0; i_it < dbLs.size(); i_it++) if(itReg.find(dbLs[i_it]) == itReg.end() && SYS->chkSelDB(tmplLibAt(dbLs[i_it]).at().DB())) tmplLibUnreg(dbLs[i_it]); } } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error loading template libraries.")); } //> Load parameters try { AutoHD wmod; vector modLs, dbLs; modList(modLs); for(unsigned iMd = 0; iMd < modLs.size(); iMd++) { wmod = at(modLs[iMd]); TConfig gCfg(&wmod.at()); //gCfg.cfgViewAll(false); itReg.clear(); //>> Search into DB and create new controllers SYS->db().at().dbList(dbLs, true); dbLs.push_back(DB_CFG); for(unsigned iDB = 0; iDB < dbLs.size(); iDB++) for(int fldCnt = 0; SYS->db().at().dataSeek(dbLs[iDB]+"."+subId()+"_"+wmod.at().modId(),wmod.at().nodePath()+"DAQ",fldCnt++,gCfg,false,&full); ) { string mId = gCfg.cfg("ID").getS(); try { if(!wmod.at().present(mId)) wmod.at().add(mId,(dbLs[iDB]==SYS->workDB())?"*.*":dbLs[iDB]); wmod.at().at(mId).at().load(&gCfg); itReg[mId] = true; } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error adding controller '%s'."), mId.c_str()); } } //>>> Check for remove items removed from DB wmod.at().list(dbLs); for(unsigned i_it = 0; i_it < dbLs.size(); i_it++) if(itReg.find(dbLs[i_it]) == itReg.end() && SYS->chkSelDB(wmod.at().at(dbLs[i_it]).at().DB())) wmod.at().del(dbLs[i_it]); } } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } //> Load parameters from config-file and SYS DB setRdStLevel(s2i(TBDS::genDBGet(nodePath()+"RdStLevel",i2s(rdStLevel())))); setRdTaskPer(s2r(TBDS::genDBGet(nodePath()+"RdTaskPer",r2s(rdTaskPer())))); setRdRestConnTm(s2i(TBDS::genDBGet(nodePath()+"RdRestConnTm",i2s(rdRestConnTm())))); setRdRestDtTm(s2r(TBDS::genDBGet(nodePath()+"RdRestDtTm",r2s(rdRestDtTm())))); string stLs = TBDS::genDBGet(nodePath()+"RdStList"), stId; ResAlloc res(mRdRes, true); for( int off = 0; (stId=TSYS::strSepParse(stLs,0,';',&off)).size(); ) if( mSt.find(stId) == mSt.end() ) mSt[stId] = SStat(); } void TDAQS::save_( ) { //> Save parameters to SYS DB TBDS::genDBSet(nodePath()+"RdStLevel", i2s(rdStLevel())); TBDS::genDBSet(nodePath()+"RdTaskPer", r2s(rdTaskPer())); TBDS::genDBSet(nodePath()+"RdRestConnTm", i2s(rdRestConnTm())); TBDS::genDBSet(nodePath()+"RdRestDtTm", r2s(rdRestDtTm())); ResAlloc res(mRdRes, false); string stLs; for( map::iterator sit = mSt.begin(); sit != mSt.end(); sit++ ) stLs += sit->first+";"; TBDS::genDBSet(nodePath()+"RdStList", stLs); } TVariant TDAQS::objFuncCall( const string &iid, vector &prms, const string &user ) { // bool funcCall(string progLang, TVarObj args, string prog, string fixId = "") - // Call function text whith arguments for program language // and with the fixed identifier (automatic for this empty). Return "true" on a well call. // For the fixed function recreate you need change the program or clean up by the function original id. // progLang - program procedure language or the stored function's address, after call with ; // args - function arguments; // prog - function text; // fixId - two direction field of fixed identifier of the function; // for the field empty the function id will be automatic and destroy at end, // else the id will used on the function creation and replaced by an address to it. if(iid == "funcCall" && prms.size() >= 3 && prms[1].type() == TVariant::Object) { string fixId = (prms.size() >= 4) ? prms[3].getS() : ""; string faddr; AutoHD wFnc; if(fixId.size()) wFnc = SYS->nodeAt(fixId, 0, 0, 0, true); AutoHD args = prms[1].getO(); vector als; args.at().propList(als); TVariant aVal; try { //New call environment preparing or modifying presented if(wFnc.freeStat() || prms[2].getS() != wFnc.at().prog()) { // Update present function if(!wFnc.freeStat()) { wFnc.at().setStart(false); wFnc.at().setProg(prms[2].getS()); wFnc.at().setStart(true); } else { string langMod = TSYS::strParse(prms[0].getS(), 0, "."); if(!modPresent(langMod)) return false; //Prepare arguments structure TFunction argStr(fixId.size()?"uf_"+TSYS::strEncode(fixId,TSYS::oscdID):""); for(unsigned iA = 0; iA < als.size(); iA++) { aVal = args.at().propGet(als[iA]); IO::Type tp = IO::String; switch(aVal.type()) { case TVariant::Boolean: tp = IO::Boolean; break; case TVariant::Integer: tp = IO::Integer; break; case TVariant::Real: tp = IO::Real; break; case TVariant::String: tp = IO::String; break; case TVariant::Object: tp = IO::Object; break; default: break; } argStr.ioAdd(new IO(als[iA].c_str(),als[iA].c_str(),tp,IO::Default)); } //Get function id and compile. faddr = at(langMod).at().compileFunc(TSYS::strParse(prms[0].getS(),1,"."), argStr, prms[2].getS()); wFnc = SYS->nodeAt(faddr); } } //Prepare and execute TValFunc wCtx("UserFunc", &wFnc.at(), true, user); // Load values for(unsigned iA = 0; iA < als.size(); iA++) switch((aVal=args.at().propGet(als[iA])).type()) { case TVariant::Boolean: wCtx.setB(iA, aVal.getB()); break; case TVariant::Integer: wCtx.setI(iA, aVal.getI()); break; case TVariant::Real: wCtx.setR(iA, aVal.getR()); break; case TVariant::String: wCtx.setS(iA, aVal.getS()); break; case TVariant::Object: wCtx.setO(iA, aVal.getO()); break; default: break; } // Call function wCtx.calc(); // Place the call results and remove function object. for(int iA = 0; iA < wCtx.ioSize(); iA++) switch(wCtx.ioType(iA)) { case IO::Boolean: args.at().propSet(als[iA], wCtx.getB(iA)); break; case IO::Integer: args.at().propSet(als[iA], wCtx.getI(iA)); break; case IO::Real: args.at().propSet(als[iA], wCtx.getR(iA)); break; case IO::String: args.at().propSet(als[iA], wCtx.getS(iA)); break; case IO::Object: args.at().propSet(als[iA], wCtx.getO(iA)); break; default: break; } // Remove compiled function object wCtx.setFunc(NULL); wFnc.free(); if(faddr.size()) { if(fixId.size()) { prms[3].setS(faddr); prms[3].setModify(); } else SYS->nodeDel(faddr); } return true; } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } return false; } return TCntrNode::objFuncCall(iid, prms, user); } void TDAQS::subStart( ) { vector m_l, tmpl_lst; bool reply = false; int try_cnt = 0; do { //> Start template's libraries tmplLibList(tmpl_lst); for(unsigned i_lb = 0; i_lb < tmpl_lst.size(); i_lb++) try { tmplLibAt(tmpl_lst[i_lb]).at().start(true); } catch(TError &err) { if(try_cnt) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error starting the templates library '%s'."), tmpl_lst[i_lb].c_str()); } reply = true; } //> Enable controllers modList(m_l); for(unsigned i_m = 0; i_m < m_l.size(); i_m++) { vector c_l; at(m_l[i_m]).at().list(c_l); for(unsigned i_c = 0; i_c < c_l.size(); i_c++) { AutoHD cntr = at(m_l[i_m]).at().at(c_l[i_c]); if(/*!cntr.at().enableStat() &&*/ cntr.at().toEnable()) try{ cntr.at().enable(); } catch(TError &err) { if(try_cnt) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error enabling the templates library '%s'."), (m_l[i_m]+"."+c_l[i_c]).c_str()); } reply = true; } } } try_cnt++; } while(reply && try_cnt < 2); //> Archive subsystem start if(!SYS->archive().at().subStartStat() || !SYS->stopSignal()) SYS->archive().at().subStart(); //> Redundant task start if(!prcStRd) SYS->taskCreate(nodePath('.',true)+".redundant", 5, TDAQS::RdTask, this, 5, NULL, &prcStRd); //> Controllers start TSubSYS::subStart( ); } void TDAQS::subStop( ) { if(prcStRd) SYS->taskDestroy(nodePath('.',true)+".redundant", &endrunRd); vector m_l; //> Stop modList(m_l); for(unsigned i_m = 0; i_m < m_l.size(); i_m++) { vector c_l; at(m_l[i_m]).at().list(c_l); for(unsigned i_c = 0; i_c < c_l.size(); i_c++) { AutoHD cntr = at(m_l[i_m]).at().at(c_l[i_c]); if(cntr.at().startStat()) try{ cntr.at().stop(); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error stopping the templates library '%s'."), (m_l[i_m]+"."+c_l[i_c]).c_str()); } } } //> Disable for(unsigned i_m = 0; i_m < m_l.size(); i_m++) { vector c_l; at(m_l[i_m]).at().list(c_l); for(unsigned i_c = 0; i_c < c_l.size(); i_c++) { AutoHD cntr = at(m_l[i_m]).at().at(c_l[i_c]); if(cntr.at().enableStat()) try{ cntr.at().disable(); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); mess_sys(TMess::Error, _("Error disabling the templates library '%s'."), (m_l[i_m]+"."+c_l[i_c]).c_str()); } } } //> Stop template's libraries tmplLibList(m_l); for(unsigned i_lb = 0; i_lb < m_l.size(); i_lb++) tmplLibAt(m_l[i_lb]).at().start(false); TSubSYS::subStop(); } AutoHD TDAQS::daqAt( const string &path, char sep, bool noex, bool waitForAttr ) const { string cEl; AutoHD DAQnd = const_cast(this); const char *c_grp = "mod_"; for(int c_off = 0, c_lv = 0; (sep && (cEl=TSYS::strSepParse(path,0,sep,&c_off)).size()) || (!sep && (cEl=TSYS::pathLev(path,0,true,&c_off)).size()); ++c_lv) { bool lastEl = (c_lv > 2 && c_off >= (int)path.size()); if(waitForAttr && lastEl) c_grp = "a_"; AutoHD tNd = DAQnd.at().nodeAt(c_grp+cEl, 0, sep, 0, true); if(tNd.freeStat() && !(strcmp(c_grp,"a_") != 0 && lastEl && !(tNd=DAQnd.at().nodeAt("a_"+cEl,0,sep,0,true)).freeStat())) { if(noex) return AutoHD(); else throw err_sys(_("Missing the DAQ node '%s'."), path.c_str()); } c_grp = (c_lv == 0) ? "cntr_" : "prm_"; DAQnd = tNd; } return DAQnd; } AutoHD TDAQS::prmAt( const string &path, char sep, bool noex ) const { AutoHD DAQnd = daqAt(path, sep, noex); if(DAQnd.freeStat() || !dynamic_cast(&DAQnd.at())) { if(noex) return AutoHD(); else throw err_sys(_("The specified node is not the parameter '%s'."), path.c_str()); } return DAQnd; } AutoHD TDAQS::attrAt( const string &path, char sep, bool noex ) const { AutoHD DAQnd = daqAt(path, sep, noex, true); if(DAQnd.freeStat() || !dynamic_cast(&DAQnd.at())) { if(noex) return AutoHD(); else throw err_sys(_("The specified node is not the attribute '%s'."), path.c_str()); } return DAQnd; } bool TDAQS::rdActive( ) { ResAlloc res(mRdRes, false); for(map::iterator sit = mSt.begin(); sit != mSt.end(); sit++) if(sit->second.isLive) return true; return false; } string TDAQS::rdStRequest( const string &cntr, XMLNode &req, const string &prevSt, bool toRun ) { bool prevPresent = false; map::iterator sit; map::iterator cit; string lcPath = req.attr("path"); ResAlloc res(mRdRes, false); for(sit = mSt.begin(); sit != mSt.end(); sit++) { if(sit->second.isLive && (cit=sit->second.actCntr.find(cntr)) != sit->second.actCntr.end() && (!toRun || cit->second)) { if(prevSt.size() && !prevPresent) { if(sit->first == prevSt) prevPresent = true; continue; } //> Real request req.setAttr("path", "/"+sit->first+lcPath); try { SYS->transport().at().cntrIfCmd(req, "DAQRedundant"); sit->second.cnt++; return sit->first; } catch(TError err) { sit->second.isLive = false; sit->second.cnt = rdRestConnTm(); sit->second.lev = 0; sit->second.actCntr.clear(); continue; } } } at(TSYS::strSepParse(cntr,0,'.')).at().at(TSYS::strSepParse(cntr,1,'.')).at().setRedntUse(false); return ""; } void *TDAQS::RdTask( void *param ) { TDAQS &daq = *(TDAQS *)param; daq.endrunRd = false; vector cls; XMLNode req("st"); AutoHD cntr; map::iterator sit; map::iterator cit; while(!daq.endrunRd) try { int64_t work_tm = SYS->curTime(); daq.prcStRd = true; //Moved here for prevent long connection wait and next crash //> Update wait time for dead stations and process connections to stations ResAlloc res(daq.mRdRes, false); for(sit = daq.mSt.begin(); sit != daq.mSt.end(); sit++) { //>> Live stations and connect to new station process if(sit->second.isLive || (!sit->second.isLive && sit->second.cnt <= 0)) { //>> Send request for configuration to remote station req.clear()->setAttr("path","/"+sit->first+"/DAQ/%2fserv%2fredundant"); try { if(SYS->transport().at().cntrIfCmd(req,"DAQRedundant")) continue; sit->second.lev = s2i(req.attr("StLevel")); sit->second.actCntr.clear(); for(unsigned i_c = 0; i_c < req.childSize(); i_c++) if(req.childGet(i_c)->name() == "cntr") sit->second.actCntr[req.childGet(i_c)->attr("id")] = s2i(req.childGet(i_c)->attr("run")); sit->second.isLive = true; } catch(TError err) { sit->second.isLive = false; sit->second.lev = 0; sit->second.actCntr.clear(); sit->second.cnt = daq.rdRestConnTm(); continue; } } //>> Reconnect counter process if(!sit->second.isLive && sit->second.cnt > 0) sit->second.cnt -= daq.rdTaskPer(); } res.release(); //daq.prcStRd = true; //> Planing controllers' run and process requests to remote run controllers daq.rdActCntrList(cls); for(unsigned i_c = 0; i_c < cls.size(); i_c++) { cntr = daq.at(TSYS::strSepParse(cls[i_c],0,'.')).at().at(TSYS::strSepParse(cls[i_c],1,'.')); //>> Check contoller run plane if(cntr.at().redntMode() == TController::Off) cntr.at().setRedntUse(false); else { res.request(false); if(cntr.at().redntRun( ) == "") { int wLev = daq.rdStLevel(); for(sit = daq.mSt.begin(); sit != daq.mSt.end(); sit++) if(sit->second.isLive && (cit=sit->second.actCntr.find(cntr.at().workId())) != sit->second.actCntr.end() && cit->second) wLev = vmax(wLev,sit->second.lev); cntr.at().setRedntUse(daq.rdStLevel() < wLev); } else if(cntr.at().redntRun( ) == "") { int wLev = daq.rdStLevel(); for(sit = daq.mSt.begin(); sit != daq.mSt.end(); sit++) if(sit->second.isLive && (cit=sit->second.actCntr.find(cntr.at().workId())) != sit->second.actCntr.end() && cit->second) wLev = vmin(wLev,sit->second.lev); cntr.at().setRedntUse( daq.rdStLevel()>wLev ); } else if(cntr.at().redntRun( ) == "") { vector cls_lc; daq.rdActCntrList(cls_lc,true); bool remPresent = false; for(sit = daq.mSt.begin(); sit != daq.mSt.end(); sit++) if(sit->second.isLive && (cit=sit->second.actCntr.find(cntr.at().workId())) != sit->second.actCntr.end()) { if(!remPresent) remPresent = cit->second; int aCntr = 0; for(map::iterator scit = sit->second.actCntr.begin(); scit != sit->second.actCntr.end(); scit++) if(scit->second) aCntr++; if(((int)cls_lc.size()-aCntr) >= 0 && cit->second) break; } cntr.at().setRedntUse(sit != daq.mSt.end()); } else { for(sit = daq.mSt.begin(); sit != daq.mSt.end(); sit++) if(sit->second.isLive && (cit=sit->second.actCntr.find(cntr.at().workId())) != sit->second.actCntr.end() && cit->second && cntr.at().redntRun( ) == sit->first) break; cntr.at().setRedntUse(sit != daq.mSt.end()); } res.release(); } //>> Process remote run controllers if(cntr.at().startStat() && cntr.at().redntUse()) cntr.at().redntDataUpdate(); cntr.free(); } daq.mRdPrcTm = SYS->curTime()-work_tm; TSYS::taskSleep((int64_t)(daq.rdTaskPer()*1e9)); } catch(TError err) { mess_err(err.cat.c_str(),"%s",err.mess.c_str()); } daq.prcStRd = false; return NULL; } string TDAQS::optDescr( ) { return TSYS::strMess(_( "=================== Subsystem \"Data acquisition\" options ================\n" "------ Parameters of the section '%s' of the configuration file ------\n" "RdStLevel The current station redundant level.\n" "RdTaskPer The redundant task call period.\n" "RdRestConnTm Restore connection timeout to dead reserve stations.\n" "RdRestDtTm Depth of recovery time of archive data from the reserve station, when startup, in hours.\n\n" "RdStList Redundant stations list, separated symbol ';' (st1;st2).\n\n" ),nodePath().c_str()) + TSubSYS::optDescr(); } void TDAQS::cntrCmdProc( XMLNode *opt ) { string a_path = opt->attr("path"); //> Service commands process if(a_path == "/serv/redundant") { //Redundant service requests if(ctrChkNode(opt,"st",RWRWR_,"root",SDAQ_ID,SEC_RD)) { opt->setAttr("StLevel",i2s(rdStLevel())); map cntrLs; vector cls; rdActCntrList(cls); for(unsigned i_l = 0; i_l < cls.size(); i_l++) cntrLs[cls[i_l]] = false; rdActCntrList(cls,true); for(unsigned i_l = 0; i_l < cls.size(); i_l++) cntrLs[cls[i_l]] = true; for(map::iterator cit = cntrLs.begin(); cit != cntrLs.end(); cit++) opt->childAdd("cntr")->setAttr("id",cit->first)->setAttr("run",cit->second?"1":"0"); return; } } else if(a_path == "/serv/PrmAttr" && ctrChkNode(opt,"list",RWRWR_,"root",SDAQ_ID,SEC_RD)) //Parameter and/or attributes list-browse ctrListPrmAttr(opt, opt->attr("base"), s2i(opt->attr("toPrm")), opt->attr("sep")[0], opt->attr("pref")); //> Get page info if(opt->name() == "info") { TSubSYS::cntrCmdProc(opt); ctrMkNode("grp",opt,-1,"/br/tmplb_",_("Templates library"),RWRWR_,"root",SDAQ_ID,2,"idm",OBJ_NM_SZ,"idSz",OBJ_ID_SZ); if(ctrMkNode("area",opt,0,"/redund",_("Redundancy"))) { ctrMkNode("fld",opt,-1,"/redund/status",_("Status"),R_R_R_,"root",SDAQ_ID,1,"tp","str"); ctrMkNode("fld",opt,-1,"/redund/statLev",_("Station level"),RWRWR_,"root",SDAQ_ID,1,"tp","dec"); ctrMkNode("fld",opt,-1,"/redund/tskPer",_("Redundant task period, seconds"),RWRWR_,"root",SDAQ_ID,1,"tp","real"); ctrMkNode("fld",opt,-1,"/redund/restConn",_("Restore connection timeout, seconds"),RWRWR_,"root",SDAQ_ID,1,"tp","dec"); ctrMkNode("fld",opt,-1,"/redund/restDtTm",_("Depth time of restoring data at the starting, hours"),RWRWR_,"root",SDAQ_ID,1, "tp","real"); if(ctrMkNode("table",opt,-1,"/redund/sts",_("Stations"),RWRWR_,"root",SDAQ_ID,2,"key","st","s_com","add,del")) { ctrMkNode("list",opt,-1,"/redund/sts/st",_("Identifier"),RWRWR_,"root",SDAQ_ID,3,"tp","str","dest","select","select","/redund/lsSt"); ctrMkNode("list",opt,-1,"/redund/sts/name",_("Name"),R_R_R_,"root",SDAQ_ID,1,"tp","str"); ctrMkNode("list",opt,-1,"/redund/sts/live",_("Live"),R_R_R_,"root",SDAQ_ID,1,"tp","bool"); ctrMkNode("list",opt,-1,"/redund/sts/lev",_("Level"),R_R_R_,"root",SDAQ_ID,1,"tp","dec"); ctrMkNode("list",opt,-1,"/redund/sts/cnt",_("Counter"),R_R_R_,"root",SDAQ_ID,1,"tp","real"); ctrMkNode("list",opt,-1,"/redund/sts/run",_("Run"),R_R_R_,"root",SDAQ_ID,1,"tp","str"); } ctrMkNode("comm",opt,-1,"/redund/hostLnk",_("Go to remote stations list configuration"),0660,"root","Transport",1,"tp","lnk"); if(ctrMkNode("table",opt,-1,"/redund/cntr",_("Controllers"),RWRWR_,"root",SDAQ_ID,1,"key","id")) { ctrMkNode("list",opt,-1,"/redund/cntr/id",_("Controller"),R_R_R_,"root",SDAQ_ID,1,"tp","str"); ctrMkNode("list",opt,-1,"/redund/cntr/nm",_("Name"),R_R_R_,"root",SDAQ_ID,1,"tp","str"); ctrMkNode("list",opt,-1,"/redund/cntr/start",_("Run."),RWRWR_,"root",SDAQ_ID,1,"tp","bool"); ctrMkNode("list",opt,-1,"/redund/cntr/rdndt",_("Redund."),RWRWR_,"root",SDAQ_ID,4, "tp","int", "dest","select", "sel_id",(i2s(TController::Off)+";"+i2s(TController::Asymmetric)/*+";"+i2s(TController::OnlyAlarms)*/).c_str(), "sel_list",_("Off;Asymmetric"/*;Only alarms"*/)); ctrMkNode("list",opt,-1,"/redund/cntr/prefRun",_("Pref. to run"),RWRWR_,"root",SDAQ_ID,4,"tp","str", "idm","1","dest","select","select","/redund/lsMode"); ctrMkNode("list",opt,-1,"/redund/cntr/remoted",_("Remote"),R_R_R_,"root",SDAQ_ID,1,"tp","bool"); } } if(ctrMkNode("area",opt,1,"/tpllibs",_("Template libraries"))) ctrMkNode("list",opt,-1,"/tpllibs/lb",_("Template libraries"),RWRWR_,"root",SDAQ_ID,5, "tp","br","idm",OBJ_NM_SZ,"s_com","add,del","br_pref","tmplb_","idSz",OBJ_ID_SZ); ctrMkNode("fld",opt,-1,"/help/g_help",_("Options help"),R_R___,"root",SDAQ_ID,3,"tp","str","cols","90","rows","10"); return; } //> Process command to page if(a_path == "/br/tmplb_" || a_path == "/tpllibs/lb") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) { vector lst; tmplLibList(lst); for(unsigned iA = 0; iA < lst.size(); iA++) opt->childAdd("el")->setAttr("id",lst[iA])->setText(tmplLibAt(lst[iA]).at().name()); } if(ctrChkNode(opt,"add",RWRWR_,"root",SDAQ_ID,SEC_WR)) tmplLibReg(new TPrmTmplLib(TSYS::strEncode(opt->attr("id"),TSYS::oscdID).c_str(),opt->text().c_str(),"*.*")); if(ctrChkNode(opt,"del",RWRWR_,"root",SDAQ_ID,SEC_WR)) tmplLibUnreg(opt->attr("id"),1); } else if(a_path == "/redund/status" && ctrChkNode(opt,"get",R_R_R_,"root",SDAQ_ID)) opt->setText(TSYS::strMess(_("Spent time: %s."),tm2s(1e-6*mRdPrcTm).c_str())); else if(a_path == "/redund/statLev") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) opt->setText(i2s(rdStLevel())); if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR)) setRdStLevel(s2i(opt->text())); } else if(a_path == "/redund/tskPer") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) opt->setText(r2s(rdTaskPer())); if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR)) setRdTaskPer(s2r(opt->text())); } else if(a_path == "/redund/restConn") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) opt->setText(i2s(rdRestConnTm())); if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR)) setRdRestConnTm(s2i(opt->text())); } else if(a_path == "/redund/restDtTm") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) opt->setText(r2s(rdRestDtTm())); if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR)) setRdRestDtTm(s2r(opt->text())); } else if(a_path == "/redund/sts") { ResAlloc res(mRdRes, true); if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) { XMLNode *n_st = ctrMkNode("list",opt,-1,"/redund/sts/st","",RWRWR_,"root",SDAQ_ID); XMLNode *n_name = ctrMkNode("list",opt,-1,"/redund/sts/name","",R_R_R_,"root",SDAQ_ID); XMLNode *n_live = ctrMkNode("list",opt,-1,"/redund/sts/live","",R_R_R_,"root",SDAQ_ID); XMLNode *n_lev = ctrMkNode("list",opt,-1,"/redund/sts/lev","",R_R_R_,"root",SDAQ_ID); XMLNode *n_cnt = ctrMkNode("list",opt,-1,"/redund/sts/cnt","",R_R_R_,"root",SDAQ_ID); XMLNode *n_run = ctrMkNode("list",opt,-1,"/redund/sts/run","",R_R_R_,"root",SDAQ_ID); for(map::iterator sit = mSt.begin(); sit != mSt.end(); sit++) { if(n_st) n_st->childAdd("el")->setText(sit->first); if(n_name) n_name->childAdd("el")->setText(SYS->transport().at().extHostGet("*",sit->first).name); if(n_live) n_live->childAdd("el")->setText(sit->second.isLive?"1":"0"); if(n_lev) n_lev->childAdd("el")->setText(i2s(sit->second.lev)); if(n_cnt) n_cnt->childAdd("el")->setText(r2s(sit->second.cnt)); if(n_run) { string cls; for( map::iterator cit = sit->second.actCntr.begin(); cit != sit->second.actCntr.end(); cit++ ) cls += cit->first+(cit->second?" (+); ":"; "); n_run->childAdd("el")->setText(cls); } } } if(ctrChkNode(opt,"add",RWRWR_,"root",SDAQ_ID,SEC_WR)) { mSt[_("")] = SStat(); modif(); } if(ctrChkNode(opt,"del",RWRWR_,"root",SDAQ_ID,SEC_WR)) { mSt.erase(opt->attr("key_st")); modif(); } if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR) && opt->attr("col") == "st") { mSt.erase(opt->attr("key_st")); mSt[opt->text()] = SStat(); modif(); } } else if(a_path == "/redund/lsSt" && ctrChkNode(opt)) { vector hls; SYS->transport().at().extHostList("*", hls); for(unsigned iH = 0; iH < hls.size(); iH++) opt->childAdd("el")->setText(hls[iH].id); } else if(a_path == "/redund/hostLnk" && ctrChkNode(opt,"get",0660,"root","Transport",SEC_RD)) opt->setText("/Transport"); else if(a_path == "/redund/cntr") { if(ctrChkNode(opt,"get",RWRWR_,"root",SDAQ_ID,SEC_RD)) { XMLNode *n_id = ctrMkNode("list",opt,-1,"/redund/cntr/id","",R_R_R_,"root",SDAQ_ID); XMLNode *n_nm = ctrMkNode("list",opt,-1,"/redund/cntr/nm","",R_R_R_,"root",SDAQ_ID); XMLNode *n_start = ctrMkNode("list",opt,-1,"/redund/cntr/start","",RWRWR_,"root",SDAQ_ID); XMLNode *n_rdndt = ctrMkNode("list",opt,-1,"/redund/cntr/rdndt","",RWRWR_,"root",SDAQ_ID); XMLNode *n_prefRun = ctrMkNode("list",opt,-1,"/redund/cntr/prefRun","",RWRWR_,"root",SDAQ_ID); XMLNode *n_rem = ctrMkNode("list",opt,-1,"/redund/cntr/remoted","",R_R_R_,"root",SDAQ_ID); vector mls, cls; modList(mls); AutoHD cntr; for(unsigned i_m = 0; i_m < mls.size(); i_m++) { if(!at(mls[i_m]).at().redntAllow()) continue; at(mls[i_m]).at().list(cls); for(unsigned i_c = 0; i_c < cls.size(); i_c++) { cntr = at(mls[i_m]).at().at(cls[i_c]); if(n_id) n_id->childAdd("el")->setText(mls[i_m]+"."+cls[i_c]); if(n_nm) n_nm->childAdd("el")->setText(cntr.at().name()); if(n_start) n_start->childAdd("el")->setText(cntr.at().startStat()?"1":"0"); if(n_rdndt) n_rdndt->childAdd("el")->setText(i2s(cntr.at().redntMode())); if(n_prefRun) n_prefRun->childAdd("el")->setText(cntr.at().redntRun()); if(n_rem) n_rem->childAdd("el")->setText(cntr.at().redntUse( )?"1":"0"); } } } if(ctrChkNode(opt,"set",RWRWR_,"root",SDAQ_ID,SEC_WR)) { string col = opt->attr("col"); AutoHD cntr = at(TSYS::strSepParse(opt->attr("key_id"),0,'.')).at(). at(TSYS::strSepParse(opt->attr("key_id"),1,'.')); if(col == "start") s2i(opt->text()) ? cntr.at().start() : cntr.at().stop(); else if(col == "rdndt") cntr.at().setRedntMode((TController::Redundant)s2i(opt->text())); else if(col == "prefRun") cntr.at().setRedntRun(opt->text()); } } else if(a_path == "/redund/lsMode" && ctrChkNode(opt)) { opt->childAdd("el")->setAttr("id","")->setText(_("")); opt->childAdd("el")->setAttr("id","")->setText(_("")); opt->childAdd("el")->setAttr("id","")->setText(_("")); vector sls; rdStList(sls); for(unsigned i_s = 0; i_s < sls.size(); i_s++) opt->childAdd("el")->setAttr("id",sls[i_s])->setText(SYS->transport().at().extHostGet("*",sls[i_s]).name); } else if(a_path == "/help/g_help" && ctrChkNode(opt,"get",R_R___,"root",SDAQ_ID)) opt->setText(optDescr()); else TSubSYS::cntrCmdProc(opt); }