//OpenSCADA system file: tsys.h /*************************************************************************** * 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. * ***************************************************************************/ #ifndef TSYS_H #define TSYS_H //Program constants #define PACKAGE_LICENSE "GPL v2" #define PACKAGE_DESCR _("Open Supervisory Control And Data Acquisition") #define PACKAGE_AUTHOR _("Roman Savochenko") #define PACKAGE_SITE "http://oscada.org" //Other system's constants #define OBJ_ID_SZ "20" // Typical object's ID size. Warning, the size can cause key limit on MySQL like DB. #define OBJ_NM_SZ "50" // Typical object's NAME size. #define USER_FILE_LIMIT 1048576 // Loading and processing files limit into userspace #define STR_BUF_LEN 10000 // Length of string buffers (no string class) #define NSTR_BUF_LEN 100 // Length of string buffers for number #define STD_WAIT_DELAY 100 // Standard wait dalay (ms) #define STD_CACHE_LIM 100 // Standard caches limit #define STD_WAIT_TM 10 // Standard timeouts length (s), and interface wait for long #define STD_INTERF_TM 5 // Interface wait for long (s) #define BUF_ARCH_NM "" #define ALRM_ARCH_NM "" #define DB_CFG "" #define DB_NULL "" #include #include #include #include #include #include #include #define __func__ __PRETTY_FUNCTION__ #define vmin(a,b) ((a) < (b) ? (a) : (b)) #define vmax(a,b) ((a) > (b) ? (a) : (b)) #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "tbds.h" #include "tuis.h" #include "tarchives.h" #include "tdaqs.h" #include "tprotocols.h" #include "ttransports.h" #include "tspecials.h" #include "tmodschedul.h" #include "tsecurity.h" using std::string; using std::vector; namespace OSCADA { //************************************************* //* TSYS * //************************************************* class TSYS : public TCntrNode { friend class TMess; public: //Data enum Code { PathEl, HttpURL, Html, JavaSc, SQL, Custom, base64, FormatPrint, oscdID, Bin, Reverse, ShieldSimb, ToLower }; enum IntView { Dec, Oct, Hex }; // Task structure class STask { public: //Data enum Flgs { Detached = 0x01, FinishTask = 0x02 }; //Methods STask( ) : thr(0), policy(0), prior(0), tid(0), flgs(0), tm_beg(0), tm_end(0), tm_per(0), tm_pnt(0), cycleLost(0), lagMax(0), consMax(0) { } STask( pthread_t ithr, char ipolicy, char iprior ) : thr(ithr), policy(ipolicy), prior(iprior), tid(0), flgs(0), tm_beg(0), tm_end(0), tm_per(0), tm_pnt(0), cycleLost(0), lagMax(0), consMax(0) { } float consumpt( ) const { return tm_beg ? 1e-9*(tm_end-tm_beg) : 0; } float period( ) const { return tm_beg ? 1e-9*(tm_per-tm_beg) : 0; } //Attributes string path; pthread_t thr; uint8_t policy, prior; pid_t tid; ResString cpuSet; void *(*task) (void *); void *taskArg; unsigned flgs; int64_t tm_beg, tm_end, tm_per, tm_pnt, cycleLost, lagMax, consMax; }; //Public methods TSYS( int argi, char **argb, char **env ); ~TSYS( ); int start( ); void stop( ); int stopSignal( ) { return mStopSignal; } //> Programs options string id( ) { return mId.c_str(); } string name( ) { return mName; } void setName( const string &vl ) { mName = vl; modif(); } string user( ) { return mUser; } //Run user name string host( ); void list( vector &list ) const { chldList(mSubst, list); } bool present( const string &name ) const { return chldPresent(mSubst, name); } void add( TSubSYS *sub ) { chldAdd(mSubst, sub); } void del( const string &name ) { chldDel(mSubst, name); } AutoHD at( const string &name ) const { return chldAt(mSubst, name); } AutoHD ui( ) { return at("UI"); } AutoHD archive( ) { return at("Archive"); } AutoHD db( ) { return at("BD"); } AutoHD daq( ) { return at("DAQ"); } AutoHD protocol( ) { return at("Protocol"); } AutoHD transport( ) { return at("Transport"); } AutoHD special( ) { return at("Special"); } AutoHD modSchedul( ) { return at("ModSched"); } AutoHD security( ) { return at("Security"); } string workDir( ); string icoDir( ) { return mIcoDir; } string modDir( ) { return mModDir; } void setWorkDir( const string &wdir, bool init = false ); void setIcoDir( const string &idir, bool init = false ); void setModDir( const string &mdir, bool init = false ); //> Config-file functions string cfgFile( ) { return mConfFile; } XMLNode &cfgRoot( ) { return rootN; } XMLNode *cfgNode( const string &path, bool create = false ); void modifCfg( bool chkPossibleWR = false ); string workDB( ) { return mWorkDB; } string selDB( ) { return mSelDB; } string mainCPUs( ) { return mMainCPUs; } bool clockRT( ) { return mClockRT; } bool saveAtExit( ) { return mSaveAtExit; } int savePeriod( ) { return mSavePeriod; } void setWorkDB( const string &wdb ) { mWorkDB = wdb; modifG(); } void setSelDB( const string &vl ) { mSelDB = vl; } void setMainCPUs( const string &vl ); void setClockRT( bool vl ) { mClockRT = vl; modif(); } void setSaveAtExit( bool vl ) { mSaveAtExit = vl; modif(); } void setSavePeriod( int vl ) { mSavePeriod = vmax(0,vl); modif(); } bool chkSelDB( const string& wDB, bool isStrong = false ); static void sighandler( int signal, siginfo_t *siginfo, void *context ); //> Short time dimensions int nCPU( ) { return mN_CPU; } uint64_t sysClk( ) { return mSysclc; } void clkCalc( ); uint64_t shrtCnt( ) { #if defined (__i386__) || defined (__x86_64__) unsigned int cntl, cnth; asm volatile("rdtsc; movl %%eax,%0; movl %%edx,%1;":"=r"(cntl),"=r"(cnth)::"%eax","%edx"); return ((uint64_t)cnth<<32)+cntl; #else return 0; #endif } static long HZ( ); static int64_t curTime( ); //Current system time (usec) //> Tasks control void taskCreate( const string &path, int priority, void *(*start_routine)(void *), void *arg, int wtm = 5, pthread_attr_t *pAttr = NULL, bool *startSt = NULL ); void taskDestroy( const string &path, bool *endrunCntr = NULL, int wtm = 5, bool noSignal = false ); double taskUtilizTm( const string &path, bool max = false ); static bool taskEndRun( ); // Check for the task endrun by signal SIGUSR1 static const STask& taskDescr( ); // Get the current task control structure //> Sleep task for period grid on ns or to cron time. static int sysSleep( float tm ); //System sleep in seconds down to nanoseconds (1e-9) static void taskSleep( int64_t per, const string &cron = "", int64_t *lag = NULL ); // in nanoseconds static time_t cron( const string &vl, time_t base = 0 ); //> Wait event with timeout support static bool eventWait( bool &m_mess_r_stat, bool exempl, const string &loc, time_t time = 0 ); // Program counters bool cntrEmpty( ); double cntrGet( const string &id ); void cntrSet( const string &id, double vl ); void cntrIter( const string &id, double vl ); //> Convert value to string static string int2str( int val, IntView view = Dec ); static string uint2str( unsigned val, IntView view = Dec ); static string ll2str( long long val, IntView view = Dec ); static string real2str( double val, int prec = 15, char tp = 'g' ); static double realRound( double val, int dig = 0, bool toint = false ) { double rez = floor(val*pow(10,dig)+0.5)/pow(10,dig); return toint ? floor(rez+0.5) : rez; } static string atime2str( time_t tm, const string &format = "" ); static string time2str( double tm ); static string cpct2str( double cnt ); // Convert value to string static double str2real( const string &val ); // Adress convertors static string addr2str( void *addr ); static void *str2addr( const string &str ); //> Path and string parse static string strTrim( const string &val, const string &cfg = " \n\t\r" ); static string strSepParse( const string &str, int level, char sep, int *off = NULL ); static string strParse( const string &str, int level, const string &sep, int *off = NULL, bool mergeSepSymb = false ); static string strLine( const string &str, int level, int *off = NULL ); static string pathLev( const string &path, int level, bool decode = true, int *off = NULL ); static string path2sepstr( const string &path, char sep = '.' ); static string sepstr2path( const string &str, char sep = '.' ); static string strEncode( const string &in, Code tp, const string &opt1 = "" ); static string strDecode( const string &in, Code tp = Custom, const string &opt1 = "" ); static string strMess( const char *fmt, ... ); static string strMess( unsigned len, const char *fmt, ... ); static string strLabEnum( const string &base ); static string strCompr( const string &in, int lev = -1 ); static string strUncompr( const string &in ); //> Unaligned read from memory for some ARM and other static inline uint16_t getUnalign16( const void *p ) { struct su16 { uint16_t x; } __attribute__((packed)); const struct su16 *ptr = (const struct su16 *)p; return ptr->x; } static inline uint32_t getUnalign32( const void *p ) { struct su32 { uint32_t x; } __attribute__((packed)); const struct su32 *ptr = (const struct su32 *)p; return ptr->x; } static inline uint64_t getUnalign64( const void *p ) { struct su64 { uint64_t x; } __attribute__((packed)); const struct su64 *ptr = (const struct su64 *)p; return ptr->x; } static inline int getUnalignInt( const void *p ) { struct suInt { int x; } __attribute__((packed)); const struct suInt *ptr = (const struct suInt *)p; return ptr->x; } static inline float getUnalignFloat( const void *p ) { struct sFloat64 { float x; } __attribute__((packed)); const struct sFloat64 *ptr = (const struct sFloat64 *)p; return ptr->x; } static inline double getUnalignDbl( const void *p ) { struct sDbl { double x; } __attribute__((packed)); const struct sDbl *ptr = (const struct sDbl *)p; return ptr->x; } //> Endian convert static uint16_t i16_LE( uint16_t in ); static uint32_t i32_LE( uint32_t in ); static uint64_t i64_LE( uint64_t in ); static uint16_t i16_BE( uint16_t in ); static uint32_t i32_BE( uint32_t in ); static uint64_t i64_BE( uint64_t in ); static float floatLE( float in ); static float floatLErev( float in ); static double doubleLE( double in ); static double doubleLErev( double in ); static float floatBE( float in ); static float floatBErev( float in ); static double doubleBE( double in ); static double doubleBErev( double in ); //> Reentrant commandline processing string optDescr( ); //get comand line options string getCmdOpt( int &curPos, string *argVal = NULL ); static string getCmdOpt_( int &curPos, string *argVal, int argc, char **argv ); bool cmdOptPresent( const string &opt ); string cmdOpt( const string &opt, const string &setVl = "" ); int permCrtFiles( bool exec = false ); // Control interface functions static void ctrListFS( XMLNode *nd, const string &fsBase, const string &fileExt = "" ); //Inline file system browsing ResRW &cfgRes( ) { return mCfgRes; } //Public attributes static bool finalKill; //Final object's kill flag. For dead requsted resources protected: //Protected methods void load_( ); void save_( ); private: //Private attributes const int argc; //Comand line seting counter. const char **argv; //Comand line seting buffer. const char **envp; //System environment. //Data enum MdfSYSFlds { MDF_WorkDir = 0x01, MDF_IcoDir = 0x02, MDF_ModDir = 0x04, MDF_LANG = 0x08 }; //Private methods const char *nodeName( ) const { return mId.c_str(); } const char *nodeNameSYSM( ) const { return mName.c_str(); } void cfgFileLoad( ); void cfgFileSave( ); void cfgPrmLoad( ); void cfgFileScan( bool first = false, bool up = false ); void cntrCmdProc( XMLNode *opt ); // Control interface command process TVariant objFuncCall( const string &id, vector &prms, const string &user ); static unsigned char getBase64Code( unsigned char asymb ); static void *taskWrap( void *stas ); //Private attributes string mUser, // A owner user name! mConfFile, // Config-file name mId, // Station id mName, // Station name mIcoDir, // Icons directory mModDir; // Modules directory string mWorkDB, mSelDB,// Work and selected DB mMainCPUs; // Main used processors set bool mSaveAtExit; // Save at exit int mSavePeriod; // Save period (s) for periodic system saving to DB XMLNode rootN; // Root of the config-file tree string rootCfgFl; // Root node's config-file name time_t rootFlTm; // Root node's config-file's modify time unsigned rootModifCnt; // Root tree modify counter, used for save tree to file detect unsigned sysModifFlgs; // System fields modif flags int mStopSignal, // Stop station signal mSubst; // Subsystem tree id map mTasks; static pthread_key_t sTaskKey; ResRW taskRes, mCfgRes; int mN_CPU; pthread_t mainPthr; uint64_t mSysclc; bool mClockRT; //Used clock REALTIME, else it is MONOTONIC map mCmdOpts; map mCntrs; //Counters struct sigaction sigActOrig; }; //************************************************* //* Global functions for OSCADA namespace * template fVal fmin( fVal a, fVal b ) { return (a < b) ? a : b; } template fVal fmax( fVal a, fVal b ) { return (a > b) ? a : b; } inline string i2s( int val, TSYS::IntView view = TSYS::Dec ) { return TSYS::int2str(val, view); } inline string u2s( unsigned val, TSYS::IntView view = TSYS::Dec ){ return TSYS::uint2str(val, view); } inline string ll2s( long long val, TSYS::IntView view = TSYS::Dec ){ return TSYS::ll2str(val, view); } inline string r2s( double val, int prec = 15, char tp = 'g' ) { return TSYS::real2str(val, prec, tp); } inline double rRnd( double val, int dig = 0, bool toint = false ){ return TSYS::realRound(val, dig, toint); } inline string atm2s( time_t tm, const string &format = "" ) { return TSYS::atime2str(tm, format); } inline string tm2s( double tm ) { return TSYS::time2str(tm); } inline int s2i( const string &val ) { return atoi(val.c_str()); } inline long long s2ll( const string &val ) { return atoll(val.c_str()); } inline double s2r( const string &val ) { return /*TSYS::str2real(val); }*/ atof(val.c_str()); } inline string sTrm( const string &val, const string &cfg = " \n\t\r") { return TSYS::strTrim(val, cfg); } extern TSYS *SYS; } #endif // TSYS_H