//--------------------------------------------------------------------------- // // ljacklm.c // // Source code for accessing the LabJack U12. // // Based on the Windows ljackuw driver, ljackv118 template, and Linux // ljackul version 1.184 code. // // support@labjack.com // 10/2013 //---------------------------------------------------------------------- // #include #include #include "ljacklm.h" /* Unix includes, defines, macros, etc. */ #include #include #include #include #include #include #include "labjackusb.h" //Macros replacing those in the Windows bitops.h #define BitSet(arg,posn) ((arg) | (1L << (posn))) #define BitClr(arg,posn) ((arg) & ~(1L << (posn))) #define BitFlp(arg,posn) ((arg) ^ (1L << (posn))) #define BitTst(arg,posn) (!(!((arg) & (1L << (posn))))) //Sleep in miliseconds like on Windows. #define Sleep(a) usleep((a)*1000) /* Unix end */ #define VERSION (float)1.2002 #define LABJACK_VENDOR_ID (unsigned short)3285 #define LABJACK_U12_PRODUCT_ID (unsigned short)0001 #define INPUT_BUFFER_SIZE_LJ (unsigned long)198 #define RAM_BUFF_ROWS 64 #define MAX_DEVICES_LJ 256 //local ID range determines this #define FCDD_MAX 128 #define READ_TIMEOUT_MS 2000 #define NO_ERROR_LJ (long)0 //must be 0 #define UNKNOWN_ERROR_LJ (long)1 #define NO_DEVICES_FOUND_LJ (long)2 #define DEVICE_N_NOT_FOUND_LJ (long)3 #define SET_BUFFER_ERROR_LJ (long)4 #define OPEN_HANDLE_ERROR_LJ (long)5 #define CLOSE_HANDLE_ERROR_LJ (long)6 #define INVALID_ID_LJ (long)7 #define ARRAY_SIZE_OR_VALUE_ERROR_LJ (long)8 #define INVALID_POWER_INDEX_LJ (long)9 #define FCDD_SIZE_LJ (long)10 #define HVC_SIZE_LJ (long)11 #define READ_ERROR_LJ (long)12 #define READ_TIMEOUT_ERROR_LJ (long)13 #define WRITE_ERROR_LJ (long)14 #define FEATURE_ERROR_LJ (long)15 #define ILLEGAL_CHANNEL_LJ (long)16 #define ILLEGAL_GAIN_INDEX_LJ (long)17 #define ILLEGAL_AI_COMMAND_LJ (long)18 #define ILLEGAL_AO_COMMAND_LJ (long)19 #define BITS_OUT_OF_RANGE_LJ (long)20 #define ILLEGAL_NUMBER_OF_CHANNELS_LJ (long)21 #define ILLEGAL_SCAN_RATE_LJ (long)22 #define ILLEGAL_NUM_SAMPLES_LJ (long)23 #define AI_RESPONSE_ERROR_LJ (long)24 #define RAM_CS_ERROR_LJ (long)25 #define AI_SEQUENCE_ERROR_LJ (long)26 #define NUM_STREAMS_ERROR_LJ (long)27 #define AI_STREAM_START_LJ (long)28 #define PC_BUFF_OVERFLOW_LJ (long)29 #define LJ_BUFF_OVERFLOW_LJ (long)30 #define STREAM_READ_TIMEOUT_LJ (long)31 #define ILLEGAL_NUM_SCANS_LJ (long)32 #define NO_STREAM_FOUND_LJ (long)33 #define ILLEGAL_INPUT_ERROR_LJ (long)40 #define ECHO_ERROR_LJ (long)41 #define DATA_ECHO_ERROR_LJ (long)42 #define RESPONSE_ERROR_LJ (long)43 #define ASYNCH_TIMEOUT_ERROR_LJ (long)44 #define ASYNCH_START_ERROR_LJ (long)45 #define ASYNCH_FRAME_ERROR_LJ (long)46 #define ASYNCH_DIO_CONFIG_ERROR_LJ (long)47 #define INPUT_CAPS_ERROR_LJ (long)48 #define OUTPUT_CAPS_ERROR_LJ (long)49 #define FEATURE_CAPS_ERROR_LJ (long)50 #define NUM_CAPS_ERROR_LJ (long)51 #define GET_ATTRIBUTES_WARNING_LJ (long)52 #define WRONG_FIRMWARE_VERSION_LJ (long)57 #define DIO_CONFIG_ERROR_LJ (long)58 #define CLAIM_ALL_DEVICES_LJ (long)64 #define RELEASE_ALL_DEVICES_LJ (long)65 #define CLAIM_DEVICE_LJ (long)66 #define RELEASE_DEVICE_LJ (long)67 #define CLAIMED_ABANDONED_LJ (long)68 #define LOCALID_NEG_LJ (long)69 #define STOP_THREAD_TIMEOUT_LJ (long)70 #define TERMINATE_THREAD_LJ (long)71 #define FEATURE_HANDLE_LJ (long)72 #define CREATE_MUTEX_LJ (long)73 #define SYNCH_CSSTATETRIS_ERROR_LJ (long)80 #define SYNCH_SCKTRIS_ERROR_LJ (long)81 #define SYNCH_MISOTRIS_ERROR_LJ (long)82 #define SYNCH_MOSITRIS_ERROR_LJ (long)83 #define SHT1X_CRC_ERROR_LJ (long)89 #define SHT1X_MEASREADY_ERROR_LJ (long)90 #define SHT1X_ACK_ERROR_LJ (long)91 #define SHT1X_SERIAL_RESET_ERROR_LJ (long)92 #define STREAMBUFF_ERROR_OFFSET_LJ (long)256 //bit 8 is set for errors in the stream thread #define GETFIRMWAREVERSION_ERROR_OFFSET_LJ (long)512 //bit 9 is set typedef struct _LABJACK_INFO { pthread_mutex_t mutex; //mutex variable bool isMutexInit; //indicates if the mutex was initialized HANDLE hDevice; //Exodriver handle long serialNumber; bool errorDetected; //Forces a handle close } LABJACK_INFO; typedef struct _STREAM_INFO { long errorcode; float streamBuff[RAM_BUFF_ROWS][7]; //V1,(V2),(V3),(V4),stateIO,overvoltage,ljbacklog long numScansBuff; //number of processed scans in the buffer long previousCount; long localID; //-1 means not owned long demo; unsigned long demoTick; long scanCount; long turbo; long disableCal; long numChannels; long scanMult; float scanRate; long readCount; //>0 means return the counter reading long ch1num; long ch2num; long ch3num; long ch4num; long ch1gain; long ch2gain; long ch3gain; long ch4gain; } STREAM_INFO; //Globals STREAM_INFO streamInfo={0}; pthread_mutex_t streamInfoMutex; //stream info mutex variable bool isStreamInfoMutexInit; //indicates if the stream info mutex was initialized long gTrisD[MAX_DEVICES_LJ]={0}; //referenced to PIC, 0=Output long gTrisIO[MAX_DEVICES_LJ]={0}; //referenced to PIC, 0=Output long gStateD[MAX_DEVICES_LJ]={0}; //output states long gStateIO[MAX_DEVICES_LJ]={0}; //output states float gAO0[MAX_DEVICES_LJ]={0}; //current AO0 setting float gAO1[MAX_DEVICES_LJ]={0}; //current AO1 setting LABJACK_INFO labjackInfo[MAX_DEVICES_LJ]; //1 structure for each labjack char ljmutexName[12]={'l','j','a','c','k','u','w','i','0','0','0','\000'}; //put index in bits 8,9,10 char streammutexName[12]={'l','j','a','c','k','u','w','s','0','0','0','\000'}; typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_LJ { long cbSize; char DevicePath[FCDD_MAX]; } SP_DEVICE_INTERFACE_DETAIL_DATA_LJ, *PSP_DEVICE_INTERFACE_DETAIL_DATA_LJ; //local functions long OpenLabJack( long *errorcode, unsigned int vendorID, unsigned int productID, long *idnum, long *serialnum, long *calData); long WriteRead( long localID, long timeoutms, unsigned char *sendBuffer, unsigned char *readBuffer); long WriteLabJack( long localID, unsigned char *sendBuffer); long ReadLabJack( long localID, long timeout, long feature, unsigned char *buffer); long CloseAll( long localID); long BuildAICommand( long command, //4-bit command, 1CCC, 12=C/R,10=burst,9=stream unsigned char sendBuff5, //buffer+4 unsigned char sendBuff7, //buffer+6 unsigned char sendBuff8, //buffer+7 long stateIO, long ch1num, long ch2num, long ch3num, long ch4num, long ch1gain, long ch2gain, long ch3gain, long ch4gain, unsigned char *sendBuffer); long BuildGainMuxCommand( long chnum, long chgain, unsigned char *gainmux); long ParseAIResponse( unsigned char *sendBuffer, unsigned char *readBuffer, long disableCal, long *calData, //20 element array long *stateIO, long *overVoltage, float *voltage1, float *voltage2, float *voltage3, float *voltage4, unsigned char *echoIn, long *ofchecksumError, long *backlog, long *iterationCount, long readCount); long ApplyCal( unsigned char gainmux, long *calData, long *bits); long BuildAOCommand( long trisD, long trisIO, long stateD, long stateIO, long updateDigital, long resetCounter, float analogOut0, float analogOut1, unsigned char *sendBuffer); long ParseAOResponse( unsigned char *readBuffer, long *stateD, long *stateIO, unsigned long *count); long RoundFL( float fp); long SHTWriteRead( long localID, long softComm, // >0 means bit-bang in software long waitMeas, // >0 means wait for measurement ready long serialReset, // >0 means start with a serialReset long dataRate, // 0=default,1=300us delay,2=1ms delay long numWrite, // 0-4 long numRead, // 0-4 unsigned char *datatx, //4 byte write array unsigned char *datarx); //4 byte read array unsigned char ReverseByte( unsigned char byteIn); long GetU12Information( HANDLE hDevice, long *serialnum, long *localID, long *power, long *calData, long *fcddMaxSize, long *hvcMaxSize); unsigned long GetTickCount( void); __attribute__((constructor)) static void initializer() { int i; for(i=0;i0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does // little but simulate execution time. // channel -Channel command is 0-7 for SE or 8-11 for Diff. // gain -Gain command is 0=1,1=2,...,7=20. Gain only // available for differential channels. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *overVoltage -If >0, an overvoltage has been detected // on the analog input (I32). // voltage -Returns the voltage reading (SGL). // // Time: 20 ms //---------------------------------------------------------------------- long EAnalogIn( long *idnum, long demo, long channel, long gain, long *overVoltage, float *voltage) { long errorcode; long localID=0; float avgVolts; long avgBits; unsigned char echoOut,echoIn; unsigned char sendBuff5=0; long junk=0; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain; long stateIO=0,disableCal=0; float voltages[4]={0,0,0,0}; long serialnum=0; if(!demo) { //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *overVoltage=0; return errorcode; } } //The LabJack echos 1 byte so we can make sure we are getting the expected response echoOut = (unsigned char)GetTickCount(); //set bit 0 to turn the LED on sendBuff5 = BitSet(sendBuff5,0); //Fill sendBuffer with the proper values. ch1num=channel; ch2num=channel; ch3num=channel; ch4num=channel; ch1gain=gain; ch2gain=gain; ch3gain=gain; ch4gain=gain; errorcode = BuildAICommand(12,sendBuff5,0,echoOut,stateIO,ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain,sendBuffer); if(errorcode) { *overVoltage=0; CloseAll(localID); return errorcode; } if(!demo) { //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *overVoltage=0; CloseAll(localID); return errorcode; } //Parse the response errorcode = ParseAIResponse(sendBuffer,readBuffer,disableCal,calData,&stateIO,overVoltage,&voltages[0],&voltages[1],&voltages[2],&voltages[3],&echoIn,&junk,&junk,&junk,0); if(errorcode) { *overVoltage=0; voltage=0; CloseAll(localID); return errorcode; } if(echoOut != echoIn) { errorcode=ECHO_ERROR_LJ; *overVoltage=0; voltage=0; CloseAll(localID); return errorcode; } } else { //Demo Mode Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); voltages[0]=2.5F; voltages[1]=2.5F; voltages[2]=2.5F; voltages[3]=2.5F; } //Only 1 channel so average 4 readings to get voltage. avgVolts = (voltages[0]+voltages[1]+voltages[2]+voltages[3])/4.0F; errorcode = VoltsToBits(ch1num,ch1gain,avgVolts,&avgBits); errorcode = BitsToVolts(ch1num,ch1gain,avgBits,voltage); if(!demo) { errorcode = CloseAll(localID); } return errorcode; } //====================================================================== // EAnalogOut: Easy function sets the voltages of both analog outputs. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does little // but simulate execution time. // analogOut0 -Voltage from 0 to 5 for AO0 (SGL). // analogOut1 -Voltage from 0 to 5 for AO1 (SGL). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 20 ms //---------------------------------------------------------------------- long EAnalogOut( long *idnum, long demo, float analogOut0, float analogOut1) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long stateD=0,stateIO=0; unsigned long count=0; long serialnum=0; //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } if(analogOut0<0) { analogOut0=gAO0[localID]; } if(analogOut1<0) { analogOut1=gAO1[localID]; } //Fill sendBuffer with the proper values. errorcode = BuildAOCommand(0,0,0,0,0,0,analogOut0,analogOut1,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //update globals gAO0[localID]=analogOut0; gAO1[localID]=analogOut1; //Parse the response errorcode = ParseAOResponse(readBuffer,&stateD,&stateIO,&count); if(errorcode) { CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // ECount: Easy function to read & reset the counter. Calling this // function disables STB (which is the default anyway). // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // resetCounter -If >0, the counter is reset to zero after // being read (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *count -Current count, before reset. // *ms -Value of the current time, expressed as millisconds // since the Epoch, during the counter read (within // a few ms). // // Time: 20 ms //---------------------------------------------------------------------- long ECount ( long *idnum, long demo, long resetCounter, double *count, double *ms) { long errorcode; long localID; long stateD=0,stateIO=0; unsigned long ucount=0; unsigned long initial,final; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); *count=GetTickCount(); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *count=0; *ms=0; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[6]=82; sendBuffer[1]=0; if(resetCounter) { sendBuffer[1] = BitSet(sendBuffer[1],0); //set bit } //Get millisecond count before sending command initial=GetTickCount(); //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *ms=0; *count=0; CloseAll(localID); return errorcode; } //Get millisecond count after receiving response final=GetTickCount(); //Estimate time when counter was actual read. if(final>initial) { *ms=initial+((final-initial)/2); } else { *ms=(double)(initial+((((4294967295U-initial)+1)+final)/2)); } //Parse the response errorcode = ParseAOResponse(readBuffer,&stateD,&stateIO,&ucount); if(errorcode) { *ms=0; *count=0; CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); *count = (double)ucount; return errorcode; } //====================================================================== // EDigitalIn: Easy function reads 1 digital input. Also configures // the requested pin to input and leaves it that way. // // Note that this is a simplified version of the lower // level function DigitalIO, which operates on all 20 // digital lines. The DLL keeps track of the current // direction and output state of all lines, so that this // easy function can operate on a single line without // changing the others. When the DLL is first loaded, // though, it does not know the direction and state of // the lines and assumes all directions are input and // output states are low. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // channel -Line to read. 0-3 for IO or 0-15 for D. // readD -If >0, a D line is read instead of an IO line. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *state -TRUE/Set if >0. FALSE/Clear if 0. // // Time: 20 ms //---------------------------------------------------------------------- long EDigitalIn( long *idnum, long demo, long channel, long readD, long *state) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long trisD=0,trisIO=0,stateD=0,stateIO=0; long serialnum=0; //Make sure each DIO input is within the proper range if (readD) { if ((channel<0) || (channel>15)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; *state=-1; return errorcode; } } else { if ((channel<0) || (channel>3)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; *state=-1; return errorcode; } } //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *state=-1; return errorcode; } //Set the desired line to input if(readD) { trisD=BitSet(gTrisD[localID],channel); trisIO=gTrisIO[localID]; } else { trisD=gTrisD[localID]; trisIO=BitSet(gTrisIO[localID],channel); } //Fill sendBuffer with the proper values. sendBuffer[1]=(unsigned char)(trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(gStateD[localID]/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(gStateD[localID]%256); //lower byte of stateD sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)gStateIO[localID]); sendBuffer[6]=87; sendBuffer[7]=0; //Set updateDigital TRUE sendBuffer[7] = BitSet(sendBuffer[7],0); //set bit 0 //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *state=-1; CloseAll(localID); return errorcode; } //Update tris and state globals with current output values gTrisD[localID]=trisD; gTrisIO[localID]=trisIO; //Parse the response if (!((readBuffer[1]==87)||(readBuffer[1]==119))) { errorcode=RESPONSE_ERROR_LJ; } stateD = ((long)readBuffer[2]) * 256; stateD += ((long)readBuffer[3]); stateIO = ((long)readBuffer[4]) / 16; if(readD) { *state=BitTst(stateD,channel); } else { *state=BitTst(stateIO,channel); } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // EDigitalOut: Easy function writes 1 digital output. Also configures the // the requested pin to output and leaves it that way. // // Note that this is a simplified version of the lower // level function DigitalIO, which operates on all 20 // digital lines. The DLL keeps track of the current // direction and output state of all lines, so that this // easy function can operate on a single line without // changing the others. When the DLL is first loaded, // though, it does not know the direction and state of // the lines and assumes all directions are input and // output states are low. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // channel -Line to write. 0-3 for IO or 0-15 for D. // writeD -If >0, a D line is written instead of an IO line. // state -TRUE/Set if >0. FALSE/Clear if 0. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 20 ms //---------------------------------------------------------------------- long EDigitalOut( long *idnum, long demo, long channel, long writeD, long state) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long trisD=0,trisIO=0,stateD=0,stateIO=0; long serialnum=0; //Make sure each DIO input is within the proper range if (writeD) { if ((channel<0) || (channel>15)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } } else { if ((channel<0) || (channel>3)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } } //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Set the desired line to output and set state if(writeD) { trisD=BitClr(gTrisD[localID],channel); if(state) { stateD=BitSet(gStateD[localID],channel); } else { stateD=BitClr(gStateD[localID],channel); } trisIO=gTrisIO[localID]; stateIO=gStateIO[localID]; } else { trisD=gTrisD[localID]; stateD=gStateD[localID]; trisIO=BitClr(gTrisIO[localID],channel); if(state) { stateIO=BitSet(gStateIO[localID],channel); } else { stateIO=BitClr(gStateIO[localID],channel); } } //Fill sendBuffer with the proper values. sendBuffer[1]=(unsigned char)(trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(stateD/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(stateD%256); //lower byte of stateD sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); sendBuffer[6]=87; sendBuffer[7]=0; //Set updateDigital TRUE. sendBuffer[7] = BitSet(sendBuffer[7],0); //set bit 0 //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Update tris and state globals with current output values gTrisD[localID]=trisD; gTrisIO[localID]=trisIO; gStateD[localID]=stateD; gStateIO[localID]=stateIO; //Parse the response if (!((readBuffer[1]==87)||(readBuffer[1]==119))) { errorcode=RESPONSE_ERROR_LJ; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // AsynchConfig: Requires firmware V1.08 or higher. // // This function writes to the asynch registers and sets the // direction of the D lines (input/output) as needed. // // The actual 1-bit time is about 1.833 plus a "full" delay (us). // The actual 1/2-bit time is about 1.0 plus a "half" delay (us). // // full/half delay = 0.833 + 0.833C + 0.667BC + 0.5ABC // // Common baud rates (full A,B,C; half A,B,C): // 1 55,153,232 ; 114,255,34 // 10 63,111,28 ; 34,123,23 // 100 51,191,2 ; 33,97,3 // 300 71,23,4 ; 84,39,1 // 600 183,3,6 ; 236,7,1 // 1000 33,29,2 ; 123,8,1 // 1200 23,17,4 ; 14,54,1 // 2400 21,37,1 ; 44,3,3 // 4800 10,18,2 ; 1,87,1 // 7200 134,2,1 ; 6,9,2 // 9600 200,1,1 ; 48,2,1 // 10000 63,3,1 ; 46,2,1 // 19200 96,1,1 ; 22,2,1 // 38400 3,5,2 ; 9,2,1 // 57600 3,3,2 ; 11,1,1 // 100000 3,3,1 ; 1,2,1 // 115200 9,1,1 ; 2,1,1 or 1,1,1 // // // When using data rates over 38.4 kbps, the following conditions // need to be considered: // -When reading the first byte, the start bit is first tested // about 11.5 us after the start of the tx stop bit. // -When reading bytes after the first, the start bit is first // tested about "full" + 11 us after the previous bit 8 read, // which probably occurs near the middle of bit 8. // // When enabled, STB does the following to aid in debugging // asynchronous reads: // -STB is set about 6 us after the start of the last tx stop bit, or // about "full" + 6 us after the previous bit 8 read. // -STB is cleared about 0-2 us after the rx start bit is detected. // -STB is set after about "half". // -STB is cleared after about "full". // -Bit 0 is read about 1 us later. // -STB is set about 1 us after the bit 0 read. // -STB is cleared after about "full". // -Bit 1 is read about 1 us later. // -STB is set about 1 us after the bit 1 read. // -STB is cleared after about "full". // -This continues for all 8 data bits and the stop bit, after // which STB remains low. // // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // timeoutMult -If enabled, read timeout is about 100 // milliseconds times this value (I32, 0-255). // configA -If >0, D8 is set to output-high and D9 is set to // input (I32). // configB -If >0, D10 is set to output-high and D11 is set to // input (I32). // configTE -If >0, D12 is set to output-low (I32). // fullA -A time value for a full bit (I32, 1-255). // fullB -B time value for a full bit (I32, 1-255). // fullC -C time value for a full bit (I32, 1-255). // halfA -A time value for a half bit (I32, 1-255). // halfB -B time value for a half bit (I32, 1-255). // halfC -C time value for a half bit (I32, 1-255). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 60 ms //---------------------------------------------------------------------- long AsynchConfig( long *idnum, long demo, long timeoutMult, long configA, long configB, long configTE, long fullA, long fullB, long fullC, long halfA, long halfB, long halfC) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; long trisD=0,trisIO=0,stateD=0,stateIO=0; //Make sure each input is within the proper range if ((timeoutMult<0) || (timeoutMult>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((fullA<1) || (fullA>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((fullB<1) || (fullB>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((fullC<1) || (fullC>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((halfA<1) || (halfA>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((halfB<1) || (halfB>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((halfC<1) || (halfC>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Do demo here if(demo) { Sleep(40); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Make sure firmware is V1.05 or higher if(serialnum < 100010000) { CloseAll(localID); return WRONG_FIRMWARE_VERSION_LJ; } //Initialize local tris and state variables trisD=gTrisD[localID]; stateD=gStateD[localID]; trisIO=gTrisIO[localID]; stateIO=gStateIO[localID]; //If configA is true, set D8 to output-high, and set D9 to input. if(configA) { trisD=BitClr(trisD,8); //In firmware, 0=Output and 1=Input stateD=BitSet(stateD,8); trisD=BitSet(trisD,9); //In firmware, 0=Output and 1=Input } //If configB is true, set D10 to output-high, and set D11 to input. if(configB) { trisD=BitClr(trisD,10); //In firmware, 0=Output and 1=Input stateD=BitSet(stateD,10); trisD=BitSet(trisD,11); //In firmware, 0=Output and 1=Input } //If configTE is true, set D12 to output-low. if(configA) { trisD=BitClr(trisD,12); //In firmware, 0=Output and 1=Input stateD=BitClr(stateD,12); } //Fill sendBuffer with the proper values. sendBuffer[1]=(unsigned char)(trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(stateD/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(stateD%256); //lower byte of stateD sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); sendBuffer[6]=87; //DigitalIO function sendBuffer[7]=0; //Set updateDigital TRUE. sendBuffer[7] = BitSet(sendBuffer[7],0); //set bit 0 //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Update tris and state globals with current output values gTrisD[localID]=trisD; gTrisIO[localID]=trisIO; gStateD[localID]=stateD; gStateIO[localID]=stateIO; //Parse the response if (!((readBuffer[1]==87)||(readBuffer[1]==119))) { errorcode = CloseAll(localID); return RESPONSE_ERROR_LJ; } errorcode = CloseAll(localID); if(errorcode) return errorcode; //Call WriteMem twice to load configuration parameters. //Address 0x070 to 0x07F Asynch (fullA,fullB,fullC,halfA,halfB,halfC,tomult,empty ...). errorcode = WriteMem(&localID,1,112,fullA,fullB,fullC,halfA); if(errorcode) return errorcode; errorcode = WriteMem(&localID,1,116,halfB,halfC,timeoutMult,0); return errorcode; } //====================================================================== // Asynch: Requires firmware V1.05 or higher. // // This function writes and then reads half-duplex asynchronous // data on 1 of two pairs of D lines (8,n,1). Call AsynchConfig // to set the baud rate. Similar to RS232, except that logic is // normal CMOS/TTL (0=low=GND, 1=high=+5V, idle state of // transmit line is high). Connection to a normal RS232 device // will probably require a converter chip such as the MAX233. // // PortA => TX is D8 and RX is D9 // PortB => TX is D10 and RX is D11 // Transmit Enable is D12 // // Up to 18 bytes can be written and read. If more than 4 bytes // are written or read, this function uses calls to // WriteMem/ReadMem to load/read the LabJack's data buffer. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // portB -If >0, asynch PortA is used instead of PortA. // enableTE -If >0, D12 (Transmit Enable) is set high during // transmit and low during receive (I32). // enableTO -If >0, timeout is enabled for the receive phase (per byte). // enableDel -If >0, a 1 bit delay is inserted between each // transmit byte. // baudrate -This is the bps as set by AsynchConfig. Asynch needs this // so it has an idea how long the transfer should take. // numWrite -Number of bytes to write (I32, 0-18). // numRead -Number of bytes to read (I32, 0-18). // *data -Serial data buffer. Send an 18 element // array. Fill unused locations with zeros (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *data -Serial data buffer. Returns any serial read // data. Unused locations are filled // with 9999s. (I32). // // Time: 20 ms to read and/or write up to 4 bytes, plus 20 ms for each // additional 4 bytes to read or write. Possibly extra // time for slow baud rates. //---------------------------------------------------------------------- long Asynch( long *idnum, long demo, long portB, long enableTE, long enableTO, long enableDel, long baudrate, long numWrite, long numRead, long *data) { long errorcode=0,result=0,i=0,j=0, usbTimeout=0; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0,numPackets=0,memAddress=0,numFill=0; //Make sure each input is within the proper range if ((numWrite<0) || (numWrite>18)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((numRead<0) || (numRead>18)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } for(i=0;i<18;i++) { if(i >= numWrite) { if(data[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } } else { if((data[i]<0)||(data[i]>255)) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } } } //If we are writing more than 4 bytes, put them in the LabJack's NVRAM buffer. numPackets = 0; if(numWrite>4) { numPackets = (numWrite-1)/4; for(i=0;i= numRead) { data[i]=9999; } } result = CloseAll(localID); if(result) return result; } else //demo { Sleep(20); } //If we are reading more than 4 bytes, get them from the LabJack's NVRAM buffer. numPackets = 0; if(numRead>4) { numPackets = (numRead-1)/4; numFill = 4-(numRead%4); for(i=0;i255)) { errorcode=INVALID_ID_LJ; return errorcode; } errorcode = WriteMem(idnum,1,8,0,0,0,localID); return errorcode; } //====================================================================== // PulseOut: Requires firmware V1.05 or higher. // // The timeout of this function, in milliseconds, is set to: // 5000+numPulses*((B1*C1*0.02)+(B2*C2*0.02)) // // This command creates pulses on any/all of D0-D7. The // desired D lines must be set to output using another // function (DigitalIO or AOUpdate). All selected lines // are pulsed at the same time, at the same rate, for the // same number of pulses. // // This function commands the time for the first half cycle // of each pulse, and the second half cycle of each pulse. // Each time is commanded by sending a value B & C, where // the time is, // // 1st half-cycle microseconds = ~17 + 0.83*C + 20.17*B*C // 2nd half-cycle microseconds = ~12 + 0.83*C + 20.17*B*C // // which can be approximated as, // // microseconds = 20*B*C // // For best accuracy when using the approximation, minimize C. // B and C must be between 1 and 255, so each half cycle can // vary from about 38/33 microseconds to just over 1.3 seconds. // // If you have enabled the LabJack Watchdog function, make sure // it's timeout is longer than the time it takes to output all // pulses. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // lowFirst -If >0, each line is set low then high, otherwise // the lines are set high then low (I32). // bitSelect -Set bits 0 to 7 to enable pulsing on each of // D0-D7 (I32, 0-255). // numPulses -Number of pulses for all lines (I32, 1-32767). // timeB1 -B value for first half cycle (I32, 1-255). // timeC1 -C value for first half cycle (I32, 1-255). // timeB2 -B value for second half cycle (I32, 1-255). // timeC2 -C value for second half cycle (I32, 1-255). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 20 ms plus pulse time (make sure watchdog is longer if active) //---------------------------------------------------------------------- long PulseOut( long *idnum, long demo, long lowFirst, long bitSelect, long numPulses, long timeB1, long timeC1, long timeB2, long timeC2) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long pulseMS = 0; long timeoutMS = 0; long serialnum=0; //Make sure each input is within the proper range if ((bitSelect<0) || (bitSelect>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((numPulses<1) || (numPulses>32767)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeB1<1) || (timeB1>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeC1<1) || (timeC1>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeB2<1) || (timeB2>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeC2<1) || (timeC2>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } pulseMS = (long)((float)numPulses * (((float)(timeB1*timeC1)*0.02) + ((float)(timeB2*timeC2)*0.02))); timeoutMS = pulseMS + 5000; //Do demo here if(demo) { Sleep(14 + ((long)(6.0F * (float)rand()/(float)RAND_MAX)) + pulseMS); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Make sure firmware is V1.05 or higher if(serialnum < 100010000) { CloseAll(localID); return WRONG_FIRMWARE_VERSION_LJ; } //Fill sendBuffer with the proper values. // buffer B1 // buffer+1 C1 // buffer+2 B2 // buffer+3 C2 // buffer+4 Bit Mask for D7..D0 (set a bit to pulse that D line) // buffer+5 011XX100 (Command) // buffer+6 H,MSB (L=Clear First?, MSB Number of Pulses is upper 7 bits) // buffer+7 LSB Number of Pulses sendBuffer[6]=100; //Pulseout command sendBuffer[1]=(unsigned char)timeB1; sendBuffer[2]=(unsigned char)timeC1; sendBuffer[3]=(unsigned char)timeB2; sendBuffer[4]=(unsigned char)timeC2; sendBuffer[5]=(unsigned char)bitSelect; sendBuffer[7]=(unsigned char)(numPulses/256); sendBuffer[8]=(unsigned char)(numPulses%256); if(lowFirst) { sendBuffer[7] = BitSet(sendBuffer[7],7); //set bit 7 } //Write & Read data to/from the LabJack errorcode = WriteRead(localID,timeoutMS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } if(readBuffer[5] != 0) { CloseAll(localID); return DIO_CONFIG_ERROR_LJ; } if(readBuffer[6] != 100) { CloseAll(localID); return ECHO_ERROR_LJ; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // PulseOutStart: Requires firmware V1.07 or higher. // // PulseOutStart and PulseOutFinish are used as an // alternative to PulseOut. PulseOutStart starts the // pulse output and returns without waiting for the // finish. PulseOutFinish waits for the LabJack's // response which signifies the end of the pulse // output. If anything besides PulseOutFinish is // called after PulseOutStart, the pulse output // will be terminated and the LabJack will execute // the new command. // // Note that due to boot-up tests on the LabJack // U12, if PulseOutStart is the first command sent // to the LabJack after reset or power-up, there // would be no response for PulseOutFinish. In // practice, even if no precautions were taken, this // would probably never happen, since before calling // PulseOutStart a call is needed to set the desired // D lines to output. // // Also note that PulseOutFinish must be called before // the LabJack completes the pulse output to read the // response. If PulseOutFinish is not called until // after the LabJack sends it's response, the function // will never receive the response and will timeout. // // This command creates pulses on any/all of D0-D7. The // desired D lines must be set to output using another // function (DigitalIO or AOUpdate). All selected lines // are pulsed at the same time, at the same rate, for the // same number of pulses. // // This function commands the time for the first half cycle // of each pulse, and the second half cycle of each pulse. // Each time is commanded by sending a value B & C, where // the time is, // // 1st half-cycle microseconds = ~17 + 0.83*C + 20.17*B*C // 2nd half-cycle microseconds = ~12 + 0.83*C + 20.17*B*C // // which can be approximated as, // // microseconds = 20*B*C // // For best accuracy when using the approximation, minimize C. // B and C must be between 1 and 255, so each half cycle can // vary from about 38/33 microseconds to just over 1.3 seconds. // // If you have enabled the LabJack Watchdog function, make sure // it's timeout is longer than the time it takes to output all // pulses. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // lowFirst -If >0, each line is set low then high, otherwise // the lines are set high then low (I32). // bitSelect -Set bits 0 to 7 to enable pulsing on each of // D0-D7 (I32, 0-255). // numPulses -Number of pulses for all lines (I32, 1-32767). // timeB1 -B value for first half cycle (I32, 1-255). // timeC1 -C value for first half cycle (I32, 1-255). // timeB2 -B value for second half cycle (I32, 1-255). // timeC2 -C value for second half cycle (I32, 1-255). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // //---------------------------------------------------------------------- long PulseOutStart( long *idnum, long demo, long lowFirst, long bitSelect, long numPulses, long timeB1, long timeC1, long timeB2, long timeC2) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Make sure each input is within the proper range if ((bitSelect<0) || (bitSelect>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((numPulses<1) || (numPulses>32767)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeB1<1) || (timeB1>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeC1<1) || (timeC1>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeB2<1) || (timeB2>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((timeC2<1) || (timeC2>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Do demo here if(demo) { return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Make sure firmware is V1.07 or higher if(serialnum < 100011007) { CloseAll(localID); return WRONG_FIRMWARE_VERSION_LJ; } //Fill sendBuffer with the proper values. // buffer B1 // buffer+1 C1 // buffer+2 B2 // buffer+3 C2 // buffer+4 Bit Mask for D7..D0 (set a bit to pulse that D line) // buffer+5 011XX100 (Command) // buffer+6 H,MSB (L=Clear First?, MSB Number of Pulses is upper 7 bits) // buffer+7 LSB Number of Pulses sendBuffer[6]=100; //Pulseout command sendBuffer[1]=(unsigned char)timeB1; sendBuffer[2]=(unsigned char)timeC1; sendBuffer[3]=(unsigned char)timeB2; sendBuffer[4]=(unsigned char)timeC2; sendBuffer[5]=(unsigned char)bitSelect; sendBuffer[7]=(unsigned char)(numPulses/256); sendBuffer[8]=(unsigned char)(numPulses%256); if(lowFirst) { sendBuffer[7] = BitSet(sendBuffer[7],7); //set bit 7 } //Write to the LabJack errorcode = WriteLabJack(localID,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // PulseOutFinish: Requires firmware V1.07 or higher. // // PulseOutStart and PulseOutFinish are used as an // alternative to PulseOut. PulseOutStart starts the // pulse output and returns without waiting for the // finish. PulseOutFinish waits for the LabJack's // response which signifies the end of the pulse // output. If anything besides PulseOutFinish is // called after PulseOutStart, the pulse output // will be terminated and the LabJack will execute // the new command. // // Note that due to boot-up tests on the LabJack // U12, if PulseOutStart is the first command sent // to the LabJack after reset or power-up, there // would be no response for PulseOutFinish. In // practice, even if no precautions were taken, this // would probably never happen, since before calling // PulseOutStart a call is needed to set the desired // D lines to output. // // Also note that PulseOutFinish must be called before // the LabJack completes the pulse output to read the // response. If PulseOutFinish is not called until // after the LabJack sends it's response, the function // will never receive the response and will timeout. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // timeoutMS -Amount of time, in milliseconds, that this // function will wait for the Pulseout response (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // //---------------------------------------------------------------------- long PulseOutFinish( long *idnum, long demo, long timeoutMS) { long errorcode; long localID; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Do demo here if(demo) { return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Make sure firmware is V1.07 or higher if(serialnum < 100011007) { CloseAll(localID); return WRONG_FIRMWARE_VERSION_LJ; } //Read the Pulseout response errorcode = ReadLabJack(localID,timeoutMS,0,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } if(readBuffer[5] != 0) { CloseAll(localID); return DIO_CONFIG_ERROR_LJ; } if(readBuffer[6] != 100) { CloseAll(localID); return ECHO_ERROR_LJ; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // PulseOutCalc: // // This function can be used to calculate the cycle times // for PulseOut or PulseOutStart. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *frequency -Desired frequency in Hz (SGL). // Outputs: *frequency -Actual best frequency found in Hz (SGL). // *timeB -B value for first and second half cycle (I32). // *timeC -C value for first and second half cycle (I32). // // Time: //---------------------------------------------------------------------- long PulseOutCalc( float *frequency, long *timeB, long *timeC) { long errorcode; long b,c; float bf,cf; float ferror=999999.0; float ferrorbest=999999.0; float fdesired,fcurrent; fdesired = *frequency; //Make sure each input is within the proper range if ((fdesired<0.763) || (fdesired>28436)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; return errorcode; } for(b=1;b<256;b++) { for(c=1;c<256;c++) { bf=(float)b; cf=(float)c; fcurrent=1000000/((85+5*cf+121*bf*cf)/3); ferror=fdesired-fcurrent; if(ferror<0) { ferror = -1.0F*ferror; } if(ferror0) break; } } return 0; } //====================================================================== // ReEnum: Causes the LabJack to detach and re-attach from the bus // so it will re-enumerate. Configuration constants (local ID, // power allowance, calibration data) are updated. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 10 ms //---------------------------------------------------------------------- long ReEnum( long *idnum) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } sendBuffer[6]=64; //Write data to the LabJack errorcode = WriteLabJack(localID,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // Reset: Causes the LabJack to reset after about 2 seconds. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 10 ms //---------------------------------------------------------------------- long Reset( long *idnum) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } sendBuffer[6]=95; //Write data to the LabJack errorcode = WriteLabJack(localID,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); gTrisD[localID]=65535; //referenced to PIC, 0=Output gTrisIO[localID]=15; //referenced to PIC, 0=Output gStateD[localID]=0; //output states gStateIO[localID]=0; //output states gAO0[localID]=0.0F; //current AO0 setting gAO1[localID]=0.0F; //current AO1 setting return errorcode; } //====================================================================== // ResetLJ: Same as "Reset". // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 10 ms //---------------------------------------------------------------------- long ResetLJ( long *idnum) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } sendBuffer[6]=95; //Write data to the LabJack errorcode = WriteLabJack(localID,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); gTrisD[localID]=65535; //referenced to PIC, 0=Output gTrisIO[localID]=15; //referenced to PIC, 0=Output gStateD[localID]=0; //output states gStateIO[localID]=0; //output states gAO0[localID]=0.0F; //current AO0 setting gAO1[localID]=0.0F; //current AO1 setting return errorcode; } //====================================================================== // SHT1X: This function retrieves temperature and/or humidity // readings from a SHT1X sensor. Data rate is about 2 kbps // with firmware V1.09 or higher (hardware communication). // If firmware is less than V1.09, or TRUE is passed for // softComm, data rate is about 20 bps. // // DATA = IO0 // SCK = IO1 // // The EI-1050 has an extra enable line that allows multiple // probes to be connected at the same time using only the one // line for DATA and one line for SCK. This function does not // control the enable line. // // This function automatically configures IO0 has an input // and IO1 as an output. // // Note that internally this function operates on the state and // direction of IO0 and IO1, and to operate on any of the IO // lines the LabJack must operate on all 4. The DLL keeps track // of the current direction and output state of all lines, so that // this function can operate on IO0 and IO1 without changing // IO2 and IO3. When the DLL is first loaded, // though, it does not know the direction and state of // the lines and assumes all directions are input and // output states are low. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // softComm -If >0, forces software based communication. Otherwise // software communication is only used if the LabJack U12 // firmware version is less than V1.09. // mode -0=temp and RH,1=temp only,2=RH only. If mode is 2, // the current temperature must be passed in for the // RH corrections using *tempC. // statusReg -Current value of the SHT1X status register. The // value of the status register is 0 unless you // have used advanced functions to write to the // status register (enabled heater, low resolution, or // no reload from OTP). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *tempC -Returns temperature in degrees C. If mode is 2, // the current temperature must be passed in for the // RH corrections. // *tempF -Returns temperature in degrees F. // *rh -Returns RH in percent. // // Time: About 20 ms plus SHT1X measurement time for hardware comm. // Default measurement time is 210 ms for temp and 55 ms for RH. // About 2 s per measurement for software comm. //---------------------------------------------------------------------- long SHT1X( long *idnum, long demo, long softComm, long mode, long statusReg, float *tempC, float *tempF, float *rh) { long errorcode=0; long localID; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unsigned char datatx[4]={0,0,0,0}; unsigned char datarx[4]={0,0,0,0}; unsigned char resettx[4]={30,0,0,0}; long serialnum=0; long numComms=0,maxNumComms=4; long needTemp=1,needRH=1; float sorh=0,rhlinear=0; long serialReset; if(demo) { Sleep(20); *tempC=25.0; *tempF=77.0; *rh=50.0; return errorcode; } //Open the specified or first found LabJack and call the asynch function localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Use software communication if requested or if firmware is < V1.09 softComm = softComm || (serialnum < 100012000); //first get temperature if requested if(mode<=1) { serialReset=0; //attempt to get reading until no error or too many retries while(needTemp && (numComms1))&&(errorcode==0)) { serialReset=0; //attempt to get reading until no error or too many retries while(needRH && (numComms<=maxNumComms)) { numComms++; datatx[0]=5; //RH measurement opcode errorcode=SHTWriteRead(localID,softComm,1,serialReset,0,1,3,datatx,datarx); if(errorcode) { if((errorcode==SHT1X_SERIAL_RESET_ERROR_LJ)||(errorcode==SHT1X_MEASREADY_ERROR_LJ)||(errorcode==SHT1X_ACK_ERROR_LJ)) { serialReset=1; needRH=1; } else { CloseAll(localID); return errorcode; } } else { errorcode=SHTCRC(statusReg,1,3,datatx,datarx); if(errorcode) { //Reset SHT1X. SHTWriteRead(localID,softComm,0,1,0,1,0,resettx,datarx); Sleep(12); //just to make sure //if statusReg was not the default, we need to reload it if(statusReg!=0) { datatx[0]=6; //write status opcode datatx[1]=(unsigned char)statusReg; SHTWriteRead(localID,softComm,0,1,0,2,0,datatx,datarx); } needRH=1; errorcode=SHT1X_CRC_ERROR_LJ; } else { sorh=(((float)datarx[0])*256.0F)+((float)datarx[1]); if(BitTst(statusReg,0)) { rhlinear=(-0.00072F*sorh*sorh)+(0.648F*sorh)-4.0F; *rh=((*tempC-25.0F)*(0.01F+(0.00128F*sorh)))+rhlinear; } else { rhlinear=(-0.0000028F*sorh*sorh)+(0.0405F*sorh)-4.0F; *rh=((*tempC-25.0F)*(0.01F+(0.00008F*sorh)))+rhlinear; } needRH=0; errorcode=0; } } // end else no SHTWriteRead error } // end while } else { *rh=9999.0F; } if(errorcode) { CloseAll(localID); } else { errorcode=CloseAll(localID); } return errorcode; } //====================================================================== // SHTWriteRead: Handles data communication with an SHT1X. //---------------------------------------------------------------------- long SHTWriteRead( long localID, long softComm, // >0 means bit-bang in software long waitMeas, // >0 means wait for measurement ready long serialReset, // >0 means start with a serialReset long dataRate, // 0=default,1=300us delay,2=1ms delay (hardware comm only) long numWrite, // 0-4 long numRead, // 0-4 unsigned char *datatx, //4 byte write array unsigned char *datarx) //4 byte read array { long errorcode=0,i=0,j=0; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long trisD,stateD,trisIO,stateIO; long numToggles,totToggles,DATA; if(softComm) { //Initialize local tris and state variables trisD=gTrisD[localID]; stateD=gStateD[localID]; trisIO=gTrisIO[localID]; stateIO=gStateIO[localID]; //sendBuffer never changes for D lines sendBuffer[1]=(unsigned char)(trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(stateD/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(stateD%256); //lower byte of stateD sendBuffer[6]=87; //DigitalIO function sendBuffer[7]=1; //update digital is true //Initialize DATA as input and SCK as output low trisIO=BitSet(trisIO,0); //In firmware, 0=Output and 1=Input stateIO=BitClr(stateIO,0); trisIO=BitClr(trisIO,1); //In firmware, 0=Output and 1=Input stateIO=BitClr(stateIO,1); sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; //Start with serial reset if enabled if(serialReset) { numToggles=10; totToggles=0; while(numToggles>0) { stateIO=BitSet(stateIO,1); //Set SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); //Read DATA DATA=BitTst(readBuffer[4],4); if(errorcode) return errorcode; stateIO=BitClr(stateIO,1); //Clear SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; if(!DATA) numToggles=11; numToggles--; totToggles++; if(totToggles>60) return SHT1X_SERIAL_RESET_ERROR_LJ; } } //Transaction start stateIO=BitSet(stateIO,1); //Set SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; trisIO=BitClr(trisIO,0); //DATA Low sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; stateIO=BitClr(stateIO,1); //Clear SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; stateIO=BitSet(stateIO,1); //Set SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; trisIO=BitSet(trisIO,0); //Release DATA sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; stateIO=BitClr(stateIO,1); //Clear SCK sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) return errorcode; //Write Bytes if(numWrite>0) { //Each byte for(i=0;i0) { //Each byte for(i=0;i0, forces software based communication. Otherwise // software communication is only used if the LabJack U12 // firmware version is less than V1.09. // waitMeas -If >0, this is a T or RH measurement request. // serialReset -If >0, a serial reset is issued before sending and // receiving bytes. // dataRate -0=no extra delay (default),1=medium delay,2=max delay. // numWrite -Number of bytes to write (0-4,I32). // numRead -Number of bytes to read (0-4,I32). // *datatx -Array of 0-4 bytes to send. Make sure you pass at least // numWrite number of bytes (U8). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *datarx -Returns 0-4 read bytes as determined by numRead (U8). // // Time: About 20 ms plus SHT1X measurement time for hardware comm. // Default measurement time is 210 ms for temp and 55 ms for RH. // About 2 s per measurement for software comm. //---------------------------------------------------------------------- long SHTComm( long *idnum, long softComm, long waitMeas, long serialReset, long dataRate, long numWrite, long numRead, unsigned char *datatx, unsigned char *datarx) { long errorcode=0; long localID; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Open the specified or first found LabJack and call the asynch function localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Used software communication if requested of if firmware is < V1.09 softComm = softComm || (serialnum < 100012000); //SHTWriteRead(localID,softComm,waitMeas,serialReset,dataRate,numWrite,numRead,*datatx,*datarx). errorcode=SHTWriteRead(localID,softComm,waitMeas,serialReset,dataRate,numWrite,numRead,datatx,datarx); if(errorcode) { CloseAll(localID); } else { errorcode=CloseAll(localID); } return errorcode; } //====================================================================== // Synch: Requires firmware V1.09 or higher. // // This function performs SPI communication. Data rate is // about 160 kbps with no extra delay, although delays of // 100 us or 1 ms per bit can be enabled. // // Control of CS (chip select) can be enabled in this // function for D0-D7 or handled externally via any digital // output. // // MOSI is D13 // MISO is D14 // SCK is D15 // // If using the CB25, the protection resistors might need to be // shorted on all SPI connections (MOSI,MISO,SCK,CS). // // The initial state of SCK is set properly (CPOL), by // this function, before !CS is brought low (final state is also // set properly before !CS is brought high again). If chip-select // is being handled manually, outside of this function, care // must be taken to make sure SCK is initially set to CPOL. // // All modes supported (A, B, C, and D). // // Mode A: CPHA=1, CPOL=1 // Mode B: CPHA=1, CPOL=0 // Mode C: CPHA=0, CPOL=1 // Mode D: CPHA=0, CPOL=0 // // If Clock Phase (CPHA) is 1, data is valid on the edge // going to CPOL. If CPHA is 0, data is valid on the edge // going away from CPOL. // Clock Polarity (CPOL) determines the idle state of SCK. // // Up to 18 bytes can be written/read. Communication is full // duplex so 1 byte is read at the same time each byte is written. // If more than 4 bytes are written or read, this function uses // calls to WriteMem/ReadMem to load/read the LabJack's data buffer. // // This function has the option (configD) to automatically configure // default state and direction for MOSI (D13 Output), MISO (D14 Input), // SCK (D15 Output CPOL), and CS (D0-D7 Output High for !CS). This // function uses a call to DigitalIO to do this. Similar to // EDigitalIn and EDigitalOut, the DLL keeps track of the current // direction and output state of all lines, so that these 4 D lines // can be configured without affecting other digital lines. When the // DLL is first loaded, though, it does not know the direction and // state of the lines and assumes all directions are input and // output states are low. // // Note that this is a simplified version of the lower // level function DigitalIO, which operates on all 20 // digital lines. The DLL keeps track of the current // direction and output state of all lines, so that this // easy function can operate on a single line without // changing the others. When the DLL is first loaded, // though, it does not know the direction and state of // the lines and assumes all directions are input and // output states are low. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // mode -Specify SPI mode as: 0=A,1=B,2=C,3=D (I32, 0-3). // msDelay -If >0, a 1 ms delay is added between each bit. // husDelay -If >0, a hundred us delay is added between each bit. // controlCS -If >0, D0-D7 is automatically controlled as CS. The // state and direction of CS is only tested if control // is enabled. // csLine -D line to use as CS if enabled (I32, 0-7). // csState -Active state for CS line. This would be 0 for the // normal !CS, or >0 for the less common CS. // configD -If >0, state and tris are configured for D13, D14, // D15, and !CS. // numWriteRead -Number of bytes to write and read (I32, 1-18). // *data -Serial data buffer. Send an 18 element // array of bytes. Fill unused locations with zeros (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *data -Serial data buffer. Returns any serial read // data. Unused locations are filled // with 9999s. (I32). // // Time: 20 ms to read & write up to 4 bytes, plus 40 ms for each // additional 4 bytes to read or write. Extra 20 ms if configD // is true. Extra time if delays are enabled. //---------------------------------------------------------------------- long Synch( long *idnum, long demo, long mode, long msDelay, long husDelay, long controlCS, long csLine, long csState, long configD, long numWriteRead, long *data) { long errorcode=0,result=0,i=0,j=0; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0,numPackets=0,memAddress=0,numFill=0; long trisD=0,trisIO=0,stateD=0,stateIO=0; //Make sure each input is within the proper range if ((mode<0) || (mode>3)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((numWriteRead<1) || (numWriteRead>18)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((csLine<0) || (csLine>7)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } for(i=0;i<18;i++) { if(i >= numWriteRead) { if(data[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } } else { if((data[i]<0)||(data[i]>255)) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } } } //If we are writing more than 4 bytes, put them in the LabJack's NVRAM buffer. numPackets = 0; if(numWriteRead>4) { numPackets = (numWriteRead-1)/4; for(i=0;i= numWriteRead) { data[i]=9999; } } result = CloseAll(localID); if(result) return result; } else //demo { Sleep(20); } //If we are reading more than 4 bytes, get them from the LabJack's NVRAM buffer. numPackets = 0; if(numWriteRead>4) { numPackets = (numWriteRead-1)/4; numFill = 4-(numWriteRead%4); for(i=0;i0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // active -Enables the LabJack watchdog function. If // enabled, the 32-bit counter is disabled. // timeout -Timer reset value in seconds (I32). // reset -If >0, the LabJack will reset on timeout (I32). // activeDn -If >0, Dn will be set to stateDn upon // timeout (I32). // stateDn -Timeout state of Dn, 0=low, >0=high (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 20 ms //---------------------------------------------------------------------- long Watchdog( long *idnum, long demo, long active, long timeout, long reset, long activeD0, long activeD1, long activeD8, long stateD0, long stateD1, long stateD8) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Make sure inputs are valid if ((timeout<1) || (timeout>715)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[5]=0; if(active) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],0); } if(reset) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],1); } if(activeD0) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],7); } if(activeD1) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],5); } if(activeD8) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],3); } if(stateD0) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],6); } if(stateD1) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],4); } if(stateD8) { //set bit sendBuffer[5] = BitSet(sendBuffer[5],2); } sendBuffer[6]=83; timeout *= (6000000/65536); sendBuffer[7]=(unsigned char)(timeout/256); sendBuffer[8]=(unsigned char)(timeout%256); sendBuffer[1]=0; //clear the "ignore commands" bit //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Parse the response if(sendBuffer[5] != readBuffer[5]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(readBuffer[6] != 83) { errorcode=RESPONSE_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[7] != readBuffer[7]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[8] != readBuffer[8]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // Counter: Controls and reads the counter. The counter is disabled if // the watchdog timer is enabled. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // resetCounter -If >0, the counter is reset to zero after // being read (I32). // enableSTB -If >0, STB is enabled (I32). Only works with // firmware V1.02 or later. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *stateD -States of D0-D15 (I32). // *stateIO -States of IO0-IO3 (I32). // *count -Current count, before reset (U32). // // Time: 20 ms //---------------------------------------------------------------------- long Counter( long *idnum, long demo, long *stateD, long *stateIO, long resetCounter, long enableSTB, unsigned long *count) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); *count=GetTickCount(); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *stateD=0; *stateIO=0; *count=0; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[6]=82; sendBuffer[1]=0; if(resetCounter) { sendBuffer[1] = BitSet(sendBuffer[1],0); //set bit } if(enableSTB) { sendBuffer[1] = BitSet(sendBuffer[1],1); //set bit } //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *stateD=0; *stateIO=0; *count=0; CloseAll(localID); return errorcode; } //Parse the response errorcode = ParseAOResponse(readBuffer,stateD,stateIO,count); if(errorcode) { *stateD=0; *stateIO=0; *count=0; CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // DigitalIO: Reads and writes to the digital I/O. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function to // be called without a LabJack, and does little but // simulate execution time. // *trisD -Directions for D0-D15. 0=Input, 1=Output (I32). // trisIO -Directions for IO0-IO3. 0=Input, 1=Output (I32). // *stateD -Output states for D0-D15 (I32). // *stateIO -Output states for IO0-IO3 (I32). // updateDigital -If >0, tris and state values will be written. // Otherwise, just a read is performed (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *trisD -Returns a read of the direction registers // for D0-D15 (I32). // *stateD -States of D0-D15 (I32). // *stateIO -States of IO0-IO3 (I32). // *outputD -Returns a read of the output registers // for D0-D15 (I32). // // Time: 20 ms //---------------------------------------------------------------------- long DigitalIO( long *idnum, long demo, long *trisD, long trisIO, long *stateD, long *stateIO, long updateDigital, long *outputD) { long errorcode; int i; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Firmware expects 1=true=input and 0=false=output, but we want //input to be the more natural default, so flip all the bits here //in the LabJack driver so that 0=input and 1=output at //the application layer. for(i=0;i<16;i++) { *trisD=BitFlp(*trisD,i); } for(i=0;i<4;i++) { trisIO=BitFlp(trisIO,i); } //Make sure each DIO input is within the proper range if ((*trisD<0) || (*trisD>65535)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((trisIO<0) || (trisIO>15)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((*stateD<0) || (*stateD>65535)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((*stateIO<0) || (*stateIO>15)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *trisD=0; *stateD=0; *stateIO=0; *outputD=0; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[1]=(unsigned char)(*trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(*trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(*stateD/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(*stateD%256); //lower byte of stateD sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)*stateIO); sendBuffer[6]=87; sendBuffer[7]=0; if(updateDigital) { sendBuffer[7] = BitSet(sendBuffer[7],0); //set bit 0 } //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *trisD=0; *stateD=0; *stateIO=0; *outputD=0; CloseAll(localID); return errorcode; } //Update tris and state globals with current output values if(updateDigital) { gTrisD[localID]=*trisD; gTrisIO[localID]=trisIO; gStateD[localID]=*stateD; gStateIO[localID]=*stateIO; } //Parse the response if (!((readBuffer[1]==87)||(readBuffer[1]==119))) { errorcode=RESPONSE_ERROR_LJ; } *stateD = ((long)readBuffer[2]) * 256; *stateD += ((long)readBuffer[3]); *stateIO = ((long)readBuffer[4]) / 16; *trisD = ((long)readBuffer[5]) * 256; *trisD += ((long)readBuffer[6]); for(i=0;i<16;i++) { *trisD=BitFlp(*trisD,i); } *outputD = ((long)readBuffer[7]) * 256; *outputD += ((long)readBuffer[8]); errorcode = CloseAll(localID); return errorcode; } //====================================================================== // BitsToVolts: Converts a 12-bit (0-4095) binary value into a LabJack // voltage. Volts=((2*Bits*Vmax/4096)-Vmax)/Gain where // Vmax=10 for SE, 20 for Diff. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: chnum -Channel index. 0-7=SE, 8-11=Diff (I32). // chgain -Gain index. 0=1,1=2,...,7=20 (I32). // bits -Binary value from 0-4095 (I32). // Outputs: *volts -Voltage. SE=+/-10, Diff=+/-20 (SGL). //---------------------------------------------------------------------- long BitsToVolts( long chnum, long chgain, long bits, float *volts) { long errorcode=NO_ERROR_LJ; float gain; if((chnum<0) || (chnum>15)) { errorcode = ILLEGAL_CHANNEL_LJ; *volts = 9999.0; return errorcode; } if((chgain<0) || (chgain>7)) { errorcode = ILLEGAL_GAIN_INDEX_LJ; *volts = 9999.0; return errorcode; } if((bits<0) || (bits>4095)) { errorcode = BITS_OUT_OF_RANGE_LJ; *volts = 9999.0; return errorcode; } switch(chgain) { case 0: gain = 1.0F; break; case 1: gain = 2.0F; break; case 2: gain = 4.0F; break; case 3: gain = 5.0F; break; case 4: gain = 8.0F; break; case 5: gain = 10.0F; break; case 6: gain = 16.0F; break; case 7: gain = 20.0F; break; default: errorcode=UNKNOWN_ERROR_LJ; return errorcode; } if (chnum<8) { //single-ended *volts = ((float)bits * 20.0F / 4096.0F) - 10.0F; } else { //differential *volts = (((float)bits * 40.0F / 4096.0F) - 20.0F) / gain; } return errorcode; } //====================================================================== //VoltsToBits: Converts a voltage to it's 12-bit (0-4095) binary // representation. Bits=(4096*((Volts*Gain)+Vmax))/(2*Vmax) // where Vmax=10 for SE, 20 for Diff. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: chnum -Channel index. 0-7=SE, 8-11=Diff (I32). // chgain -Gain index. 0=1,1=2,...,7=20 (I32). // volts -Voltage. SE=+/-10, Diff=+/-20 (SGL). // Outputs: *bits -Binary value from 0-4095 (I32). //---------------------------------------------------------------------- long VoltsToBits( long chnum, long chgain, float volts, long *bits) { long errorcode=NO_ERROR_LJ; float gain; if((chnum<0) || (chnum>15)) { errorcode = ILLEGAL_CHANNEL_LJ; *bits = 9999; return errorcode; } if((chgain<0) || (chgain>7)) { errorcode = ILLEGAL_GAIN_INDEX_LJ; *bits = 9999; return errorcode; } if(chnum<8) { if(volts<-10.0F) volts=-10.0F; if(volts>((4095.0F*20.0F/4096.0F)-10.0F)) volts=(4095.0F*20.0F/4096.0F)-10.0F; } else { if(volts<-20.0F) volts=-20.0F; if(volts>((4095.0F*40.0F/4096.0F)-20.0F)) volts=(4095.0F*40.0F/4096.0F)-20.0F; } switch(chgain) { case 0: gain = 1.0F; break; case 1: gain = 2.0F; break; case 2: gain = 4.0F; break; case 3: gain = 5.0F; break; case 4: gain = 8.0F; break; case 5: gain = 10.0F; break; case 6: gain = 16.0F; break; case 7: gain = 20.0F; break; default: errorcode=UNKNOWN_ERROR_LJ; return errorcode; } if (chnum<8) { //single-ended *bits = RoundFL((volts+10.0F)/(20.0F/4096.0F)); } else { //differential *bits = RoundFL(((volts*gain)+20.0F)/(40.0F/4096.0F)); } return errorcode; } //====================================================================== // ReadMem: Reads 4 bytes from a specified address in the LabJack's // nonvolatile memory. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // address -Starting address of data to read // from 0-8188 (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *data3 -Byte at address (I32). // *data2 -Byte at address+1 (I32). // *data1 -Byte at address+2 (I32). // *data0 -Byte at address+3 (I32). // // Time: 20 ms //---------------------------------------------------------------------- long ReadMem( long *idnum, long address, long *data3, long *data2, long *data1, long *data0) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Make sure inputs are valid if ((address<0) || (address>8188)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[6]=80; sendBuffer[7]=(unsigned char)(address/256); sendBuffer[8]=(unsigned char)(address%256); //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Parse the response if(readBuffer[1] != 80) { errorcode=RESPONSE_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[7] != readBuffer[7]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[8] != readBuffer[8]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } *data3 = readBuffer[2]; *data2 = readBuffer[3]; *data1 = readBuffer[4]; *data0 = readBuffer[5]; errorcode = CloseAll(localID); return errorcode; } //====================================================================== // WriteMem: Writes 4 bytes to the LabJack's nonvolatile memory at a // specified address. The data is read back and verified // after the write. Memory 0-511 is used for configuration // and calibration data. Memory from 512-1023 is unused by the // the LabJack and available for the user (this corresponds to // starting addresses from 512-1020). Memory 1024-8191 is // used as a data buffer in hardware timed AI modes. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // unlocked -If >0, addresses 0-511 are unlocked for // writing (I32). // address -Starting address for writing 0-8188 (I32). // data3 -Byte for address (I32). // data2 -Byte for address+1 (I32). // data1 -Byte for address+2 (I32). // data0 -Byte for address+3 (I32). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // // Time: 20 ms //---------------------------------------------------------------------- long WriteMem( long *idnum, long unlocked, long address, long data3, long data2, long data1, long data0) { long errorcode; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Make sure inputs are valid if(unlocked) { if ((address<0) || (address>8188)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } } else { if ((address<512) || (address>8188)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } } if ((data3<0) || (data3>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((data2<0) || (data2>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((data1<0) || (data1>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if ((data0<0) || (data0>255)) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } //Fill sendBuffer with the proper values. sendBuffer[6]=81; sendBuffer[7]=(unsigned char)(address/256); sendBuffer[8]=(unsigned char)(address%256); sendBuffer[1]=((unsigned char)data3); sendBuffer[2]=((unsigned char)data2); sendBuffer[3]=((unsigned char)data1); sendBuffer[4]=((unsigned char)data0); //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Parse the response if(readBuffer[1] != 81) { errorcode=RESPONSE_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[1] != readBuffer[2]) { errorcode=DATA_ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[2] != readBuffer[3]) { errorcode=DATA_ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[3] != readBuffer[4]) { errorcode=DATA_ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[4] != readBuffer[5]) { errorcode=DATA_ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[7] != readBuffer[7]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } if(sendBuffer[8] != readBuffer[8]) { errorcode=ECHO_ERROR_LJ; CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // AOUpdate: Sets the voltages of the analog outputs. Also // controls/reads the digital IO and counter. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does little // but simulate execution time. // trisD -Directions for D0-D16. 0=Input, 1=Output (I32). // trisIO -Directions for IO0-IO3. 0=Input, 1=Output (I32). // *stateD -Output states for D0-D16 (I32). // *stateIO -Output states for IO0-IO3 (I32). // updateDigital -If >0, tris and state values will be written. // Otherwise, just a read is performed (I32). // resetCounter -If >0, the counter is reset to zero after // being read (I32). // analogOut0 -Voltage from 0 to 5 for AO0 (SGL). // analogOut1 -Voltage from 0 to 5 for AO1 (SGL). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *stateD -States of D0-D15 (I32). // *stateIO -States of IO0-IO3 (I32). // *count -Current count, before reset (U32). // // Time: 20 ms //---------------------------------------------------------------------- long AOUpdate( long *idnum, long demo, long trisD, long trisIO, long *stateD, long *stateIO, long updateDigital, long resetCounter, unsigned long *count, float analogOut0, float analogOut1) { long errorcode,i; long localID; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long serialnum=0; //Do demo here if(demo) { Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); *count=GetTickCount(); return NO_ERROR_LJ; } //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *stateD=0; *stateIO=0; *count=0; return errorcode; } if(analogOut0<0) { analogOut0=gAO0[localID]; } if(analogOut1<0) { analogOut1=gAO1[localID]; } //Fill sendBuffer with the proper values. errorcode = BuildAOCommand(trisD,trisIO,*stateD,*stateIO,updateDigital,resetCounter,analogOut0,analogOut1,sendBuffer); if(errorcode) { *stateD=0; *stateIO=0; *count=0; CloseAll(localID); return errorcode; } //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *stateD=0; *stateIO=0; *count=0; CloseAll(localID); return errorcode; } //Update tris and state globals with current output values if(updateDigital) { //Global tris variables are referenced to PIC, so bits must be flipped. for(i=0;i<16;i++) { trisD=BitFlp(trisD,i); } for(i=0;i<4;i++) { trisIO=BitFlp(trisIO,i); } gTrisD[localID]=trisD; gTrisIO[localID]=trisIO; gStateD[localID]=*stateD; gStateIO[localID]=*stateIO; } gAO0[localID]=analogOut0; gAO1[localID]=analogOut1; //Parse the response errorcode = ParseAOResponse(readBuffer,stateD,stateIO,count); if(errorcode) { *stateD=0; *stateIO=0; *count=0; CloseAll(localID); return errorcode; } errorcode = CloseAll(localID); return errorcode; } //====================================================================== // AISample: Reads the voltages from 1,2, or 4 analog inputs. Also // controls/reads the 4 IO ports. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does // little but simulate execution time. // *stateIO -Output states for IO0-IO3 (I32). // updateIO -If >0, state values will be written. Otherwise, // just a read is performed (I32). // ledOn -If >0, the LabJack LED is turned on (I32). // numChannels -Number of channels. 1, 2, or 4 (I32). // *channels -Pointer to an array of channel commands with // at least numChannels elements (I32). Each // channel command is 0-7 for SE or 8-11 for Diff. // *gains -Pointer to an array of gain commands with at // least numChannels elements (I32). Gain commands // are 0=1,1=2,...,7=20. Gain only available for // differential channels. // disableCal -If >0, voltages returned will be raw readings // that are not corrected using calibration // constants (I32). // *voltages -Voltage readings buffer. Send a 4 element // array of zeros (SGL). // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *overVoltage -If >0, an overvoltage has been detected // on one of the analog inputs (I32). // *voltages -Returns numChannels voltage readings (SGL). // // Time: 20 ms //---------------------------------------------------------------------- long AISample( long *idnum, long demo, long *stateIO, long updateIO, long ledOn, long numChannels, long *channels, long *gains, long disableCal, long *overVoltage, float *voltages) { long errorcode; long localID=0; float avgVolts; long avgBits; unsigned char echoOut,echoIn; unsigned char sendBuff5=0; long i,junk=0; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain; long serialnum=0; //Make sure array is filled with zeros for(i=0;i<4;i++) { if(voltages[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } voltages[i] = 9999.0F; } //Make sure inputs are valid if (!((numChannels==1)||(numChannels==2)||(numChannels==4))) { errorcode=ILLEGAL_NUMBER_OF_CHANNELS_LJ; *idnum=-1; *stateIO=0; *overVoltage=0; return errorcode; } if(!demo) { //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; *stateIO=0; *overVoltage=0; return errorcode; } } //The LabJack echos 1 byte so we can make sure we are getting the expected response echoOut = (unsigned char)GetTickCount(); if(ledOn) { //set bit 0 to turn the LED on sendBuff5 = BitSet(sendBuff5,0); } if(updateIO) { //set bit 1 to indicate update IO sendBuff5 = BitSet(sendBuff5,1); } //Fill sendBuffer with the proper values. ch1num=channels[0]; ch2num=channels[0]; ch3num=channels[0]; ch4num=channels[0]; ch1gain=gains[0]; ch2gain=gains[0]; ch3gain=gains[0]; ch4gain=gains[0]; if(numChannels==2) { ch3num=channels[1]; ch4num=channels[1]; ch3gain=gains[1]; ch4gain=gains[1]; } if(numChannels==4) { ch2num=channels[1]; ch3num=channels[2]; ch4num=channels[3]; ch2gain=gains[1]; ch3gain=gains[2]; ch4gain=gains[3]; } errorcode = BuildAICommand(12,sendBuff5,0,echoOut,*stateIO,ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain,sendBuffer); if(errorcode) { *stateIO=0; *overVoltage=0; CloseAll(localID); return errorcode; } if(!demo) { //Write & Read data to/from the LabJack errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); if(errorcode) { *stateIO=0; *overVoltage=0; CloseAll(localID); return errorcode; } //Update state IO global with current output values if(updateIO) { gStateIO[localID]=*stateIO; } //Parse the response errorcode = ParseAIResponse(sendBuffer,readBuffer,disableCal,calData,stateIO,overVoltage,&voltages[0],&voltages[1],&voltages[2],&voltages[3],&echoIn,&junk,&junk,&junk,0); if(errorcode) { *stateIO=0; *overVoltage=0; for(i=0;i<4;i++) { voltages[i]=0; } CloseAll(localID); return errorcode; } if(echoOut != echoIn) { errorcode=ECHO_ERROR_LJ; *stateIO=0; *overVoltage=0; for(i=0;i<4;i++) { voltages[i]=0; } CloseAll(localID); return errorcode; } } else { //Demo Mode Sleep(14+((long)(6.0F * (float)rand()/(float)RAND_MAX))); voltages[0]=2.5F; voltages[1]=2.5F; voltages[2]=2.5F; voltages[3]=2.5F; if(numChannels == 2) { voltages[2] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F; voltages[3] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F; } if(numChannels == 4) { voltages[1]=-2.5F; voltages[2]=(10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F; voltages[3]=(10.0F * ((float)(GetTickCount()%2048))/2048) - 5.0F; } } if(numChannels == 1) { avgVolts = (voltages[0]+voltages[1]+voltages[2]+voltages[3])/4.0F; errorcode = VoltsToBits(ch1num,ch1gain,avgVolts,&avgBits); errorcode = BitsToVolts(ch1num,ch1gain,avgBits,&voltages[0]); voltages[1]=9999.0F; voltages[2]=9999.0F; voltages[3]=9999.0F; } if(numChannels == 2) { avgVolts = (voltages[0]+voltages[1])/2.0F; errorcode = VoltsToBits(ch1num,ch1gain,avgVolts,&avgBits); errorcode = BitsToVolts(ch1num,ch1gain,avgBits,&voltages[0]); avgVolts = (voltages[2]+voltages[3])/2.0F; errorcode = VoltsToBits(ch3num,ch3gain,avgVolts,&avgBits); errorcode = BitsToVolts(ch3num,ch3gain,avgBits,&voltages[1]); voltages[2]=9999.0F; voltages[3]=9999.0F; } if(!demo) { errorcode = CloseAll(localID); } return errorcode; } //====================================================================== // AIBurst: Reads a certain number of scans at a certain scan rate // from 1,2, or 4 analog inputs. First, data is acquired and // stored in the LabJacks 4096 sample RAM buffer. Then, the // data is transferred to the PC application. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does little // but simulate execution time. // stateIOin -Output states for IO0-IO3 (I32). // updateIO -If >0, state values will be written. Otherwise, // just reads are performed (I32). // ledOn -If >0, the LabJack LED is turned on (I32). // numChannels -Number of channels. 1, 2, or 4 (I32). // *channels -Pointer to an array of channel commands with at // least numChannels elements (I32). Each channel // command is 0-7 for SE or 8-11 for Diff. // *gains -Pointer to an array of gain commands with at // least numChannels elements (I32). Gain // commands are 0=1,1=2,...,7=20. Gain only // available for differential channels. // *scanRate -Scans acquired per second (SGL). A scan is a // reading from every channel (1,2, or 4). The // sample rate (scanRate*numChannels) must // be 400-8192. // disableCal -If >0, voltages returned will be raw readings // that are not corrected using calibration // constants (I32). // triggerIO -Set the IO port to trigger on. 0=none, // 1=IO0, or 2=IO1 (I32). // triggerState -If >0, the acquisition will be triggered // when the selected IO port reads high (I32). // numScans -Number of scans which will be collected (I32). // Minimum is 1. Maximum numSamples is 4096 where // numSamples is numScans * numChannels. // timeout -Function timeout value in seconds (I32). Note // that if timeout is >= 4, the transferMode // is automatically set to normal. // *voltages -Voltage readings buffer. Send a 4096 by 4 // element array of zeros (SGL). // *stateIOout -IO state readings buffer. Send a 4096 element // array of zeros (I32). // transferMode -0=auto,1=normal,2=turbo (I32). If auto, // turbo mode is used unless timeout is >= 4, // or numScans/scanRate >=4. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *scanRate -Returns the actual scan rate, which due to // clock resolution is not always exactly the // same as the desired scan rate (SGL). // *voltages -Voltage readings are returned in this 4096 by // 4 array (SGL). Unused locations are filled // with 9999s. // *stateIOout -The states of all 4 IO are returned in this // array (I32). Unused locations are filled // with 9999s. // *overVoltage -If >0, an overvoltage has been detected on // at least one sample of at least one of the // analog inputs (I32). // // Time: The execution time of this function, in milliseconds, can be // estimated with the below formulas. The actual number of samples // collected and transferred by the LabJack is the smallest power // of 2 from 64 to 4096 which is at least as big as numScans*numChannels. // This is represented below as numSamplesActual. // Normal => 30+(1000*numSamplesActual/sampleRate)+(2.5*numSamplesActual) // Turbo => 30+(1000*numSamplesActual/sampleRate)+(0.4*numSamplesActual) //---------------------------------------------------------------------- long AIBurst( long *idnum, long demo, long stateIOin, long updateIO, long ledOn, long numChannels, long *channels, long *gains, float *scanRate, long disableCal, long triggerIO, long triggerState, long numScans, long timeout, float (*voltages)[4], long *stateIOout, long *overVoltage, long transferMode) { long errorcode; int i,j,k,l; long junk=0; long ovtemp; long csError,iterationCount,previousCount; unsigned char junkuc=0; long localID=0; long turbo = false; long sampleInt; long numScansLJ,numScansIndexLJ; unsigned char sendBuff5,sendBuff7,sendBuff8; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unsigned char featureBuff[129]={0}; long ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain; long serialnum=0; //junk variables for warm-up call to AISample long sio=0,chns[4]={0,0,0,0},gns[4]={0,0,0,0},ovlt=0; float vlts[4]={0,0,0,0}; //Make sure arrays are filled with zeros for(i=0;i<4096;i++) { if(stateIOout[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } stateIOout[i] = 9999; } for(i=0;i<4096;i++) { for(j=0;j<4;j++) { if(voltages[i][j] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } voltages[i][j] = 9999.0F; } } //Make sure inputs are valid if (timeout<1) { errorcode=ILLEGAL_INPUT_ERROR_LJ; *idnum=-1; return errorcode; } if (!((numChannels==1)||(numChannels==2)||(numChannels==4))) { errorcode=ILLEGAL_NUMBER_OF_CHANNELS_LJ; return errorcode; } if ((numScans<1) || ((numScans*numChannels)>4096)) { errorcode=ILLEGAL_NUM_SCANS_LJ; return errorcode; } switch(transferMode) { //auto case 0: if(timeout>=4) //Turbo mode does not work with a timeout over 4. { turbo = false; } else { if((((float)numScans)/(*scanRate)) >=4.0) { turbo = false; } else { turbo = true; } } break; //normal case 1: turbo = false; break; //turbo case 2: turbo = true; break; default: return ILLEGAL_INPUT_ERROR_LJ; } //Determine how many LabJack 4-channel scans are required (1024,512,256,128,64,32,16). numScansIndexLJ=0; numScansLJ=1024; if((numScans*numChannels)<=2048) { numScansIndexLJ=1; numScansLJ=512; if((numScans*numChannels)<=1024) { numScansIndexLJ=2; numScansLJ=256; if((numScans*numChannels)<=512) { numScansIndexLJ=3; numScansLJ=128; if((numScans*numChannels)<=256) { numScansIndexLJ=4; numScansLJ=64; if((numScans*numChannels)<=128) { numScansIndexLJ=5; numScansLJ=32; if((numScans*numChannels)<=64) { numScansIndexLJ=6; numScansLJ=16; } } } } } } sampleInt = RoundFL(6000000.0F/(*scanRate * (float)numChannels)); //sampleInt must be >= 733 if(sampleInt == 732) sampleInt = 733; if ((sampleInt<733) || (sampleInt>16383)) { errorcode=ILLEGAL_SCAN_RATE_LJ; return errorcode; } *scanRate = 6000000.0F/((float)(sampleInt * numChannels)); if(!demo) { //Make a warm-up call to AISample to flush and init the host read buffer. errorcode = AISample(idnum,0,&sio,0,ledOn,4,chns,gns,0,&ovlt,vlts); if(errorcode) return errorcode; //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; return errorcode; } } //Build sendBuff5 switch(triggerIO) { case 0: sendBuff5=0; sendBuff7=0; break; case 1: sendBuff5=0; sendBuff7=64; break; case 2: sendBuff5=8; sendBuff7=64; break; default: errorcode=ILLEGAL_AI_COMMAND_LJ; CloseAll(localID); return errorcode; } if(triggerState) { //set bit 2 sendBuff5 = BitSet(sendBuff5,2); } if(ledOn) { //set bit 0 to turn the LED on sendBuff5 = BitSet(sendBuff5,0); } if(updateIO) { //set bit 1 to indicate update IO sendBuff5 = BitSet(sendBuff5,1); } sendBuff5 += (unsigned char)(numScansIndexLJ*32); //sendBuff5 is ready if(turbo) { //set bit 7 to indicate turbo mode (feature reports) sendBuff7 = BitSet(sendBuff7,7); } sendBuff7 += sampleInt/256; //sendBuff7 is ready sendBuff8 = sampleInt%256; //sendBuff8 is ready //Fill sendBuffer with the proper values. ch1num=channels[0]; ch2num=channels[0]; ch3num=channels[0]; ch4num=channels[0]; ch1gain=gains[0]; ch2gain=gains[0]; ch3gain=gains[0]; ch4gain=gains[0]; if(numChannels==2) { ch2num=channels[1]; ch4num=channels[1]; ch2gain=gains[1]; ch4gain=gains[1]; } if(numChannels==4) { ch2num=channels[1]; ch3num=channels[2]; ch4num=channels[3]; ch2gain=gains[1]; ch3gain=gains[2]; ch4gain=gains[3]; } errorcode = BuildAICommand(10,sendBuff5,sendBuff7,sendBuff8,stateIOin,ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } //Write command to LabJack to start burst mode if(!demo) { errorcode=WriteLabJack(localID,sendBuffer); if(errorcode) { CloseAll(localID); return errorcode; } } if(!demo) { //Don't issue a read command until after data is aquired Sleep(2+((unsigned long)(1000*((float)numScansLJ)/(*scanRate * numChannels)))); previousCount = 6; *overVoltage = 0; if(turbo) { //use control transfers (feature reports) //read 16 scans at a time for(i=0;i<(numScansLJ/16);i++) { //Read the feature report Sleep(1); //delay 1ms between feature report requests errorcode = ReadLabJack(localID,(((unsigned long)timeout)*1000),1,featureBuff); if(errorcode) { //read error CloseAll(localID); return errorcode; } for(k=0;k<16;k++) { //Put each scan in readBuffer readBuffer[0]=0; for(l=0;l<8;l++) { readBuffer[l+1]=featureBuff[(k*8)+l+1]; } //Parse each scan errorcode = ParseAIResponse(sendBuffer,readBuffer,disableCal,calData,&stateIOout[(i*16)+k],&ovtemp,&voltages[(i*16)+k][0],&voltages[(i*16)+k][1],&voltages[(i*16)+k][2],&voltages[(i*16)+k][3],&junkuc,&csError,&junk,&iterationCount,0); if(ovtemp) *overVoltage += 1; if(errorcode) { CloseAll(localID); return errorcode; } if(csError) { CloseAll(localID); return RAM_CS_ERROR_LJ; } if(iterationCount==0) { if(previousCount != 6) { CloseAll(localID); return AI_SEQUENCE_ERROR_LJ; } } else { if(iterationCount != (previousCount+1)) { CloseAll(localID); return AI_SEQUENCE_ERROR_LJ; } } previousCount = iterationCount; } } } else { //use interrupt transfers for(i=0;i=0;i--) { voltages[i*4][0]=voltages[i][0]; stateIOout[i*4]=stateIOout[i]; stateIOout[(i*4)+1]=stateIOout[i]; stateIOout[(i*4)+2]=stateIOout[i]; stateIOout[(i*4)+3]=stateIOout[i]; } for(i=0;i<1024;i++) { voltages[(i*4)+1][0]=voltages[i][1]; voltages[(i*4)+2][0]=voltages[i][2]; voltages[(i*4)+3][0]=voltages[i][3]; voltages[i][1]=9999.0F; voltages[i][2]=9999.0F; voltages[i][3]=9999.0F; } } if(numChannels == 2) { for(i=1023;i>=0;i--) { voltages[i*2][0]=voltages[i][0]; voltages[i*2][1]=voltages[i][1]; stateIOout[i*2]=stateIOout[i]; stateIOout[(i*2)+1]=stateIOout[i]; } for(i=0;i<1024;i++) { voltages[(i*2)+1][0]=voltages[i][2]; voltages[(i*2)+1][1]=voltages[i][3]; voltages[i][2]=9999.0F; voltages[i][3]=9999.0F; } } //delete extra data for(i=((numScansLJ*4)/numChannels) - numScans;i>0;i--) { if(numChannels == 1) { voltages[(numScansLJ*4)-i][0]=9999.0F; stateIOout[(numScansLJ*4)-i]=9999; } if(numChannels == 2) { voltages[(numScansLJ*2)-i][0]=9999.0F; voltages[(numScansLJ*2)-i][1]=9999.0F; stateIOout[(numScansLJ*2)-i]=9999; } if(numChannels == 4) { voltages[numScansLJ-i][0]=9999.0F; voltages[numScansLJ-i][1]=9999.0F; voltages[numScansLJ-i][2]=9999.0F; voltages[numScansLJ-i][3]=9999.0F; stateIOout[numScansLJ-i]=9999; } } if(!demo) { errorcode = CloseAll(localID); } return errorcode; } //====================================================================== // AIStreamStart: Starts a hardware timed continuous acquisition where data // is sampled and stored in the LabJack RAM buffer, and // simultaneously transferred out of the RAM buffer to the // PC application. A call to this function should be // followed by periodic calls to AIStreamRead, and eventually // a call to AIStreamClear. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *idnum -Local ID, Serial Number, or -1 for first // found (I32). // demo -Send 0 for normal operation, >0 for demo // mode (I32). Demo mode allows this function // to be called without a LabJack, and does little // but simulate execution time. // stateIOin -Output states for IO0-IO3 (I32). // updateIO -If >0, state values will be written. Otherwise, // just reads are performed (I32). // ledOn -If >0, the LabJack LED is turned on (I32). // numChannels -Number of channels. 1, 2, or 4 (I32). If // readCount is >0, numChannels should be 4. // *channels -Pointer to an array of channel commands with at // least numChannels elements (I32). Each channel // command is 0-7 for SE or 8-11 for Diff. // *gains -Pointer to an array of gain commands with at // least numChannels elements (I32). Gain commands // are 0=1,1=2,...,7=20. Gain only available for // differential channels. // *scanRate -Scans acquired per second (SGL). A scan is a // reading from every channel (1,2, or 4). The // sample rate (scanRate*numChannels) must // be 200-1200. // disableCal -If >0, voltages returned will be raw readings // that are not corrected using calibration // constants (I32). // transferMode -0=auto,1=normal,2=turbo (I32) // readCount -If >0, the counter read is returned instead of // the 2nd, 3rd, and 4th channel (I32). 2nd // channel is bits 0-11, 3rd channel is bits // 12-23, and 4th channel is bits 24-31. // Only works with firmware V1.03 or higher. // Outputs: *idnum -Returns the Local ID or -1 if no LabJack is // found (I32). // *scanRate -Returns the actual scan rate, which due to clock // resolution is not always exactly the same as the // desired scan rate (SGL). //---------------------------------------------------------------------- long AIStreamStart( long *idnum, long demo, long stateIOin, long updateIO, long ledOn, long numChannels, long *channels, long *gains, float *scanRate, long disableCal, long reserved1, long readCount) { long errorcode=NO_ERROR_LJ; long sampleInt; long scanMult=1; long localID; long turbo = false; unsigned char sendBuff5; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain; float firmwareVersion; long serialnum=0; //junk variables for warm-up call to AISample long sio=0,chns[4]={0,0,0,0},gns[4]={0,0,0,0},ovlt=0; float vlts[4]={0,0,0,0}; //Make sure inputs are valid if (!((numChannels==1)||(numChannels==2)||(numChannels==4))) { errorcode=ILLEGAL_NUMBER_OF_CHANNELS_LJ; return errorcode; } if ((readCount>0)&&(numChannels!=4)) { errorcode=ILLEGAL_NUMBER_OF_CHANNELS_LJ; return errorcode; } if (((*scanRate * numChannels)<200) || ((*scanRate * numChannels)>1200)) { errorcode=ILLEGAL_SCAN_RATE_LJ; return errorcode; } switch(reserved1) { case 0: turbo = true; break; case 1: //turbo = false; return ILLEGAL_INPUT_ERROR_LJ; break; case 2: turbo = true; break; default: return ILLEGAL_INPUT_ERROR_LJ; } //Claim the stream info structure and see if it is available if(!isStreamInfoMutexInit) { //Initialize stream mutex if(pthread_mutex_init(&streamInfoMutex, NULL) != 0) { return CREATE_MUTEX_LJ; } else { isStreamInfoMutexInit = true; } } //Lock stream info mutex if(pthread_mutex_trylock(&streamInfoMutex) == 0) { if(streamInfo.localID == -1) { //Locked the mutex and streamInfo is available errorcode = NO_ERROR_LJ; } else { //Locked the mutex but streamInfo is in use pthread_mutex_unlock(&streamInfoMutex); return NUM_STREAMS_ERROR_LJ; } } //Problem locking mutex else { return CLAIM_DEVICE_LJ; } sampleInt = RoundFL(6000000.0F/(*scanRate * (float)numChannels * (float)scanMult)); *scanRate = 6000000.0F/((float)(sampleInt * numChannels * scanMult)); if(!demo) { if(readCount) { //Check that firmware is V1.03 or newer firmwareVersion = GetFirmwareVersion(idnum); if(firmwareVersion > 0.1) { if(GetFirmwareVersion(idnum) < 1.0290) { errorcode=WRONG_FIRMWARE_VERSION_LJ; pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } else { //GetFirmwareVersion returned an error errorcode = *idnum - GETFIRMWAREVERSION_ERROR_OFFSET_LJ; pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } else { //Make a warm-up call to AISample to flush and init the readBuffer. errorcode = AISample(idnum,0,&sio,0,ledOn,4,chns,gns,0,&ovlt,vlts); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } Sleep(1); //Open the specified or first found LabJack localID = OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,idnum,&serialnum,calData); if(errorcode) { *idnum=-1; pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } else { if((*idnum>=0)&&(*idnum<=255)) { localID = *idnum; } else { localID = (long)(255.0F * (((float)rand())/((float)RAND_MAX))); *idnum = localID; } } //Build sendBuff5 sendBuff5 = 0; if(turbo) { //set bit 7 sendBuff5 = BitSet(sendBuff5,7); } if(readCount) { //set bit 6 sendBuff5 = BitSet(sendBuff5,6); } if(ledOn) { //set bit 0 to turn the LED on sendBuff5 = BitSet(sendBuff5,0); } if(updateIO) { //set bit 1 to indicate update IO sendBuff5 = BitSet(sendBuff5,1); } //Fill sendBuffer with the proper values. ch1num=channels[0]; ch2num=channels[0]; ch3num=channels[0]; ch4num=channels[0]; ch1gain=gains[0]; ch2gain=gains[0]; ch3gain=gains[0]; ch4gain=gains[0]; if(numChannels==2) { ch2num=channels[1]; ch4num=channels[1]; ch2gain=gains[1]; ch4gain=gains[1]; } if((numChannels==4)&&(readCount<1)) { ch2num=channels[1]; ch3num=channels[2]; ch4num=channels[3]; ch2gain=gains[1]; ch3gain=gains[2]; ch4gain=gains[3]; } errorcode = BuildAICommand(9,sendBuff5,(unsigned char)(sampleInt/256),(unsigned char)(sampleInt%256),stateIOin,ch1num,ch2num,ch3num,ch4num,ch1gain,ch2gain,ch3gain,ch4gain,sendBuffer); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); if(!demo) { CloseAll(localID); } return errorcode; } //Write command to LabJack to start continuous acquisition if(!demo) { errorcode=WriteLabJack(localID,sendBuffer); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); CloseAll(localID); return errorcode; } } //Load the super-global streamInfo structure streamInfo.localID = localID; streamInfo.errorcode = 0; streamInfo.ch1num = ch1num; streamInfo.ch2num = ch2num; streamInfo.ch3num = ch3num; streamInfo.ch4num = ch4num; streamInfo.ch1gain = ch1gain; streamInfo.ch2gain = ch2gain; streamInfo.ch3gain = ch3gain; streamInfo.ch4gain = ch4gain; streamInfo.demo = demo; streamInfo.demoTick = GetTickCount(); streamInfo.scanCount = 0; streamInfo.disableCal = disableCal; streamInfo.numChannels = numChannels; streamInfo.scanMult = scanMult; streamInfo.scanRate = *scanRate; streamInfo.turbo = turbo; streamInfo.numScansBuff=0; streamInfo.previousCount=6; streamInfo.readCount=readCount; //Unlock stream info mutex if(pthread_mutex_unlock(&streamInfoMutex) != 0) { if(!demo) { CloseAll(localID); } return AI_STREAM_START_LJ; } if(!demo) { errorcode = CloseAll(localID); } return errorcode; } //====================================================================== // AIStreamRead: Waits for a specified number of scans to be available and // reads them. AIStreamStart should be called before this // function and AIStreamClear should be called when finished. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: localID -Send the local ID from AIStreamStart (I32). // numScans -Function will wait until this number of scans is // available (I32). Minimum is 1. Maximum // numSamples is 4096 where numSamples is // equal to numScans * numChannels. Internally, // this function gets data from the LabJack in // blocks of 64 samples, so it is recommended that // numSamples be at least 64. // timeout -Function timeout value in seconds (I32). // *voltages -Voltage readings buffer. Send a 4096 by 4 // element array of zeros (SGL). // *stateIOout -IO state readings buffer. Send a 4096 element // array of zeros (I32). // Outputs: *voltages -Voltage readings are returned in this 4096 by 4 // array (SGL). Unused locations are filled // with 9999s. // *stateIOout -The states of all 4 IO are returned in this // array (I32). Unused locations are filled // with 9999s. // *pcScanBacklog -Reserved for future use (I32). // *ljScanBacklog -Returns the scan backlog of the LabJack RAM // buffer (I32). // *overVoltage -If >0, an overvoltage has been detected on // at least one sample of at least one of the // analog inputs (I32). //---------------------------------------------------------------------- long AIStreamRead( long localID, long numScans, long timeout, float (*voltages)[4], long *stateIOout, long *reserved, long *ljScanBacklog, long *overVoltage) { long errorcode = NO_ERROR_LJ; long i,j,k,l,m; unsigned long currentTime; long numScansLJ; unsigned long initialTick; float v1=0,v2=0,v3=0,v4=0; long sio=0,ov=0; long bocsError=0,backlog=0; long currentCount=6; unsigned char junk=0; unsigned char sendBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char readBuffer[9]={0,0,0,0,0,0,0,0,0}; unsigned char featureBuff[129]={0}; long calData[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //float tempBuff[4096][7]={{0}}; //V1,(V2),(V3),(V4),stateIO,overvoltage,ljScanBacklog long junkid; long serialnum=0; float **tempBuff = malloc(4096 * sizeof(float *)); for(i = 0; i < 4096; i++) { tempBuff[i] = malloc(7 * sizeof(float)); } for(i = 0; i < 4096; i++) { for(j = 0; j < 7; j++) { tempBuff[i][j] = 0; } } initialTick = GetTickCount(); if(timeout<1) { errorcode=ILLEGAL_INPUT_ERROR_LJ; for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return errorcode; } if((localID<0) || (localID>255)) { errorcode=INVALID_ID_LJ; for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return errorcode; } //Make sure arrays are filled with zeros for(i=0;i<4096;i++) { if(stateIOout[i] != 0) { for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } stateIOout[i] = 9999; } for(i=0;i<4096;i++) { for(j=0;j<4;j++) { if(voltages[i][j] != 0) { for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } voltages[i][j] = 9999.0F; tempBuff[i][j] = 9999.0F; } } //Claim the stream info structure and see if it is available if(!isStreamInfoMutexInit) { //Initialize stream mutex if(pthread_mutex_init(&streamInfoMutex, NULL) != 0) { return CREATE_MUTEX_LJ; } else { isStreamInfoMutexInit = true; } } //Lock stream info mutex if(pthread_mutex_trylock(&streamInfoMutex) == 0) { if(streamInfo.localID == localID) { //Locked the mutex and has matching local ID errorcode = NO_ERROR_LJ; } else { //Wrong local ID errorcode = UNKNOWN_ERROR_LJ; if(streamInfo.localID == -1) { errorcode = streamInfo.errorcode; } pthread_mutex_unlock(&streamInfoMutex); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return NUM_STREAMS_ERROR_LJ; } } //Problem locking mutex else { for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return CLAIM_DEVICE_LJ; } //Claim device code removed here. //If we get here we successfully claimed streamInfo and localID matched //Make sure numScans is valid. if ((numScans<1) || ((numScans*streamInfo.numChannels)>4096)) { pthread_mutex_unlock(&streamInfoMutex); errorcode=ILLEGAL_NUM_SCANS_LJ; for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return errorcode; } //Determine if and how many scans we need from the LabJack if((numScans - streamInfo.numScansBuff) <= 0) { //There are enough scans already in the buffer *overVoltage=0; //Read data from streamBuff for(i=0;i= ((unsigned long)(timeout*1000))) { //timeout error pthread_mutex_unlock(&streamInfoMutex); AIStreamClear(localID); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return STREAM_READ_TIMEOUT_LJ; } else //proper time has elapsed without timeout { //maximum data transfer is 4x the scan rate while((GetTickCount()-initialTick)<((unsigned long)(250*4*((float)numScansLJ)/(streamInfo.scanRate*streamInfo.numChannels)))); streamInfo.demoTick += ((long)(1000*4*((float)numScansLJ)/(streamInfo.scanRate*streamInfo.numChannels))); *ljScanBacklog = numScansLJ * ((GetTickCount()-streamInfo.demoTick)/((long)(1000*4*((float)numScans)/(streamInfo.scanRate*streamInfo.numChannels)))); if(((*ljScanBacklog * streamInfo.numChannels)/4) >= 1024) { //LabJack buffer overflow pthread_mutex_unlock(&streamInfoMutex); AIStreamClear(localID); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return LJ_BUFF_OVERFLOW_LJ; } } } else //not demo { //Open the LabJack junkid = localID; OpenLabJack(&errorcode,LABJACK_VENDOR_ID,LABJACK_U12_PRODUCT_ID,&junkid,&serialnum,calData); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return errorcode; } //Read the data for(i=0;i((unsigned long)(timeout*1000))) { pthread_mutex_unlock(&streamInfoMutex); CloseAll(localID); AIStreamClear(localID); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return STREAM_READ_TIMEOUT_LJ; } } //end for each 16-scan feature report //Close the LabJack errorcode = CloseAll(localID); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); for(m = 0; m < 4096; m++) { free(tempBuff[m]); } free(tempBuff); return errorcode; } } //end else not demo //We now have the required scans in tempBuff. Take what we //need and put the rest in streamBuff for next time. *overVoltage=0; //Read data from streamBuff first for(i=0;i255)) { errorcode=INVALID_ID_LJ; return errorcode; } //Claim the stream info structure and see if it is available if(!isStreamInfoMutexInit) { //Initialize stream mutex if(pthread_mutex_init(&streamInfoMutex, NULL) != 0) { return CREATE_MUTEX_LJ; } else { isStreamInfoMutexInit = true; } } //Lock stream info mutex if(pthread_mutex_trylock(&streamInfoMutex) == 0) { if(streamInfo.localID == localID) { //Locked the mutex and streamInfo and has matching local ID errorcode = NO_ERROR_LJ; streamInfo.localID = -1; //release streamInfo //Send any command to stop the stream on the LabJack. if(!streamInfo.demo) { errorcode = ReadMem(&localID,16,&junk3,&junk2,&junk1,&junk0); if(errorcode) { pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } if(pthread_mutex_unlock(&streamInfoMutex) != 0) { return RELEASE_DEVICE_LJ; } } else { //Wrong local ID errorcode = UNKNOWN_ERROR_LJ; if(streamInfo.localID == -1) { errorcode = streamInfo.errorcode; } else { errorcode = NO_STREAM_FOUND_LJ; } pthread_mutex_unlock(&streamInfoMutex); return errorcode; } } //Problem locking mutex else { return CLAIM_DEVICE_LJ; } return errorcode; } //====================================================================== // ListAll: Searches the USB for all LabJacks. // // Returns: LabJack errorcodes or 0 for no error (I32). // Inputs: *productIDList -Send a 127 element array of zeros (I32). // *serialnumList -Send a 127 element array of zeros (I32). // *localIDList -Send a 127 element array of zeros (I32). // *powerList -Send a 127 element array of zeros (I32). // *calMatrix -Send a 127 by 20 element array of // zeros (I32). // Outputs: *productIDList -Returns the product ID for each LabJack on // the USB (I32). Unused elements filled // with 9999s. // *serialnumList -Returns the serial number for each LabJack // on the USB (I32). Unused elements filled // with 9999s. // *localIDList -Returns the local ID for each LabJack on // the USB (I32). Unused elements filled // with 9999s. // *powerList -Returns the power allowance for each LabJack // on the USB (I32). Unused elements filled // with 9999s. // *calMatrix -Returns the cal constants for each LabJack // on the USB (I32). Unused elements filled // with 9999s. // *numberFound -Number of LabJacks found on the USB (I32). // *fcddMaxSize -Max size of fcdd (I32). // *hvcMaxSize -Max size of hvc (I32). //---------------------------------------------------------------------- long ListAll( long *productIDList, long *serialnumList, long *localIDList, long *powerList, long (*calMatrix)[20], long *numberFound, long *fcddMaxSize, long *hvcMaxSize) { unsigned int devCount = 0; long errorcode = 0; long i, j; HANDLE hDevice; *numberFound=0; //Make sure all arrays have 127 zeros. for(i = 0; i < 127; i++) { if(productIDList[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } productIDList[i] = 9999; if(serialnumList[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } serialnumList[i] = 9999; if(localIDList[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } localIDList[i] = 9999; if(powerList[i] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } powerList[i] = 9999; for(j = 0; j < 20; j++) { if(calMatrix[i][j] != 0) { return ARRAY_SIZE_OR_VALUE_ERROR_LJ; } calMatrix[i][j] = 9999; } } //Claim all mutexes before searching for(i = 0; i < MAX_DEVICES_LJ; i++) { if(!labjackInfo[i].isMutexInit) { //initialize mutex if(pthread_mutex_init(&labjackInfo[i].mutex, NULL) != 0) { //Could not create mutex. Close previously locked mutexes. for(j=0; j 255)) { return INVALID_ID_LJ; } if(labjackInfo[localID].hDevice == NULL) { //Nothing to do return 0; } //Try to claim device if(!labjackInfo[localID].isMutexInit) { //initialize mutex if(pthread_mutex_init(&labjackInfo[localID].mutex, NULL) != 0) { //Could not create mutex return CREATE_MUTEX_LJ; } else { labjackInfo[localID].isMutexInit = true; } } //lock mutex if(pthread_mutex_trylock(&labjackInfo[localID].mutex) != 0) { return CLAIM_DEVICE_LJ; } labjackInfo[localID].errorDetected = true; //Not actually an error, but forces the handle to close return CloseAll(localID); } //====================================================================== //OpenLabJack: Returns an index (localID 0-255) to a LABJACK_INFO structure // in the labjackInfo array containing the mutex, // device handle, read handle, and read event handle. // If idnum is <0, it opens the first LabJack found, otherwise // it opens the first LabJack it finds with a matching localID // or serial #. Local ID is also returned by *idnum. // Errors returned in the errorcode parameter (0 for no error). //---------------------------------------------------------------------- long OpenLabJack( long *errorcode, unsigned int vendorID, unsigned int productID, long *idnum, long *serialnum, long *calData) { HANDLE hDevice; long cal[20]; long localID = -1, serial = -1; long power = -1; long t1 = 0, t2 = 0; //junk variables long i, j; unsigned int devCount; static pthread_mutex_t exoMutex; static bool exoMutexInit = false; *errorcode = 0; //First iterate through already opened devices for(i = 0; i < MAX_DEVICES_LJ; i++) { if(labjackInfo[i].hDevice != NULL && labjackInfo[i].isMutexInit) { //lock mutex if(pthread_mutex_trylock(&labjackInfo[i].mutex) != 0) { //Check if this was the device we wanted if(*idnum >= 0) { //Want a specific device if(*idnum == i || *idnum == labjackInfo[i].serialNumber) { //We want this device, but it is busy *errorcode = CLAIM_DEVICE_LJ; return -1; } continue; } else { //Device is busy, so pass on it continue; } } //Check if this is our device *errorcode = GetU12Information(labjackInfo[i].hDevice, &serial, &localID, &power, cal, &t1, &t2); if(*errorcode) { labjackInfo[i].errorDetected = true; CloseAll(i); continue; } if(*idnum >= 0) { //Want a specific device if(*idnum != localID && *idnum != serial) { //Not the device we want CloseAll(i); continue; } } if(localID != i) { //Local ID changed. Close current local ID mutex and claim new one. pthread_mutex_unlock(&labjackInfo[i].mutex); if(!labjackInfo[localID].isMutexInit) { //initialize mutex if(pthread_mutex_init(&labjackInfo[localID].mutex, NULL) != 0) { //Could not create mutex *errorcode = CREATE_MUTEX_LJ; LJUSB_CloseDevice(labjackInfo[i].hDevice); labjackInfo[i].hDevice = NULL; return -1; } else { labjackInfo[localID].isMutexInit = true; } } //lock mutex if(pthread_mutex_trylock(&labjackInfo[localID].mutex) != 0) { *errorcode = CLAIM_DEVICE_LJ; LJUSB_CloseDevice(labjackInfo[i].hDevice); labjackInfo[i].hDevice = NULL; return -1; } labjackInfo[localID].hDevice = labjackInfo[i].hDevice; labjackInfo[i].hDevice = NULL; } labjackInfo[localID].serialNumber = serial; labjackInfo[localID].errorDetected = false; for(j = 0 ; j < 20; j++) { calData[j] = cal[j]; } *idnum = localID; *serialnum = serial; return localID; } } //Now iterate through unopened devices (Slow on Mac OS X with libusb. 900+ ms) //Try to claim exodriver open calls if(!exoMutexInit) { //initialize mutex if(pthread_mutex_init(&exoMutex, NULL) != 0) { //Could not create mutex *errorcode = CREATE_MUTEX_LJ; return -1; } else { exoMutexInit = true; } } //lock mutex if(pthread_mutex_trylock(&exoMutex) != 0) { *errorcode = CLAIM_DEVICE_LJ; return -1; } devCount = LJUSB_GetDevCount(U12_PRODUCT_ID); for(i = 0; i < devCount; i++) { hDevice = LJUSB_OpenDevice(i+1, 0, U12_PRODUCT_ID); if(hDevice != NULL) { *errorcode = GetU12Information(hDevice, &serial, &localID, &power, cal, &t1, &t2); if(*errorcode) { LJUSB_CloseDevice(hDevice); continue; } if(*idnum >= 0) { //Want a specific device if(*idnum != localID && *idnum != serial) { //Not the device we want LJUSB_CloseDevice(hDevice); continue; } } //Try to claim device if(!labjackInfo[localID].isMutexInit) { //initialize mutex if(pthread_mutex_init(&labjackInfo[localID].mutex, NULL) != 0) { //Could not create mutex *errorcode = CREATE_MUTEX_LJ; LJUSB_CloseDevice(hDevice); pthread_mutex_unlock(&exoMutex); return -1; } else { labjackInfo[localID].isMutexInit = true; } } //lock mutex if(pthread_mutex_trylock(&labjackInfo[localID].mutex) != 0) { *errorcode = CLAIM_DEVICE_LJ; LJUSB_CloseDevice(hDevice); pthread_mutex_unlock(&exoMutex); return -1; } labjackInfo[localID].hDevice = hDevice; labjackInfo[localID].serialNumber = serial; labjackInfo[localID].errorDetected = false; for(j = 0 ; j < 20; j++) { calData[j] = cal[j]; } *idnum = localID; *serialnum = serial; pthread_mutex_unlock(&exoMutex); return localID; } pthread_mutex_unlock(&exoMutex); } pthread_mutex_unlock(&exoMutex); *errorcode = DEVICE_N_NOT_FOUND_LJ; localID = -1; return localID; } //====================================================================== //WriteRead: Writes & reads 1+8 bytes to the labjack specified // by localID. Returns 0 for no error. //---------------------------------------------------------------------- long WriteRead( long localID, long timeoutms, unsigned char *sendBuffer, unsigned char *readBuffer) { long result=0; result = WriteLabJack(localID,sendBuffer); if(result) { //error, try to write again Sleep(20); result = WriteLabJack(localID,sendBuffer); } if(!result) { //write was good so try to read the response result = ReadLabJack(localID, timeoutms, 0, readBuffer); if(result) { //error, try to write&read one more time Sleep(20); result = WriteLabJack(localID,sendBuffer); if(!result) { //write was good so try to read the response result = ReadLabJack(localID,timeoutms,0,readBuffer); } //else 2nd write failed, quit and return the result of WriteHID as errorcode } //else write & read succeeded, quit and return the result=0 as errorcode } //else write failed, quit and return the result of WriteHID as errorcode if(!result) { //successful write/read, so clearing error detection labjackInfo[localID].errorDetected = false; } return result; } //====================================================================== //WriteLabJack: Writes 1+8 bytes in sendBuffer to the labjack specified // by localID. Returns 0 for // no error. //---------------------------------------------------------------------- long WriteLabJack( long localID, unsigned char *sendBuffer) { unsigned long result = 0; long errorcode = 0; result = LJUSB_Write(labjackInfo[localID].hDevice, sendBuffer+1, 8); if(result == 8) { errorcode=NO_ERROR_LJ; } else { errorcode = WRITE_ERROR_LJ; labjackInfo[localID].errorDetected = true; } return errorcode; } //====================================================================== //ReadLabJack: Reads an "IN" or feature report from a LabJack. //---------------------------------------------------------------------- long ReadLabJack( long localID, long timeout, //ms long feature, unsigned char *buffer) //9 or 129 bytes { long errorcode=0, result=0; //Read data from the USB host to the PC RAM buffer without a thread. if(feature) { result = LJUSB_StreamTO(labjackInfo[localID].hDevice, buffer+1, 128, (unsigned int)timeout); if(result == 128) { errorcode = NO_ERROR_LJ; } else { errorcode = FEATURE_ERROR_LJ; labjackInfo[localID].errorDetected = true; } } else { result = LJUSB_ReadTO(labjackInfo[localID].hDevice, buffer+1, 8, (unsigned int)timeout); if(result == 8) { errorcode = NO_ERROR_LJ; } else { errorcode = READ_ERROR_LJ; labjackInfo[localID].errorDetected = true; } } return errorcode; } //====================================================================== //CloseAll: Closes all handles for the HID specified // by refnum. Returns 0 for // no error. //---------------------------------------------------------------------- long CloseAll( long localID) { long mresult = 0; long errorcode = 0; //close all handles if(labjackInfo[localID].errorDetected) { //only close when error detect LJUSB_CloseDevice(labjackInfo[localID].hDevice); labjackInfo[localID].hDevice = NULL; labjackInfo[localID].errorDetected = false; } //close mutex mresult = pthread_mutex_unlock(&labjackInfo[localID].mutex); //result1 = !( (!result1) || (!result2) || (!result4) || (!result3) ); if(mresult == 0) { errorcode=NO_ERROR_LJ; } else { errorcode=CLOSE_HANDLE_ERROR_LJ; } return errorcode; } //====================================================================== //BuildAICommand: Builds the 1+8 byte analog input command to send to // a LabJack. Returns 0 for no error. //---------------------------------------------------------------------- long BuildAICommand( long command, //4-bit command, 1CCC, 12=C/R,10=burst,9=stream unsigned char sendBuff5, //buffer+4 unsigned char sendBuff7, //buffer+6 unsigned char sendBuff8, //buffer+7 long stateIO, long ch1num, long ch2num, long ch3num, long ch4num, long ch1gain, long ch2gain, long ch3gain, long ch4gain, unsigned char *sendBuffer) { long errorcode=NO_ERROR_LJ; //Make sure inputs are within the proper range if ((stateIO<0) || (stateIO>15)) { errorcode=ILLEGAL_AI_COMMAND_LJ; return errorcode; } sendBuffer[5]=sendBuff5; sendBuffer[6]=(((unsigned char)command)*16) + ((unsigned char)stateIO); sendBuffer[7]=sendBuff7; sendBuffer[8]=sendBuff8; errorcode=BuildGainMuxCommand(ch1num,ch1gain,&sendBuffer[1]); if(errorcode) { return errorcode; } errorcode=BuildGainMuxCommand(ch2num,ch2gain,&sendBuffer[2]); if(errorcode) { return errorcode; } errorcode=BuildGainMuxCommand(ch3num,ch3gain,&sendBuffer[3]); if(errorcode) { return errorcode; } errorcode=BuildGainMuxCommand(ch4num,ch4gain,&sendBuffer[4]); if(errorcode) { return errorcode; } return errorcode; } //====================================================================== //BuildGainMuxCommand: Builds the 8-bit gain/mux command to send to // a LabJack. Returns 0 for no error. //---------------------------------------------------------------------- long BuildGainMuxCommand( long chnum, long chgain, unsigned char *gainmux) { long errorcode=NO_ERROR_LJ; *gainmux=0; //gain is bits 6, 5, and 4 if ((chgain<0) || (chgain>7)) { errorcode=ILLEGAL_GAIN_INDEX_LJ; return errorcode; } //PGA only works with differential channels if ((chnum<8) && (chgain!=0)) { errorcode=ILLEGAL_GAIN_INDEX_LJ; return errorcode; } *gainmux=(unsigned char)(chgain*16); //mux is bits 3, 2, 1, and 0 switch(chnum) { case 0: *gainmux += 8; break; case 1: *gainmux += 9; break; case 2: *gainmux += 10; break; case 3: *gainmux += 11; break; case 4: *gainmux += 12; break; case 5: *gainmux += 13; break; case 6: *gainmux += 14; break; case 7: *gainmux += 15; break; case 8: *gainmux += 0; break; case 9: *gainmux += 1; break; case 10: *gainmux += 2; break; case 11: *gainmux += 3; break; case 12: *gainmux += 4; break; case 13: *gainmux += 5; break; case 14: *gainmux += 6; break; case 15: *gainmux += 7; break; default: errorcode=ILLEGAL_CHANNEL_LJ; } //set bit 7 to indicate analog command *gainmux = BitSet(*gainmux,7); //set high bit return errorcode; } //====================================================================== //ParseAIResponse: Returns 0 for no error. //---------------------------------------------------------------------- long ParseAIResponse( unsigned char *sendBuffer, unsigned char *readBuffer, long disableCal, long *calData, //20 element array long *stateIO, long *overVoltage, float *voltage1, float *voltage2, float *voltage3, float *voltage4, unsigned char *echoIn, long *ofchecksumError, long *backlog, long *iterationCount, long readCount) { long errorcode=NO_ERROR_LJ; long bits; long chnum,chgain; //Bit 7 of first byte should be a 1 if (!(BitTst(readBuffer[1],7))) { errorcode=AI_RESPONSE_ERROR_LJ; return errorcode; } *overVoltage=0; if (BitTst(readBuffer[1],4)) *overVoltage=1; *stateIO = readBuffer[1] % 16; *echoIn = readBuffer[2]; //command/response *ofchecksumError=0; if (BitTst(readBuffer[1],5)) *ofchecksumError=1; *backlog = ((long)(readBuffer[2] % 32)) * 256 / 7; *iterationCount = readBuffer[2] / 32; //Calculate voltage reading from 1st channel bits = (readBuffer[3] / 16) * 256; bits += readBuffer[4]; if(!disableCal) { ApplyCal(sendBuffer[1],calData,&bits); } chgain = sendBuffer[1]; //make a copy of XGGGMMMM command byte for this channel chgain = BitClr(chgain,7); //clear high bit chgain /= 16; //get value of GGG (0 to 7) chnum = sendBuffer[1]; //make a copy of XGGGMMMM command byte for this channel chnum %= 16; //MMMM chnum = BitFlp(chnum,3); //now it is channel index errorcode = BitsToVolts (chnum,chgain,bits,voltage1); if (errorcode!=0) return errorcode; if (readCount) { *voltage2 = (float)(((((long)readBuffer[7])%16) * 256) + ((long)readBuffer[8])); //bits 0-11 of counter *voltage3 = (float)((((long)readBuffer[7])/16) + (((long)readBuffer[6])*16)); //bits 12-23 of counter *voltage4 = (float)readBuffer[5]; //bits 24-31 of counter } else { //Calculate voltage reading from 2nd channel bits = (readBuffer[3] % 16) * 256; bits += readBuffer[5]; if(!disableCal) { ApplyCal(sendBuffer[2],calData,&bits); } chgain = sendBuffer[2]; //make a copy of XGGGMMMM command byte for this channel chgain = BitClr(chgain,7); //clear high bit chgain /= 16; //get value of GGG (0 to 7) chnum = sendBuffer[2]; //make a copy of XGGGMMMM command byte for this channel chnum %= 16; //MMMM chnum = BitFlp(chnum,3); //now it is channel index errorcode = BitsToVolts (chnum,chgain,bits,voltage2); if (errorcode!=0) return errorcode; //Calculate voltage reading from 3rd channel bits = (readBuffer[6] / 16) * 256; bits += readBuffer[7]; if(!disableCal) { ApplyCal(sendBuffer[3],calData,&bits); } chgain = sendBuffer[3]; //make a copy of XGGGMMMM command byte for this channel chgain = BitClr(chgain,7); //clear high bit chgain /= 16; //get value of GGG (0 to 7) chnum = sendBuffer[3]; //make a copy of XGGGMMMM command byte for this channel chnum %= 16; //MMMM chnum = BitFlp(chnum,3); //now it is channel index errorcode = BitsToVolts (chnum,chgain,bits,voltage3); if (errorcode!=0) return errorcode; //Calculate voltage reading from 4th channel bits = (readBuffer[6] % 16) * 256; bits += readBuffer[8]; if(!disableCal) { ApplyCal(sendBuffer[4],calData,&bits); } chgain = sendBuffer[4]; //make a copy of XGGGMMMM command byte for this channel chgain = BitClr(chgain,7); //clear high bit chgain /= 16; //get value of GGG (0 to 7) chnum = sendBuffer[4]; //make a copy of XGGGMMMM command byte for this channel chnum %= 16; //MMMM chnum = BitFlp(chnum,3); //now it is channel index errorcode = BitsToVolts (chnum,chgain,bits,voltage4); if (errorcode!=0) return errorcode; } return errorcode; } //====================================================================== //ApplyCal: Returns 0 for no error. //---------------------------------------------------------------------- long ApplyCal( unsigned char gainmux, long *calData, long *bits) { long errorcode=NO_ERROR_LJ; float gain; float czse; long ccdiff; switch((BitClr(gainmux,7)/16)) { case 0: gain = 1.0F; break; case 1: gain = 2.0F; break; case 2: gain = 4.0F; break; case 3: gain = 5.0F; break; case 4: gain = 8.0F; break; case 5: gain = 10.0F; break; case 6: gain = 16.0F; break; case 7: gain = 20.0F; break; default: errorcode=UNKNOWN_ERROR_LJ; return errorcode; } if (BitTst(gainmux,3)) { //single-ended gainmux = gainmux % 8; //gainmux now equals channel # (0-7) *bits -= calData[gainmux]; //subtract offset *bits += RoundFL( (((float)(*bits-2048)) / ((float)512)) * ((float)(calData[gainmux]-calData[gainmux+8])) ); //span correction } else { //differential gainmux = gainmux % 4; //gainmux now equals channel # (0-3) //Offset Correction czse = (float)(calData[2*gainmux]-calData[(2*gainmux)+1]); *bits -= (long)((gain*czse/2.0F) + (((float)calData[gainmux+16])-(czse/2.0F))); //Span Correction // If the difference in spans (ccdiff) is at least 2 bits, we do a // one bit per 256 bits correction. This is a conservative correction // that follows from experimental data. ccdiff = (calData[(2*gainmux)+8]-calData[2*gainmux]) - (calData[(2*gainmux)+9]-calData[(2*gainmux)+1]); if(ccdiff >= 2) { *bits -= RoundFL(((float)(*bits-2048))/256.0F); } if(ccdiff <= -2) { *bits += RoundFL(((float)(*bits-2048))/256.0F); } } if((*bits)>4095) *bits=4095; if((*bits)<0) *bits=0; return errorcode; } //====================================================================== //BuildAOCommand: Builds the 1+8 byte counter/pwm command to send to // a LabJack. Returns 0 for no error. //---------------------------------------------------------------------- long BuildAOCommand( long trisD, long trisIO, long stateD, long stateIO, long updateDigital, long resetCounter, float analogOut0, float analogOut1, unsigned char *sendBuffer) { long errorcode=NO_ERROR_LJ; int binAO; int i; //Firmware expects 1=true=input and 0=false=output, but I want //input to be the more natural default, so I flip all the bits here //in the LabJack driver so that 0=input and 1=output at //the application layer. for(i=0;i<16;i++) { trisD=BitFlp(trisD,i); } for(i=0;i<4;i++) { trisIO=BitFlp(trisIO,i); } //Make sure each DIO input is within the proper range if ((trisD<0) || (trisD>65535)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } if ((trisIO<0) || (trisIO>15)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } if ((stateD<0) || (stateD>65535)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } if ((stateIO<0) || (stateIO>15)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } //Make sure each of the voltages are within the proper range if ((analogOut0<0) || (analogOut0>5.0)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } if ((analogOut1<0) || (analogOut1>5.0)) { errorcode=ILLEGAL_AO_COMMAND_LJ; return errorcode; } sendBuffer[1]=(unsigned char)(trisD/256); //upper byte of trisD sendBuffer[2]=(unsigned char)(trisD%256); //lower byte of trisD sendBuffer[3]=(unsigned char)(stateD/256); //upper byte of stateD sendBuffer[4]=(unsigned char)(stateD%256); //lower byte of stateD sendBuffer[5]=((unsigned char)(trisIO*16)) + ((unsigned char)stateIO); sendBuffer[6]=0; if(updateDigital) { sendBuffer[6] = BitSet(sendBuffer[6],4); //set bit 4 } if(resetCounter) { sendBuffer[6] = BitSet(sendBuffer[6],5); //set bit 5 } binAO = (int)(RoundFL((1023.0F * (analogOut0 / 5.0F)))); if (BitTst(binAO,1)) sendBuffer[6]=BitSet(sendBuffer[6],3); if (BitTst(binAO,0)) sendBuffer[6]=BitSet(sendBuffer[6],2); sendBuffer[7] = (unsigned char)(binAO/4); //upper 8 bits of pwm command binAO = (int)(RoundFL((1023.0F * (analogOut1 / 5.0F)))); if (BitTst(binAO,1)) sendBuffer[6]=BitSet(sendBuffer[6],1); if (BitTst(binAO,0)) sendBuffer[6]=BitSet(sendBuffer[6],0); sendBuffer[8] = (unsigned char)(binAO/4); //upper 8 bits of pwm command return errorcode; } //====================================================================== //ParseAOResponse: Returns 0 for no error. //---------------------------------------------------------------------- long ParseAOResponse( unsigned char *readBuffer, long *stateD, long *stateIO, unsigned long *count) { long errorcode=NO_ERROR_LJ; //Bit 7 of first byte should be a 0 if ((BitTst(readBuffer[1],7))) { errorcode=RESPONSE_ERROR_LJ; return errorcode; } *stateD = ((long)readBuffer[2]) * 256; *stateD += ((long)readBuffer[3]); *stateIO = ((long)readBuffer[4]) / 16; *count = (unsigned long)readBuffer[8]; *count += ((unsigned long)readBuffer[7]) * 256; *count += ((unsigned long)readBuffer[6]) * 65536; *count += ((unsigned long)readBuffer[5]) * 16777216; return errorcode; } //====================================================================== //RoundFL: Send a float and it is rounded to a long. //---------------------------------------------------------------------- long RoundFL( float fp) { if((fmod((double)fp,1.0)) >= 0.50) { fp += 0.50F; } return (long)fp; //fp gets truncated here } //====================================================================== //GetU12Information: Gets the U12 information needed by OpenLabJack and // ListAll functions. Handle must be from a valid U12. // Returns 0 for no error. //---------------------------------------------------------------------- long GetU12Information( HANDLE hDevice, long *serialnum, long *localID, long *power, long *calData, long *fcddMaxSize, long *hvcMaxSize) { unsigned char repDesc[75] = {0}; unsigned long result = 0, temp = 0; int i = 0; temp = (unsigned long)LJUSB_GetDeviceDescriptorReleaseNumber(hDevice) * 65536; //upper two bytes of serial # result = LJUSB_GetHIDReportDescriptor(hDevice, repDesc, 75); if(result < 75) { //Failed getting descriptor. First capability would of been input, so //return an error on that. return INPUT_CAPS_ERROR_LJ; } *fcddMaxSize = 0; //Not relevent with Exodriver. *hvcMaxSize = result; //Report descriptor size //Check input report bytes if(repDesc[14] != 0x37 || repDesc[19] != 0x47 || repDesc[28] != 0x81) { return INPUT_CAPS_ERROR_LJ; } //Check output report bytes if(repDesc[36] != 0x37 || repDesc[41] != 0x47 || repDesc[50] != 0x91) { return OUTPUT_CAPS_ERROR_LJ; } //Check feature report bytes if(repDesc[58] != 0x37 || repDesc[63] != 0x47 || repDesc[72] != 0xb1) { return FEATURE_CAPS_ERROR_LJ; } *serialnum = (long)((unsigned long)repDesc[15] + (unsigned long)repDesc[16]*256 + temp); //lower 2 bytes of serial number *localID = (long)repDesc[17]; //local ID, 0 - 255 *power = 2*(long)repDesc[18]; //Power allowance //Getting calibration data for(i = 0; i < 4; i++) { calData[i] = (long)repDesc[37 + i]; //SE0-3 Zero calData[4+i] = (long)repDesc[42+i]; //SE4-7 Zero calData[8+i] = (long)repDesc[59+i]; //SE0-3 Cal calData[12+i] = (long)repDesc[64+i]; //SE4-7 Cal calData[16+i] = (long)repDesc[20+i]; //Diff0-3 Zero } //2's complement on calibration data for(i = 0; i < 20; i++) { if(BitTst(calData[i], 7)) { calData[i] -= 256; } } return 0; } //====================================================================== //GetTickCount: Implementation of GetTickCount() for Unix. Returns the // current time, expressed as millisconds since the Epoch //---------------------------------------------------------------------- unsigned long GetTickCount( void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); }