/** * This is a generalized polling module for SICS. With this module * SICS variables can be polled regulary for updates. For different types of * SICS variables different polling mechanisms are required. In order to cope with * this requirement a polling interface and different drivers are defined in the * sister module polldriv.h and polldriv.c. This module implements the interface * to configure polling and the SICS task to run polling. * * Copyright: see COPYRIGHT * * Mark Koennecke, November-December 2006 */ <%! source sicstemplates.tcl %> <% stdIncludes %> #include "polldriv.h" #include "splitter.h" #include #include "lld.h" /*================== data structure =====================================*/ static SConnection *defCon = NULL; struct __SICSPOLL{ pObjectDescriptor pDes; int pollList; /* list with polled objects */ int listDirty; /* a flag to set when the list has been modified. This will cause the list polling task to go back to the start. */ SConnection *pCon; /* connection to use for polling */ int iEnd; /* flag ending this */ int nPoll; /* how many to poll in one run */ long taskID; }; /*-----------------------------------------------------------------------*/ void killSicsPoll(void *data){ pSicsPoll self = (pSicsPoll)data; int status; pPollDriv poll = NULL; self->iEnd = 1; status = LLDnodePtr2First(self->pollList); while(status != 0){ poll = LLDnodePtr(self->pollList); if(poll != NULL){ deletePollDriv(poll); } status = LLDnodePtr2Next(self->pollList); } LLDdelete(self->pollList); free(self); if(defCon != NULL){ SCDeleteConnection(defCon); } } /*----------------- list access -----------------------------------------*/ static pPollDriv locateObject(int list, char *objectIdentifier){ int status; pPollDriv data = NULL; status = LLDnodePtr2First(list); while(status != 0){ data = (pPollDriv)LLDnodePtr(list); if(data != NULL){ if(strcmp(data->objectIdentifier,objectIdentifier) == 0){ return data; } } status = LLDnodePtr2Next(list); } return NULL; } /*===================== task function ==================================*/ static int incrList(int list){ int status; if(LLDcheck(list) == LIST_EMPTY){ return 0; } status = LLDnodePtr2Next(list); if(status == 0) { status = LLDnodePtr2First(list); } return status; } /*---------------------------------------------------------------------------*/ void SicsPollSignal(void *pData, int iSignal, void *pSigData){ pSicsPoll self = NULL; int *iInt; self = (pSicsPoll)pData; if(iSignal == SICSINT){ iInt = (int *)pSigData; if(*iInt == eEndServer){ self->iEnd = 1; } } } /*----------------------------------------------------------------------*/ static int PollTask(void *data){ pSicsPoll self = (pSicsPoll) data; pPollDriv poll = NULL; int status, i; time_t now = time(NULL); if(self == NULL || self->iEnd == 1){ return 0; } if(LLDcheck(self->pollList) == LIST_EMPTY){ return 1; } /* * increment list */ if(self->listDirty == 1){ self->listDirty = 0; status = LLDnodePtr2First(self->pollList); } /* * actually do poll */ for(i = 0; i < self->nPoll; i++){ status = incrList(self->pollList); poll = (pPollDriv)LLDnodePtr(self->pollList); if(status != 0 && poll != NULL){ if(poll->isDue(poll,now,self->pCon)){ poll->poll(poll,self->pCon); } } } return 1; } /*==================== interface functions ==============================*/ int removePollObject(pSicsPoll self, char *objectIdentifier){ pPollDriv target = NULL; self->listDirty = 1; target = locateObject(self->pollList, objectIdentifier); if(target != NULL){ LLDnodeDelete(self->pollList); deletePollDriv(target); return 1; } else{ return 0; } } /*------------------------------------------------------------------------*/ int addPollObject(SicsPoll *self, SConnection *pCon, char *objectIdentifier, char *driver, int argc, char *argv[]){ int status; pPollDriv driv = NULL; driv = makePollDriver(pCon, driver,objectIdentifier, argc,argv); if(driv == NULL){ return 0; } LLDnodeAppend(self->pollList,&driv); return 1; } /*-----------------------------------------------------------------------*/ static void printPollList(pSicsPoll self, SConnection *pCon){ int status; pPollDriv driv = NULL; char buffer[512]; status = LLDnodePtr2First(self->pollList); while(status != 0){ driv = (pPollDriv)LLDnodePtr(self->pollList); if(driv != NULL){ snprintf(buffer,512,"%60s %3d", driv->objectIdentifier, driv->pollIntervall); SCWrite(pCon,buffer,eValue); } status = LLDnodePtr2Next(self->pollList); } } /*================== interpreter interface ===============================*/ <%makeSicsFunc SICSPollWrapper%>{ pSicsPoll self = (pSicsPoll)pData; pPollDriv driv = NULL; int status, iVal; char buffer[512]; pDynString txt = NULL; assert(self != NULL); <%testNoPar 2 5%> strtolower(argv[1]); if(strcmp(argv[1],"del") == 0) { <%testNoPar 3 9%> <%testPriv usMugger 9%> status = removePollObject(self,argv[2]); if(status == 0) { SCWrite(pCon,"ERROR: object to remove from poll list not found",eError); return 0; } else { SCSendOK(pCon); return 1; } } else if(strcmp(argv[1],"add") == 0) { <%testNoPar 4 9%> <%testPriv usMugger 9%> driv = makePollDriver(pCon,argv[3], argv[2], argc-3, &argv[4]); if(driv != NULL){ LLDnodeAppend(self->pollList,&driv); SCSendOK(pCon); return 1; } else { return 0; } } else if (strcmp(argv[1],"npoll") == 0) { <%# sicsPar name, c-name nargs priv type indent sicsPar npoll self->nPoll 3 usMugger int 9%> } else if (strcmp(argv[1],"listen") == 0) { self->pCon = pCon; SCSendOK(pCon); return 1; } else if (strcmp(argv[1],"unlisten") == 0) { self->pCon = defCon; SCSendOK(pCon); return 1; } else if (strcmp(argv[1],"intervall") == 0){ <%testNoPar 3 9%> <%testPriv usMugger 9%> driv = locateObject(self->pollList,argv[2]); if(driv == NULL){ SCWrite(pCon,"ERROR: object not in polling list",eError); return 0; } if(argc > 3){ status = sscanf(argv[3],"%d", &iVal); if(status != 1){ snprintf(buffer,511,"ERROR: failed to convert %s to int", argv[3]); SCWrite(pCon,buffer,eError); return 0; } if(iVal < 0) { SCWrite(pCon,"ERROR: new value for intervall out of range",eError); return 0; } driv->pollIntervall = iVal; SCSendOK(pCon); return 1; } else { snprintf(buffer,511,"%s.intervall = %d",driv->objectIdentifier, driv->pollIntervall); SCWrite(pCon,buffer,eValue); return 1; } } else if (strcmp(argv[1],"list") == 0) { SCStartBuffering(pCon); printPollList(self,pCon); txt = SCEndBuffering(pCon); if(txt != NULL){ SCWrite(pCon,GetCharArray(txt),eValue); } return 1; } else if (strcmp(argv[1],"poll") == 0) { <%testNoPar 3 9%> driv = locateObject(self->pollList,argv[2]); if(driv == NULL){ SCWrite(pCon,"ERROR: object not in polling list",eError); return 0; } status = driv->poll(driv,pCon); if(status != 1){ SCWrite(pCon,"ERROR: polling object",eError); return 0; } SCWrite(pCon,"Object polled OK",eError); return 1; } return 1; } /*------------------------------------------------------------------------*/ <%makeSicsFunc InstallSICSPoll%>{ pSicsPoll pNew = NULL; <%newStrucRet SicsPoll 5 0%> pNew->pDes = CreateDescriptor("SicsPoll"); pNew->pollList = LLDcreate(sizeof(void *)); defCon = SCCreateDummyConnection(pSics); if(pNew->pDes == NULL|| pNew->pollList < 0 || defCon == NULL){ SCWrite(pCon,"ERROR: out of memory creating SicsPoll",eError); return 0; } pNew->pCon = defCon; pNew->nPoll = 3; TaskRegister(pServ->pTasker,PollTask,SicsPollSignal,NULL,pNew, TASK_PRIO_HIGH); if(argc > 1){ AddCommand(pSics,argv[1],SICSPollWrapper, killSicsPoll,pNew); } else { AddCommand(pSics,"sicspoll",SICSPollWrapper, killSicsPoll,pNew); } return 1; }