/** * This is a module to manage the LMD-400 device used to monitor HRPT detector * electronics temperatures and pressures. It is read only. The device sends * alarm messages or temperature readings any now and then asynchronously. The * format of the messages is: * - Alarm message: date time device type of alarm * - Data message: 3 lines * --- date time * --- 001..008 val val val .... * --- 009..016 val val .... * Please note that the values use a komma as the decimal separator and not a . * * copyright: see file COPYRIGHT * * Mark Koennecke, October 2007 */ #include #include #include #include #include #include #include /* * possible states */ #define IDLE 0 #define WAITDATA1 1 #define WAITDATA2 2 /* * private data structure */ #define BUFLEN 1024 typedef struct { int state; char host[256]; int port; mkChannel *pSock; pNWContext watchContext; char lineBuffer[BUFLEN]; } LMD200, *pLMD200; /*----------------------------------------------------------------------------*/ static void killLMD200(void *data){ pLMD200 priv = (pLMD200)data; if(priv == NULL){ return; } if(priv->watchContext != NULL){ NetWatchRemoveCallback(priv->watchContext); } if(priv->pSock != NULL){ NETClosePort(priv->pSock); free(priv->pSock); } free(priv); } /*-------------------------------------------------------------------------*/ static void setAlarm(pSICSOBJ self, char *text){ hdbValue alarmVal; pHdb node = NULL; alarmVal = MakeHdbText(text); node = GetHipadabaNode(self->objectNode,"alarm"); assert(node != NULL); UpdateHipadabaPar(node,alarmVal, NULL); ReleaseHdbValue(&alarmVal); } /*--------------------------------------------------------------------------*/ static void doAlarm(pSICSOBJ self, char *lineBuffer){ setAlarm(self,lineBuffer); WriteToCommandLog("CERCA>> ", lineBuffer); ServerWriteGlobal(lineBuffer,eError); } /*--------------------------------------------------------------------------*/ extern char *trim(char *); static void storeData(pSICSOBJ self, int start, char *lineBuffer){ pHdb node = NULL; char number[80], *pPtr = NULL, *pKomma; node = GetHipadabaNode(self->objectNode,"data"); assert(node != NULL); /* * throw first away */ pPtr = stptok(lineBuffer,number,80," "); pPtr = trim(pPtr); pPtr = stptok(pPtr,number,80," "); while(pPtr != NULL){ if(strstr(number,"noinp") != NULL){ node->value.v.floatArray[start] = -9999.99; start++; } else { pKomma = strchr(number,','); if(pKomma != NULL){ *pKomma = '.'; } pKomma = strchr(number,'('); if(pKomma != NULL){ *pKomma = ' '; } pKomma = strchr(number,')'); if(pKomma != NULL){ *pKomma = ' '; } node->value.v.floatArray[start] = atof(trim(number)); start++; } pPtr = trim(pPtr); pPtr = stptok(pPtr,number,80," "); } } /*--------------------------------------------------------------------------*/ static int countTokens(char *lineBuffer){ int count = 0; char myBuffer[BUFLEN], token[60]; char *pPtr = NULL; memset(myBuffer,0,BUFLEN); strcpy(myBuffer, lineBuffer); pPtr = myBuffer; pPtr = stptok(pPtr,token, 60," \r\n"); while(pPtr != NULL){ count++; pPtr = trim(pPtr); pPtr = stptok(pPtr,token,60," \r\n"); } return count; } /*--------------------------------------------------------------------------*/ static void interpretLine(pSICSOBJ self, pLMD200 priv){ pHdb node = NULL; switch(priv->state){ case IDLE: if(strstr(priv->lineBuffer, "Alarm") != NULL){ doAlarm(self, priv->lineBuffer); return; } else if(strstr(priv->lineBuffer,"Pre") != NULL){ setAlarm(self,priv->lineBuffer); } else { priv->state = WAITDATA1; setAlarm(self,"I do not feel very alarmed"); return; } break; case WAITDATA1: if(strstr(priv->lineBuffer,"...0") == NULL){ /* this data is out of order, recover...*/ priv->state == IDLE; return; } storeData(self, 0, priv->lineBuffer); priv->state = WAITDATA2; break; case WAITDATA2: if(strstr(priv->lineBuffer,"...0") == NULL){ /* this data is out of order, recover...*/ priv->state == IDLE; return; } storeData(self, 8, priv->lineBuffer); priv->state = IDLE; node = GetHipadabaNode(self->objectNode,"data"); assert(node != NULL); NotifyHipadabaPar(node,NULL); break; } } /*--------------------------------------------------------------------------- * This handles the terminator discovery and causes the evaluation of complete * lines. * --------------------------------------------------------------------------*/ static int LMD200Callback(void *context, int mode){ pSICSOBJ self = (pSICSOBJ)context; pLMD200 priv = NULL; char buffer[512], *pPtr = NULL, line[132]; assert(self != NULL); priv = (pLMD200)self->pPrivate; if(mode == nwatch_read){ memset(buffer,0,512); memset(line,0,132); NETRead(priv->pSock, buffer, 512, 0); pPtr = stptok(buffer,line,132,"\r"); while(pPtr != NULL){ if(strlen(line) > 3){ strncpy(priv->lineBuffer,line,BUFLEN); interpretLine(self, priv); priv->lineBuffer[0] = '\0'; } pPtr = stptok(pPtr,line,132,"\r"); } } return 1; } /*---------------------------------------------------------------------------*/ int MakeLMD200(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pSICSOBJ self = NULL; pLMD200 priv = NULL; hdbValue dataValue, textValue; int status; if(argc < 4){ SCWrite(pCon, "ERROR: require name host and port parameters for initialization", eError); return 0; } priv = (pLMD200)malloc(sizeof(LMD200)); memset(priv,0,sizeof(LMD200)); strncpy(priv->host,argv[2], 256); priv->port = atoi(argv[3]); priv->pSock = NETConnect(priv->host,priv->port); if(priv->pSock == NULL){ SCWrite(pCon,"ERROR: failed to connect to LMD200",eError); killLMD200(priv); return 0; } self = MakeSICSOBJv(argv[1],"LMD400",HIPNONE, 0); if(self == NULL || priv == NULL){ return 0; } textValue = MakeHdbText("I do not feel very alarmed"); dataValue = makeHdbValue(HIPFLOATAR,16); AddSICSHdbPar(self->objectNode,"alarm", usInternal,textValue); AddSICSHdbPar(self->objectNode,"data", usInternal,dataValue); self->pPrivate = priv; self->KillPrivate = killLMD200; ReleaseHdbValue(&dataValue); ReleaseHdbValue(&textValue); NetWatchRegisterCallback(&priv->watchContext, priv->pSock->sockid, LMD200Callback, self); status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, KillSICSOBJ, self); if(status != 1){ KillSICSOBJ(self); SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]); return 0; } return 1; }