/*-------------------------------------------------------------------------- W E S T 4 1 0 0 U T I L . C A few utility functions for dealing with a WEST4100 temperature controller within the SINQ setup: host -- TCP/IP -- MAC --- RS-232. Mark Koennecke, Juli 1997 Mark Lesha, January 2006 (based on ITC4 code) Paul Barron, January 2008 (Note: This is based on the old LAKESHORE340 code and not the new LS340 code written by Rodney Davies Feb 08) Copyright: Labor fuer Neutronenstreuung Paul Scherrer Institut CH-5423 Villigen-PSI The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include "west4100util.h" #include "modbustcp.h" /* -------------------------------------------------------------------------*/ int WEST4100_Check_Status(pWEST4100 self) /* Can be called to check for correct operation of the WEST4100 */ { int iRet, iRetry; unsigned char pCommand[20]; unsigned char pReply[132]; iRetry=0; do { // Check Alarm 1 printf("%-9s %-23s","Checking:", "Status Alarm 1........"); sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,0x01,0x00,0x05,0x00,0x01); if ((iRet=transactModbusTCP(self->controller,pCommand,6,pReply,79))<=0) return iRet; if(pReply[3] != 0x0) { printf("Warning: Alarm 1 Activated\n"); strcpy(self->pAns,pReply); return 1; }else printf("OK\n"); // Check Alarm 2 printf("%-9s %-23s","Checking:", "Status Alarm 2........"); sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,0x01,0x00,0x06,0x00,0x01); if ((iRet=transactModbusTCP(self->controller,pCommand,6,pReply,79))<=0) return iRet; if(pReply[3]!=0x0) { printf("Warning: Alarm 2 Activated\n"); strcpy(self->pAns,pReply); return 1; }else{ printf("OK\n"); return 1; } } while((++iRetry<10)); /* If we fell out of the loop, the WEST4100 recieved a bad response*/ sprintf(self->pAns,"Write Status=%s",pReply); printf("Bad response received!\n"); return WEST4100__BADREAD; } /* -------------------------------------------------------------------------*/ int WEST4100_ConfigureAndQueryGen(pWEST4100 self, char *command, int fParAdr, float fVal, char *diagnosis) { int iRet; unsigned char pCommandSet[79], pCommandCheck[79]; unsigned char pReply[79]; unsigned char fParAdrHex[2],fValHex[2]; // Convert int to hexstring if((iRet=(int2hexstring((int)fParAdr,fParAdrHex)))==0) return iRet; if((iRet=(int2hexstring((int)fVal,fValHex)))==0) return iRet; /* Construct a write command. */ printf("%-9s %-23s","Setting: ",command); sprintf(pCommandSet,"%c%c%c%c%c%c",self->iAdr,0x06, fParAdrHex[0],fParAdrHex[1],fValHex[0],fValHex[1]); /* Issue a write command. */ if((iRet=transactModbusTCP(self->controller,pCommandSet,/*strlen(pCommand)*/6,pReply,79))!=1) return iRet; printf("OK\n"); /* Construct a read command to check that the paramater was set.*/ printf("%-9s %-23s","Checking:",command); sprintf(pCommandCheck,"%c%c%c%c%c%c",self->iAdr,04,fParAdrHex[0],fParAdrHex[1],0x00,0x1); /* Issue a read command .*/ if ((iRet=transactModbusTCP(self->controller,pCommandCheck,6,pReply,79))<=0) { printf("transactRS232 error! Code=%d.\n",iRet); printf("DEBUG: pReply='%s' len=%d \n",pReply,strlen(pReply)); return iRet; } // Check that the read data is the same as that was set if ( (pCommandSet[4]!=pReply[3]) || (pCommandSet[5]!=pReply[4]) ) { printf("Response was bad, Data not set.\n"); if (diagnosis&&*diagnosis) sprintf(self->pAns,"%s response=%s (%s.)",command,pReply,diagnosis); else sprintf(self->pAns,"%s response=%s",command,pReply); return WEST4100__BADREAD; } printf("OK\n"); return 1; } /* -------------------------------------------------------------------------*/ int WEST4100_SetControl(pWEST4100 self, int iControl) { // Left over from lakeshore code, West only has 1 sensor to choose from. return 1; } /* -------------------------------------------------------------------------*/ int WEST4100_Setup(pWEST4100 self) { int iRet; unsigned char pCommand[40]; unsigned char pReply[132]; //int fVal = 999999.; /* Check the WEST4100 status */ if ((iRet=WEST4100_Check_Status(self))!=1) return iRet; // Check the write status printf("%-9s %-23s","Checking:", "Write Status.........."); sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,0x01,0x00,0x01,0x00,0x01); if ((iRet=transactModbusTCP(self->controller,pCommand,6,pReply,79))<=0) { printf("Comms error!\n"); return iRet; // Comms problem } if (pReply[3] & 0x1) { printf("OK\n"); }else if (pReply[3] == 0x00) { printf("Status is Write Disabled.\n"); return WEST4100__READONLY; } /* Check that the controller is a gen-new-wine WEST4100 */ printf("%-9s %-23s","Checking:", "ID...................."); sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,0x03,0x00,122,0x00,0x01); if((iRet=transactModbusTCP(self->controller,pCommand,/*strlen*/6,pReply,79))!=1) return iRet; if ((pReply[3]!=0x17) || (pReply[4]!=0xd4)) { printf("Error: Incorrect ID\n"); strcpy(self->pAns,pReply); return WEST4100__NOWEST4100; } else printf("OK\n"); // Set Output Limit if((iRet=WEST4100_ConfigureAndQueryGen(self,"Output Power to 40%..",20,40,""))!=1) return iRet; // Set Alarm1 Limit if((iRet=WEST4100_ConfigureAndQueryGen(self,"Alarm1 to 1600........",13,1600,""))!=1) return iRet; // Set Alarm2 Limit if((iRet=WEST4100_ConfigureAndQueryGen(self,"Alarm2 to 0...........",14,0,""))!=1) return iRet; // Set Upper Limit if((iRet=WEST4100_ConfigureAndQueryGen(self,"Upper Limit to 1800...",22,1800,""))!=1) return iRet; // Set Lower Limit if((iRet=WEST4100_ConfigureAndQueryGen(self,"Lower Limit to 0......",23,0,""))!=1) return iRet; // Set Ramp Rate if((iRet=WEST4100_ConfigureAndQueryGen(self,"Ramp Rate to 0ff......",24,10000,""))!=1) return iRet; /* Check the WEST4100 operating status one last time */ if ((iRet=WEST4100_Check_Status(self))!=1) return iRet; return 1; /* Success */ } /* -------------------------------------------------------------------------*/ int WEST4100_Open(pWEST4100 *pData, char *pRS232, int iAddress, int iTransaction) { pWEST4100 self = NULL; self = (pWEST4100)malloc(sizeof(WEST4100)); if(self == NULL) { return WEST4100__BADMALLOC; } *pData = self; self->iAdr = iAddress; self->iTransact = iTransaction; self->controller = NULL; self->controller = (prs232)FindCommandData(pServ->pSics,pRS232, "RS232 Controller"); if(!self->controller){ /*SCWrite(pCon,"ERROR: motor controller not found",eError); */ return WEST4100__BADCOM; } return WEST4100_Setup(self); } /*--------------------------------------------------------------------------*/ void WEST4100_Close(pWEST4100 *pData) { pWEST4100 self; self = *pData; if (!self) return; // Just in case return; } /*--------------------------------------------------------------------------*/ int WEST4100_Config(pWEST4100 *pData, int iTmo, int iRead, int iControl) { pWEST4100 self; self = *pData; return 1; } /* --------------------------------------------------------------------------*/ int WEST4100_Send(pWEST4100 *pData, char *pCommand, char *pReply, int iLen) { int iRet; pWEST4100 self; self = *pData; char *ptr = pCommand; unsigned int byte; unsigned char pCommandHex[79]; size_t i; // Convert char string command to hex string with every two characters concatenated to one array field for (i=0;icontroller,pCommandHex,6,pReply,79))!=1){ printf("%-s","Response: "); displayHexString(pReply); return iRet; } printf("OK\n"); printf("%-s","Response: "); displayHexString(pReply); /* Check the WEST4100 operating status after issuing the command, if it was successful */ if (iRet>=1) iRet=WEST4100_Check_Status(self); return iRet; } /*--------------------------------------------------------------------------*/ int WEST4100_Read(pWEST4100 *pData, float *fVal) { unsigned char pCommand[20], pReply[132]; int iRet; float fRead = -999999.; pWEST4100 self; self = *pData; sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,04,0x0,0x1,0x0,0x1); if ((iRet=transactModbusTCP(self->controller,pCommand,6,pReply,79))<=0) { printf("transactRS232 error! Code=%d.\n",iRet); printf("DEBUG: pReply='%s' len=%d \n",pReply,strlen(pReply)); return iRet; } // Because a value read will never be greater than FF FF we can use a simple line to convert fRead=(256*pReply[3])+pReply[4]; if(fRead > 65535 || fRead < 0) // Not a number, probably an error response { return WEST4100__BADREAD; } *fVal = fRead; return 1; } /*--------------------------------------------------------------------------*/ int WEST4100_Query(pWEST4100 *pData, int parAddress, int *parValue) { unsigned char pCommand[20], pReply[132], pAddress[1]; int iRet; pWEST4100 self; self = *pData; int2hexstring(parAddress,pAddress); sprintf(pCommand,"%c%c%c%c%c%c",self->iAdr,0x4,pAddress[0],pAddress[1],0x0,0x1); if ((iRet=transactModbusTCP(self->controller,pCommand,6,pReply,79))<=0) { printf("transactRS232 error! Code=%d.\n",iRet); printf("DEBUG: pReply='%s' len=%d \n",pReply,strlen(pReply)); return iRet; } // Because a value read will never be greater than FF FF we can use a simple line to convert *parValue=(256*pReply[3])+pReply[4]; if(*parValue > 65535 || *parValue < 0) // Not a number, probably an error response { return WEST4100__BADREAD; } return 1; } /* -------------------------------------------------------------------------*/ int WEST4100_Write(pWEST4100 *pData, int parAddress, int parValue) { unsigned char displaytext[20]; int iRet; pWEST4100 self; self = *pData; sprintf(displaytext,"Parameter Number %d...",parAddress); if((iRet=WEST4100_ConfigureAndQueryGen(self,displaytext,parAddress,parValue,""))!=1) return iRet; if ((iRet=WEST4100_Check_Status(self))!=1) return iRet; return 1; } /* -------------------------------------------------------------------------*/ int WEST4100_Set(pWEST4100 *pData, float fVal) { int iRet, i; pWEST4100 self; self = *pData; for(i = 0; i < 3; i++) { // Set setpoint if((iRet=WEST4100_ConfigureAndQueryGen(self,"Setpoint...",0x02,fVal,""))!=1) return iRet; printf("SETP OK, checking status and returning.\n"); iRet=WEST4100_Check_Status(self); return iRet; } printf("SETP failed!\n"); return WEST4100__BADSET; } /* -------------------------------------------------------------------------*/ void WEST4100_ErrorTxt(pWEST4100 *pData,int iCode, char *pError, int iLen) { char pBueffel[512]; pWEST4100 self; self = *pData; switch(iCode) { case WEST4100__BADCOM: sprintf(pBueffel,"WEST4100: Invalid command or offline, got %s", self->pAns); strncpy(pError,pBueffel,iLen); break; case WEST4100__BADPAR: strncpy(pError,"WEST4100: Invalid parameter specified",iLen); break; case WEST4100__BADMALLOC: strncpy(pError,"WEST4100: Error allocating memory in WEST4100",iLen); break; case WEST4100__BADREAD: strncpy(pError,"WEST4100: Badly formatted answer",iLen); break; case WEST4100__BADSET: strncpy(pError,"WEST4100: Failed three times to write new set value to WEST4100",iLen); break; case WEST4100__FAULT: // Covers various WEST4100 self-diagnosed fault conditions sprintf(pBueffel,"WEST4100: Internal fault condition detected: %s",self->pAns); strncpy(pError,pBueffel,iLen); break; case WEST4100__NOWEST4100: sprintf(pBueffel,"WEST4100: Wrong model number (driver is for Model 340 only): %s",self->pAns); strncpy(pError,pBueffel,iLen); break; default: getRS232Error(iCode, pError,iLen); break; } } /* -------------------------------------------------------------------------*/ int int2hexstring(int fVal, unsigned char *hexstring) { size_t k; int fValInt; unsigned char temp[79]; int result,remainder,index,index2; fValInt=fVal; if(fValInt>65535) { printf("Value greater than FF FF"); return 0; } // Convert integer to hex and putting each char in an array memset(temp,0,sizeof(temp)); result=1; for(k=0;result!=0;k++) { result=fValInt/16; remainder=fValInt%16; fValInt=result; temp[k]=remainder; } // Formatting a new array so that there is one byte per array field if((k%2)==0) index2=k/2-1; else index2=k/2; if(fVal>255) { for(index=0;index2>=0;(index=index+2),index2--) { hexstring[index2]=(temp[index+1]*16)+temp[index]; } }else{ hexstring[0]=0x0; hexstring[1]=(temp[1]*16)+temp[0]; } return 1; } /* -------------------------------------------------------------------------*/ void displayHexString(unsigned char *hexstring) { int i; for(i=0;(i<5)|(hexstring[i]!='\0');i++)printf("%02x ",hexstring[i]); printf("\n"); }