diff --git a/dgrambroadcast.c b/dgrambroadcast.c new file mode 100644 index 0000000..c1dbf7b --- /dev/null +++ b/dgrambroadcast.c @@ -0,0 +1,342 @@ + +/* + * Send UDP multicast message + * Send UDP broadcast message +*/ + +// #define SEND_BCASTS_TOO Yes +#ifdef SEND_BCASTS_TOO +/* broadcast address for our network */ +/* unsigned int brAddr = 0x818197ff; - only our network */ +unsigned int brAddr[] = { + 0x818197ff, /* 129.129.151.255 */ + 0x818196ff, /* 129.129.150.255 - same router as our subnet */ + 0x81818aff, /* 129.129.138.255 - same router as our subnet */ +}; +int nrBrAddr = sizeof(brAddr) / sizeof(unsigned int); +#endif + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef vaxc +# ifndef HP_RT +# ifndef __osf__ +# ifndef linux +# include +# endif +# endif +# else +# include +# endif +#else +# include +#endif + + +/* #define TESTING Yes */ + +#ifdef TESTING +#define PERROR(x) perror(x) +#else +#define PERROR(x) +#endif + + +#include "dgrambroadcast.h" + + +int McastSocket; /* multicast socket */ +struct sockaddr_in McastDestination; /* multicast destination address */ + + +/*********************************************************************/ + +// -DDESTINATION_MCAST="\"226.129.151.57\"" +// which is acs-gateway with first byte replaced to 226 + +static char DESTINATION_MCAST[128] = {0}; // place to hold x.y.z.w IPv4 address + +void initDestMcastAddr() +{ + struct hostent *hp; + + if (memcmp(DESTINATION_MCAST, "226.", 4) == 0) { + return; // already initialized + } + + hp = gethostbyname(SERVER_HOST); + if (hp == (struct hostent *) 0) { + printf("%s: unknown host", SERVER_HOST); + exit(99); + } + + sprintf(DESTINATION_MCAST, "226.%d.%d.%d", hp->h_addr[1]&0xFF, hp->h_addr[2]&0xFF, hp->h_addr[3]&0xFF); + //printf("Got DESTINATION_MCAST = '%s'\n", DESTINATION_MCAST); +} + +/*********************************************************************/ +void closeBroadcastSocket(sendSocket) +int sendSocket; +{ +#ifdef TESTING + printf("closeBroadcastSocket()\n"); +#endif + close(sendSocket); + + if (McastSocket >= 0) close(McastSocket); + +} + + +/*********************************************************************/ +int openBroadcastSocket() +{ + //unsigned char ttl; + int ttl; + int sendSocket; + int enableBroadcast; + + int status; + + + initDestMcastAddr(); + +#ifdef TESTING + printf("openBroadcastSocket()\n"); +#endif + + sendSocket = socket(AF_INET, SOCK_DGRAM, 0); + if (sendSocket < 0) { + PERROR("socket"); + return sendSocket; + } + + enableBroadcast = 1; + status = setsockopt(sendSocket, SOL_SOCKET, SO_BROADCAST, (char *) &enableBroadcast, sizeof(enableBroadcast)); + if (status < 0) { + PERROR("setsockopt"); + return status; + } + + + /* open multicast socket */ + McastSocket = socket(AF_INET, SOCK_DGRAM, 0); + if (McastSocket < 0) { + PERROR("McastSocket"); + } + //else { printf("Multicast socket opened\n");} + + ttl = 4; // with less then 2 it does not work + if(setsockopt(McastSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof(ttl)) < 0) { + perror("setsockopt() failed setting IP_MULTICAST_TTL"); + } + //else {printf("Multicast socket configured\n");} + + McastDestination.sin_family = AF_INET; + McastDestination.sin_port = htons(SEND_PORT); + McastDestination.sin_addr.s_addr = inet_addr(DESTINATION_MCAST); + + + return sendSocket; + +} + +/*********************************************************************/ +int openReceiveSocket(port) +unsigned short port; +{ + struct sockaddr_in name; + int recvSocket; + + initDestMcastAddr(); + +#ifdef TESTING + printf("openReceiveSocket()\n"); +#endif + + recvSocket = socket(AF_INET, SOCK_DGRAM, 0); + if (recvSocket < 0) { + PERROR("socket"); + return recvSocket; + } + + { + int sopt = 1; + + if (setsockopt(recvSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &sopt, sizeof(int)) != 0) { + perror("SO_REUSEADDR"); + printf("not fatal, continuing\n"); + } + } + + /* Create name with wildcards. */ + name.sin_family = AF_INET; + name.sin_addr.s_addr = INADDR_ANY; + name.sin_port = htons(port); + if (bind(recvSocket, (struct sockaddr *) &name, sizeof(name))) { + PERROR("bind"); + recvSocket = -1; + return recvSocket; + } + +#ifdef USE_MULTICAST + { + char group[100]; // group address string + struct ip_mreq McastReq; // multicast group request + + printf("Receive on port 0x%04X=%d, use multicast group=\"%s\" addr=INADDR_ANY\n", + port & 0xFFFF, port, DESTINATION_MCAST); + + // Join the multicast group from we want to receive datagrams. + // Initialize the multicast request structure and then pass + // it as an option to setsockopt(). The imr_multiaddr element + // is initialized to the desired multicast group. The + // imr_interface element is initilized to IPADDR_ANY which + // causes the multcast receives to come from the default + // interface. + + // Set defaults and get group address and port number if + // specified in command line. + strcpy(group, DESTINATION_MCAST ); + + McastReq.imr_multiaddr.s_addr = inet_addr(group); + McastReq.imr_interface.s_addr = INADDR_ANY; + + if(setsockopt(recvSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &McastReq, sizeof(McastReq)) < 0) + perror("setsockopt failed for IP_ADD_MEMBERSHIP"); + } +#endif + + return recvSocket; + +} + +/*********************************************************************/ +void receiveJoinMCast(recvSocket) +int recvSocket; +{ + struct ip_mreq McastReq; // multicast group request + char *group; + + + initDestMcastAddr(); + + group = DESTINATION_MCAST; + + + McastReq.imr_multiaddr.s_addr = inet_addr(group); + McastReq.imr_interface.s_addr = INADDR_ANY; + + if(setsockopt(recvSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &McastReq, sizeof(McastReq)) < 0) + perror("setsockopt failed for IP_ADD_MEMBERSHIP"); + +} + +/*********************************************************************/ +int selectReceiveSocket(recvSocket, usec) +int recvSocket; +int usec; +{ + struct timeval tv; + int nfds, rm, wm, em; + int status; + +#ifdef TESTING + printf("selectReceiveSocket()\n"); +#endif + + nfds = 32; + rm = 1 << recvSocket; + wm = 0; + em = 0; + tv.tv_sec = 0; + tv.tv_usec = usec; + +#ifndef vaxc + status = select(nfds, (fd_set *) &rm, (fd_set *) &wm, (fd_set *) &em, &tv); +#else + status = select(nfds, &rm, &wm, &em, &tv); +#endif + + return status; /* 0 = nothing to read, 1 = ready for read, -1 = error */ +} + +int readReceiveSocket(recvSocket, buff, len) +int recvSocket; +unsigned char *buff; +int len; +{ + int status; + +#ifdef TESTING + printf("readReceiveSocket()\n"); +#endif + + memset(buff, '\0', len); + status = read(recvSocket, buff, len); + if (status < 0) PERROR("read"); + return status; +} + +/*********************************************************************/ +int sendBroadcastMessage(sendSocket, sendPort, sndMsg, sndMsgLen) +int sendSocket; +unsigned short sendPort; +unsigned char *sndMsg; +int sndMsgLen; +{ + int status; +#ifdef SEND_BCASTS_TOO + int i; + int flags; + struct sockaddr_in sendName; +#endif + + +#ifdef TESTING + printf("sendBroadcastMessage(s=%d, 0x%04X, msg, len=%d)\n", sendSocket, sendPort, sndMsgLen); +#endif + + /* send multicast message */ + status = sendto(McastSocket, (char *) sndMsg, sndMsgLen, 0, (struct sockaddr *) &McastDestination, sizeof(McastDestination)); + return status; + + +#ifdef SEND_BCASTS_TOO + /* send to all broadcast addresses from the list */ + for (i = 0; i < nrBrAddr; i++) { + + sendName.sin_family = AF_INET; + sendName.sin_addr.s_addr = htonl(brAddr[i]); + sendName.sin_port = htons(sendPort); + + flags = 0; + status = sendto(sendSocket, (char *) sndMsg, sndMsgLen, + flags, (struct sockaddr *) &sendName, + sizeof(sendName)); + + if (status != sndMsgLen) { +/*printf("sendBroadcastMessage(s=%d, 0x%04X, msg, len=%d - FAILED)\n", brAddr[i], sendPort, sndMsgLen);*/ + PERROR("sendto"); + } +/*else{printf("sendBroadcastMessage(s=%d, 0x%04X, msg, len=%d - OK)\n", brAddr[i], sendPort, sndMsgLen);}*/ + } +#endif + + + return status; + +} + diff --git a/dgrambroadcast.h b/dgrambroadcast.h new file mode 100644 index 0000000..456f723 --- /dev/null +++ b/dgrambroadcast.h @@ -0,0 +1,11 @@ + +#define MAX_BROADCAST_MSG_LEN 1472 + +int openBroadcastSocket ( /* void */ ); +void closeBroadcastSocket( /* sendSocket */ ); +int sendBroadcastMessage( /* sendSocket, sendPort, sndMsg, sndMsgLen */ ); + +int openReceiveSocket ( /* port */ ); +int readReceiveSocket ( /* recvSocket, buff, len */ ); +int selectReceiveSocket ( /* recvSocket, usec */ ); + diff --git a/make_gen b/make_gen index cc52067..a7db738 100644 --- a/make_gen +++ b/make_gen @@ -16,8 +16,8 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ el755driv.o amorscan.o serial.o scontroller.o t_update.o \ t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \ el737hpv2driv.o swmotor2.o tricssupport.o \ - oicom.o fsm.o remob.o eve.o logger.o \ - ipsdriv.o itcdriv.o ilmdriv.o lcdriv.o + oicom.o fsm.o remob.o eve.o logger.o dgrambroadcast.o \ + ipsdriv.o itcdriv.o ilmdriv.o lcdriv.o sinq.o libpsi.a: $(OBJ) rm -f libpsi.a @@ -27,3 +27,10 @@ libpsi.a: $(OBJ) clean: rm -f *.a rm -f *.o + +SINQOPT=-DGRAPH_MHC3 -DUSE_MULTICAST -DSEND_PORT=0xABCB -DSERVER_HOST="\"acslg1\"" +dgrambroadcast.o: dgrambroadcast.h dgrambroadcast.c + $(CC) $(SINQOPT) -c -g dgrambroadcast.c + +sinq.o: sinq.c sinq.h dgrambroadcast.h + $(CC) $(SINQOPT) -I../ -g -c sinq.c diff --git a/psi.c b/psi.c index 830a699..14630a2 100644 --- a/psi.c +++ b/psi.c @@ -51,6 +51,7 @@ #include "fomerge.h" #include "remob.h" #include "tricssupport.h" +#include "sinq.h" static pSite sitePSI = NULL; @@ -81,6 +82,7 @@ static void AddPsiCommands(SicsInterp *pInter){ AddCommand(pInter,"InstallFocusMerge",InstallFocusMerge,NULL,NULL); AddCommand(pInter,"Remob",RemobCreate,NULL,NULL); AddCommand(pInter,"Graph",LoggerGraph,NULL,NULL); + AddCommand(pInter,"MakeSinq",SinqFactory,NULL,NULL); /* AddCommand(pInter,"MakeDifrac",MakeDifrac,NULL,NULL); */ @@ -109,6 +111,7 @@ static void RemovePsiCommands(SicsInterp *pSics){ RemoveCommand(pSics,"MakeECB"); RemoveCommand(pSics,"MakePSDFrame"); RemoveCommand(pSics,"SerialInit"); + RemoveCommand(pSics,"MakeSinq"); } /*---------------------------------------------------------------------*/ MotorDriver *CreateEL734(SConnection *pCon, int argc, char *argv[]); diff --git a/sinq.c b/sinq.c new file mode 100644 index 0000000..95b9df2 --- /dev/null +++ b/sinq.c @@ -0,0 +1,201 @@ +/*-------------------------------------------------------------------------- + * A module which reads the broadcast messages from the PSI Accelerator group + * and allows to use the information in them in SICS. This facility runs + * as a SICS task which tries to read incoming messages and stores the + * messages of interest in an internal data structure. Some code is provided + * to make the content of these messages available within SICS. This code + * follows very closely the DoesItComeMC program from Demir Anici + * + * The module also holds a circular backlog of the last MAXLOG measurements. + * This is used in order to calulcate an average. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2005 + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "dgrambroadcast.h" + +#include "sinq.h" +#ifdef SEND_PORT +#define RECEIVE_PORT SEND_PORT +#else +#define RECEIVE_PORT 0xABCC +#endif +#define MAX_BLEN 2048 +/*====================== life and death =====================================*/ +static int SinqTask(void *data){ + pSinq self = (pSinq)data; + char buff[MAX_BLEN]; + int status, sinq; + + if(self == NULL){ + return 0; + } + status = selectReceiveSocket(self->receiveSocket, 0); + if(status <= 0){ + /* + * no pending message + */ + return 1; + } + memset(buff,0,MAX_BLEN); + status = read(self->receiveSocket, buff, MAX_BLEN); + if(status < 0) { + ServerWriteGlobal("WARNING: failed to read Sinq Status",eWarning); + return 1; + } + if(memcmp(buff,"D110",4) == 0){ + strcpy(self->d110,buff); + sinq = getSinqBeam(self,SINQBEAM); + self->lastSinq[self->lastCount] = sinq; + self->lastCount++; + if(self->lastCount >= MAXLOG){ + self->lastCount = 0; + } + } + if(memcmp(buff,"A110",4) == 0){ + strcpy(self->a110,buff); + } + /* + * ignore any other message + */ + return 1; +} +/*------------------------------------------------------------------------*/ +static void KillSinq(void *data){ + pSinq self = (pSinq)data; + if(self == NULL){ + return; + } + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + free(self); +} +/*-------------------------------------------------------------------------*/ +int SinqFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]){ + pSinq pNew = NULL; + int i; + + pNew = (pSinq)malloc(sizeof(Sinq)); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory allocating Sinq",eError); + return 0; + } + memset(pNew,0,sizeof(Sinq)); + pNew->pDes = CreateDescriptor("Sinq"); + if(pNew->pDes == NULL){ + SCWrite(pCon,"ERROR: out of memory allocating Sinq",eError); + free(pNew); + return 0; + } + pNew->receiveSocket = openReceiveSocket(RECEIVE_PORT); + if(pNew->receiveSocket < 0){ + SCWrite(pCon,"ERROR: failed to open Sinq Status Broadcast port", + eError); + KillSinq(pNew); + return 0; + } + for(i = 0; i < MAXLOG; i++){ + pNew->lastSinq[i] = -200; + } + TaskRegister(pServ->pTasker,SinqTask, + NULL, + NULL, + pNew, + 1); + return AddCommand(pSics,"sinq",SinqWrapper, + KillSinq, + pNew); +} +/*===================== actual Action ====================================*/ +extern char *trim(char *txt); +/*-----------------------------------------------------------------------*/ +int getSinqBeam(pSinq self, int code){ + int result, i; + char *pPtr; + + if(self == NULL) { + return -900; + } + switch(code){ + case SINQBEAM: + pPtr = strstr(&self->d110[4],"MHC6"); + break; + case RINGBEAM: + pPtr = strstr(&self->d110[4],"MHC3"); + break; + default: + return -900; + } + if(pPtr == NULL){ + printf("Invalid Sinq message: %s\n",&self->d110[4]); + return -900; + } + pPtr = strstr(pPtr,":"); + if(pPtr == NULL){ + return -900; + } + pPtr++; + /* + * zero out units + */ + for(i = strlen(pPtr); i > 0; i--){ + if(isdigit(pPtr[i])){ + break; + } else { + pPtr[i] = '\0'; + } + } + return atoi(trim(pPtr)); +} +/*-------------------------------------------------------------------------*/ +int SinqWrapper(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]){ + pSinq self = (pSinq)pData; + char pBueffel[132]; + int sum, count, i, avg; + + + assert(self != NULL); + + if(argc < 2) { + SCWrite(pCon,&self->a110[4],eValue); + return 1; + } + strtolower(argv[1]); + if(strcmp(argv[1],"beam") == 0){ + snprintf(pBueffel,131,"sinq.beam = %d", getSinqBeam(self,SINQBEAM)); + } else if(strcmp(argv[1],"ring") == 0){ + snprintf(pBueffel,131,"sinq.ring = %d", getSinqBeam(self,RINGBEAM)); + } else if(strcmp(argv[1],"beamavg") == 0){ + for(i = 0, count = 0, sum = 0; i < MAXLOG; i++){ + if(self->lastSinq[i] > -50) { + count++; + sum += self->lastSinq[i]; + } + } + if(count > 0){ + avg = sum/count; + } else { + avg = 0; + } + snprintf(pBueffel,131,"sinq.beamavg = %d", avg); + } else{ + SCWrite(pCon,"ERROR: invalid key, I understand: beam, ring",eError); + return 0; + } + SCWrite(pCon,pBueffel,eValue); + return 1; +} diff --git a/sinq.h b/sinq.h new file mode 100644 index 0000000..30c2797 --- /dev/null +++ b/sinq.h @@ -0,0 +1,42 @@ +/*-------------------------------------------------------------------------- + * A module which reads the broadcast messages from the PSI Accelerator group + * and allows to use the information in them in SICS. This facility runs + * as a SICS task which tries to read incoming messages and stores the + * messages of interest in an internal data structure. Some code is provided + * to make the content of these messages available within SICS. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2005 + */ +#ifndef _SINQ_H_ +#define _SINQ_H_ +#include +/*-------------------------------------------------------------------------*/ +#define MAXLOG 300 +/*-------------------------------------------------------------------------*/ +typedef struct { + pObjectDescriptor pDes; + char d110[2024]; + char a110[2024]; + int receiveSocket; + int lastSinq[MAXLOG]; + int lastCount; +}Sinq, *pSinq; +/*----------------------- interpreter interface ------------------------*/ +int SinqFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]); +int SinqWrapper(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]); +/*-------------------------------------------------------------------------*/ +#define SINQBEAM 1 +#define RINGBEAM 2 +/** + * get the SINQ beam intensity. + * @param self A pointer to the SINQ data structure + * @param code either SINQBEAM or RINGBEAM + * @return The last read intensity of the appropriate beam or -900 on error + */ +int getSinqBeam(pSinq self, int code); + +#endif //_SINQ_H_