/** * This is a protocol handler for the Munich sputter system. The protocol * is described in a separate manual. Messages to send look like this: * * 2 character length of message + command=value or ? + checksum * * Responses come like this: * * 2 characters length + status = transmission code + checksum * 2 character length + 2 characters command status + command=value + checksum * * An additional feauture is that the Labview server closes the connection after * each communication......... * * I am lazy: rather then creating a private data structure I use the line count * to keep track of the 2 messages expected as reply. The linecount also signals * reconnect with a value of -10 * * Mark Koennecke, October 2013 */ #include #include #include static int mustReadMore(Ascon *a) { int len; char lenString[3], *cmd; if(GetDynStringLength(a->rdBuffer) < 2){ return 1; } cmd = GetCharArray(a->rdBuffer); memset(lenString,0,sizeof(lenString)); lenString[0] = cmd[0]; lenString[1] = cmd[1]; len = atoi(lenString); if(GetDynStringLength(a->rdBuffer) < len + 2){ /* length + checksum */ return 1; } return 0; } /*-------------------------------------------------------------------------------*/ static void processStatusLine(Ascon *a) { char *cmd, *pPtr; int status; cmd = GetCharArray(a->rdBuffer); if(strstr(cmd,"status") == NULL){ AsconError(a,"wrong reply",0); return; } pPtr = strchr(cmd,'='); pPtr++; pPtr[3] = '\0'; status = atoi(pPtr); if(status != 10) { AsconError(a,"bad transmission status",status); } DynStringClear(a->rdBuffer); a->lineCount++; } /*-------------------------------------------------------------------------------*/ static void processPayLoad(Ascon *a) { char *cmd, code[3]; int status, len; cmd = strdup(GetCharArray(a->rdBuffer)); memset(code,0,sizeof(code)); code[0] = cmd[2]; code[1] = cmd[3]; status = atoi(code); switch(status){ case 30: len = strlen(cmd); cmd[len-2] = '\0'; DynStringClear(a->rdBuffer); DynStringConcat(a->rdBuffer,cmd+4); break; case 35: DynStringClear(a->rdBuffer); DynStringConcat(a->rdBuffer,"ERROR: Command unknown"); break; case 36: DynStringClear(a->rdBuffer); DynStringConcat(a->rdBuffer,"ERROR: Syntax error"); break; case 37: DynStringClear(a->rdBuffer); DynStringConcat(a->rdBuffer,"ERROR: out of range"); break; } free(cmd); a->state = AsconReadDone; a->lineCount = -10; } /*-------------------------------------------------------------------------------*/ static int SputterHandler(Ascon *a) { char *cmd, lenString[3], chr; int len, checksum, i, ret; switch(a->state){ case AsconWriteStart: /* reconnect when something had been done */ if(a->lineCount == -10){ AsconReconnect(a,NULL); a->lineCount = 0; return 1; } /* Prepend length and append checksum */ cmd = strdup(GetCharArray(a->wrBuffer)); len = strlen(cmd) + 2; DynStringClear(a->wrBuffer); sprintf(lenString,"%02d",len); DynStringConcat(a->wrBuffer,lenString); DynStringConcat(a->wrBuffer,cmd); free(cmd); cmd = GetCharArray(a->wrBuffer); for(i = 0, checksum = 0; i < strlen(cmd); i++){ checksum += (int)cmd[i]; } checksum = checksum % 256; sprintf(lenString,"%2X",checksum); if(lenString[0] == ' ') { lenString[0] = '0'; } DynStringConcat(a->wrBuffer,lenString); a->state = AsconWriting; a->lineCount = 0; a->wrPos = 0; DynStringClear(a->rdBuffer); break; case AsconReading: if(mustReadMore(a)){ ret = AsconReadChar(a->fd, &chr); if (ret < 0) { /* EINTR means we must retry */ if (errno != EINTR && errno != EAGAIN) { AsconError(a, "AsconReadChar failed:", errno); } } else if (ret > 0) { DynStringConcatChar(a->rdBuffer,chr); } } else { if(a->lineCount == 0) { processStatusLine(a); } else { processPayLoad(a); } } break; default: return AsconStdHandler(a); } return 1; } /*----------------------------------------------------------------------------*/ static int SputterInit(Ascon *a, SConnection *con, int argc, char *argv[]) { a->hostport = strdup(argv[1]); a->timeout = 3*60; return 1; } /*-----------------------------------------------------------------------------*/ void AddSputterProtocoll() { AsconProtocol *prot = NULL; prot = calloc(sizeof(AsconProtocol), 1); prot->name = strdup("sputter"); prot->init = SputterInit; prot->handler = SputterHandler; AsconInsertProtocol(prot); }