New example server that monitors all the IOC on a network
This commit is contained in:
12
src/cas/example/iocmonitor/Makefile
Normal file
12
src/cas/example/iocmonitor/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
# $Log$
|
||||
# Revision 1.2 1997/03/05 21:16:21 jbk
|
||||
# Fixes cvs log id at top
|
||||
#
|
||||
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
include $(TOP)/config/RULES_ARCHS
|
||||
|
||||
25
src/cas/example/iocmonitor/Makefile.Host
Normal file
25
src/cas/example/iocmonitor/Makefile.Host
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
# $Log$
|
||||
# Revision 1.2 1997/03/05 21:16:21 jbk
|
||||
# Fixes cvs log id at top
|
||||
#
|
||||
CAS = ../../..
|
||||
TOP = $(CAS)/../..
|
||||
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
CXXCMPLR = STRICT
|
||||
|
||||
PROD_LIBS := cas ca gdd Com
|
||||
|
||||
SRCS += mon.cc monAdl.cc monNode.cc monServer.cc
|
||||
|
||||
PROD := iocMonitor
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
||||
|
||||
clean::
|
||||
@$(RM) iocMonitor
|
||||
@$(RM) -rf Templates.DB
|
||||
@$(RM) core
|
||||
|
||||
337
src/cas/example/iocmonitor/mon.cc
Normal file
337
src/cas/example/iocmonitor/mon.cc
Normal file
@@ -0,0 +1,337 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "caProto.h"
|
||||
|
||||
// use lower 11 bits of address as index
|
||||
|
||||
#define ADDR_MASK 0x000007ff
|
||||
#define ADDR_CHECK 10
|
||||
#define ADDR_WARNING 20
|
||||
#define ADDR_DEATH 40
|
||||
#define REPEATER_PORT 5065
|
||||
|
||||
typedef enum { nodeAlive=0, nodeUnknown, nodeDead } nodeState;
|
||||
|
||||
// ----------------------------- host node ------------------------------
|
||||
|
||||
class netNode
|
||||
{
|
||||
public:
|
||||
netNode(unsigned long a,const char* pre);
|
||||
~netNode(void);
|
||||
|
||||
void report(void);
|
||||
void ping(void);
|
||||
nodeState state(void);
|
||||
nodeState state(time_t);
|
||||
|
||||
unsigned long addr;
|
||||
time_t last_ping;
|
||||
const char* name;
|
||||
struct netNode* next;
|
||||
};
|
||||
|
||||
netNode::netNode(unsigned long a,const char* pre)
|
||||
{
|
||||
struct in_addr& in = (struct in_addr&)a;
|
||||
struct hostent* entry;
|
||||
char *n,*x;
|
||||
|
||||
addr=a;
|
||||
time(&last_ping);
|
||||
|
||||
if((entry=gethostbyaddr((char*)&a,sizeof(a),AF_INET))==NULL)
|
||||
n=inet_ntoa(in);
|
||||
else
|
||||
n=entry->h_name;
|
||||
|
||||
x=new char[strlen(n)+1+strlen(pre)];
|
||||
strcpy(x,pre);
|
||||
strcat(x,n);
|
||||
name=x;
|
||||
next=NULL;
|
||||
}
|
||||
|
||||
netNode::~netNode(void)
|
||||
{
|
||||
char* n = (char*)name;
|
||||
delete [] n;
|
||||
}
|
||||
|
||||
void netNode::ping(void)
|
||||
{
|
||||
time(&last_ping);
|
||||
}
|
||||
|
||||
nodeState netNode::state(void)
|
||||
{
|
||||
time_t t;
|
||||
time(&t);
|
||||
return state(t);
|
||||
}
|
||||
|
||||
nodeState netNode::state(time_t t)
|
||||
{
|
||||
nodeState s;
|
||||
time_t x;
|
||||
x=t-last_ping;
|
||||
if(x<ADDR_WARNING)
|
||||
s=nodeAlive;
|
||||
else if(x<ADDR_DEATH)
|
||||
s=nodeUnknown;
|
||||
else
|
||||
s=nodeDead;
|
||||
return s;
|
||||
}
|
||||
|
||||
void netNode::report(void)
|
||||
{
|
||||
switch(state())
|
||||
{
|
||||
case nodeDead: printf(" IOC %s Dead\n",name); break;
|
||||
case nodeAlive: printf(" IOC %s Alive\n",name); break;
|
||||
case nodeUnknown: printf(" IOC %s Unknown\n",name); break;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------- database ---------------------------
|
||||
|
||||
class addrDb
|
||||
{
|
||||
public:
|
||||
addrDb(const char* p);
|
||||
~addrDb(void);
|
||||
|
||||
void report(void);
|
||||
netNode* findNode(unsigned long addr);
|
||||
netNode* addNode(unsigned long addr);
|
||||
private:
|
||||
const char* prefix;
|
||||
netNode** db;
|
||||
};
|
||||
|
||||
addrDb::addrDb(const char* p)
|
||||
{
|
||||
int i;
|
||||
const char* x = p?p:"_";
|
||||
char* y;
|
||||
y=new char[strlen(x)+1];
|
||||
strcpy(y,x);
|
||||
prefix=y;
|
||||
db=new netNode*[ADDR_MASK];
|
||||
for(i=0;i<ADDR_MASK;i++) db[i]=NULL;
|
||||
}
|
||||
|
||||
addrDb::~addrDb(void)
|
||||
{
|
||||
int i;
|
||||
netNode *c,*p;
|
||||
for(i=0;i<ADDR_MASK;i++)
|
||||
{
|
||||
for(c=db[i];c;)
|
||||
{
|
||||
p=c->next;
|
||||
delete c;
|
||||
c=p;
|
||||
}
|
||||
}
|
||||
delete [] db;
|
||||
}
|
||||
|
||||
void addrDb::report(void)
|
||||
{
|
||||
int i;
|
||||
netNode* n;
|
||||
for(i=0;i<ADDR_MASK;i++)
|
||||
{
|
||||
for(n=db[i];n;n=n->next)
|
||||
n->report();
|
||||
}
|
||||
}
|
||||
|
||||
netNode* addrDb::findNode(unsigned long addr)
|
||||
{
|
||||
netNode* t;
|
||||
for(t=db[addr&ADDR_MASK];t && t->addr!=addr;t=t->next);
|
||||
return t;
|
||||
}
|
||||
|
||||
netNode* addrDb::addNode(unsigned long addr)
|
||||
{
|
||||
unsigned long i;
|
||||
netNode* t;
|
||||
if((t=findNode(addr))==NULL)
|
||||
{
|
||||
i=addr&ADDR_MASK;
|
||||
t=new netNode(addr,prefix);
|
||||
t->next=db[i];
|
||||
db[i]=t;
|
||||
}
|
||||
else
|
||||
t->ping();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
addrDb* db;
|
||||
|
||||
int main(int argc, char* argv[] )
|
||||
{
|
||||
caHdr msg;
|
||||
struct sockaddr_in tsin;
|
||||
struct sockaddr ssin;
|
||||
struct timeval tout;
|
||||
struct hostent* entry;
|
||||
fd_set fds;
|
||||
char* name;
|
||||
netNode* node;
|
||||
int soc,retry,done,rlen,len;
|
||||
unsigned short cmd;
|
||||
unsigned long* iaddr;
|
||||
time_t curr,last;
|
||||
|
||||
if(argc<2)
|
||||
{
|
||||
fprintf(stderr,"Must enter a prefix for PVs on command line\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
db=new addrDb(argv[1]);
|
||||
|
||||
tsin.sin_port=htons(0);
|
||||
tsin.sin_family=AF_INET;
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((soc=socket(AF_INET,SOCK_DGRAM,17))<0)
|
||||
{
|
||||
perror("open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(soc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("local bind failed to soc failed");
|
||||
close(soc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char*)&msg,0,sizeof(msg));
|
||||
msg.m_cmmd = htons(REPEATER_REGISTER);
|
||||
msg.m_available = tsin.sin_addr.s_addr;
|
||||
tsin.sin_port=htons(REPEATER_PORT);
|
||||
|
||||
for(done=0,retry=0;done==0 && retry<3;retry++)
|
||||
{
|
||||
if(sendto(soc,(char*)&msg,sizeof(msg),0,
|
||||
(struct sockaddr*)&tsin,sizeof(tsin))<0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
close(soc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc,&fds);
|
||||
tout.tv_sec=0;
|
||||
tout.tv_usec=500000;
|
||||
|
||||
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
|
||||
{
|
||||
case -1: /* bad */
|
||||
perror("first select failed");
|
||||
return -1;
|
||||
case 0: /* timeout */
|
||||
break;
|
||||
default: /* data ready */
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
|
||||
if(done==1)
|
||||
{
|
||||
rlen=0;
|
||||
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
|
||||
{
|
||||
perror("first recvfrom failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd=ntohs(msg.m_cmmd);
|
||||
|
||||
if(cmd==REPEATER_CONFIRM)
|
||||
printf("Connected to repeater\n");
|
||||
else
|
||||
{
|
||||
printf("Cannot connect to repeater (%d)\n",(int)cmd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Cannot connect to repeater\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---------------- ready ---------------- */
|
||||
last=0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc,&fds);
|
||||
tout.tv_sec=ADDR_CHECK;
|
||||
tout.tv_usec=0;
|
||||
|
||||
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
|
||||
{
|
||||
case -1: /* bad */
|
||||
perror("main select failed");
|
||||
case 0: /* timeout */
|
||||
// db->report();
|
||||
break;
|
||||
default: /* data ready */
|
||||
{
|
||||
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
|
||||
{
|
||||
perror("first recvfrom failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
iaddr=(unsigned long*)&msg.m_available;
|
||||
node=db->addNode(*iaddr);
|
||||
|
||||
// cmd=ntohs(msg.m_cmmd);
|
||||
// if(cmd==CA_PROTO_RSRV_IS_UP)
|
||||
// {
|
||||
// printf("Alive\n");
|
||||
// }
|
||||
// else
|
||||
// printf("Unidentified Command from 0x%8.8x\n",*iaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
time(&curr);
|
||||
if((curr-last)>=ADDR_CHECK)
|
||||
{
|
||||
db->report();
|
||||
last=curr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
src/cas/example/iocmonitor/monAdl.cc
Normal file
89
src/cas/example/iocmonitor/monAdl.cc
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "monNode.h"
|
||||
#include "monServer.h"
|
||||
|
||||
#define WIDTH 180
|
||||
#define HEIGHT 10
|
||||
#define MAX_WIDTH 1000
|
||||
#define MAX_HEIGHT 700
|
||||
#define TOTAL_X (MAX_WIDTH/WIDTH)
|
||||
#define TOTAL_Y (MAX_HEIGHT/HEIGHT)
|
||||
|
||||
int monAdl(monNode** head, char* fname,const char* prefix)
|
||||
{
|
||||
FILE *fdout;
|
||||
int dh;
|
||||
int i,j,k;
|
||||
monNode* node;
|
||||
|
||||
if((fdout=fopen(fname,"w"))==NULL)
|
||||
{
|
||||
fprintf(stderr,"Cannot open the ADL file %s\n",fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dh=monNode::total/TOTAL_X;
|
||||
if((dh*TOTAL_X)!=monNode::total) ++dh;
|
||||
|
||||
fprintf(fdout,"\nfile { name=\"ioc_status.adl\" version=020209 }\n");
|
||||
fprintf(fdout,"display {\n");
|
||||
fprintf(fdout," object { x=0 y=0 width=%d height=%d }\n",
|
||||
MAX_WIDTH,dh*HEIGHT+40);
|
||||
fprintf(fdout," clr=37 bclr=14 cmap=\"\"\n}\n");
|
||||
|
||||
fprintf(fdout,"\"color map\" { ncolors=65 colors {\n");
|
||||
fprintf(fdout,"ffffff, ececec, dadada, c8c8c8, bbbbbb, aeaeae, 9e9e9e,\n");
|
||||
fprintf(fdout,"919191, 858585, 787878, 696969, 5a5a5a, 464646, 2d2d2d,\n");
|
||||
fprintf(fdout,"000000, 00d800, 1ebb00, 339900, 2d7f00, 216c00, fd0000,\n");
|
||||
fprintf(fdout,"de1309, be190b, a01207, 820400, 5893ff, 597ee1, 4b6ec7,\n");
|
||||
fprintf(fdout,"3a5eab, 27548d, fbf34a, f9da3c, eeb62b, e19015, cd6100,\n");
|
||||
fprintf(fdout,"ffb0ff, d67fe2, ae4ebc, 8b1a96, 610a75, a4aaff, 8793e2,\n");
|
||||
fprintf(fdout,"6a73c1, 4d52a4, 343386, c7bb6d, b79d5c, a47e3c, 7d5627,\n");
|
||||
fprintf(fdout,"58340f, 99ffff, 73dfff, 4ea5f9, 2a63e4, 0a00b8, ebf1b5,\n");
|
||||
fprintf(fdout,"d4db9d, bbc187, a6a462, 8b8239, 73ff6b, 52da3b, 3cb420,\n");
|
||||
fprintf(fdout,"289315, 1a7309,\n");
|
||||
fprintf(fdout,"} }\n");
|
||||
|
||||
// ----------------------- heading ----------------------------------
|
||||
i=(MAX_WIDTH/2)-(300/2);
|
||||
fprintf(fdout," text { object { x=%d y=2 width=300 height=25 }\n",i);
|
||||
fprintf(fdout," \"basic attribute\" { clr=37 }\n");
|
||||
fprintf(fdout," textix=\"%d IOC STATUS MONITOR\"\n",monNode::total);
|
||||
fprintf(fdout," align=\"horiz. centered\"\n}\n");
|
||||
|
||||
// ---------------------- generate new file button -------------------
|
||||
fprintf(fdout,"\"message button\" { object\n");
|
||||
fprintf(fdout," { x=%d y=2 width=180 height=22 }\n",MAX_WIDTH-180);
|
||||
fprintf(fdout," control { chan=\"%smakeScreen\" clr=31 bclr=47 }\n",prefix);
|
||||
fprintf(fdout," label=\"Make New Screen\" press_msg=\"1\"\n}\n");
|
||||
|
||||
fprintf(fdout,"\"text update\" { object { x=1 y=2 width=180 height=22 }\n");
|
||||
fprintf(fdout," monitor { chan=\"%siocCount\" clr=31 bclr=14 }\n",prefix);
|
||||
fprintf(fdout,"}\n");
|
||||
|
||||
// -------------- make all the buttons
|
||||
i=0;j=0;
|
||||
for(k=0;k<ADDR_TOTAL;k++)
|
||||
{
|
||||
for(node=head[k];node;node=node->next)
|
||||
{
|
||||
fprintf(fdout,"\"text update\" {\n");
|
||||
fprintf(fdout," object { x=%d y=%d width=%d height=%d }\n",
|
||||
i*WIDTH,j*HEIGHT+30,WIDTH,HEIGHT);
|
||||
|
||||
if(++i>=TOTAL_X) { i=0; ++j; }
|
||||
|
||||
fprintf(fdout," monitor { chan=\"%s\" clr=0 bclr=14 }\n",
|
||||
node->name);
|
||||
fprintf(fdout," clrmod=\"alarm\"\n}\n");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
277
src/cas/example/iocmonitor/monNode.cc
Normal file
277
src/cas/example/iocmonitor/monNode.cc
Normal file
@@ -0,0 +1,277 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "gddAppTable.h"
|
||||
#include "monServer.h"
|
||||
#include "monNode.h"
|
||||
|
||||
// --------------------------- monPv ----------------------------
|
||||
|
||||
monPv::monPv(const casCtx& c,monServer& s,monNode* n,const char* name):
|
||||
casPV(c,name),node(n),mrg(s)
|
||||
{
|
||||
monDebug1(5,"monPV: Creating PV for %s\n",name);
|
||||
data=NULL;
|
||||
markNotInterested();
|
||||
node->setPv(this);
|
||||
}
|
||||
|
||||
monPv::~monPv(void)
|
||||
{
|
||||
node->clearPv();
|
||||
if(data) data->unreference();
|
||||
monDebug1(5,"monPV: Deleting PV for %s\n",node->name);
|
||||
}
|
||||
|
||||
unsigned monPv::maxSimultAsyncOps(void) const { return 5000u; }
|
||||
void monPv::interestDelete(void) { markNotInterested(); }
|
||||
aitEnum monPv::bestExternalType(void) const { return aitEnumString; }
|
||||
unsigned monPv::maxDimension(void) const { return 0; }
|
||||
aitIndex monPv::maxBound(unsigned dim) const { return 0; }
|
||||
void monPv::destroy(void) { casPV::destroy(); }
|
||||
|
||||
caStatus monPv::interestRegister(void)
|
||||
{
|
||||
markInterested();
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
caStatus monPv::read(const casCtx& ctx, gdd& dd)
|
||||
{
|
||||
monDebug1(5,"monPV: Read PV data=0x%8.8x\n",(int)data);
|
||||
gddApplicationTypeTable& table=gddApplicationTypeTable::AppTable();
|
||||
if(data) table.smartCopy(&dd,data);
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
caStatus monPv::write(const casCtx& /*ctx*/, gdd& /*dd*/)
|
||||
{
|
||||
// cannot write to these PVs
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
void monPv::eventData(void)
|
||||
{
|
||||
struct tm* t;
|
||||
char val[40];
|
||||
char str[10];
|
||||
aitTimeStamp stamp(node->state_ping,0);
|
||||
|
||||
// prepare a new gdd used for posting and reads
|
||||
if(data) data->unreference();
|
||||
data=new gddScalar(mrg.appValue,aitEnumString);
|
||||
t=localtime(&node->state_ping);
|
||||
|
||||
switch(node->state())
|
||||
{
|
||||
case monAlive:
|
||||
strcpy(str,"Up");
|
||||
data->setStatSevr(0,NO_ALARM);
|
||||
break;
|
||||
case monUnknown:
|
||||
strcpy(str,"?");
|
||||
data->setStatSevr(TIMEOUT_ALARM,MINOR_ALARM);
|
||||
break;
|
||||
case monDead:
|
||||
strcpy(str,"Down");
|
||||
data->setStatSevr(COMM_ALARM,MAJOR_ALARM);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
sprintf(val,"(%s %s %2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d)",
|
||||
&node->name[mrg.prefix_length],str,
|
||||
t->tm_mon+1,t->tm_mday,t->tm_year,t->tm_hour,t->tm_min,t->tm_sec);
|
||||
*/
|
||||
sprintf(val,"(%2.2d/%2.2d %2.2d:%2.2d:%2.2d %s)",
|
||||
t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec,
|
||||
&node->name[mrg.prefix_length]);
|
||||
|
||||
data->reference();
|
||||
data->setTimeStamp(&stamp);
|
||||
data->put(val);
|
||||
|
||||
monDebug1(5,"monPV: eventData data=0x%8.8x\n",(int)data);
|
||||
if(debugLevel>6) data->dump();
|
||||
|
||||
if(isMonitored())
|
||||
{
|
||||
monDebug0(5,"monPV: PV monitored\n");
|
||||
casEventMask select(
|
||||
mrg.alarmEventMask|mrg.valueEventMask|mrg.logEventMask);
|
||||
postEvent(select,*data);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- monNode ----------------------------
|
||||
|
||||
monNode::monNode(unsigned long a,const char* prefix)
|
||||
{
|
||||
struct in_addr& in = (struct in_addr&)a;
|
||||
struct hostent* entry;
|
||||
char *n,*x;
|
||||
|
||||
addr=a;
|
||||
time(&last_ping);
|
||||
state_ping=last_ping;
|
||||
|
||||
if((entry=gethostbyaddr((char*)&a,sizeof(a),AF_INET))==NULL)
|
||||
n=inet_ntoa(in);
|
||||
else
|
||||
n=entry->h_name;
|
||||
|
||||
x=new char[strlen(n)+1+strlen(prefix)];
|
||||
strcpy(x,prefix);
|
||||
strcat(x,n);
|
||||
name=x;
|
||||
next=NULL;
|
||||
pv=NULL;
|
||||
last_state=monAlive;
|
||||
++monNode::total;
|
||||
monDebug1(5,"monNode: Created node %s\n",name);
|
||||
}
|
||||
|
||||
monNode::~monNode(void)
|
||||
{
|
||||
monDebug1(5,"monNode: Deleted node %s\n",name);
|
||||
char* n = (char*)name;
|
||||
delete [] n;
|
||||
}
|
||||
|
||||
int monNode::total=0;
|
||||
|
||||
void monNode::ping(void)
|
||||
{
|
||||
time(&last_ping);
|
||||
}
|
||||
|
||||
monState monNode::state(void)
|
||||
{
|
||||
return last_state;
|
||||
}
|
||||
|
||||
monState monNode::state(time_t t)
|
||||
{
|
||||
monState s;
|
||||
time_t x;
|
||||
x=t-last_ping;
|
||||
if(x<ADDR_WARNING)
|
||||
s=monAlive;
|
||||
else if(x<ADDR_DEATH)
|
||||
s=monUnknown;
|
||||
else
|
||||
s=monDead;
|
||||
return s;
|
||||
}
|
||||
|
||||
void monNode::check(time_t t)
|
||||
{
|
||||
monState s = state(t);
|
||||
monDebug1(9,"monNode: Checking node %s\n",name);
|
||||
|
||||
if(s!=last_state)
|
||||
{
|
||||
last_state=s;
|
||||
// only change boot time if going from/to dead
|
||||
if(s==monDead || last_state==monDead) state_ping=t;
|
||||
if(pv) pv->eventData();
|
||||
}
|
||||
}
|
||||
|
||||
void monNode::setPv(monPv* p)
|
||||
{
|
||||
int need;
|
||||
monDebug1(9,"monNode: Setting PV for %s\n",name);
|
||||
|
||||
if(pv==NULL)
|
||||
need=1;
|
||||
else
|
||||
need=0;
|
||||
|
||||
pv=p;
|
||||
if(need) pv->eventData();
|
||||
}
|
||||
|
||||
void monNode::clearPv(void) { pv=NULL; }
|
||||
|
||||
void monNode::report(FILE* fd)
|
||||
{
|
||||
struct in_addr* ia = (struct in_addr*)&addr;
|
||||
switch(state())
|
||||
{
|
||||
case monDead:
|
||||
fprintf(fd,"%s %s Dead\n",name,inet_ntoa(*ia));
|
||||
break;
|
||||
case monAlive:
|
||||
fprintf(fd,"%s %s Alive\n",name,inet_ntoa(*ia));
|
||||
break;
|
||||
case monUnknown:
|
||||
fprintf(fd,"%s %s Unknown\n",name,inet_ntoa(*ia));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- status PVs -----------------------
|
||||
|
||||
makeScreenPV::~makeScreenPV(void) { }
|
||||
aitEnum makeScreenPV::bestExternalType(void) const { return aitEnumInt32; }
|
||||
|
||||
caStatus makeScreenPV::read(const casCtx& /*ctx*/, gdd& /*dd*/)
|
||||
{
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
caStatus makeScreenPV::write(const casCtx& /*ctx*/, gdd& /*dd*/)
|
||||
{
|
||||
mrg.makeADL();
|
||||
return S_casApp_success; // cannot write to these PVs
|
||||
}
|
||||
|
||||
// -------------
|
||||
|
||||
iocCountPV::~iocCountPV(void) { mrg.count_pv=NULL; }
|
||||
void iocCountPV::interestDelete(void) { monitored=0; }
|
||||
|
||||
aitEnum iocCountPV::bestExternalType(void) const { return aitEnumInt32; }
|
||||
|
||||
void iocCountPV::postValue(void)
|
||||
{
|
||||
gdd* value=new gddScalar(mrg.appValue,aitEnumInt32);
|
||||
value->put(monNode::total);
|
||||
|
||||
if(monitored)
|
||||
{
|
||||
casEventMask select(
|
||||
mrg.alarmEventMask|mrg.valueEventMask|mrg.logEventMask);
|
||||
postEvent(select,*value);
|
||||
}
|
||||
}
|
||||
|
||||
caStatus iocCountPV::interestRegister(void)
|
||||
{
|
||||
monitored=1;
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
|
||||
caStatus iocCountPV::read(const casCtx& ctx, gdd& dd)
|
||||
{
|
||||
// this is bad, should check for dd to be scalar, if it is not a scalar,
|
||||
// then find the value gdd within the container
|
||||
dd.put(monNode::total);
|
||||
return S_casApp_success;
|
||||
}
|
||||
|
||||
caStatus iocCountPV::write(const casCtx& /*ctx*/, gdd& /*dd*/)
|
||||
{
|
||||
return S_casApp_success; // cannot write to these PVs
|
||||
}
|
||||
|
||||
109
src/cas/example/iocmonitor/monNode.h
Normal file
109
src/cas/example/iocmonitor/monNode.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef MONNODE_H
|
||||
#define MONNODE_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "aitTypes.h"
|
||||
#include "casdef.h"
|
||||
|
||||
typedef enum { monAlive=0, monUnknown, monDead } monState;
|
||||
|
||||
#define ADDR_CHECK 10
|
||||
#define ADDR_WARNING 20
|
||||
#define ADDR_DEATH 40
|
||||
|
||||
class monNode;
|
||||
class monServer;
|
||||
class gdd;
|
||||
|
||||
class monPv : public casPV
|
||||
{
|
||||
public:
|
||||
monPv(const casCtx&,monServer&,monNode*,const char* pv_name);
|
||||
virtual ~monPv(void);
|
||||
|
||||
// CA server interface functions
|
||||
virtual caStatus interestRegister(void);
|
||||
virtual void interestDelete(void);
|
||||
virtual aitEnum bestExternalType(void) const;
|
||||
virtual caStatus read(const casCtx &ctx, gdd &prototype);
|
||||
virtual caStatus write(const casCtx &ctx, gdd &value);
|
||||
virtual void destroy(void);
|
||||
virtual unsigned maxSimultAsyncOps(void) const;
|
||||
virtual unsigned maxDimension(void) const;
|
||||
virtual aitIndex maxBound(unsigned dim) const;
|
||||
|
||||
void eventData(void);
|
||||
|
||||
void markInterested(void) { monitor=1; }
|
||||
void markNotInterested(void) { monitor=0; }
|
||||
int isMonitored(void) { return monitor; }
|
||||
|
||||
monServer& mrg;
|
||||
monNode* node;
|
||||
int monitor;
|
||||
gdd* data;
|
||||
};
|
||||
|
||||
class monNode
|
||||
{
|
||||
public:
|
||||
monNode(unsigned long a, const char* prefix);
|
||||
~monNode(void);
|
||||
|
||||
void report(FILE*);
|
||||
void ping(void);
|
||||
void check(time_t);
|
||||
monState state(void);
|
||||
monState state(time_t);
|
||||
void setPv(monPv*);
|
||||
void clearPv(void);
|
||||
|
||||
unsigned long addr;
|
||||
time_t last_ping;
|
||||
time_t state_ping;
|
||||
const char* name;
|
||||
monPv* pv;
|
||||
monNode* next;
|
||||
monState last_state;
|
||||
static int total;
|
||||
};
|
||||
|
||||
// ---------------------------- status PVs --------------------------
|
||||
|
||||
class makeScreenPV : public casPV
|
||||
{
|
||||
public:
|
||||
makeScreenPV(const casCtx& c,const char* pv_name,monServer& s):
|
||||
casPV(c,pv_name),mrg(s){}
|
||||
virtual ~makeScreenPV(void);
|
||||
|
||||
// CA server interface functions
|
||||
virtual aitEnum bestExternalType(void) const;
|
||||
virtual caStatus read(const casCtx &ctx, gdd &prototype);
|
||||
virtual caStatus write(const casCtx &ctx, gdd &value);
|
||||
|
||||
monServer& mrg;
|
||||
};
|
||||
|
||||
class iocCountPV : public casPV
|
||||
{
|
||||
public:
|
||||
iocCountPV(const casCtx& c,const char* pv_name,monServer& s):
|
||||
casPV(c,pv_name),mrg(s),monitored(0) {}
|
||||
virtual ~iocCountPV(void);
|
||||
|
||||
// CA server interface functions
|
||||
virtual caStatus interestRegister(void);
|
||||
virtual void interestDelete(void);
|
||||
virtual aitEnum bestExternalType(void) const;
|
||||
virtual caStatus read(const casCtx &ctx, gdd &prototype);
|
||||
virtual caStatus write(const casCtx &ctx, gdd &value);
|
||||
|
||||
void postValue(void);
|
||||
|
||||
int monitored;
|
||||
monServer& mrg;
|
||||
};
|
||||
|
||||
#endif
|
||||
352
src/cas/example/iocmonitor/monServer.cc
Normal file
352
src/cas/example/iocmonitor/monServer.cc
Normal file
@@ -0,0 +1,352 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "caProto.h"
|
||||
#include "gddAppTable.h"
|
||||
|
||||
#include "monServer.h"
|
||||
#include "monNode.h"
|
||||
|
||||
int debugLevel=0;
|
||||
int makeReport=0;
|
||||
int keepGoing=1;
|
||||
|
||||
typedef void (*SIG_FUNC)(int);
|
||||
|
||||
static SIG_FUNC save_hup = NULL;
|
||||
static SIG_FUNC save_int = NULL;
|
||||
static SIG_FUNC save_term = NULL;
|
||||
static SIG_FUNC save_usr1 = NULL;
|
||||
|
||||
static void sig_end(int)
|
||||
{
|
||||
signal(SIGHUP,sig_end);
|
||||
signal(SIGTERM,sig_end);
|
||||
signal(SIGINT,sig_end);
|
||||
keepGoing=0;
|
||||
}
|
||||
static void sig_usr1(int) { makeReport=1; signal(SIGUSR1,sig_usr1); }
|
||||
|
||||
extern int monAdl(monNode**,char*,const char*);
|
||||
|
||||
// ------------------------- file descriptor servicing ----------------------
|
||||
|
||||
monFd::~monFd(void) { }
|
||||
void monFd::callBack(void) { server.dataReady(); }
|
||||
|
||||
// -------------------------- server -----------------------------
|
||||
|
||||
monServer::monServer(unsigned namelen,unsigned pvcount,unsigned simio,
|
||||
const char* p):caServer(namelen,pvcount,simio)
|
||||
{
|
||||
int i;
|
||||
count_pv=NULL;
|
||||
const char* x = p?p:"_";
|
||||
prefix=new char[strlen(x)+1];
|
||||
strcpy(prefix,x);
|
||||
prefix_length=strlen(prefix);
|
||||
soc_fd=NULL;
|
||||
db=new monNode*[ADDR_TOTAL];
|
||||
for(i=0;i<ADDR_TOTAL;i++) db[i]=NULL;
|
||||
|
||||
gddApplicationTypeTable& tt = gddApplicationTypeTable::AppTable();
|
||||
appValue=tt.getApplicationType("value");
|
||||
|
||||
sprintf(ioc_count_name,"%siocCount",prefix);
|
||||
sprintf(make_screen_name,"%smakeScreen",prefix);
|
||||
}
|
||||
|
||||
monServer::~monServer(void)
|
||||
{
|
||||
int i;
|
||||
monNode *c,*p;
|
||||
for(i=0;i<ADDR_TOTAL;i++)
|
||||
{
|
||||
for(c=db[i];c;)
|
||||
{
|
||||
p=c->next;
|
||||
delete c;
|
||||
c=p;
|
||||
}
|
||||
}
|
||||
delete [] db;
|
||||
}
|
||||
|
||||
void monServer::report(FILE* fd)
|
||||
{
|
||||
int i;
|
||||
monNode* n;
|
||||
for(i=0;i<ADDR_TOTAL;i++)
|
||||
{
|
||||
for(n=db[i];n;n=n->next)
|
||||
n->report(fd);
|
||||
}
|
||||
}
|
||||
|
||||
monNode* monServer::findNode(unsigned long addr)
|
||||
{
|
||||
monNode* t;
|
||||
for(t=db[addr&ADDR_MASK];t && t->addr!=addr;t=t->next);
|
||||
return t;
|
||||
}
|
||||
|
||||
monNode* monServer::addNode(unsigned long addr)
|
||||
{
|
||||
unsigned long i;
|
||||
monNode* t;
|
||||
if((t=findNode(addr))==NULL)
|
||||
{
|
||||
i=addr&ADDR_MASK;
|
||||
t=new monNode(addr,prefix);
|
||||
t->next=db[i];
|
||||
db[i]=t;
|
||||
pv_list.add(t->name,*t);
|
||||
if(count_pv) count_pv->postValue();
|
||||
}
|
||||
else
|
||||
t->ping();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void monServer::checkEvent(void)
|
||||
{
|
||||
// go through all the nodes and send out monitors on PV if required
|
||||
time_t t;
|
||||
int i;
|
||||
monNode* n;
|
||||
time(&t);
|
||||
|
||||
for(i=0;i<ADDR_TOTAL;i++)
|
||||
{
|
||||
for(n=db[i];n;n=n->next)
|
||||
n->check(t);
|
||||
}
|
||||
}
|
||||
|
||||
pvExistReturn monServer::pvExistTest(const casCtx& c,const char* pvname)
|
||||
{
|
||||
monNode* node;
|
||||
|
||||
if(strcmp(pvname,ioc_count_name)==0)
|
||||
return pvExistReturn(S_casApp_success,ioc_count_name);
|
||||
|
||||
if(strcmp(pvname,make_screen_name)==0)
|
||||
return pvExistReturn(S_casApp_success,make_screen_name);
|
||||
|
||||
if(pv_list.find(pvname,node)==0)
|
||||
return pvExistReturn(S_casApp_success,node->name);
|
||||
else
|
||||
return pvExistReturn(S_casApp_pvNotFound);
|
||||
}
|
||||
|
||||
casPV* monServer::createPV(const casCtx& c,const char* pvname)
|
||||
{
|
||||
monNode* node;
|
||||
|
||||
if(strcmp(pvname,ioc_count_name)==0)
|
||||
return count_pv=new iocCountPV(c,pvname,*this);
|
||||
|
||||
if(strcmp(pvname,make_screen_name)==0)
|
||||
return new makeScreenPV(c,pvname,*this);
|
||||
|
||||
if(pv_list.find(pvname,node)==0)
|
||||
return new monPv(c,*this,node,pvname);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int monServer::repeaterConnect(void)
|
||||
{
|
||||
caHdr msg;
|
||||
struct sockaddr_in tsin;
|
||||
struct sockaddr ssin;
|
||||
struct timeval tout;
|
||||
fd_set fds;
|
||||
int retry,done,rlen,len;
|
||||
|
||||
tsin.sin_port=htons(0);
|
||||
tsin.sin_family=AF_INET;
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((soc=socket(AF_INET,SOCK_DGRAM,17))<0)
|
||||
{
|
||||
perror("open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(soc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("local bind failed to soc failed");
|
||||
close(soc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char*)&msg,0,sizeof(msg));
|
||||
msg.m_cmmd = htons(REPEATER_REGISTER);
|
||||
msg.m_available = tsin.sin_addr.s_addr;
|
||||
tsin.sin_port=htons(REPEATER_PORT);
|
||||
|
||||
for(done=0,retry=0;done==0 && retry<3;retry++)
|
||||
{
|
||||
if(sendto(soc,(char*)&msg,sizeof(msg),0,
|
||||
(struct sockaddr*)&tsin,sizeof(tsin))<0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
close(soc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc,&fds);
|
||||
tout.tv_sec=0;
|
||||
tout.tv_usec=500000;
|
||||
|
||||
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
|
||||
{
|
||||
case -1: /* bad */
|
||||
perror("first select failed");
|
||||
return -1;
|
||||
case 0: /* timeout */
|
||||
break;
|
||||
default: /* data ready */
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
|
||||
if(done==1)
|
||||
{
|
||||
rlen=0;
|
||||
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
|
||||
{
|
||||
perror("first recvfrom failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ntohs(msg.m_cmmd)==REPEATER_CONFIRM)
|
||||
printf("Connected to repeater\n");
|
||||
else
|
||||
{
|
||||
printf("Cannot connect to repeater (%d)\n",(int)ntohs(msg.m_cmmd));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Cannot connect to repeater\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
soc_fd=new monFd(soc,fdrRead,*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void monServer::dataReady(void)
|
||||
{
|
||||
caHdr msg;
|
||||
struct sockaddr ssin;
|
||||
monNode* node;
|
||||
int rlen,len;
|
||||
unsigned long* iaddr;
|
||||
|
||||
rlen=0;
|
||||
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
|
||||
{
|
||||
perror("first recvfrom failed");
|
||||
}
|
||||
else if(ntohs(msg.m_cmmd)==CA_PROTO_RSRV_IS_UP)
|
||||
{
|
||||
iaddr=(unsigned long*)&msg.m_available;
|
||||
node=addNode(*iaddr);
|
||||
}
|
||||
}
|
||||
|
||||
void monServer::mainLoop(void)
|
||||
{
|
||||
osiTime delay(ADDR_CHECK,0u);
|
||||
time_t curr,prev;
|
||||
|
||||
if(repeaterConnect()<0) return;
|
||||
|
||||
prev=0;
|
||||
while(keepGoing)
|
||||
{
|
||||
fileDescriptorManager.process(delay);
|
||||
time(&curr);
|
||||
if((curr-prev)>=ADDR_CHECK)
|
||||
{
|
||||
checkEvent();
|
||||
prev=curr;
|
||||
}
|
||||
|
||||
if(makeReport)
|
||||
{
|
||||
FILE* fd;
|
||||
if((fd=fopen("PV_REPORT","w")))
|
||||
{
|
||||
report(fd);
|
||||
fclose(fd);
|
||||
}
|
||||
makeADL();
|
||||
makeReport=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void monServer::makeADL(void) { monAdl(db,"ioc_status.adl",prefix); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc<2)
|
||||
{
|
||||
fprintf(stderr,"Must enter a prefix for PVs on command line\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(argc==3) sscanf(argv[2],"%d",&debugLevel);
|
||||
|
||||
// disassociate from parent
|
||||
switch(fork())
|
||||
{
|
||||
case -1: // error
|
||||
perror("Cannot create gateway processes");
|
||||
return -1;
|
||||
case 0: // child
|
||||
#if defined linux || defined SOLARIS
|
||||
setpgrp();
|
||||
#else
|
||||
setpgrp(0,0);
|
||||
#endif
|
||||
setsid();
|
||||
break;
|
||||
default: // parent
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
save_hup=signal(SIGHUP,sig_end);
|
||||
save_term=signal(SIGTERM,sig_end);
|
||||
save_int=signal(SIGINT,sig_end);
|
||||
save_usr1=signal(SIGUSR1,sig_usr1);
|
||||
|
||||
monServer* ms = new monServer(32u,5u,2000u,argv[1]);
|
||||
ms->mainLoop();
|
||||
delete ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
86
src/cas/example/iocmonitor/monServer.h
Normal file
86
src/cas/example/iocmonitor/monServer.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef MONSERVER_H
|
||||
#define MONSERVER_H
|
||||
|
||||
#include "casdef.h"
|
||||
#include "tsHash.h"
|
||||
#include "fdManager.h"
|
||||
|
||||
#include "monNode.h"
|
||||
|
||||
class gdd;
|
||||
class monServer;
|
||||
|
||||
// use lower 11 bits of address as index
|
||||
#define ADDR_MASK 0x0000001f
|
||||
#define ADDR_TOTAL (ADDR_MASK+1)
|
||||
#define REPEATER_PORT 5065
|
||||
|
||||
// ---------------------- fd manager ------------------------
|
||||
|
||||
class monFd : public fdReg
|
||||
{
|
||||
public:
|
||||
monFd(const int fdIn,const fdRegType typ,monServer& s):
|
||||
fdReg(fdIn,typ),server(s) { }
|
||||
virtual ~monFd(void);
|
||||
private:
|
||||
virtual void callBack(void);
|
||||
monServer& server;
|
||||
};
|
||||
|
||||
// ---------------------------- server -------------------------------
|
||||
|
||||
class monServer : public caServer
|
||||
{
|
||||
public:
|
||||
monServer(unsigned max_name_len,unsigned pv_count_est,unsigned max_sim_io,
|
||||
const char* pre);
|
||||
virtual ~monServer(void);
|
||||
|
||||
// CAS virtual overloads
|
||||
virtual pvExistReturn pvExistTest(const casCtx& c,const char* pvname);
|
||||
virtual casPV* createPV(const casCtx& c,const char* pvname);
|
||||
|
||||
// CAS application management functions
|
||||
int repeaterConnect(void);
|
||||
void checkEvent(void);
|
||||
void dataReady(void);
|
||||
void mainLoop(void);
|
||||
void report(FILE*);
|
||||
void makeADL(void);
|
||||
|
||||
monNode* findNode(unsigned long addr);
|
||||
monNode* addNode(unsigned long addr);
|
||||
|
||||
int appValue;
|
||||
char* prefix;
|
||||
int prefix_length;
|
||||
iocCountPV* count_pv;
|
||||
private:
|
||||
tsHash<monNode> pv_list; // client pv list
|
||||
monNode** db;
|
||||
monFd* soc_fd;
|
||||
int soc;
|
||||
char ioc_count_name[40];
|
||||
char make_screen_name[40];
|
||||
};
|
||||
|
||||
extern int debugLevel;
|
||||
|
||||
/* debug macro creation */
|
||||
#ifdef NODEBUG
|
||||
#define monDebug(l,f,v) ;
|
||||
#else
|
||||
#define monDebug(l,f,v) { if(l<=debugLevel) \
|
||||
{ fprintf(stderr,f,v); fflush(stderr); }}
|
||||
#define monDebug0(l,f) { if(l<=debugLevel) \
|
||||
{ fprintf(stderr,f); fflush(stderr); } }
|
||||
#define monDebug1(l,f,v) { if(l<=debugLevel) \
|
||||
{ fprintf(stderr,f,v); fflush(stderr); }}
|
||||
#define monDebug2(l,f,v1,v2) { if(l<=debugLevel) \
|
||||
{ fprintf(stderr,f,v1,v2); fflush(stderr); }}
|
||||
#define monDebug3(l,f,v1,v2,v3) { if(l<=debugLevel) \
|
||||
{ fprintf(stderr,f,v1,v2,v3); fflush(stderr); }}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
106
src/cas/example/iocmonitor/tsDLHashList.h
Normal file
106
src/cas/example/iocmonitor/tsDLHashList.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef tsDLHashList_H
|
||||
#define tsDLHashList_H
|
||||
|
||||
extern "C" {
|
||||
#include "gpHash.h"
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class tsHash
|
||||
{
|
||||
private:
|
||||
void* hash_table;
|
||||
|
||||
public:
|
||||
gpHash(void)
|
||||
{
|
||||
hash_table=NULL;
|
||||
gphInitPvt(&hash_table);
|
||||
}
|
||||
|
||||
~gateHash(void) { gphFreeMem(hash_table); }
|
||||
|
||||
int add(const char* key, T& item);
|
||||
{
|
||||
GPHENTRY* entry;
|
||||
int rc;
|
||||
|
||||
entry=gphAdd(hash_table,(char*)key,hash_table);
|
||||
|
||||
if(entry==(GPHENTRY*)NULL)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
entry->userPvt=(void*)&item;
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int remove(const char* key,T*& item);
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(find(key,item)<0)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
gphDelete(hash_table,(char*)key,hash_table);
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int find(const char* key, T*& item);
|
||||
{
|
||||
GPHENTRY* entry;
|
||||
int rc;
|
||||
|
||||
entry=gphFind(hash_table,(char*)key,hash_table);
|
||||
|
||||
if(entry==(GPHENTRY*)NULL)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
item=(T*)entry->userPvt;
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class tsDLHashList : public tsDLList<T>
|
||||
{
|
||||
private:
|
||||
tsHash<T> h;
|
||||
public:
|
||||
int add(const char* key, T& item)
|
||||
{
|
||||
int rc;
|
||||
rc=h.add(key,item);
|
||||
add(item);
|
||||
return rc;
|
||||
}
|
||||
int find(const char* key, T*& item);
|
||||
{
|
||||
int rc=0;
|
||||
if(h.find(key,item)!=0)
|
||||
rc=-1;
|
||||
return rc;
|
||||
}
|
||||
int remove(const char* key,T*& item);
|
||||
{
|
||||
int rc=0;
|
||||
if(h.find(key,item)==0)
|
||||
{
|
||||
h.remove(key,item);
|
||||
remove(*item);
|
||||
}
|
||||
else
|
||||
rc=-1;
|
||||
return rc;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
143
src/cas/example/iocmonitor/tsHash.h
Normal file
143
src/cas/example/iocmonitor/tsHash.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#ifndef tsDLHashList_H
|
||||
#define tsDLHashList_H
|
||||
|
||||
/*
|
||||
* Author: Jim Kowalkowski
|
||||
* Date: 7/96
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.2 1996/08/14 21:10:35 jbk
|
||||
* next wave of updates, menus stopped working, units working, value not
|
||||
* working correctly sometimes, can't delete the channels
|
||||
*
|
||||
* Revision 1.1 1996/07/23 16:32:46 jbk
|
||||
* new gateway that actually runs
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "gpHash.h"
|
||||
}
|
||||
|
||||
#include "tsDLList.h"
|
||||
|
||||
template <class T>
|
||||
class tsHash
|
||||
{
|
||||
private:
|
||||
void* hash_table;
|
||||
friend class tsDLHashIter<T>;
|
||||
|
||||
public:
|
||||
tsHash(void)
|
||||
{
|
||||
hash_table=0;
|
||||
gphInitPvt(&hash_table,2048); // 2048 is a guess
|
||||
}
|
||||
|
||||
~tsHash(void)
|
||||
{
|
||||
gphFreeMem(hash_table);
|
||||
}
|
||||
|
||||
int add(const char* key, T& item)
|
||||
{
|
||||
GPHENTRY* entry;
|
||||
int rc;
|
||||
|
||||
entry=gphAdd(hash_table,(char*)key,hash_table);
|
||||
|
||||
if(entry==0)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
entry->userPvt=(void*)&item;
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int remove(const char* key,T*& item)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(find(key,item)<0)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
gphDelete(hash_table,(char*)key,hash_table);
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int find(const char* key, T*& item)
|
||||
{
|
||||
GPHENTRY* entry;
|
||||
int rc;
|
||||
|
||||
entry=gphFind(hash_table,(char*)key,hash_table);
|
||||
|
||||
if(entry==0)
|
||||
rc=-1;
|
||||
else
|
||||
{
|
||||
item=(T*)entry->userPvt;
|
||||
rc=0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class tsDLHashList : public tsDLList<T>
|
||||
{
|
||||
private:
|
||||
tsHash<T> h;
|
||||
friend class tsDLHashIter<T>;
|
||||
|
||||
public:
|
||||
tsDLHashList(void) { }
|
||||
~tsDLHashList(void) { }
|
||||
|
||||
int add(const char* key, T& item)
|
||||
{
|
||||
int rc;
|
||||
rc=h.add(key,item);
|
||||
tsDLList<T>::add(item);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int find(const char* key, T*& item)
|
||||
{
|
||||
int rc=0;
|
||||
if(h.find(key,item)!=0)
|
||||
rc=-1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int remove(const char* key,T*& item)
|
||||
{
|
||||
int rc=0;
|
||||
if(h.find(key,item)==0)
|
||||
{
|
||||
h.remove(key,item);
|
||||
tsDLList<T>::remove(*item);
|
||||
}
|
||||
else
|
||||
rc=-1;
|
||||
return rc;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class tsDLHashNode : public tsDLNode<T>
|
||||
{
|
||||
public:
|
||||
T* getNext(void) { return tsDLNode<T>::getNext(); }
|
||||
T* getPrev(void) { return tsDLNode<T>::getPrev(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user