diff --git a/delcam.c b/delcam.c index 5b5f6c3..9dfddf8 100644 --- a/delcam.c +++ b/delcam.c @@ -43,6 +43,7 @@ typedef struct { AUD_HANDLE aud_handle; int amplictrl; + int amplion; int shutterctrl; int nClear; int running; @@ -76,6 +77,16 @@ static int DelcamConfigure(pHistDriver self, SConnection * pCon, SCWrite(pCon, "ERROR: invalid amplictrl value, range 0 - 8", eError); pPriv->amplictrl = 0; } + if (StringDictGet(pOpt, "amplion", buffer, 79) == 1) { + pPriv->amplion = atoi(buffer); + } else { + pPriv->amplion = 1; + } + if(pPriv->amplion != 0 && pPriv->amplion != 1){ + SCWrite(pCon, "ERROR: invalid amplion value, 0,1 allowed", eError); + pPriv->amplion = 1; + } + if (StringDictGet(pOpt, "shutterctrl", buffer, 79) == 1) { pPriv->shutterctrl = atoi(buffer); } else { @@ -252,6 +263,7 @@ static int DelcamCountStatus(pHistDriver self, SConnection * pCon) return HWBusy; } if (status != HWBusy && pPriv->running == 1) { + pPriv->count->pDriv->ReadValues(pPriv->count->pDriv); pPriv->running = 0; /* * stop the CCD and transfer data @@ -267,21 +279,23 @@ static int DelcamCountStatus(pHistDriver self, SConnection * pCon) } usleep(SHUTTER_DELAY * 1000); } - status = aud_amplifier_set(pPriv->aud_handle, 1); - if (status != 0) { - snprintf(buffer, 80, "ERROR: failed to stop amplifier, errno = %d", - errno); - SCWrite(pCon, buffer, eError); - pPriv->error = FAULT; - status = HWFault; + if(pPriv->amplion == 1){ + status = aud_amplifier_set(pPriv->aud_handle, 1); + if (status != 0) { + snprintf(buffer, 80, "ERROR: failed to start amplifier, errno = %d", + errno); + SCWrite(pCon, buffer, eError); + pPriv->error = FAULT; + status = HWFault; + } + usleep(AMPLIFIER_DELAY*1000); } - /* usleep(AMPLIFIER_DELAY*1000); */ usleep(pPriv->schnarch * 1000); SCWrite(pCon, - "WARNING: computer freeze for ~15 sec is normal during readout", + "WARNING: starting readout, computer freeze for ~15 sec is normal during readout", eWarning); status = aud_image_read(pPriv->aud_handle, &shittyCompiler, @@ -301,7 +315,10 @@ static int DelcamCountStatus(pHistDriver self, SConnection * pCon) } free(imData); } + SCWrite(pCon, + "WARNING: CCD read",eWarning); } + return status; } @@ -506,6 +523,7 @@ pHistDriver MakeDelcamHM(pStringDict pOption) /* add our options */ StringDictAddPair(pOption, "amplictrl", "0"); + StringDictAddPair(pOption, "amplion", "1"); StringDictAddPair(pOption, "shutterctrl", "0"); StringDictAddPair(pOption, "clear", "1"); StringDictAddPair(pOption, "schnarch", "1"); diff --git a/fetchwrite.c b/fetchwrite.c deleted file mode 100644 index 5c58c11..0000000 --- a/fetchwrite.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * fetchwrite.c - * - * This is the implementation for the Siemens S5 FETCH/Write - * protocol support functions. Docs see header file - * - * Created on: Mar 24, 2010 - * Author: koennecke - */ -#include -#include -#include "fetchwrite.h" - -Request makeS5WriteRequest(int orgID, unsigned char dbNo, - int offset, int length, void *data) -{ - Request result; - - result.totalLength = 16 + length; - result.data = malloc(result.totalLength*sizeof(char)); - if(result.data == NULL){ - return result; - } - memset(result.data,0,result.totalLength*sizeof(char)); - - result.data[0] = 'S'; - result.data[1] = '5'; - result.data[2] = 0x10; - result.data[3] = 0x01; - result.data[4] = 0x03; - result.data[5] = 0x03; - result.data[6] = 0x03; - result.data[7] = 0x08; - result.data[8] = (unsigned char)orgID; - result.data[9] = dbNo; - result.data[10] = (unsigned short)offset; - result.data[12] = (unsigned short)length; - result.data[14] = 0xFF; - result.data[15] = 0x02; - memcpy(result.data+16,data,length); - - return result; -} -/*-------------------------------------------------------------*/ -int decodeS5Response(unsigned char data[16]) -{ - if(data[0] != 'S' || data[1] != '5'){ - return S5INVALID; - } - return (int)data[8]; -} -/*---------------------------------------------------------------*/ -Request makeS5FetchRequest(int orgID, unsigned char dbNo, - int offset, int length) -{ - Request result; - - result.totalLength = 16; - result.data = malloc(result.totalLength*sizeof(char)); - if(result.data == NULL){ - return result; - } - memset(result.data,0,result.totalLength*sizeof(char)); - - result.data[0] = 'S'; - result.data[1] = '5'; - result.data[2] = 0x10; - result.data[3] = 0x01; - result.data[4] = 0x03; - result.data[5] = 0x05; - result.data[6] = 0x03; - result.data[7] = 0x08; - result.data[8] = (unsigned char)orgID; - result.data[9] = dbNo; - result.data[10] = (unsigned short)offset; - result.data[12] = (unsigned short)length; - result.data[14] = 0xFF; - result.data[15] = 0x02; - return result; -} diff --git a/make_gen b/make_gen index 4c7be07..da9b1a8 100644 --- a/make_gen +++ b/make_gen @@ -10,7 +10,7 @@ tjxp $*.tc $*.c OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\ - pipiezo.o sanswave.o faverage.o fetchwrite.o\ + pipiezo.o sanswave.o faverage.o spss7.o\ amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \ polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \ ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \ @@ -20,10 +20,10 @@ OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\ t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \ el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \ $(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\ - dgrambroadcast.o sinq.o tabledrive.o julcho.o \ + dgrambroadcast.o sinq.o tabledrive.o julcho.o sinqhttpopt.o\ ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \ rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \ - pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o + pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o .SECONDARY.: sanslirebin.c diff --git a/psi.c b/psi.c index 88dda31..ddb7553 100644 --- a/psi.c +++ b/psi.c @@ -65,6 +65,7 @@ void SiteInit(void) */ INIT(AddJulChoProtocoll); INIT(AddHttpProtocoll); + INIT(AddHttpOptProtocoll); INIT(AddPMACProtocoll); INIT(AddPfeifferProtocoll); INIT(AddTermProtocoll); @@ -112,7 +113,9 @@ static void AddPsiCommands(SicsInterp * pInter) SCMD("MakeSansliRebin", MakeSansliRebin); SCMD("MakeSANSWave", MakeSANSWave); SCMD("MakeSinq", SinqFactory); + SCMD("MakeSinqRedirect", SinqRedirectFactory); SCMD("MakeSPS", SPSFactory); + SCMD("MakeSPSS7", MakeSPSS7); PCMD("MakeSWHPMotor", MakeSWHPMotor); SCMD("MakeSWMotor", MakeSWMotor); SCMD("MakeTableDrive", TableDriveFactory); diff --git a/sinq.c b/sinq.c index 5fbcb04..dd3645b 100644 --- a/sinq.c +++ b/sinq.c @@ -12,6 +12,12 @@ * copyright: see file COPYRIGHT * * Mark Koennecke, July 2005 + * + * Modified to also hold the code for a second version which + * uses the redirector on lnsl15. This has to be used by instruments in + * the private network as they cannot receive the ACS broadacst. + * + * Mark Koennecke, July 2010 */ #include #include @@ -26,6 +32,8 @@ #include "dgrambroadcast.h" #include "sinq.h" +#include + #ifdef SEND_PORT #define RECEIVE_PORT SEND_PORT #else @@ -83,9 +91,11 @@ static void KillSinq(void *data) if (self->pDes != NULL) { DeleteDescriptor(self->pDes); } + if(self->anet){ + ANETclose(self->receiveSocket); + } free(self); } - /*-------------------------------------------------------------------------*/ int SinqFactory(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) @@ -202,3 +212,87 @@ int SinqWrapper(SConnection * pCon, SicsInterp * pSics, SCWrite(pCon, pBueffel, eValue); return 1; } +/*-------------------------------------------------------------------------*/ +static char* searchMessage(char *pPtr, int length) +{ + int i; + + for(i = 0; i < length; i++){ + if(pPtr[i] == (char) 4 && pPtr[i+1] == (char)4){ + return pPtr + i-1; + } + } + return NULL; +} +/*-------------------------------------------------------------------------*/ +static int SINQRedirectCallback(int handle, void *userData){ + pSinq self = (pSinq)userData; + char *pPtr = NULL, *pTerm = NULL,pID[5]; + int length, sinq; + + pPtr = ANETreadPtr(handle, &length); + pTerm = searchMessage(pPtr,length); + while(pTerm != NULL){ + /* + strlcpy(pID, pPtr, 5); + printf("Received message with ID: %s\n", pID); + */ + if (memcmp(pPtr, "D110", 4) == 0) { + strlcpy(self->d110, pPtr, pTerm - pPtr); + sinq = getSinqBeam(self, SINQBEAM); + self->lastSinq[self->lastCount] = sinq; + self->lastCount++; + if (self->lastCount >= MAXLOG) { + self->lastCount = 0; + } + } + if (memcmp(pPtr, "A110", 4) == 0) { + strlcpy(self->a110, pPtr, pTerm - pPtr); + } + ANETreadConsume(handle, (pTerm - pPtr) + 3); + pPtr = ANETreadPtr(handle, &length); + pTerm = searchMessage(pPtr,length); + } + + return 1; +} +/*-------------------------------------------------------------------------*/ +int SinqRedirectFactory(SConnection * pCon, SicsInterp * pSics, + void *pData, int argc, char *argv[]) +{ + pSinq pNew = NULL; + int i; + + if(argc < 3){ + SCWrite(pCon,"ERROR: need host port argument to SinqRedirectFactory", eError); + return 0; + } + + 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 = ANETconnect(argv[1],atoi(argv[2])); + if (pNew->receiveSocket < 0) { + SCWrite(pCon, "ERROR: failed to open Sinq Status port", + eError); + KillSinq(pNew); + return 0; + } + ANETsetReadCallback(pNew->receiveSocket, SINQRedirectCallback, pNew, NULL); + pNew->anet = 1; + + for (i = 0; i < MAXLOG; i++) { + pNew->lastSinq[i] = -200; + } + return AddCommand(pSics, "sinq", SinqWrapper, KillSinq, pNew); +} + diff --git a/sinq.h b/sinq.h index 3fb41b4..a942bbd 100644 --- a/sinq.h +++ b/sinq.h @@ -22,10 +22,13 @@ typedef struct { int receiveSocket; int lastSinq[MAXLOG]; int lastCount; + int anet; } Sinq, *pSinq; /*----------------------- interpreter interface ------------------------*/ int SinqFactory(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]); +int SinqRedirectFactory(SConnection * pCon, SicsInterp * pSics, + void *pData, int argc, char *argv[]); int SinqWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]); /*-------------------------------------------------------------------------*/ diff --git a/sinqhttpopt.c b/sinqhttpopt.c new file mode 100644 index 0000000..5f29560 --- /dev/null +++ b/sinqhttpopt.c @@ -0,0 +1,470 @@ +/** + * This is an asynchronous protocol implementation for HTTP. + * It includes special features to store binary data coming + * from a SINQ http histogram memory in a sinqdata object. + * Which has to be specified on initialisation. + * + * copyright: see file COPYRIGHT + * + * After finding that libghttp actually blocks on sockets, this is + * a reimplementation doing everything itself. + * + * Mark Koennecke, November 2010 + */ +#include +#include +#include +#include +#include +#include +#include "sicshipadaba.h" +#include +extern char *trim(char *txt); +/*------------------------------------------------------------------------------- + * taken from libghttp + */ +static const char b64_alphabet[65] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/=" }; + +static char * +http_base64_encode(const char *text) { + /* The tricky thing about this is doing the padding at the end, + * doing the bit manipulation requires a bit of concentration only */ + char *buffer = NULL; + char *point = NULL; + int inlen = 0; + int outlen = 0; + + /* check our args */ + if (text == NULL) + return NULL; + + /* Use 'buffer' to store the output. Work out how big it should be... + * This must be a multiple of 4 bytes */ + + inlen = strlen( text ); + /* check our arg...avoid a pesky FPE */ + if (inlen == 0) + { + buffer = malloc(sizeof(char)); + buffer[0] = '\0'; + return buffer; + } + outlen = (inlen*4)/3; + if( (inlen % 3) > 0 ) /* got to pad */ + outlen += 4 - (inlen % 3); + + buffer = malloc( outlen + 1 ); /* +1 for the \0 */ + memset(buffer, 0, outlen + 1); /* initialize to zero */ + + /* now do the main stage of conversion, 3 bytes at a time, + * leave the trailing bytes (if there are any) for later */ + + for( point=buffer; inlen>=3; inlen-=3, text+=3 ) { + *(point++) = b64_alphabet[ *text>>2 ]; + *(point++) = b64_alphabet[ (*text<<4 & 0x30) | *(text+1)>>4 ]; + *(point++) = b64_alphabet[ (*(text+1)<<2 & 0x3c) | *(text+2)>>6 ]; + *(point++) = b64_alphabet[ *(text+2) & 0x3f ]; + } + + /* Now deal with the trailing bytes */ + if( inlen ) { + /* We always have one trailing byte */ + *(point++) = b64_alphabet[ *text>>2 ]; + *(point++) = b64_alphabet[ (*text<<4 & 0x30) | + (inlen==2?*(text+1)>>4:0) ]; + *(point++) = (inlen==1?'=':b64_alphabet[ *(text+1)<<2 & 0x3c ] ); + *(point++) = '='; + } + + *point = '\0'; + + return buffer; +} +/*---------------------------------------------------------------------*/ +typedef struct { + char *userName; + char *password; + pSICSData binData; + pHdb node; + int sockHandle; + int bytesExpected; + char *contentType; +} HttpProt, *pHttpProt; +/*---------------------------------------------------------------------*/ +static int HTTPcallback(int handle, void *userData) +{ + Ascon *a = (Ascon *)userData; + pHttpProt pHttp = NULL; + unsigned char ch; + int length; + char *data; + + if(a == NULL){ + printf("really serious error in HTTPcallback\n"); + return 0; + } + pHttp = (pHttpProt)a->private; + + data = (char *)ANETreadPtr(handle,&length); + if(data != NULL){ + DynStringConcatBytes(a->rdBuffer,data,length); + } + ANETreadConsume(handle,length); + return 1; + +} +/*---------------------------------------------------------------------*/ +static void sendAuth(pHttpProt pHttp) +{ + char buffer[256]; + char *encoded = NULL; + + if(pHttp->userName != NULL){ + snprintf(buffer,255,"%s:%s", pHttp->userName,pHttp->password); + encoded = http_base64_encode(buffer); + if(encoded != NULL){ + snprintf(buffer,255,"Authorization: Basic %s\r\n\r\n", encoded); + free(encoded); + } + } else { + strcpy(buffer,"\r\n"); + } + ANETwrite(pHttp->sockHandle,buffer,strlen(buffer)); +} +/*---------------------------------------------------------------------*/ +static void sendGet(pHttpProt pHttp, char *path) +{ + char buffer[1024]; + char hostname[256]; + + gethostname(hostname,255); + snprintf(buffer,1024,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n", + path, hostname); + ANETwrite(pHttp->sockHandle, buffer,strlen(buffer)); + sendAuth(pHttp); +} +/*---------------------------------------------------------------------*/ +static void sendPost(pHttpProt pHttp, char *path, char *data) +{ + char buffer[1024]; + char hostname[256]; + + gethostname(hostname,255); + snprintf(buffer,1024,"POST %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n", + path, hostname); + ANETwrite(pHttp->sockHandle, buffer,strlen(buffer)); + snprintf(buffer,1024,"Content-Length: %d\r\n", strlen(data)); + ANETwrite(pHttp->sockHandle, buffer,strlen(buffer)); + sendAuth(pHttp); + ANETwrite(pHttp->sockHandle,data,strlen(data)); +} +/*---------------------------------------------------------------------*/ +static void sendRequest(pHttpProt pHttp, char *data) +{ + char *path, *dataCopy, *pPtr; + + dataCopy = strdup(data); + + pPtr = strchr(dataCopy,':'); + if(pPtr == NULL){ + path = dataCopy; + sendGet(pHttp,path); + free(dataCopy); + return; + } else { + if(strstr(dataCopy,"node") != NULL){ + path = pPtr+1; + pPtr = strchr(path,':'); + *pPtr = '\0'; + pHttp->node = FindHdbNode(NULL,path,pServ->dummyCon); + path = pPtr+1; + sendGet(pHttp,path); + free(dataCopy); + return; + } else if(strstr(dataCopy,"post") != NULL){ + path = pPtr+1; + pPtr = strchr(path,':'); + *pPtr = '\0'; + sendPost(pHttp,path, pPtr+1); + free(dataCopy); + } + } +} +/*---------------------------------------------------------------------*/ +static void handleReply(Ascon * a) +{ + char *pPtr = NULL, *pType = NULL, *path = NULL; + int len, i, *dataPtr = NULL; + HistInt *hmData = NULL; + pHttpProt pHttp = (pHttpProt) a->private; + + pPtr = GetCharArray(a->rdBuffer); + len = GetDynStringLength(a->rdBuffer); + if (strstr(pPtr, "ERROR") != NULL) { + AsconError(a, pPtr, 0); + } else if (strstr(pPtr, "Authentication Error") != NULL) { + AsconError(a, pPtr, 0); + } else { + pType = pHttp->contentType; + if (strstr(pType, "sinqhm") != NULL) { + hmData = (HistInt *) pPtr; + len = len / sizeof(HistInt); + if(pHttp->node == NULL){ + clearSICSData(pHttp->binData); + dataPtr = getSICSDataPointer(pHttp->binData, 0, len); + for (i = 0; i < len; i++) { + dataPtr[i] = htonl(hmData[i]); + } + assignSICSType(pHttp->binData, 0, len, INTTYPE); + DynStringClear(a->rdBuffer); + DynStringCopy(a->rdBuffer, "SICSDATA"); + } else { + if(pHttp->node->value.arrayLength != len){ + if(pHttp->node->value.v.intArray != NULL){ + free(pHttp->node->value.v.intArray); + } + pHttp->node->value.v.intArray = malloc(len*sizeof(int)); + if(pHttp->node->value.v.intArray == NULL){ + AsconError(a,"Out of memory ",0); + return; + } + pHttp->node->value.arrayLength = len; + } + for(i = 0; i < len; i++){ + pHttp->node->value.v.intArray[i] = htonl(hmData[i]); + } + NotifyHipadabaPar(pHttp->node,NULL); + /* + path = GetHipadabaPath(pHttp->node); + if(path != NULL){ + printf("Sinqhttpprot has updated node: %s\n", path); + free(path); + } + */ + } + } + } +} +/*---------------------------------------------------------------------*/ +static int processHeader(Ascon *a) +{ + char line[132], *pPtr, *data, *colon; + pHttpProt pHttp = (pHttpProt) a->private; + int status, length; + + data = GetCharArray(a->rdBuffer); + assert(data != NULL); + /* + * printf("%s",data); + */ + + pPtr = data; + pPtr = stptok(pPtr, line, 132, "\n"); + sscanf(line,"HTTP/1.%*d %03d", &status); + if(status != 200 && status != 201){ + AsconError(a,line,AsconFailure); + return 0; + } + while((pPtr = stptok(pPtr,line,132,"\n")) != NULL){ + colon = strchr(line,':'); + if(colon != NULL){ + *colon = '\0'; + colon++; + strtolower(line); + if(strstr(line,"content-length") != NULL){ + pHttp->bytesExpected = atoi(trim(colon)); + } + if(strstr(line,"content-type") != NULL){ + if(pHttp->contentType != NULL){ + free(pHttp->contentType); + } + pHttp->contentType = strdup(trim(colon)); + } + if(strstr(line,"connection") != NULL){ + strtolower(colon); + if(strstr(colon,"close") != NULL){ + pHttp->bytesExpected = INT32_MAX; + } + } + } + } + /** + * Hack off the header + */ + pPtr = strstr(data, "\r\n\r\n"); + length = GetDynStringLength(a->rdBuffer); + length -= 4 + (pPtr - data); + if(length > 0){ + data = malloc(length*sizeof(char)); + if(data == NULL){ + AsconError(a,"Out of memory", AsconFailure); + return 0; + } + memcpy(data,pPtr+4,length); + DynStringClear(a->rdBuffer); + DynStringConcatBytes(a->rdBuffer,data,length); + free(data); + } else { + DynStringClear(a->rdBuffer); + } + + return 1; +} +/*---------------------------------------------------------------------*/ +static int HttpHandler(Ascon * a) +{ + pHttpProt pHttp = (pHttpProt) a->private; + int socke, selStat, port, status; + fd_set rmask; + struct timeval tmo = { 0, 0 }; + char buffer[1024]; + char *hostport, *colon; + + switch (a->state) { + case AsconConnectStart: + a->state = AsconConnecting; + break; + case AsconConnecting: + a->state = AsconConnectDone; /* success */ + break; + case AsconWriteStart: + if(!ANETvalidHandle(pHttp->sockHandle)){ + hostport = strdup(a->hostport); + colon = strchr(hostport, ':'); + if (colon == NULL){ + port = 80; + } else { + *colon = '\0'; + port = atoi(colon + 1); + } + if (port <= 0) { + AsconError(a, "bad port number", 0); + return 1; + } + pHttp->sockHandle = ANETconnect(hostport,port); + free(hostport); + if(pHttp->sockHandle < 0){ + AsconError(a,"Failed to connect", 0); + } else { + ANETsetReadCallback(pHttp->sockHandle, + HTTPcallback, a,NULL); + a->state = AsconWriting; + } + } else { + a->state = AsconWriting; + } + return 1; + break; + case AsconWriting: + sendRequest(pHttp,GetCharArray(a->wrBuffer)); + a->state = AsconWriteDone; + a->start = DoubleTime(); + pHttp->bytesExpected = -1; + DynStringClear(a->rdBuffer); + return 1; + break; + case AsconReading: + ANETprocess(); + /** + * Here we have basically three conditions to check: + * - detected means that we received + * the complete header. + * - enough bytes read: termination + * - socket closed means all data has been read + */ + if(strstr(GetCharArray(a->rdBuffer), "\r\n\r\n") != NULL){ + status = processHeader(a); + if(status != 1){ + a->state = AsconReadDone; + return 1; + } + } + if(!ANETvalidHandle(pHttp->sockHandle)){ + handleReply(a); + a->state = AsconReadDone; + return 1; + } + if(pHttp->bytesExpected > 0 && GetDynStringLength(a->rdBuffer) >= pHttp->bytesExpected ){ + handleReply(a); + a->state = AsconReadDone; + return 1; + } + return 0; + break; + default: + return AsconStdHandler(a); + } + return 1; +} + +/*------------------------------------------------------------------------*/ +static void killHttp(void *data) +{ + pHttpProt prot = (pHttpProt) data; + if (prot == NULL) { + return; + } + if (prot->password != NULL) { + free(prot->password); + } + if (prot->userName != NULL) { + free(prot->userName); + } + if(prot->contentType != NULL){ + free(prot->contentType); + } + free(prot); +} + +/*------------------------------------------------------------------------*/ +static int HttpProtInit(Ascon * a, SConnection * con, + int argc, char *argv[]) +{ + pHttpProt pHttp = NULL; + + pHttp = calloc(sizeof(HttpProt), 1); + if (pHttp == NULL) { + SCWrite(con, "ERROR: out of memory in HttpProtInit", eError); + return 0; + } + if (argc < 3) { + return 0; + } + a->hostport = strdup(argv[1]); + pHttp->binData = (pSICSData) FindCommandData(pServ->pSics, + argv[2], "SICSData"); + if (pHttp->binData == NULL) { + SCWrite(con, "ERROR: SICSData object not found", eError); + return 0; + } + if (argc > 3) { + a->timeout = atof(argv[3]); + } else { + a->timeout = 10.; + } + if (argc > 5) { + pHttp->userName = strdup(argv[4]); + pHttp->password = strdup(argv[5]); + } + pHttp->sockHandle = -10; + pHttp->contentType = strdup("text/html"); + a->private = pHttp; + a->killPrivate = killHttp; + a->state = AsconConnectStart; + return 1; +} + +/*-------------------------------------------------------------------------*/ +void AddHttpOptProtocoll() +{ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("sinqhttpopt"); + prot->init = HttpProtInit; + prot->handler = HttpHandler; + AsconInsertProtocol(prot); +} diff --git a/slsvme.c b/slsvme.c index becdbe5..d14bec7 100644 --- a/slsvme.c +++ b/slsvme.c @@ -87,8 +87,12 @@ static void locateValue(char *rawReply, char *value, int valLen) pPtr = rawReply; pPtr = stptok(pPtr, value, valLen, " "); - pPtr = stptok(pPtr, value, valLen, " "); - stptok(pPtr, value, valLen, " "); + if(pPtr != NULL){ + pPtr = stptok(pPtr, value, valLen, " "); + } + if(pPtr != NULL){ + stptok(pPtr, value, valLen, " "); + } } /*---------------------------------------------------------------------*/ diff --git a/spss7.c b/spss7.c new file mode 100644 index 0000000..6cd852d --- /dev/null +++ b/spss7.c @@ -0,0 +1,576 @@ +/* + * spss7.c + * + * This is an interface between SICS and a S7 Siemens SPS speaking the + * Fetch/Write protocol via TCP/IP. On initialization, the S7 DB area reserved + * for communication with SICS is read, parsed and nodes created representing the + * various data items in there. Suitable callbacks allow to write values into the + * SPS. Communication is via the device serializer and the genbin protocol handler. + * + * copyright: see file COPYRIGHT + * + * Created on: Jul 7, 2010 + * Author: Mark Koennecke + */ +#include +#include +#include +#include +#define MAXDATA 65552 /* 64KB + 16 Byte for headers */ + +/*----------------------- private data structure --------------*/ +typedef struct { + DevSer *devser; + int dbnum; + int dblength; + int switchdbnum; + int switchdblength; +}SPSS7, *pSPSS7; +/*------------------------------------------------------------------*/ +typedef struct { + pSPSS7 sps; + pHdb spsNode; + char sendData[MAXDATA]; + char replyData[MAXDATA]; + int toSend; + int toRead; + char message[132]; + SConnection *pCon; /* only used when writing */ +}S7Action, *pS7Action; +/*------------------------------------------------------------------*/ +static int S7ActionMatch(void *a1, void *a2) +{ + if (a1 == a2){ + return 1; + } else { + return 0; + } +} +/*------------------------------------------------------------------*/ +static void MakeFetchMessage(pS7Action self, int db, int start, int length) +{ + unsigned short num; + + memset(self->sendData,0,MAXDATA); + memset(self->replyData,0,MAXDATA); + self->sendData[0] = 'S'; + self->sendData[1] = '5'; + self->sendData[2] = 0x10; + self->sendData[3] = 0x01; + self->sendData[4] = 0x03; + self->sendData[5] = 0x05; + self->sendData[6] = 0x03; + self->sendData[7] = 0x08; + self->sendData[8] = 0x01; + self->sendData[9] = db; + self->sendData[6] = 0x03; + /* + * addresses are in words which is 16 bit = 2 bytes + */ + num = htons(start/2); + memcpy(self->sendData+10,&num,2); + num = htons(length/2); + memcpy(self->sendData+12,&num,2); + self->sendData[14] = 0xFF; + self->sendData[15] = 0x02; + self->toSend = 16; + self->toRead = 16 + length; + + sprintf(self->message,"%lx:%d:%lx:%d", (long) self->sendData, self->toSend, + (long)self->replyData, self->toRead); +} +/*-------------------------------------------------------------------*/ +static void MakeWriteMessage(pS7Action self, + int start, int length, void *data) +{ + unsigned short num; + + memset(self->sendData,0,MAXDATA); + memset(self->replyData,0,MAXDATA); + self->sendData[0] = 'S'; + self->sendData[1] = '5'; + self->sendData[2] = 0x10; + self->sendData[3] = 0x01; + self->sendData[4] = 0x03; + self->sendData[5] = 0x03; + self->sendData[6] = 0x03; + self->sendData[7] = 0x08; + self->sendData[8] = 0x01; + self->sendData[9] = self->sps->switchdbnum; + self->sendData[6] = 0x03; + /* + * Start is in bytes, length is in words which is 2 bytes.... + */ + num = htons(start); + memcpy(self->sendData+10,&num,2); + num = htons(length/2); + memcpy(self->sendData+12,&num,2); + self->sendData[14] = 0xFF; + self->sendData[15] = 0x02; + memcpy(self->sendData+16, data, length); + self->toSend = 16 + length; + self->toRead = 16; + + sprintf(self->message,"%lx:%d:%lx:%d", (long) self->sendData, self->toSend, + (long)self->replyData, self->toRead); +} +/*--------------------------------------------------------------------*/ +static int decodeString(char *pPtr, char *string, int maxlen) +{ + int fullength, used; + fullength = (int)pPtr[0]; + used = (int)pPtr[1]; + if(fullength != maxlen || used > maxlen){ + printf("Correcting DB String error\n"); + fullength = maxlen; + used = maxlen; + } + memset(string,0,fullength); + memcpy(string, pPtr+2, used); + return fullength + 2; +} +/*------------------------------------------------------------------ + * This is the action handler for writing SPS data + *-------------------------------------------------------------------*/ +static char *S7WriteHandler(void *actionData, char *reply, int comerror) +{ + pS7Action self = (pS7Action)actionData; + char message[132]; + SConnection *pCon = NULL; + + if(reply == NULL){ + return self->message; + } + + pCon = self->pCon; + if(self->replyData[8] != 0){ + snprintf(message,132,"ERROR: code %d when writing to S7/%s", + self->replyData[8], GetHipadabaPath(self->spsNode)); + if(pCon != NULL){ + SCWrite(pCon,message,eError); + printf("Write Shit %d happened\n", self->replyData[8]); + } else { + printf("%s\n", message); + } + } else { + if(pCon != NULL){ + SCSendOK(pCon); + } + } + + return NULL; +} +/*--------------------------------------------------------------------*/ +static void UpdateSPSDataBase(pS7Action self) +{ + char *pPtr; + char name[14], unit[8], description[24], reference[10], error[50]; + unsigned char type, alarm; + short val; + int ival; + unsigned char bval; + float fval; + pHdb node = NULL; + hdbValue hdbVal; + + pPtr = self->replyData + 16 + 2; + while(pPtr - self->replyData < self->toRead){ + type = pPtr[0]; + alarm = pPtr[1]; + pPtr+= 2; + pPtr += decodeString(pPtr, name,14); + pPtr += decodeString(pPtr, unit,8); + pPtr += decodeString(pPtr, description,24); + pPtr += decodeString(pPtr, reference,10); + node = GetHipadabaNode(self->spsNode,name); + switch (type) { + case 1: + case 4: + memcpy(&bval,pPtr+1,1); + hdbVal = MakeHdbInt(bval); + UpdateHipadabaPar(node,hdbVal,NULL); + pPtr += 2; + break; + case 2: + memcpy(&ival,pPtr,4); + hdbVal = MakeHdbInt(ntohl(ival)); + UpdateHipadabaPar(node,hdbVal,NULL); + pPtr += 4; + break; + case 3: + memcpy(&ival,pPtr+2,4); + ival = htonl(ival); + memcpy(&fval,&ival,4); + hdbVal = MakeHdbFloat(fval); + UpdateHipadabaPar(node,hdbVal,NULL); + pPtr += 6; + break; + } + if(alarm == 0){ + SetHdbProperty(node,"geterror", NULL); + } else { + snprintf(error,50,"Alarm %d on par",alarm); + SetHdbProperty(node,"geterror", error); + } + } +} +/*------------------------------------------------------------------ + * This is the action handler for updating the SPS data in SICS + *-------------------------------------------------------------------*/ +static char *S7UpdateHandler(void *actionData, char *reply, int comerror) +{ + pS7Action self = (pS7Action)actionData; + + if(reply == NULL){ + if(self->sps->dblength > 0){ + MakeFetchMessage(self,self->sps->dbnum, 0,self->sps->dblength); + return self->message; + } else { + return NULL; + } + } + + UpdateSPSDataBase(self); + return NULL; +} +/*-------------------------------------------------------------------*/ +static hdbCallbackReturn S7WriteCallback(pHdb currentNode, + void *userData, pHdbMessage message) +{ + pS7Action writeAction = NULL, updateAction = NULL; + pSPSS7 self = (pSPSS7)userData; + pHdbDataMessage mm = NULL; + SConnection *pCon = NULL; + int offset, type, length, idata; + float fval; + short sdata; + unsigned char bdata; + char prop[50]; + + mm = GetHdbSetMessage(message); + if(mm != NULL){ + writeAction = calloc(1,sizeof(S7Action)); + if(writeAction == NULL && mm->callData != NULL){ + pCon = (SConnection *)mm->callData; + SCWrite(pCon, "ERROR: out of memory in S7WriteCallback", eError); + return hdbContinue; + } + writeAction->sps = self; + writeAction->pCon = mm->callData; + writeAction->spsNode = currentNode; + GetHdbProperty(currentNode,"offset",prop,50); + offset = atoi(prop); + GetHdbProperty(currentNode,"type",prop,50); + type = atoi(prop); + switch(type){ + case 1: + case 4: + sdata = (short)mm->v->v.intValue; + /* sdata = htons(sdata); */ + MakeWriteMessage(writeAction,offset,2,&sdata); + break; + case 2: + idata = mm->v->v.intValue; + idata = htonl(idata); + MakeWriteMessage(writeAction,offset,4,&idata); + break; + case 3: + fval = (float)mm->v->v.doubleValue; + idata = htonl((int)fval); + MakeWriteMessage(writeAction,offset,4,&idata); + break; + default: + assert(0); + } + DevQueue(self->devser, writeAction, WritePRIO, + S7WriteHandler, S7ActionMatch, free, NULL); + + updateAction = calloc(1,sizeof(S7Action)); + if(updateAction != NULL){ + updateAction->sps = self; + updateAction->spsNode = currentNode->mama->mama; + DevQueue(self->devser, updateAction, ProgressPRIO, + S7UpdateHandler, S7ActionMatch, free, NULL); + } + } + + return hdbContinue; +} +/*--------------------------------------------------------------------*/ +static void InitializeSPSDataBase(pS7Action self, pHdb parent) +{ + char *pPtr; + char name[14], unit[8], description[24], reference[10], num[10], error[50]; + unsigned char type, alarm; + short val; + int ival; + float fval; + unsigned char bval; + pHdb node = NULL; + hdbValue hdbVal; + + pPtr = self->replyData + 16 + 2; + while(pPtr - self->replyData < self->toRead){ + type = pPtr[0]; + alarm = pPtr[1]; + pPtr+= 2; + pPtr += decodeString(pPtr, name,14); + pPtr += decodeString(pPtr, unit,8); + pPtr += decodeString(pPtr, description,24); + pPtr += decodeString(pPtr, reference,10); + switch (type) { + case 1: + case 4: + node = MakeHipadabaNode(name,HIPINT,1); + memcpy(&bval,pPtr+1,1); + hdbVal = MakeHdbInt(bval); + UpdateHipadabaPar(node,hdbVal,NULL); + snprintf(num,10,"%d", pPtr - self->replyData - 16); + SetHdbProperty(node,"offset",num); + pPtr += 2; + break; + case 2: + node = MakeHipadabaNode(name,HIPINT,1); + memcpy(&ival,pPtr,4); + hdbVal = MakeHdbInt(ntohl(ival)); + UpdateHipadabaPar(node,hdbVal,NULL); + snprintf(num,10,"%d", pPtr - self->replyData - 16); + SetHdbProperty(node,"offset",num); + pPtr += 4; + break; + case 3: + node = MakeHipadabaNode(name,HIPFLOAT,1); + memcpy(&ival,pPtr+2,4); + ival = htonl(ival); + memcpy(&fval,&ival,4); + hdbVal = MakeHdbFloat(fval); + UpdateHipadabaPar(node,hdbVal,NULL); + snprintf(num,10,"%d", pPtr - self->replyData + 2 - 16); + SetHdbProperty(node,"offset",num); + pPtr += 6; + break; + } + snprintf(num,10,"%d",type); + SetHdbProperty(node,"type", num); + if(alarm != 0){ + snprintf(error,10,"Alarm %d on par",alarm); + SetHdbProperty(node,"geterror", error); + } + SetHdbProperty(node,"unit", unit); + SetHdbProperty(node,"description", description); + SetHdbProperty(node,"reference", reference); + AddHipadabaChild(parent,node, NULL); + printf("Found parameter %s\n", name); + } +} +/*------------------------------------------------------------------ + * This is the action handler for doing the initialisation of + * The SPS + *-------------------------------------------------------------------*/ +static char *S7InitHandler(void *actionData, char *reply, int comerror) +{ + pS7Action self = (pS7Action)actionData; + short dblength; + + /* + * Start: read length of the database + */ + if(reply == NULL){ + self->sps->dblength = 0; + MakeFetchMessage(self,self->sps->dbnum, 0,2); + return self->message; + } + + /* + * we are reading the database length + */ + if(self->sps->dblength == 0){ + memcpy(&dblength, self->replyData+16,2); + self->sps->dblength = ntohs(dblength); + MakeFetchMessage(self,self->sps->dbnum, 0,ntohs(dblength)); + return self->message; + } else { + memcpy(&dblength, self->replyData+16,2); + dblength = ntohs(dblength); + InitializeSPSDataBase(self,self->spsNode); + return NULL; + } +} +/*-------------------------------------------------------------------------*/ +static void InitializeSwitches(pS7Action self) +{ + pHdb switches = NULL, node = NULL; + int i; + char name[20]; + + switches = GetHipadabaNode(self->spsNode,"switches"); + assert(switches != NULL); + + /* + * TODO: Add write callbacks to switches + */ + node = switches->child; + while(node != NULL){ + AppendHipadabaCallback(node, + MakeHipadabaCallback(S7WriteCallback,self->sps,NULL)); + node = node->next; + } + + node = GetHipadabaNode(self->spsNode,"init"); + if(node != NULL){ + UpdateHipadabaPar(node,MakeHdbInt(1), NULL); + } +} +/*-------------------------------------------------------------------------*/ +static char *S7InitSwitchHandler(void *actionData, char *reply, int comerror) +{ + pS7Action self = (pS7Action)actionData; + short dblength; + pHdb parent = NULL; + + /* + * Start: read length of the database + */ + if(reply == NULL){ + self->sps->switchdblength = 0; + MakeFetchMessage(self,self->sps->switchdbnum, 0,2); + return self->message; + } + + /* + * we are reading the database length + */ + if(self->sps->switchdblength == 0){ + memcpy(&dblength, self->replyData+16,2); + self->sps->switchdblength = ntohs(dblength); + MakeFetchMessage(self,self->sps->switchdbnum, + 0,ntohs(dblength)); + return self->message; + } else { + parent = GetHipadabaNode(self->spsNode,"switches"); + assert(parent != NULL); + InitializeSPSDataBase(self,parent); + InitializeSwitches(self); + return NULL; + } +} + +/*===================================================================*/ +static int S7UpdateCmd(pSICSOBJ ccmd, SConnection * con, + Hdb * cmdNode, Hdb * par[], int nPar) +{ + pSPSS7 self = (pSPSS7)ccmd->pPrivate; + pS7Action updateAction = NULL; + + updateAction = calloc(1,sizeof(S7Action)); + if(updateAction == NULL){ + SCWrite(con,"ERROR: out of memory in S7 update", eError); + return 0; + } + updateAction->sps = self; + updateAction->spsNode = ccmd->objectNode; + DevQueue(self->devser, updateAction, ProgressPRIO, + S7UpdateHandler, S7ActionMatch, free, NULL); + SCSendOK(con); + return 1; +} +/*---------------------------------------------------------------------*/ +static void KillSPSS7(void *data) +{ + pSPSS7 self = (pSPSS7)data; + if(self == NULL){ + return; + } + if(self->devser != NULL){ + DevKill(self->devser); + } + free(self); +} +/*--------------------------------------------------------------------*/ +int MakeSPSS7(SConnection * con, SicsInterp * sics, + void *object, int argc, char *argv[]) +{ + pSPSS7 self = NULL; + pSICSOBJ pNew = NULL; + char *devArgs[3]; + pS7Action initAction = NULL, updateAction = NULL, + initSwitchAction = NULL; + + int status; + + if(argc < 5){ + SCWrite(con,"ERROR: not enough arguments for MakeSPSS7", eError); + return 0; + } + + self = calloc(1,sizeof(SPSS7)); + if(self == NULL){ + SCWrite(con,"ERROR: out of memory in MakeSPSS7", eError); + return 0; + } + + devArgs[0] = strdup("genbin"); + devArgs[1] = strdup(argv[4]); + + self->devser = DevMake(con,2,devArgs); + if(self->devser == NULL){ + return 0; + } + free(devArgs[0]); + free(devArgs[1]); + + self->dbnum = atoi(argv[2]); + self->switchdbnum = atoi(argv[3]); + + pNew = MakeSICSOBJv(argv[1],"SPS-S7", HIPNONE, usInternal); + if(pNew == NULL){ + SCWrite(con,"ERROR: out of memory in MakeSPSS7", eError); + return 0; + } + pNew->pPrivate = self; + pNew->KillPrivate = KillSPSS7; + + status = AddCommand(sics, + argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew); + if (status != 1) { + KillSICSOBJ(pNew); + SCPrintf(con, eError, "ERROR: failed create duplicate command %s", + argv[1]); + return 0; + } + + AddSICSHdbPar(pNew->objectNode, + "update", usSpy, MakeSICSFunc(S7UpdateCmd)); + + AddHipadabaChild(pNew->objectNode, + MakeSICSROPar("init",MakeHdbInt(0)),NULL); + + AddHipadabaChild(pNew->objectNode, + MakeHipadabaNode("switches",HIPNONE,0),NULL); + + + initAction = calloc(1,sizeof(S7Action)); + initSwitchAction = calloc(1,sizeof(S7Action)); + updateAction = calloc(1,sizeof(S7Action)); + if(initAction == NULL || updateAction == NULL || initSwitchAction == NULL){ + SCWrite(con,"ERROR: out of memory in MakeSPSS7", eError); + return 0; + } + initAction->sps = self; + initAction->spsNode = pNew->objectNode; + DevQueue(self->devser, initAction, WritePRIO, + S7InitHandler, S7ActionMatch, free, NULL); + + initSwitchAction->sps = self; + initSwitchAction->spsNode = pNew->objectNode; + DevQueue(self->devser, initSwitchAction, WritePRIO, + S7InitSwitchHandler, S7ActionMatch, free, NULL); + + updateAction->sps = self; + updateAction->spsNode = pNew->objectNode; + DevSchedule(self->devser, updateAction, + ReadPRIO, 60., + S7UpdateHandler, S7ActionMatch, free, NULL); + + return 1; +}