/** * 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 * * modifed to use asynnet and to cope with even more data. * Mark Koennecke, June 2009 */ #include #include #include #include #include /* * possible states */ #define IDLE 0 #define WAITDATA1 1 #define WAITDATA2 2 /* * private data structure */ #define BUFLEN 1024 typedef struct { char host[256]; int port; int asChannel; char lineBuffer[BUFLEN]; } LMD200, *pLMD200; /*----------------------------------------------------------------------------*/ static void killLMD200(void *data) { pLMD200 priv = (pLMD200) data; if (priv == NULL) { return; } ANETclose(priv->asChannel); 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); } /*--------------------------------------------------------------------------*/ static void doAlarm(pSICSOBJ self, char *lineBuffer) { setAlarm(self, lineBuffer); Log(ERROR,"dev","CERCA:%s ", 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 || strstr(number,"----") != NULL) { node->value.v.floatArray[start] = -99.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); strlcpy(myBuffer, lineBuffer,BUFLEN); 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, stamp = NULL; hdbValue timeVal; node = GetHipadabaNode(self->objectNode, "data"); assert(node != NULL); /* printf("Interpreting line: %s\n", priv->lineBuffer); */ if (strstr(priv->lineBuffer, "Alarm") != NULL) { doAlarm(self, priv->lineBuffer); return; } else if (strstr(priv->lineBuffer, "Pre") != NULL) { setAlarm(self, priv->lineBuffer); } else if (strstr(priv->lineBuffer, "001...008") != NULL) { storeData(self, 0, priv->lineBuffer); NotifyHipadabaPar(node, NULL); return; } else if(strstr(priv->lineBuffer,"009...016") != NULL) { storeData(self, 8, priv->lineBuffer); NotifyHipadabaPar(node, NULL); } else if(strstr(priv->lineBuffer,"017...019") != NULL) { storeData(self, 16, priv->lineBuffer); NotifyHipadabaPar(node, NULL); } else { if(strlen(priv->lineBuffer) > 5){ timeVal = MakeHdbText(priv->lineBuffer); stamp = GetHipadabaNode(self->objectNode, "timestamp"); if(stamp != NULL){ UpdateHipadabaPar(stamp, timeVal, NULL); } } } } /*----------------------------------------------------------------------------*/ static int LMD200Callback(int handle, void *userData) { pSICSOBJ self = (pSICSOBJ)userData; pLMD200 priv = (pLMD200)self->pPrivate; char *pPtr = NULL, *pEnd = NULL; int length; pPtr = ANETreadPtr(priv->asChannel,&length); pEnd = strchr(pPtr,(int)'\r'); while(pEnd != NULL){ *pEnd = '\0'; strlcpy(priv->lineBuffer,pPtr,BUFLEN); interpretLine(self,priv); ANETreadConsume(priv->asChannel,(pEnd - pPtr)+1); pPtr = ANETreadPtr(priv->asChannel,&length); if(length > 0){ pEnd = strchr(pPtr,(int)'\r'); } else { pEnd = NULL; } } return 1; } /*---------------------------------------------------------------------------*/ static int ClearCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { setAlarm(ccmd,"I do not feel very alarmed..."); SCSendOK(con); 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)); strlcpy(priv->host, argv[2], 256); priv->port = atoi(argv[3]); priv->asChannel = ANETconnect(priv->host, priv->port); if (priv->asChannel < 0) { SCWrite(pCon, "ERROR: failed to connect to LMD200", eLogError); 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, 32); AddSICSHdbPar(self->objectNode, "alarm", usInternal, textValue); AddSICSHdbPar(self->objectNode, "timestamp", usInternal, textValue); AddSICSHdbPar(self->objectNode, "data", usInternal, dataValue); self->pPrivate = priv; self->KillPrivate = killLMD200; ReleaseHdbValue(&dataValue); ANETsetReadCallback(priv->asChannel,LMD200Callback,self, NULL); AddSICSHdbPar(self->objectNode, "clearalarm", usUser, MakeSICSFunc(ClearCmd)); 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; }