Commit 95ad1973 authored by Claes Sjofors's avatar Claes Sjofors

Sev stat table added, and event log first commit

parent 1d727d1f
......@@ -36,6 +36,7 @@
#if defined PWRE_CONF_MYSQL
#include <math.h>
#include "pwr.h"
#include "co_cdh.h"
......@@ -56,6 +57,7 @@
#include "rt_errh.h"
#include "pwr_baseclasses.h"
#define sev_cStatInterval 10
#define sev_cGarbageInterval 120
#define sev_cGarbageCycle 86400
......@@ -403,27 +405,54 @@ int sev_server::delete_item( qcom_sQid tgt, sev_sMsgHistItemDelete *rmsg)
int sev_server::mainloop()
{
qcom_sQid qid;
int tmo = 1000;
int tmo = 200;
qcom_sGet get;
void *mp;
pwr_tStatus sts;
pwr_tTime next_garco, currenttime;
pwr_tTime next_stat;
pwr_tDeltaTime stat_interval;
pwr_tDeltaTime garco_interval;
pwr_tTime before_get;
pwr_tDeltaTime busy = pwr_cNDeltaTime;
pwr_tDeltaTime idle = pwr_cNDeltaTime;
pwr_tDeltaTime dt;
float a = exp(-((float)sev_cStatInterval)/300);
qid.nid = 0;
qid.qix = sev_eProcSevServer;
time_FloatToD( &garco_interval, sev_cGarbageInterval);
time_FloatToD( &stat_interval, sev_cStatInterval);
time_GetTime( &currenttime);
time_Aadd( &next_garco, &currenttime, &garco_interval);
time_Aadd( &next_stat, &currenttime, &stat_interval);
m_server_status = PWR__SRUN;
for (;;) {
memset( &get, 0, sizeof(get));
time_GetTime( &before_get);
time_Adiff( &dt, &before_get, &currenttime);
time_Dadd( &busy, &busy, &dt);
mp = qcom_Get(&sts, &qid, &get, tmo);
time_GetTime( &currenttime);
time_Adiff( &dt, &currenttime, &before_get);
time_Dadd( &idle, &idle, &dt);
if ( time_Acomp( &currenttime, &next_stat) == 1) {
m_stat.current_load = 100.0 * time_DToFloat(0, &busy)/(time_DToFloat(0, &busy)+time_DToFloat(0, &idle));
if ( m_stat.medium_load == 0)
m_stat.medium_load = m_stat.current_load;
else
m_stat.medium_load = a * m_stat.medium_load + (1.0-a) * m_stat.current_load;
m_db->store_stat( &m_stat);
time_Aadd( &next_stat, &next_stat, &stat_interval);
busy = pwr_cNDeltaTime;
idle = pwr_cNDeltaTime;
}
if ( time_Acomp( &currenttime, &next_garco) == 1) {
garbage_collector();
time_Aadd( &next_garco, &next_garco, &garco_interval);
......@@ -441,12 +470,15 @@ int sev_server::mainloop()
case sev_eMsgType_HistItems:
errh_Info("Itemlist received %s", cdh_NodeIdToString( 0, get.reply.nid, 0, 0));
check_histitems( (sev_sMsgHistItems *) mp, get.size);
m_stat.items_msg_cnt++;
break;
case sev_eMsgType_HistDataStore:
receive_histdata( (sev_sMsgHistDataStore *) mp, get.size);
m_stat.datastore_msg_cnt++;
break;
case sev_eMsgType_HistDataGetRequest:
send_histdata( get.reply, (sev_sMsgHistDataGetRequest *) mp, get.size);
m_stat.dataget_msg_cnt++;
break;
case sev_eMsgType_HistItemsRequest:
send_itemlist( get.reply);
......@@ -459,6 +491,12 @@ int sev_server::mainloop()
break;
case sev_eMsgType_HistObjectDataGetRequest:
send_objecthistdata( get.reply, (sev_sMsgHistDataGetRequest *) mp, get.size);
m_stat.dataget_msg_cnt++;
break;
case sev_eMsgType_EventsStore:
printf( "sev_server Events received\n");
receive_events( (sev_sMsgEventsStore *) mp, get.size);
m_stat.eventstore_msg_cnt++;
break;
default: ;
}
......@@ -501,6 +539,7 @@ int sev_server::check_histitems( sev_sMsgHistItems *msg, unsigned int size)
}
for ( int i = 0; i < item_cnt; i++) {
if ( msg->Items[i].attrnum > 0) {
// Deadband requires id variable
if ( msg->Items[i].options & pwr_mSevOptionsMask_UseDeadBand)
......@@ -512,7 +551,7 @@ int sev_server::check_histitems( sev_sMsgHistItems *msg, unsigned int size)
if(msg->Items[i].attrnum > 1) {
//printf( "Received: %s.%s AttrNum:%d\n", msg->Items[i].oname, msg->Items[i].attr[0].aname, msg->Items[i].attrnum);
sev_sHistItem *buffP = &msg->Items[i];
while(buffP < &msg->Items[item_cnt]) {
while( (char *)buffP < (char *)msg + size) {
//for(size_t j = 0; j < buffP->attrnum; j++) {
// printf( "Received: %s.%s\n", buffP->oname, buffP->attr[j].aname);
//}
......@@ -523,8 +562,7 @@ int sev_server::check_histitems( sev_sMsgHistItems *msg, unsigned int size)
strcpy( tmpStr, buffP->oname);
//Point out attribute name
s = strchr( tmpStr, '.');
if (s)
{
if (s) {
*s = 0;
strcpy( attributeName, s+1);
}
......@@ -608,8 +646,7 @@ int sev_server::check_histitems( sev_sMsgHistItems *msg, unsigned int size)
//so that databaseadministrator knows which columns he can delete
//If something was wrong during checking of attributes we ignore this object
if ( ODD(m_sts) )
{
if ( ODD(m_sts) ) {
//Create space for the old values used if we have deadband active
if( m_db->m_items[idx].old_value != 0 ) {
free(m_db->m_items[idx].old_value);
......@@ -670,6 +707,22 @@ int sev_server::check_histitems( sev_sMsgHistItems *msg, unsigned int size)
rp->idx = idx;
}
}
else {
// SevHistEvents item
printf( "Event item received\n");
if ( !m_db->check_item( &m_sts, msg->Items[i].oid, msg->Items[i].oname, (char *)"Events",
storagetime, (pwr_eType)0, 0,
msg->Items[i].description, (char *)"", msg->Items[i].scantime,
0, msg->Items[i].options, &idx)) {
m_db->add_item( &m_sts, msg->Items[i].oid, msg->Items[i].oname, (char *)"Events",
storagetime, (pwr_eType)0, 0,
msg->Items[i].description, (char *)"", msg->Items[i].scantime,
0, msg->Items[i].options, &idx);
if ( EVEN(m_sts)) return m_sts;
}
}
}
printf( "---- Node up (%d) ----\n", nid);
return 1;
}
......@@ -824,6 +877,47 @@ int sev_server::send_objecthistdata( qcom_sQid tgt, sev_sMsgHistDataGetRequest *
return 1;
}
int sev_server::receive_events( sev_sMsgEventsStore *msg, unsigned int size)
{
sev_sEvent *ep = (sev_sEvent *)&msg->Events[0];
// Get index
int idx;
int found = 0;
for ( unsigned int i = 0; i < m_db->m_items.size(); i++) {
if ( m_db->m_items[i].deleted)
continue;
if ( cdh_ObjidIsEqual( m_db->m_items[i].oid, msg->Oid)) {
idx = i;
found = 1;
break;
}
}
if ( !found) {
errh_Error( "Unknown event table, objid (%d,%d)", msg->Oid.vid, msg->Oid.oix);
return 1;
}
for ( unsigned int i = 0; i < msg->NumEvents; i++) {
sev_event ev;
printf( "Event Type %d Id %d text \"%s\"\n", ep->type, ep->eventid_idx, ep->eventtext);
ev.type = ep->type;
ev.eventprio = ep->eventprio;
ev.eventid.Nix = ep->eventid_nix;
ev.eventid.BirthTime.tv_sec = ep->eventid_birthtime;
ev.eventid.BirthTime.tv_nsec = 0;
ev.eventid.Idx = ep->eventid_idx;
ev.time = net_NetTimeToTime( &ep->time);
strcpy( ev.eventtext, ep->eventtext);
strcpy( ev.eventname, ep->eventname);
m_db->store_event( &m_sts, idx, &ev);
ep++;
}
return 1;
}
void sev_server::garbage_collector()
{
int item_size = m_db->m_items.size();
......
......@@ -72,9 +72,9 @@ class sev_server {
public:
//TODO should this really be in this file?
static const unsigned int constSevVersion = 2;
static const unsigned int constSevVersion = 3;
sev_server() : m_server_status(0), m_refid(0), m_msg_id(0) {}
sev_server() : m_server_status(0), m_refid(0), m_msg_id(0) {memset(&m_stat,0,sizeof(m_stat));}
pwr_tStatus m_sts;
pwr_tStatus m_server_status;
......@@ -83,6 +83,7 @@ class sev_server {
unsigned int m_msg_id;
sev_db *m_db;
int m_noneth;
sev_sStat m_stat;
int init( int noneth);
int connect();
......@@ -95,6 +96,7 @@ class sev_server {
int send_itemlist( qcom_sQid tgt);
int send_server_status( qcom_sQid tgt);
int delete_item( qcom_sQid tgt, sev_sMsgHistItemDelete *rmsg);
int receive_events( sev_sMsgEventsStore *msg, unsigned int size);
void garbage_collector();
void garbage_item( int idx);
};
......
......@@ -41,9 +41,19 @@
#include "pwr.h"
#include "pwr_class.h"
#include "rt_mh_net.h"
using namespace std;
typedef struct {
float current_load;
float medium_load;
unsigned int datastore_msg_cnt;
unsigned int dataget_msg_cnt;
unsigned int items_msg_cnt;
unsigned int eventstore_msg_cnt;
} sev_sStat;
class sev_attr {
public:
pwr_tOName aname;
......@@ -53,6 +63,16 @@ class sev_attr {
pwr_tString16 unit;
};
class sev_event {
public:
unsigned int type;
unsigned int eventprio;
mh_sEventId eventid;
pwr_tTime time;
char eventtext[80];
char eventname[80];
};
class sev_item {
public:
sev_item() : deadband_active(0), last_id(0), value_size(0), old_value(0), first_storage(1), status(0), logged_status(0),
......@@ -122,6 +142,7 @@ class sev_db {
pwr_tFloat32 deadband, pwr_tMask options, unsigned int *idx) { return 0;}
virtual int store_objectitem( pwr_tStatus *sts, char *tablename, pwr_tOid oid, char *oname, char *aname,
pwr_tDeltaTime storagetime, char *description, pwr_tFloat32 scantime, pwr_tFloat32 deadband, pwr_tMask options) { return 0;}
virtual int store_event( pwr_tStatus *sts, int item_idx, sev_event *ep) { return 0;}
virtual int get_item( pwr_tStatus *sts, sev_item *item, pwr_tOid oid, char *attributename) { return 0;}
virtual int get_objectitem( pwr_tStatus *sts, sev_item *item, pwr_tOid oid, char *attributename) { return 0;}
virtual int get_objectitems( pwr_tStatus *sts) { return 0;}
......@@ -135,6 +156,7 @@ class sev_db {
virtual int handle_objectchange(pwr_tStatus *sts, char *tablename, unsigned int item_idx, bool newObject) { return 0;}
virtual int repair_table( pwr_tStatus *sts, char *tablename) { return 0;}
virtual int alter_engine( pwr_tStatus *sts, char *tablename) { return 0;}
virtual int store_stat( sev_sStat *stat) { return 0;}
};
#endif
......@@ -290,6 +290,7 @@ MYSQL *sev_dbms_env::createDb(void)
if (rc) printf( "Create items table: %s\n", mysql_error(m_con));
createSevVersion2Tables();
createSevVersion3Tables();
return con;
}
......@@ -330,6 +331,10 @@ int sev_dbms_env::checkAndUpdateVersion(unsigned int version)
printf("Updating database tables to sev version 2\n");
updateDBToSevVersion2();
}
if (old_version < 3) {
printf("Updating database tables to sev version 3\n");
createSevVersion3Tables();
}
if(old_version != version) {
char query[100];
......@@ -464,6 +469,24 @@ int sev_dbms_env::createSevVersion2Tables(void)
return 1;
}
int sev_dbms_env::createSevVersion3Tables(void)
{
char query[400];
sprintf( query, "create table sev_stat (current_load float,medium_load float,datastore_msg_cnt int unsigned,dataget_msg_cnt int unsigned,items_msg_cnt int unsigned,eventstore_msg_cnt int unsigned);");
int rc = mysql_query( m_con, query);
if (rc) {
printf("In %s row %d:\n", __FILE__, __LINE__);
printf( "Create sev_stat table: %s\n", mysql_error(m_con));
}
sprintf( query, "insert into sev_stat (current_load, medium_load) values(0,0)");
rc = mysql_query( m_con, query);
if (rc) {
printf("In %s row %d:\n", __FILE__, __LINE__);
printf( "Insert into table sev_stat: %s\n", mysql_error(m_con));
}
return 1;
}
MYSQL *sev_dbms_env::openDb()
{
......@@ -719,6 +742,83 @@ int sev_dbms::delete_table( pwr_tStatus *sts, char *tablename)
return 1;
}
int sev_dbms::create_event_table( pwr_tStatus *sts, char *tablename, pwr_tMask options)
{
char query[400];
char timeformatstr[80];
char jumpstr[80];
char idtypestr[20];
char readoptstr[80];
char engine[80];
char enginestr[100] = "";
if ( cnf_get_value( "sevMysqlEngine", engine, sizeof(engine)) != 0)
snprintf( enginestr, sizeof(enginestr), " engine=%s", engine);
if ( options & pwr_mSevOptionsMask_PosixTime) {
if ( options & pwr_mSevOptionsMask_HighTimeResolution) {
// Posix time, high resolution
strcpy( timeformatstr, "time int unsigned, ntime int unsigned");
strcpy( idtypestr, "bigint");
}
else {
// Posix time, low resolution
strcpy( timeformatstr, "time int unsigned");
strcpy( idtypestr, "int");
}
}
else {
if ( options & pwr_mSevOptionsMask_HighTimeResolution) {
// Sql time, high resolution
strcpy( timeformatstr, "time datetime not null, ntime int unsigned");
strcpy( idtypestr, "bigint");
}
else {
// Sql time, low resolution
strcpy( timeformatstr, "time datetime not null");
strcpy( idtypestr, "int");
}
}
if ( options & pwr_mSevOptionsMask_ReadOptimized)
sprintf( readoptstr, "id %s unsigned not null primary key auto_increment,", idtypestr);
else
strcpy( readoptstr, "");
strcpy( jumpstr, "");
sprintf( query, "create table %s ( %s"
"%s, eventtype int, eventprio int, eventid_nix int, eventid_birthtime int, eventid_idx int,"
"eventtext varchar(80), eventname varchar(80), index (time))%s;",
tablename, readoptstr, timeformatstr, enginestr);
int rc = mysql_query( m_env->con(), query);
if (rc) {
printf("In %s row %d:\n", __FILE__, __LINE__);
printf( "Create table: %s\n", mysql_error(m_env->con()));
*sts = SEV__DBERROR;
return 0;
}
return 1;
}
int sev_dbms::delete_event_table( pwr_tStatus *sts, char *tablename)
{
char query[200];
sprintf( query, "drop table %s;", tablename);
int rc = mysql_query( m_env->con(), query);
if (rc) {
printf("In %s row %d:\n", __FILE__, __LINE__);
printf( "Delete table: %s\n", mysql_error(m_env->con()));
*sts = SEV__DBERROR;
return 0;
}
return 1;
}
int sev_dbms::store_item( pwr_tStatus *sts, char *tablename, pwr_tOid oid, char *oname,
char *aname, pwr_tDeltaTime storagetime, pwr_eType vtype,
unsigned int vsize, char *description, char *unit, pwr_tFloat32 scantime,
......@@ -1663,6 +1763,76 @@ int sev_dbms::get_values( pwr_tStatus *sts, pwr_tOid oid, pwr_tMask options, flo
return 1;
}
int sev_dbms::store_event( pwr_tStatus *sts, int item_idx, sev_event *ep)
{
char query[400];
char timstr[40];
*sts = time_AtoAscii( &ep->time, time_eFormat_NumDateAndTime, timstr, sizeof(timstr));
if ( EVEN(*sts)) return 0;
timstr[19] = 0;
if ( m_items[item_idx].options & pwr_mSevOptionsMask_PosixTime) {
if ( m_items[item_idx].options & pwr_mSevOptionsMask_HighTimeResolution) {
// Posix time, high resolution
sprintf( query, "insert into %s (time, ntime, eventtype, eventprio, eventid_nix, eventid_birthtime,"
"eventid_idx, eventtext, eventname) values (%ld,%ld,%d,%d,%d,%d,%d,'%s','%s')",
m_items[item_idx].tablename,
(long int)ep->time.tv_sec, (long int)ep->time.tv_nsec,
ep->type, ep->eventprio, ep->eventid.Nix, ep->eventid.BirthTime.tv_sec, ep->eventid.Idx, ep->eventtext,
ep->eventname);
}
else {
// Posix time, low resolution
sprintf( query, "insert into %s (time, eventtype, eventprio, eventid_nix, eventid_birthtime,"
"eventid_idx, eventtext, eventname) values (%ld,%d,%d,%d,%d,%d,'%s','%s')",
m_items[item_idx].tablename,
(long int)ep->time.tv_sec,
ep->type, ep->eventprio, ep->eventid.Nix, ep->eventid.BirthTime.tv_sec, ep->eventid.Idx, ep->eventtext,
ep->eventname);
}
}
else {
if ( m_items[item_idx].options & pwr_mSevOptionsMask_HighTimeResolution) {
// Sql time, high resolution
sprintf( query, "insert into %s (time, ntime, eventtype, eventprio, eventid_nix, eventid_birthtime,"
"eventid_idx, eventtext, eventname) values ('%s',%ld,%d,%d,%d,%d,%d,'%s','%s')",
m_items[item_idx].tablename,
timstr, (long int)ep->time.tv_sec,
ep->type, ep->eventprio, ep->eventid.Nix, ep->eventid.BirthTime.tv_sec, ep->eventid.Idx, ep->eventtext,
ep->eventname);
}
else {
// Sql time, low resolution
sprintf( query, "insert into %s (time, eventtype, eventprio, eventid_nix, eventid_birthtime,"
"eventid_idx, eventtext, eventname) values ('%s',%d,%d,%d,%d,%d,'%s','%s')",
m_items[item_idx].tablename,
timstr,
ep->type, ep->eventprio, ep->eventid.Nix, ep->eventid.BirthTime.tv_sec, ep->eventid.Idx, ep->eventtext,
ep->eventname);
}
}
int rc = mysql_query( m_env->con(), query);
if (rc) {
// printf( "Store value: %s \"%s\"\n", mysql_error(m_env->con()), query);
*sts = SEV__DBERROR;
m_items[item_idx].status = *sts;
if ( m_items[item_idx].status != m_items[item_idx].logged_status) {
m_items[item_idx].logged_status = m_items[item_idx].status;
errh_Error( "Database store error: %s, table: %s object: %s",
mysql_error(m_env->con()), m_items[item_idx].tablename, m_items[item_idx].oname);
}
return 0;
}
*sts = SEV__SUCCESS;
m_items[item_idx].status = *sts;
m_items[item_idx].logged_status = 1;
return 1;
}
int sev_dbms::check_item( pwr_tStatus *sts, pwr_tOid oid, char *oname, char *aname,
pwr_tDeltaTime storagetime, pwr_eType type, unsigned int size,
......@@ -1765,6 +1935,9 @@ int sev_dbms::add_item( pwr_tStatus *sts, pwr_tOid oid, char *oname, char *aname
scantime, deadband, options);
if ( EVEN(*sts)) return 0;
if ( strcmp( aname, "Events") == 0)
create_event_table( sts, tablename, options);
else
create_table( sts, tablename, type, size, options, deadband);
if ( EVEN(*sts)) return 0;
......@@ -2261,8 +2434,7 @@ pwr_tUInt64 sev_dbms::get_nextAutoIncrement( char *tablename )
{
char query[200];
pwr_tUInt64 retVal = 0;
sprintf( query, "SELECT Auto_increment FROM information_schema.tables WHERE table_name='%s'", tablename);
sprintf( query, "SELECT Auto_increment FROM information_schema.tables WHERE table_name='%s' && table_schema='%s'", tablename, m_env->dbName());
//printf( "%s: %s\n", __FUNCTION__ ,query);
int rc = mysql_query( m_env->con(), query);
if (rc) {
......@@ -3553,6 +3725,22 @@ int sev_dbms::alter_engine( pwr_tStatus *sts, char *tablename)
return 1;
}
int sev_dbms::store_stat( sev_sStat *stat)
{
char query[250];
int rc;
sprintf( query, "update sev_stat set current_load = %f,medium_load = %f,datastore_msg_cnt=%d,dataget_msg_cnt=%d,items_msg_cnt=%d,eventstore_msg_cnt=%d",
stat->current_load, stat->medium_load, stat->datastore_msg_cnt, stat->dataget_msg_cnt, stat->items_msg_cnt,
stat->eventstore_msg_cnt);
rc = mysql_query( m_env->con(), query);
if (rc) {
printf("In %s row %d:\n", __FILE__, __LINE__);
printf( "Update sev_stat: %s\n", mysql_error(m_env->con()));
return 0;
}
return 1;
}
sev_dbms::~sev_dbms()
{
......
......@@ -74,7 +74,7 @@ class sev_dbms_env
sev_dbms_env(const sev_dbms_env &);
void operator = (const sev_dbms_env &);
virtual ~ sev_dbms_env() { close();}
virtual ~sev_dbms_env() { close();}
int create(const char *fileName, const char *host, const char *user, const char *passwd,
const char *dbName, unsigned int port, const char *socket);
......@@ -87,6 +87,7 @@ class sev_dbms_env
int checkAndUpdateVersion(unsigned int version);
int updateDBToSevVersion2(void);
int createSevVersion2Tables(void);
int createSevVersion3Tables(void);
MYSQL *createDb(void);
MYSQL *openDb(void);
bool exists() { return m_exists;}
......@@ -183,6 +184,9 @@ class sev_dbms : public sev_db {
int check_deadband(pwr_eType type, unsigned int size, pwr_tFloat32 deadband, void *value, void *oldvalue);
int get_objectvalues( pwr_tStatus *sts, sev_item *item, unsigned int size, pwr_tTime *starttime, pwr_tTime *endtime,
int maxsize, pwr_tTime **tbuf, void **vbuf, unsigned int *bsize);
int delete_event_table( pwr_tStatus *sts, char *tablename);
int create_event_table( pwr_tStatus *sts, char *tablename, pwr_tMask options);
int store_event( pwr_tStatus *sts, int item_idx, sev_event *ep);
pwr_tUInt64 get_minFromIntegerColumn( char *tablename, char *colname );
pwr_tUInt64 get_maxFromIntegerColumn( char *tablename, char *colname );
pwr_tUInt64 get_nextAutoIncrement( char *tablename );
......@@ -190,6 +194,7 @@ class sev_dbms : public sev_db {
int handle_objectchange(pwr_tStatus *sts, char *tablename, unsigned int item_idx, bool newObject);
int repair_table( pwr_tStatus *sts, char *tablename);
int alter_engine( pwr_tStatus *sts, char *tablename);
int store_stat( sev_sStat *stat);
inline char* create_colName(unsigned int index, char *attributename) {
static char colName[constMaxColNameLength];
strncpy(colName, attributename, constMaxColNameLength);
......
......@@ -47,6 +47,8 @@
#include "rt_ini_event.h"
#include "rt_errh.h"
#include "rt_aproc.h"
#include "rt_mh_outunit.h"
#include "rt_mh_util.h"
#include "rt_sev_net.h"
#include "rt_sevhistmon.h"
#include "rt_sev_msg.h"
......@@ -54,7 +56,22 @@
#include <iostream>
#define sevclient_cQix 121
#define evbuf_next_idx(idx)\
idx++;\
if ( idx >= sizeof(event_buffer)/sizeof(event_buffer[0]))\
idx = 0;
#define evbuf_previous_idx(idx)\
if ( idx == 0) \
idx = sizeof(event_buffer)/sizeof(event_buffer[0]) - 1; \
else \
idx--;
using namespace std;
static rt_sevhistmon *shm;
int rt_sevhistmon::init()
{
pwr_tStatus sts;
......@@ -62,7 +79,6 @@ int rt_sevhistmon::init()
qcom_sQid qini;
qcom_sNode node;
pwr_tNid nid;
pwr_tOid conf_oid;
pwr_tOName oname;
errh_Init("pwr_sevhistmon", errh_eAnix_sevhistmon);
......@@ -72,20 +88,20 @@ int rt_sevhistmon::init()
if ( EVEN(sts)) throw co_error(sts);
// Get the config object
sts = gdh_GetClassList( pwr_cClass_SevHistMonitor, &conf_oid);
sts = gdh_GetClassList( pwr_cClass_SevHistMonitor, &m_confoid);
if ( EVEN(sts)) {
errh_SetStatus( 0);
errh_CErrLog( PWR__SRVNOTCONF, 0);
exit(0);
}
m_sts = gdh_ObjidToName( conf_oid, oname, sizeof(oname), cdh_mName_volumeStrict);
m_sts = gdh_ObjidToName( m_confoid, oname, sizeof(oname), cdh_mName_volumeStrict);
if ( EVEN(m_sts)) throw co_error(m_sts);
m_sts = gdh_RefObjectInfo( oname, (void **)&m_confp, &m_conf_refid, sizeof(*m_confp));
if ( EVEN(m_sts)) throw co_error(m_sts);
aproc_RegisterObject( conf_oid);
aproc_RegisterObject( m_confoid);
m_confp->Status = m_server_status = PWR__SRVSTARTUP;
m_scantime = m_confp->ScanTime;
......@@ -137,7 +153,10 @@ int rt_sevhistmon::init()
while (EVEN(gdh_NethandlerRunning()))
sleep(1);
return init_objects();
init_objects();
init_events();
return 1;
}
int rt_sevhistmon::init_objects()
......@@ -903,6 +922,9 @@ int rt_sevhistmon::send_itemlist( pwr_tNid nid)
}
}
}
if ( m_sevhistevents) {
item_cnt++;
}
if ( item_cnt == 0 && objectitem_cnt == 0 )
return 1;
......@@ -915,7 +937,6 @@ int rt_sevhistmon::send_itemlist( pwr_tNid nid)
size += sizeof(sev_sMsgHistItems) + (objectitem_cnt - 1) * (sizeof(sev_sHistItem) - sizeof(sev_sHistAttr)) + histobjectsize;
}
put.size = size;
put.data = qcom_Alloc(&lsts, put.size);
......@@ -959,6 +980,25 @@ int rt_sevhistmon::send_itemlist( pwr_tNid nid)
}
}
if ( m_sevhistevents) {
((sev_sMsgHistItems *)put.data)->Items[k].attrnum = 0;
((sev_sMsgHistItems *)put.data)->Items[k].oid = m_sevhistevents->hs_oid;
strcpy( ((sev_sMsgHistItems *)put.data)->Items[k].oname, m_sevhistevents->oname);
((sev_sMsgHistItems *)put.data)->Items[k].storagetime = net_DeltaTimeToNetTime( &m_sevhistevents->storagetime);
((sev_sMsgHistItems *)put.data)->Items[k].deadband = 0;
((sev_sMsgHistItems *)put.data)->Items[k].options = m_sevhistevents->options;
((sev_sMsgHistItems *)put.data)->Items[k].attr[0].type = (pwr_eType)0;
((sev_sMsgHistItems *)put.data)->Items[k].attr[0].size = 0;
((sev_sMsgHistItems *)put.data)->Items[k].sevid.nid = m_nodes[0].nid;
((sev_sMsgHistItems *)put.data)->Items[k].sevid.rix = 0;
strncpy( ((sev_sMsgHistItems *)put.data)->Items[k].description,
m_sevhistevents->description,
sizeof(((sev_sMsgHistItems *)put.data)->Items[0].description));
strcpy( ((sev_sMsgHistItems *)put.data)->Items[k].attr[0].unit, "");
((sev_sMsgHistItems *)put.data)->Items[k].scantime = 0;
k++;
}
//Add the objectitems at the end of the message
sev_sHistItem *buffP = &((sev_sMsgHistItems *)put.data)->Items[k];
for ( unsigned int i = 0; i < m_hs.size(); i++) {
......@@ -1033,6 +1073,330 @@ int rt_sevhistmon::send_itemlist( pwr_tNid nid)
return 1;
}
pwr_tStatus rt_sevhistmon::mh_ack_bc( mh_sAck *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Ack;
ed.time = msg->Info.EventTime;
strcpy( ed.eventtext, "");
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Ack\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_return_bc( mh_sReturn *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Return;
ed.time = msg->Info.EventTime;
strncpy( ed.eventtext, msg->EventText, sizeof(ed.eventtext));
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Return\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_alarm_bc( mh_sMessage *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Alarm;
ed.time = msg->Info.EventTime;
strncpy( ed.eventtext, msg->EventText, sizeof(ed.eventtext));
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Alarm\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_block_bc( mh_sBlock *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Block;
ed.time = msg->Info.EventTime;
strcpy( ed.eventtext, "");
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Block\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_cancel_bc( mh_sReturn *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Cancel;
ed.time = msg->Info.EventTime;
strcpy( ed.eventtext, "");
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Cancel\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_info_bc( mh_sMessage *msg)
{
sev_sEvent ed;
ed.type = sev_eEventType_Info;
ed.time = msg->Info.EventTime;
strncpy( ed.eventtext, msg->EventText, sizeof(ed.eventtext));
strncpy( ed.eventname, msg->EventName, sizeof(ed.eventname));
ed.eventprio = msg->Info.EventPrio;
ed.eventid_idx = msg->Info.Id.Idx;
ed.eventid_nix = msg->Info.Id.Nix;
ed.eventid_birthtime = msg->Info.Id.BirthTime.tv_sec;
if ( shm->m_sevhistevents)
shm->m_sevhistevents->evbuf_insert( &ed);
printf( "Info\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_clear_alarmlist_bc( pwr_tNodeIndex nix)
{
printf( "Clearalarmlist\n");
return 1;
}
pwr_tStatus rt_sevhistmon::mh_clear_blocklist_bc( pwr_tNodeIndex nix)
{
printf( "Clearblocklist\n");
return 1;
}
void sev_sevhistevents::evbuf_insert( sev_sEvent *ev)
{
// Check if event already exist
if ( evbuf_last != ev_cInit) {
for ( unsigned int idx = evbuf_last; ;) {
if ( event_buffer[idx].eventid_idx == ev->eventid_idx &&
event_buffer[idx].eventid_nix == ev->eventid_nix &&
event_buffer[idx].eventid_birthtime == ev->eventid_birthtime) {
printf( "Rejected type %d id %d \"%s\"\n", ev->type,
ev->eventid_idx, ev->eventtext);
return;
}
if ( idx == evbuf_oldest)
break;
evbuf_previous_idx(idx);
}
}
if ( evbuf_last == ev_cInit) {
// First insert
evbuf_last = 0;
evbuf_oldest = 0;
memcpy( &event_buffer[evbuf_last], ev, sizeof(event_buffer[0]));
}
else {
unsigned int idx = evbuf_last;
evbuf_next_idx( idx);
if ( idx == evbuf_oldest &&
((evbuf_sent == evbuf_oldest) || evbuf_sent == ev_cInit))
evbuf_send();
evbuf_next_idx( evbuf_last);
if ( evbuf_oldest == evbuf_last) {
evbuf_next_idx( evbuf_oldest);
}
memcpy( &event_buffer[evbuf_last], ev, sizeof(event_buffer[0]));
}
printf( "Insert last %d oldest %d type %d id %d \"%s\"\n", evbuf_last, evbuf_oldest, event_buffer[evbuf_last].type,
event_buffer[evbuf_last].eventid_idx, event_buffer[evbuf_last].eventtext);
}
void sev_sevhistevents::evbuf_send()
{
if ( evbuf_last == ev_cInit)
return;
unsigned int num;
if ( evbuf_sent == ev_cInit) {
if ( evbuf_oldest <= evbuf_last)
num = evbuf_last - evbuf_oldest + 1;
else
num = sizeof(event_buffer)/sizeof(event_buffer[0]) + evbuf_last - evbuf_oldest + 1;
}
else {
if ( evbuf_sent <= evbuf_last)
num = evbuf_last - evbuf_sent;
else
num = sizeof(event_buffer)/sizeof(event_buffer[0]) + evbuf_last - evbuf_sent;
}
if ( !num)
return;
pwr_tStatus sts;
qcom_sPut put;
qcom_sQid tgt;
put.size = sizeof(sev_sMsgEventsStore) + (num - 1) * sizeof(sev_sEvent);
put.data = qcom_Alloc(&sts, put.size);
((sev_sMsgEventsStore *)put.data)->Type = sev_eMsgType_EventsStore;
((sev_sMsgEventsStore *)put.data)->Oid = monitor->m_sevhistevents->hs_oid;
((sev_sMsgEventsStore *)put.data)->NumEvents = num;
unsigned int ev_cnt = 0;
if ( evbuf_sent == ev_cInit) {
for ( unsigned int idx = evbuf_oldest;;) {
printf("Send idx %d id %d\n", idx, event_buffer[idx].eventid_idx);
memcpy( &((sev_sMsgEventsStore *)put.data)->Events[ev_cnt], &event_buffer[idx], sizeof(sev_sEvent));
ev_cnt++;
evbuf_sent = idx;
if ( idx == evbuf_last)
break;
evbuf_next_idx(idx);
}
}
else if ( evbuf_sent != evbuf_last) {
unsigned int start_idx = evbuf_sent;
evbuf_next_idx(start_idx);
for ( unsigned int idx = start_idx;;) {
printf("Send idx %d id %d\n", idx, event_buffer[idx].eventid_idx);
memcpy( &((sev_sMsgEventsStore *)put.data)->Events[ev_cnt], &event_buffer[idx], sizeof(sev_sEvent));
ev_cnt++;
evbuf_sent = idx;
if ( idx == evbuf_last)
break;
evbuf_next_idx(idx);
}
}
printf( "Send num: %d cnt: %d\n", num, ev_cnt);
tgt.nid = monitor->m_hs[event_thread_idx].nid;
tgt.qix = sev_eProcSevServer;
put.reply.nid = monitor->m_nodes[0].nid;
put.reply.qix = sev_eProcSevClient;
put.type.b = (qcom_eBtype) sev_cMsgClass;
put.type.s = (qcom_eStype) sev_eMsgType_EventsStore;
put.msg_id = monitor->m_msg_id++;
if ( !qcom_Put( &sts, &tgt, &put)) {
monitor->m_hs[event_thread_idx].threadp->ErrorCount++;
monitor->m_hs[event_thread_idx].threadp->Status = sts;
qcom_Free( &sts, put.data);
}
monitor->m_hs[event_thread_idx].threadp->SendCount++;
monitor->m_hs[event_thread_idx].threadp->Status = sts;
}
int rt_sevhistmon::init_events()
{
pwr_tOid he_oid;
pwr_tStatus sts;
pwr_tOName oname;
int he_cnt = 0;
// Get SevHistEvents objects
for ( sts = gdh_GetClassList( pwr_cClass_SevHistEvents, &he_oid);
ODD(sts);
sts = gdh_GetNextObject( he_oid, &he_oid)) {
he_cnt++;
sts = gdh_ObjidToName( he_oid, oname, sizeof(oname), cdh_mName_volumeStrict);
if ( EVEN(m_sts)) throw co_error(m_sts);
if ( he_cnt > 1) {
errh_Error( "SevHistEvents object ignored, %s", oname);
continue;
}
sev_sevhistevents *h = new sev_sevhistevents( this);
int hs_idx;
pwr_tAttrRef aref = cdh_ObjidToAref( he_oid);
sts = gdh_DLRefObjectInfoAttrref( &aref, (void **)&h->hsp, &h->hs_refid);
if ( EVEN(sts)) throw co_error(sts);
hs_idx = -1;
for ( int i = 0; i < (int) m_hs.size(); i++) {
if ( cdh_ObjidIsEqual( h->hsp->ThreadObject, m_hs[i].oid)) {
hs_idx = i;
break;
}
}
if ( hs_idx == -1) {
errh_Error( "Invalid thread object in SevHistEvents, %s", oname);
continue;
}
h->storagetime = h->hsp->StorageTime;
h->options = h->hsp->Options;
strcpy( h->description, h->hsp->Description);
h->disabled = h->hsp->Disable;
h->event_thread_idx = hs_idx;
h->hs_oid = he_oid;
strcpy( h->oname, oname);
m_hs[hs_idx].threadp->NoOfItems++;
// Wait for mh has flagged initizated
mh_UtilWaitForMh();
sts = mh_OutunitConnect( he_oid,
mh_eOutunitType_SevHistEvents,
0,
mh_ack_bc,
mh_alarm_bc,
mh_block_bc,
mh_cancel_bc,
mh_clear_alarmlist_bc,
mh_clear_blocklist_bc,
mh_info_bc,
mh_return_bc);
if (EVEN(sts)) return sts;
m_sevhistevents = h;
}
return 1;
}
int rt_sevhistmon::mainloop()
{
qcom_sQid qid;
......@@ -1044,6 +1408,8 @@ int rt_sevhistmon::mainloop()
qid.nid = 0;
qid.qix = sev_eProcSevClient;
shm = this;
for (;;) {
memset( &get, 0, sizeof(get));
mp = qcom_Get(&sts, &qid, &get, tmo);
......@@ -1059,6 +1425,15 @@ int rt_sevhistmon::mainloop()
retry_connect();
}
aproc_TimeStamp( m_scantime, 5);
if ( m_sevhistevents) {
sts = mh_OutunitReceive();
while (ODD(sts))
sts = mh_OutunitReceive();
m_sevhistevents->evbuf_send();
}
continue;
}
......
......@@ -42,6 +42,10 @@
#include "pwr.h"
#include "pwr_class.h"
#define ev_cInit 0xFFFF
class rt_sevhistmon;
class sev_sevhist {
public:
pwr_tAttrRef aref;
......@@ -62,6 +66,30 @@ class sev_sevhist {
pwr_tBoolean disabled;
};
class sev_sevhistevents {
public:
sev_sevhistevents( rt_sevhistmon *m) : event_thread_idx(0), evbuf_oldest(ev_cInit), evbuf_last(ev_cInit),
evbuf_sent(ev_cInit), monitor(m) {}
pwr_sClass_SevHistEvents *hsp;
pwr_tString80 description;
pwr_tOid hs_oid;
pwr_tRefId hs_refid;
pwr_tDeltaTime storagetime;
pwr_tMask options;
pwr_tBoolean disabled;
unsigned int event_thread_idx;
sev_sEvent event_buffer[20];
unsigned int evbuf_oldest;
unsigned int evbuf_last;
unsigned int evbuf_sent;
rt_sevhistmon *monitor;
pwr_tOName oname;
void evbuf_insert( sev_sEvent *ev);
void evbuf_send();
};
class sev_sevhistobjectattr {
public:
pwr_tAttrRef aref;
......@@ -117,11 +145,12 @@ class sev_node {
pwr_tStatus status;
};
class rt_sevhistmon {
public:
rt_sevhistmon() : m_msg_id(0), m_next_rix(0), m_loopcnt(0), m_allconnected(0), m_server_status(0),
m_swap(0) {}
m_swap(0), m_sevhistevents(0) {}
pwr_tStatus m_sts;
vector<sev_sevhistthread> m_hs;
......@@ -131,14 +160,17 @@ class rt_sevhistmon {
unsigned int m_loopcnt;
float m_scantime;
pwr_sClass_SevHistMonitor *m_confp;
pwr_tOid m_confoid;
pwr_tRefId m_conf_refid;
int m_allconnected;
pwr_tStatus m_server_status;
int m_swap;
sev_sevhistevents *m_sevhistevents;
int init();
int init_objects();
int init_sevhistobjects();
int init_events();
void insert_sevhistobjectattr(pwr_sAttrRef *aref,
pwr_tAName objectname,
int hs_idx,
......@@ -160,5 +192,16 @@ class rt_sevhistmon {
void receive_server_status( sev_sMsgServerStatus *msg, pwr_tNid nid);
int send_itemlist( pwr_tNid nid);
int send_data();
void evbuf_insert( sev_sEvent *ev);
void evbuf_send();
static pwr_tStatus mh_ack_bc( mh_sAck *MsgP);
static pwr_tStatus mh_return_bc( mh_sReturn *MsgP);
static pwr_tStatus mh_alarm_bc( mh_sMessage *MsgP);
static pwr_tStatus mh_block_bc( mh_sBlock *MsgP);
static pwr_tStatus mh_cancel_bc( mh_sReturn *MsgP);
static pwr_tStatus mh_info_bc( mh_sMessage *MsgP);
static pwr_tStatus mh_clear_alarmlist_bc( pwr_tNodeIndex nix);
static pwr_tStatus mh_clear_blocklist_bc( pwr_tNodeIndex nix);
};
#endif
......@@ -168,7 +168,8 @@ enum mh_eOutunitType{
mh_eOutunitType_Terminal = 4,
mh_eOutunitType_Logger = 5,
mh_eOutunitType_Post = 6,
mh_eOutunitType_ = 7
mh_eOutunitType_SevHistEvents = 7,
mh_eOutunitType_ = 8
};
enum mh_eSource {
......
......@@ -314,6 +314,11 @@ mh_OutunitConnect (
l.pSelL = (void *)&((pwr_sClass_PostConfig*) p)->EventSelectList[0];
l.SelectListIsUpdated = NULL;
break;
case pwr_cClass_SevHistEvents:
type = mh_eOutunitType_SevHistEvents;
l.pSelL = (void *)&((pwr_sClass_SevHistEvents*) p)->EventSelectList[0];
l.SelectListIsUpdated = NULL;
break;
default:
return MH__NOOUTUNIT;
break;
......
......@@ -61,9 +61,30 @@ typedef enum {
sev_eMsgType_ServerStatusRequest,
sev_eMsgType_ServerStatus,
sev_eMsgType_HistObjectDataGetRequest,
sev_eMsgType_HistObjectDataGet
sev_eMsgType_HistObjectDataGet,
sev_eMsgType_EventsStore
} sev_eMsgType;
typedef enum {
sev_eEventType_Info,
sev_eEventType_Return,
sev_eEventType_Ack,
sev_eEventType_Alarm,
sev_eEventType_Block,
sev_eEventType_Cancel
} sev_eEventType;
typedef struct {
sev_eEventType type;
unsigned int eventprio;
unsigned int eventid_nix;
unsigned int eventid_birthtime;
unsigned int eventid_idx;
net_sTime time;
char eventtext[80];
char eventname[80];
} sev_sEvent;
typedef struct {
pwr_tOName aname;
pwr_eType type;
......@@ -114,6 +135,13 @@ typedef struct {
int Data[1];
} sev_sMsgHistDataStore;
typedef struct {
sev_eMsgType Type;
pwr_tOid Oid;
unsigned int NumEvents;
sev_sEvent Events[1];
} sev_sMsgEventsStore;
typedef struct {
sev_eMsgType Type;
pwr_tOid Oid;
......
!
! Proview Open Source Process Control.
! Copyright (C) 2005-2012 SSAB EMEA AB.
!
! This file is part of Proview.
!
! 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, either version 2 of
! the License, or (at your option) any later version.
!
! 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 Proview. If not, see <http://www.gnu.org/licenses/>
!
! Linking Proview statically or dynamically with other modules is
! making a combined work based on Proview. Thus, the terms and
! conditions of the GNU General Public License cover the whole
! combination.
!
! In addition, as a special exception, the copyright holders of
! Proview give you permission to, from the build function in the
! Proview Configurator, combine Proview with modules generated by the
! Proview PLC Editor to a PLC program, regardless of the license
! terms of these modules. You may copy and distribute the resulting
! combined work under the terms of your choice, provided that every
! copy of the combined work is accompanied by a complete copy of
! the source code of Proview (the version used to produce the
! combined work), being distributed under the terms of the GNU
! General Public License plus this exception.
!
! pwrb_c_sevhistevents.wb_load -- Defines the class SevHistEvents.
!
SObject pwrb:Class
!/**
! @Version 1.0
! @Group Servers,NodeConfiguration
! Configures historical storage of events.
!
! @b See also
! @classlink SevHistMonitor pwrb_sevhistmonitor.html
! @classlink SevHistThread pwrb_sevhistthread.html
! @classlink SevHist pwrb_sevhist.html
! @classlink SevHistObject pwrb_sevhistobject.html
! @classlink SevHistServer pwrb_sevhistserver.html
!*/
Object SevHistEvents $ClassDef 603
Body SysBody
Attr Editor = pwr_eEditor_AttrEd
Attr Method = pwr_eMethod_Standard
EndBody
Object RtBody $ObjBodyDef 1
Body SysBody
Attr StructName = "SevHistEvents"
EndBody
!/**
! Optional description.
!*/
Object Description $Attribute 1
Body SysBody
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! SelectList specifies the hierarchies from which
! messages are to be sent to the user. Up to 40 different
! hierarchies can be specified. If messages from e.g. a
! Watchdog object in a node will be received, then the
! name of the node will be specified.
!
! Note! If the SelectList is left blank no message at all is
! sent to the user.
!*/
Object EventSelectList $Attribute 2
Body SysBody
Attr TypeRef = "pwrs:Type-$String80"
Attr Flags |= PWR_MASK_ARRAY
Attr Elements = 40
EndBody
EndObject
!/**
! Specifies type of stored events.
!*/
Object EventTypes $Attribute 3
Body SysBody
Attr TypeRef = "pwrb:Type-EventListMask"
EndBody
EndObject
!/**
! SevHistThread object that specifies the storage scantime
! and in which server the events are stored.
!*/
Object ThreadObject $Attribute 4
Body SysBody
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
!/**
! Time the data will be stored in the database.
! Data that is older than this time will be removed from
! the database by a garbage collector.
!*/
Object StorageTime $Attribute 5
Body SysBody
Attr TypeRef = "pwrs:Type-$DeltaTime"
EndBody
EndObject
!/**
! Storage options.
!*/
Object Options $Attribute 6
Body SysBody
Attr TypeRef = "pwrb:Type-SevHistOptionsMask"
EndBody
EndObject
!/**
! Disable storage.
!*/
Object Disable $Attribute 7
Body SysBody
Attr TypeRef = "pwrs:Type-$Boolean"
EndBody
EndObject
EndObject
Object Template SevHistEvents
Body RtBody
Attr EventTypes = 3
Attr Options = 0
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "SevHistEvents-PostCreate"
EndBody
EndObject
Object ConfiguratorPoson $Menu
Object Pointed $Menu
Object ConnectThread $MenuButton
Body SysBody
Attr ButtonName = "Connect SevHistThread"
Attr MethodName = "$Objid-Connect"
Attr MethodArguments[0] = "ThreadObject"
Attr MethodArguments[1] = "SevHistThread"
Attr FilterName = "$Objid-IsOkConnect"
Attr FilterArguments[0] = "ThreadObject"
Attr FilterArguments[1] = "SevHistThread"
EndBody
EndObject
EndObject
EndObject
EndObject
EndSObject
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment