7343 lines
196 KiB
C
Raw Normal View History

//---------------------------------------------------------------------------
//
// 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 <stdio.h>
#include <math.h>
#include "ljacklm.h"
/* Unix includes, defines, macros, etc. */
#include <stdbool.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#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;i<MAX_DEVICES_LJ;i++)
{
gTrisD[i]=65535; //referenced to PIC, 0=Output
gTrisIO[i]=15; //referenced to PIC, 0=Output
gStateD[i]=0; //output states
gStateIO[i]=0; //output states
gAO0[i]=0.0F;
gAO1[i]=0.0F;
labjackInfo[i].isMutexInit = false;
labjackInfo[i].hDevice = NULL;
labjackInfo[i].serialNumber = 0;
labjackInfo[i].errorDetected = false;
}
streamInfo.localID = -1;
streamInfo.errorcode = 0;
isStreamInfoMutexInit = false;
}
__attribute__((destructor))
static void finalizer()
{
//destroy mutexes
int i;
for(i=0;i<MAX_DEVICES_LJ;i++)
{
if(labjackInfo[i].hDevice != NULL)
{
LJUSB_CloseDevice(labjackInfo[i].hDevice);
}
if(labjackInfo[i].isMutexInit)
{
pthread_mutex_destroy(&labjackInfo[i].mutex);
}
}
if(isStreamInfoMutexInit)
{
pthread_mutex_destroy(&streamInfoMutex);
}
}
//======================================================================
// EAnalogIn: Easy function reads the voltage from 1 analog input. Calling
// this function turns/leaves the status LED on.
//
// 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 -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<numPackets;i++)
{
memAddress=132+(i*4);
if(!demo)
{
errorcode = WriteMem(idnum,1,memAddress,data[4+(i*4)],data[5+(i*4)],data[6+(i*4)],data[7+(i*4)]);
}
else
{
Sleep(20);
}
if(errorcode) return errorcode;
}
}
if(!demo)
{
//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;
}
//Make sure firmware is V1.05 or higher
if(serialnum < 100010000)
{
CloseAll(localID);
return WRONG_FIRMWARE_VERSION_LJ;
}
//Fill sendBuffer with the proper values.
sendBuffer[1]=(unsigned char)(data[3]);
sendBuffer[2]=(unsigned char)(data[2]);
sendBuffer[3]=(unsigned char)(data[1]);
sendBuffer[4]=(unsigned char)(data[0]);
sendBuffer[5]=0;
if(enableDel) sendBuffer[5]=BitSet(sendBuffer[5],3);
if(enableTO) sendBuffer[5]=BitSet(sendBuffer[5],2);
if(enableTE) sendBuffer[5]=BitSet(sendBuffer[5],1);
if(portB) sendBuffer[5]=BitSet(sendBuffer[5],0);
sendBuffer[6]=97; //DigitalIO function
sendBuffer[7]=(unsigned char)numWrite;
sendBuffer[8]=(unsigned char)numRead;
//Determine proper timeout for WriteRead
if(enableTO)
{
usbTimeout = 35000;
}
else
{
usbTimeout = (long)(1250.0*((((double)numWrite*8.0)+((double)numRead*8.0))/(double)baudrate));
if(usbTimeout<READ_TIMEOUT_MS) usbTimeout=READ_TIMEOUT_MS;
}
//Write & Read data to/from the LabJack
errorcode = WriteRead(localID,usbTimeout,sendBuffer,readBuffer);
if(errorcode)
{
CloseAll(localID);
return errorcode;
}
//Fill data array with 9999s
for(i=0;i<18;i++)
{
data[i]=9999;
}
//Parse the response
if(BitTst(readBuffer[5],5))
{
errorcode = ASYNCH_TIMEOUT_ERROR_LJ;
}
if(BitTst(readBuffer[5],4))
{
errorcode = ASYNCH_START_ERROR_LJ;
}
if(BitTst(readBuffer[5],3))
{
errorcode = ASYNCH_FRAME_ERROR_LJ;
}
if((BitTst(readBuffer[5],2))||(BitTst(readBuffer[5],1))||(BitTst(readBuffer[5],0)))
{
errorcode = ASYNCH_DIO_CONFIG_ERROR_LJ;
}
if (!((readBuffer[6]==97)&&(readBuffer[7]==(unsigned char)numWrite)&&(readBuffer[8]==(unsigned char)numRead)))
{
errorcode = CloseAll(localID);
return RESPONSE_ERROR_LJ;
}
data[0]=readBuffer[4];
data[1]=readBuffer[3];
data[2]=readBuffer[2];
data[3]=readBuffer[1];
for(i=0;i<4;i++)
{
if(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;i<numPackets;i++)
{
memAddress=196+(i*4);
if(!demo)
{
result = ReadMem(idnum,memAddress,&data[4+(i*4)],&data[5+(i*4)],&data[6+(i*4)],&data[7+(i*4)]);
}
else
{
Sleep(20);
}
//fill unused locations with 9999
if(numFill != 4)
{
for(j=0;j<numFill;j++)
{
data[7-j+(i*4)] = 9999;
}
}
if(result) return result;
}
}
return errorcode;
}
//======================================================================
//GetDriverVersion
//
// Returns: Version number of this DLL (SGL).
// Inputs: none
// Outputs: none
//----------------------------------------------------------------------
float GetDriverVersion( void)
{
return VERSION;
}
//======================================================================
//GetErrorString
//
// Returns: nothing
// Inputs: errorcode -LabJack errorcode (I32)
// *errorString -Must point to an array of at least 50
// chars (I8).
// Outputs: *errorString -A sequence a characters describing the error
// will be copied into the char (I8) array.
//----------------------------------------------------------------------
void GetErrorString( long errorcode,
char *errorString)
{
if(BitTst(errorcode,8))
{
errorcode -= STREAMBUFF_ERROR_OFFSET_LJ;
}
switch(errorcode)
{
case 0: errorString = strcpy(errorString,"No error");
break;
case 1: errorString = strcpy(errorString,"Unknown error");
break;
case 2: errorString = strcpy(errorString,"No LabJacks found");
break;
case 3: errorString = strcpy(errorString,"LabJack n not found");
break;
case 4: errorString = strcpy(errorString,"Set USB buffer error");
break;
case 5: errorString = strcpy(errorString,"Open handle error");
break;
case 6: errorString = strcpy(errorString,"Close handle error");
break;
case 7: errorString = strcpy(errorString,"Invalid ID");
break;
case 8: errorString = strcpy(errorString,"Invalid array size or value");
break;
case 9: errorString = strcpy(errorString,"Invalid power index");
break;
case 10: errorString = strcpy(errorString,"FCDD size too big");
break;
case 11: errorString = strcpy(errorString,"HVC size too big");
break;
case 12: errorString = strcpy(errorString,"Read error");
break;
case 13: errorString = strcpy(errorString,"Read timeout error");
break;
case 14: errorString = strcpy(errorString,"Write error");
break;
case 15: errorString = strcpy(errorString,"Turbo error");
break;
case 16: errorString = strcpy(errorString,"Illegal channel index");
break;
case 17: errorString = strcpy(errorString,"Illegal gain index");
break;
case 18: errorString = strcpy(errorString,"Illegal AI command");
break;
case 19: errorString = strcpy(errorString,"Illegal AO command");
break;
case 20: errorString = strcpy(errorString,"Bits out of range");
break;
case 21: errorString = strcpy(errorString,"Illegal number of channels");
break;
case 22: errorString = strcpy(errorString,"Illegal scan rate");
break;
case 23: errorString = strcpy(errorString,"Illegal number of samples");
break;
case 24: errorString = strcpy(errorString,"AI response error");
break;
case 25: errorString = strcpy(errorString,"LabJack RAM checksum error");
break;
case 26: errorString = strcpy(errorString,"AI sequence error");
break;
case 27: errorString = strcpy(errorString,"Maximum number of streams reached");
break;
case 28: errorString = strcpy(errorString,"AI stream start error");
break;
case 29: errorString = strcpy(errorString,"PC buffer overflow");
break;
case 30: errorString = strcpy(errorString,"LabJack buffer overflow");
break;
case 31: errorString = strcpy(errorString,"Stream read timeout");
break;
case 32: errorString = strcpy(errorString,"Illegal number of scans");
break;
case 33: errorString = strcpy(errorString,"No stream was found");
break;
case 40: errorString = strcpy(errorString,"Illegal input");
break;
case 41: errorString = strcpy(errorString,"Echo error");
break;
case 42: errorString = strcpy(errorString,"Data echo error");
break;
case 43: errorString = strcpy(errorString,"Response error");
break;
case 44: errorString = strcpy(errorString,"Asynch timeout error");
break;
case 45: errorString = strcpy(errorString,"Asynch start bit error");
break;
case 46: errorString = strcpy(errorString,"Asynch framing error");
break;
case 47: errorString = strcpy(errorString,"Asynch digital I/O state or tris error");
break;
case 48: errorString = strcpy(errorString,"Caps error");
break;
case 49: errorString = strcpy(errorString,"Caps error");
break;
case 50: errorString = strcpy(errorString,"Caps error");
break;
case 51: errorString = strcpy(errorString,"HID number caps error");
break;
case 52: errorString = strcpy(errorString,"HID get attributes warning");
break;
case 57: errorString = strcpy(errorString,"Wrong firmware version error");
break;
case 58: errorString = strcpy(errorString,"Digital I/O state or tris error");
break;
case 64: errorString = strcpy(errorString,"Could not claim all LabJacks");
break;
case 65: errorString = strcpy(errorString,"Error releasing all LabJacks");
break;
case 66: errorString = strcpy(errorString,"Could not claim LabJack");
break;
case 67: errorString = strcpy(errorString,"Error releasing LabJack");
break;
case 68: errorString = strcpy(errorString,"Claimed abandoned LabJack");
break;
case 69: errorString = strcpy(errorString,"Local ID -1 thread stopped");
break;
case 70: errorString = strcpy(errorString,"Stop thread timeout");
break;
case 71: errorString = strcpy(errorString,"Thread termination failed");
break;
case 72: errorString = strcpy(errorString,"Feature handle creation failed");
break;
case 73: errorString = strcpy(errorString,"Mutex creation failed");
break;
case 80: errorString = strcpy(errorString,"Synch CS state or tris error");
break;
case 81: errorString = strcpy(errorString,"Synch SCK tris error");
break;
case 82: errorString = strcpy(errorString,"Synch MISO tris error");
break;
case 83: errorString = strcpy(errorString,"Synch MOSI tris error");
break;
case 89: errorString = strcpy(errorString,"SHT1X communication error - CRC");
break;
case 90: errorString = strcpy(errorString,"SHT1X communication error - MeasReady");
break;
case 91: errorString = strcpy(errorString,"SHT1X communication error - ACK");
break;
case 92: errorString = strcpy(errorString,"SHT1X serial reset error");
break;
default: errorString=strcpy(errorString,"Unknown error code");
}
return;
}
//======================================================================
//GetFirmwareVersion: Used to retrieve the firmware version from
// the LabJack's processor.
//
// Returns: Version number of the LabJack firmware or 0 for error (SGL).
// 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). If error, returns 512 plus
// a normal LabJack errorcode.
//
// Time: 20 ms
//----------------------------------------------------------------------
float GetFirmwareVersion( long *idnum)
{
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};
float version;
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= errorcode + GETFIRMWAREVERSION_ERROR_OFFSET_LJ;
return 0;
}
sendBuffer[1]=1; //set the "ignore commands" bit
sendBuffer[6]=83; //watchdog command
//Write data to the LabJack
//errorcode = WriteRead(localID,1000,sendBuffer,readBuffer);
errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer);
if(errorcode)
{
CloseAll(localID);
*idnum= errorcode + GETFIRMWAREVERSION_ERROR_OFFSET_LJ;
return 0;
}
version = ((float)readBuffer[1]) + (((float)readBuffer[2])/100);
if(CloseAll(localID))
{
*idnum= errorcode + GETFIRMWAREVERSION_ERROR_OFFSET_LJ;
return 0;
}
return version;
}
//======================================================================
// LocalID: Change the local ID number of a LabJack. Changes will not take
// effect until the LabJack is re-enumerated.
//
// Returns: LabJack errorcodes or 0 for no error (I32).
// Inputs: *idnum -Local ID, Serial Number, or -1 for first
// found (I32).
// localID -New local ID (I32).
// Outputs: *idnum -Returns the Local ID or -1 if no LabJack is
// found (I32).
//
// Time: 20 ms
//----------------------------------------------------------------------
long LocalID( long *idnum,
long localID)
{
long errorcode;
//Make sure inputs are valid
if ((localID<0) || (localID>255))
{
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(ferror<ferrorbest)
{
ferrorbest=ferror;
*timeB=b;
*timeC=c;
*frequency=fcurrent;
}
//if f is too large, no need to check every c
if((fdesired-fcurrent)>0) 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 && (numComms<maxNumComms))
{
numComms++;
datatx[0]=3; //temp 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;
needTemp=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);
}
needTemp=1;
errorcode=SHT1X_CRC_ERROR_LJ;
}
else
{
if(BitTst(statusReg,0))
{
//low res
*tempC=(((float)datarx[0])*256.0F)+((float)datarx[1]); //bits
*tempC=(*tempC * 0.04F)-40.0F;
}
else
{
//high res
*tempC=(((float)datarx[0])*256.0F)+((float)datarx[1]); //bits
*tempC=(*tempC * 0.01F)-40.0F;
}
*tempF=(*tempC * 9.0F / 5.0F) + 32.0F;
needTemp=0;
errorcode=0;
}
} // end else no SHTWriteRead error
} // end while
}
else
{
//use passed tempC
*tempF=(*tempC * 9.0F/5.0F)+32.0F;
}
//now get RH if requested
if(((mode==0)||(mode>1))&&(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;i<numWrite;i++)
{
//Each bit
for(j=0;j<8;j++)
{
//Update DATA
trisIO=BitSet(trisIO,0);
if(!BitTst(datatx[i],(7-j))) trisIO=BitClr(trisIO,0);
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;
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;
}
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=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) return SHT1X_ACK_ERROR_LJ;
}
if(waitMeas)
{
//Wait for measurement ready.
DATA=1;
i=0;
while(DATA && (i<30))
{
errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer); //Read DATA
DATA=BitTst(readBuffer[4],4);
if(errorcode) return errorcode;
i++;
}
if(DATA) return SHT1X_MEASREADY_ERROR_LJ;
}
}
//Read Bytes
if(numRead>0)
{
//Each byte
for(i=0;i<numRead;i++)
{
datarx[i]=0;
//Each bit
for(j=0;j<8;j++)
{
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(DATA) datarx[i]=(unsigned char)(BitSet(datarx[i],(7-j)));
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;
}
//Send ACK if not last byte.
if(i<(numRead-1))
{
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=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;
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;
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;
}
}
//Reload globals with current values
gTrisD[localID]=trisD;
gStateD[localID]=stateD;
gTrisIO[localID]=trisIO;
gStateIO[localID]=stateIO;
}
else
//hardware communication
{
//fill sendBuffer with LabJack command
sendBuffer[4]=datatx[0];
sendBuffer[3]=datatx[1];
sendBuffer[2]=datatx[2];
sendBuffer[1]=datatx[3];
sendBuffer[6]=104; //SHT1X function
sendBuffer[7]=(unsigned char)numWrite;
sendBuffer[8]=(unsigned char)numRead;
sendBuffer[5]=0;
if(waitMeas) sendBuffer[5]=BitSet(sendBuffer[5],7);
if(serialReset) sendBuffer[5]=BitSet(sendBuffer[5],6);
//set delay bits if specified
if(dataRate==1) sendBuffer[5]=BitSet(sendBuffer[5],4);
if(dataRate==2) sendBuffer[5]=BitSet(sendBuffer[5],5);
//send IO3 and IO2 info so they are not changed
if(BitTst(gStateIO[localID],3)) sendBuffer[5]=BitSet(sendBuffer[5],3);
if(BitTst(gStateIO[localID],2)) sendBuffer[5]=BitSet(sendBuffer[5],2);
if(BitTst(gTrisIO[localID],3)) sendBuffer[5]=BitSet(sendBuffer[5],1);
if(BitTst(gTrisIO[localID],2)) sendBuffer[5]=BitSet(sendBuffer[5],0);
//Write & Read data to/from the LabJack
errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer);
if(!errorcode)
{
if(BitTst(readBuffer[5],2))
{
errorcode = SHT1X_SERIAL_RESET_ERROR_LJ;
}
if(BitTst(readBuffer[5],1))
{
errorcode = SHT1X_MEASREADY_ERROR_LJ;
}
if(BitTst(readBuffer[5],0))
{
errorcode = SHT1X_ACK_ERROR_LJ;
}
if (!((readBuffer[6]==104)&&(readBuffer[7]==(unsigned char)numWrite)&&(readBuffer[8]==(unsigned char)numRead)))
{
errorcode = RESPONSE_ERROR_LJ;
}
datarx[0]=readBuffer[4];
datarx[1]=readBuffer[3];
datarx[2]=readBuffer[2];
datarx[3]=readBuffer[1];
}
}
return errorcode;
}
//======================================================================
// SHTCRC: Checks the CRC on a SHT1X communication. Last byte of
// datarx is the CRC. Returns 0 if CRC is good, or
// SHT1X_CRC_ERROR_LJ if CRC is bad.
//----------------------------------------------------------------------
long SHTCRC( long statusReg,
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,numBytes=0;
unsigned char crc;
unsigned char crcRead;
unsigned char data[8]={0};
unsigned char crcTable[256]={0, 49, 98, 83, 196, 245,166, 151,185, 136,219, 234,125, 76, 31, 46, 67, 114,33, 16,
135, 182,229, 212,250, 203,152, 169,62, 15, 92, 109,134, 183,228, 213,66, 115,32, 17,
63, 14, 93, 108,251, 202,153, 168,197, 244,167, 150,1, 48, 99, 82, 124, 77, 30, 47,
184, 137,218, 235,61, 12, 95, 110,249, 200,155, 170,132, 181,230, 215,64, 113,34, 19,
126, 79, 28, 45, 186, 139,216, 233,199, 246,165, 148,3, 50, 97, 80, 187, 138,217, 232,
127, 78, 29, 44, 2, 51, 96, 81, 198, 247,164, 149,248, 201,154, 171,60, 13, 94, 111,
65, 112,35, 18, 133, 180,231, 214,122, 75, 24, 41, 190, 143,220, 237,195, 242,161, 144,
7, 54, 101, 84, 57, 8, 91, 106,253, 204,159, 174,128, 177,226, 211,68, 117,38, 23,
252, 205,158, 175,56, 9, 90, 107,69, 116,39, 22, 129, 176,227, 210,191, 142,221, 236,
123, 74, 25, 40, 6, 55, 100, 85, 194, 243,160, 145,71, 118,37, 20, 131, 178,225, 208,
254, 207,156, 173,58, 11, 88, 105,4, 53, 102, 87, 192, 241,162, 147,189, 140,223, 238,
121, 72, 27, 42, 193, 240,163, 146,5, 52, 103, 86, 120, 73, 26, 43, 188, 141,222, 239,
130, 179,224, 209,70, 119,36, 21, 59, 10, 89, 104,255, 206,157, 172};
/* The following is a test transmission that has a good CRC (26)
statusReg=0;
numWrite=1;
numRead=3;
datatx[0]=5;
datarx[0]=9;
datarx[1]=49;
datarx[2]=26;
*/
//We only get a CRC with read operations
if(numRead<1) return SHT1X_CRC_ERROR_LJ;
//Initialize CRC
crc=ReverseByte((unsigned char)statusReg);
//CRC returned by SHT1X must be reversed
crcRead=ReverseByte(datarx[numRead-1]);
//Combine write and read data
numBytes=numWrite+numRead-1; //subtract 1 for CRC byte
for(i=0;i<8;i++)
{
if(i<numBytes)
{
if(i<numWrite)
{
data[i]=datatx[i];
}
else
{
data[i]=datarx[i-numWrite];
}
}
else data[i]=0;
}
for(i=0;i<numBytes;i++)
{
crc=crc^data[i];
crc=crcTable[crc];
}
if(crc != crcRead)
{
errorcode=SHT1X_CRC_ERROR_LJ;
}
return errorcode;
}
//======================================================================
// ReverseByte: Reverses the bits in a byte.
//----------------------------------------------------------------------
unsigned char ReverseByte( unsigned char byteIn)
{
long i;
unsigned char byteOut=0;
for(i=0;i<8;i++)
{
if(BitTst(byteIn,i)) byteOut=(unsigned char)(BitSet(byteOut,7-i));
}
return byteOut;
}
//======================================================================
// SHTComm: Low-level public function to send and receive up to 4 bytes
// to from an 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).
// softComm -If >0, 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<numPackets;i++)
{
memAddress=132+(i*4);
if(!demo)
{
errorcode = WriteMem(idnum,1,memAddress,data[4+(i*4)],data[5+(i*4)],data[6+(i*4)],data[7+(i*4)]);
}
else
{
Sleep(20);
}
if(errorcode) return errorcode;
}
}
if(!demo)
{
//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;
}
//Make sure firmware is V1.09 or higher
if(serialnum < 100012000)
{
CloseAll(localID);
return WRONG_FIRMWARE_VERSION_LJ;
}
//First configure D lines if selected.
if(configD)
{
//Initialize local tris and state variables
trisD=gTrisD[localID];
stateD=gStateD[localID];
trisIO=gTrisIO[localID];
stateIO=gStateIO[localID];
//Set MOSI (D13) to output low
trisD=BitClr(trisD,13); //In firmware, 0=Output and 1=Input
stateD=BitClr(stateD,13);
//Set MISO (D14) to input
trisD=BitSet(trisD,14); //In firmware, 0=Output and 1=Input
//Set SCK (D15) to output CPOL
if((mode==0)||(mode==2))
{
//Mode A or C so SCK should be high
trisD=BitClr(trisD,15); //In firmware, 0=Output and 1=Input
stateD=BitSet(stateD,15);
}
else
{
//Mode B or D so SCK should be high
trisD=BitClr(trisD,15); //In firmware, 0=Output and 1=Input
stateD=BitClr(stateD,15);
}
//If controlCS is true, configure CS.
if(controlCS)
{
trisD=BitClr(trisD,csLine); //In firmware, 0=Output and 1=Input
if(csState)
{
stateD=BitClr(stateD,csLine); //clear CS to output-low
}
else
{
stateD=BitSet(stateD,csLine); //set !CS to output-high.
}
}
//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;
}
}
//Fill sendBuffer with the proper values for Synch call.
sendBuffer[1]=(unsigned char)(data[3]);
sendBuffer[2]=(unsigned char)(data[2]);
sendBuffer[3]=(unsigned char)(data[1]);
sendBuffer[4]=(unsigned char)(data[0]);
sendBuffer[5]=0;
if(msDelay) sendBuffer[5]=BitSet(sendBuffer[5],7);
if(husDelay) sendBuffer[5]=BitSet(sendBuffer[5],6);
if(mode==0) sendBuffer[5]=BitSet(sendBuffer[5],0);
if(mode==1) sendBuffer[5]=BitSet(sendBuffer[5],1);
if(mode==2) sendBuffer[5]=BitSet(sendBuffer[5],2);
if(mode==3) sendBuffer[5]=BitSet(sendBuffer[5],3);
sendBuffer[6]=98; //Synch function
sendBuffer[7]=(unsigned char)numWriteRead;
sendBuffer[8]=(unsigned char)csLine;
if(controlCS) sendBuffer[8]=BitSet(sendBuffer[8],7);
if(csState) sendBuffer[8]=BitSet(sendBuffer[8],6);
//Write & Read data to/from the LabJack
errorcode = WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer);
if(errorcode)
{
CloseAll(localID);
return errorcode;
}
//Fill data array with 9999s
for(i=0;i<18;i++)
{
data[i]=9999;
}
//Parse the response
if(BitTst(readBuffer[5],3))
{
errorcode = SYNCH_CSSTATETRIS_ERROR_LJ;
}
if(BitTst(readBuffer[5],2))
{
errorcode = SYNCH_SCKTRIS_ERROR_LJ;
}
if(BitTst(readBuffer[5],1))
{
errorcode = SYNCH_MISOTRIS_ERROR_LJ;
}
if(BitTst(readBuffer[5],0))
{
errorcode = SYNCH_MOSITRIS_ERROR_LJ;
}
if (!((readBuffer[6]==98)&&(readBuffer[7]==(unsigned char)numWriteRead)))
{
errorcode = CloseAll(localID);
return RESPONSE_ERROR_LJ;
}
data[0]=readBuffer[4];
data[1]=readBuffer[3];
data[2]=readBuffer[2];
data[3]=readBuffer[1];
for(i=0;i<4;i++)
{
if(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;i<numPackets;i++)
{
memAddress=196+(i*4);
if(!demo)
{
result = ReadMem(idnum,memAddress,&data[4+(i*4)],&data[5+(i*4)],&data[6+(i*4)],&data[7+(i*4)]);
}
else
{
Sleep(20);
}
//fill unused locations with 9999
if(numFill != 4)
{
for(j=0;j<numFill;j++)
{
data[7-j+(i*4)] = 9999;
}
}
if(result) return result;
}
}
return errorcode;
}
//======================================================================
// Watchdog: Controls the LabJack watchdog function.
//
// 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.
// 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<numScansLJ;i++)
{
//Try to read a scan
errorcode=ReadLabJack(localID,(((unsigned long)timeout)*1000),0,readBuffer);
if(errorcode)
{
//There was a read error, so send any command to stop the LabJack
sendBuffer[6]=80; //ReadMem
sendBuffer[7]=0;
sendBuffer[8]=16; //read address 16
//Write & Read data to/from the LabJack
WriteRead(localID,READ_TIMEOUT_MS,sendBuffer,readBuffer);
CloseAll(localID);
return errorcode;
}
//Parse the response
errorcode = ParseAIResponse(sendBuffer,readBuffer,disableCal,calData,&stateIOout[i],&ovtemp,&voltages[i][0],&voltages[i][1],&voltages[i][2],&voltages[i][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;
}
} //end else turbo
}
else
{
//Demo Mode
//simulate time
Sleep(24+((long)(6.0F * (float)rand()/(float)RAND_MAX))); //overhead time
Sleep((long)(((float)numScansLJ * 4.0F) / (*scanRate * (float)numChannels))); //acquisition time
if(turbo)
{
Sleep((long)(((float)numScansLJ * 4.0F) * 0.4F)); //turbo transfer time
}
else
{
Sleep((long)(((float)numScansLJ * 4.0F) * 2.5F)); //normal transfer time
}
for(i=0;i<numScansLJ;i++)
{
voltages[i][0]=2.5F;
voltages[i][1]=2.5F;
voltages[i][2]=2.5F;
voltages[i][3]=2.5F;
if(numChannels == 2)
{
voltages[i][2] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
voltages[i][3] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
}
if(numChannels == 4)
{
voltages[i][1]=-2.5F;
voltages[i][2]=(10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
voltages[i][3]=(10.0F * ((float)(GetTickCount()%2048))/2048) - 5.0F;
}
}
}
//interleave data as needed
if(numChannels == 1)
{
for(i=1023;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<numScans;i++)
{
voltages[i][0]=streamInfo.streamBuff[i][0];
voltages[i][1]=streamInfo.streamBuff[i][1];
voltages[i][2]=streamInfo.streamBuff[i][2];
voltages[i][3]=streamInfo.streamBuff[i][3];
stateIOout[i]=(long)streamInfo.streamBuff[i][4];
if(streamInfo.streamBuff[i][5]) *overVoltage += 1;
*ljScanBacklog=(long)streamInfo.streamBuff[i][6];
}
//Shift any leftover data to the beginning of streamBuff
streamInfo.numScansBuff = streamInfo.numScansBuff - numScans;
for(i=0;i<streamInfo.numScansBuff;i++)
{
streamInfo.streamBuff[i][0]=streamInfo.streamBuff[numScans+i][0];
streamInfo.streamBuff[i][1]=streamInfo.streamBuff[numScans+i][1];
streamInfo.streamBuff[i][2]=streamInfo.streamBuff[numScans+i][2];
streamInfo.streamBuff[i][3]=streamInfo.streamBuff[numScans+i][3];
streamInfo.streamBuff[i][4]=streamInfo.streamBuff[numScans+i][4];
streamInfo.streamBuff[i][5]=streamInfo.streamBuff[numScans+i][5];
streamInfo.streamBuff[i][6]=streamInfo.streamBuff[numScans+i][6];
}
}
else
{
//We need to retrieve scans from the LabJack
//Determine how many LabJack 4-channel scans are required
numScansLJ = ((numScans-streamInfo.numScansBuff)*streamInfo.numChannels)/4;
if((((numScans-streamInfo.numScansBuff)*streamInfo.numChannels)%4) != 0)
{
numScansLJ += 1;
}
//Force numScansLJ to be a multiple of 16
if((numScansLJ % 16) != 0)
{
numScansLJ += (16 - (numScansLJ % 16));
}
//Need to build sendBuffer for ParseAIResponse
BuildAICommand (9,0,0,0,0,streamInfo.ch1num,streamInfo.ch2num,streamInfo.ch3num,streamInfo.ch4num,streamInfo.ch1gain,streamInfo.ch2gain,streamInfo.ch3gain,streamInfo.ch4gain,sendBuffer);
if(streamInfo.demo)
{
for(i=0;i<numScansLJ;i++)
{
if(streamInfo.numChannels == 1)
{
tempBuff[(i*4)][0] = (float)((unsigned int)(streamInfo.scanCount+0));
tempBuff[(i*4)+1][0] = (float)((unsigned int)(streamInfo.scanCount+1));
tempBuff[(i*4)+2][0] = (float)((unsigned int)(streamInfo.scanCount+2));
tempBuff[(i*4)+3][0] = (float)((unsigned int)(streamInfo.scanCount+3));
}
if(streamInfo.numChannels == 2)
{
tempBuff[(i*2)][0] = (float)((unsigned int)(streamInfo.scanCount+0));
tempBuff[(i*2)+1][0] = (float)((unsigned int)(streamInfo.scanCount+1));
tempBuff[(i*2)][1] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
tempBuff[(i*2)+1][1] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
}
if(streamInfo.numChannels == 4)
{
tempBuff[i][0] = (float)((unsigned int)(streamInfo.scanCount));
if(streamInfo.readCount)
{
currentTime = GetTickCount();
tempBuff[i][1] = (float)(currentTime%4096);
tempBuff[i][2] = (float)((currentTime%16777216)/4096);
tempBuff[i][3] = (float)(currentTime/16777216);
}
else
{
tempBuff[i][1] = -2.5F;
tempBuff[i][2] = (10.0F * ((float)rand())/((float)RAND_MAX)) - 5.0F;
tempBuff[i][3] = (10.0F * ((float)(GetTickCount()%2048))/2048) - 5.0F;
}
}
streamInfo.scanCount += 4;
} //end for numScansLJ
//Check for timer roll-over.
if(GetTickCount() < initialTick) initialTick = GetTickCount();
if(GetTickCount() < streamInfo.demoTick) streamInfo.demoTick = GetTickCount();
//Wait for timeout or the proper time delay for this number of scans
while(((GetTickCount()-initialTick)<((unsigned long)(timeout*1000))) && ((GetTickCount()-streamInfo.demoTick)<((unsigned long)(1000*4*((float)numScansLJ)/(streamInfo.scanRate*streamInfo.numChannels)))));
if((GetTickCount()-initialTick) >= ((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<numScansLJ/16;i++)
{
//Turbo: Use control transfers (feature reports).
//Read the feature report (reads 16 scans per call)
errorcode = ReadLabJack(localID,READ_TIMEOUT_MS,1,featureBuff);
if(!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,
streamInfo.disableCal,
calData,
&sio,
&ov,
&v1,
&v2,
&v3,
&v4,
&junk,
&bocsError,
&backlog,
&currentCount,
streamInfo.readCount);
if(streamInfo.numChannels == 1)
{
tempBuff[((i*16)+k)*4][0] = v1;
tempBuff[(((i*16)+k)*4)+1][0] = v2;
tempBuff[(((i*16)+k)*4)+2][0] = v3;
tempBuff[(((i*16)+k)*4)+3][0] = v4;
for(j=0;j<4;j++)
{
tempBuff[(((i*16)+k)*4)+j][4]= (float)sio;
tempBuff[(((i*16)+k)*4)+j][5]= (float)ov;
tempBuff[(((i*16)+k)*4)+j][6]= (float)((backlog * 4)/streamInfo.numChannels);
}
}
if(streamInfo.numChannels == 2)
{
tempBuff[((i*16)+k)*2][0] = v1;
tempBuff[(((i*16)+k)*2)+1][0] = v3;
tempBuff[((i*16)+k)*2][1] = v2;
tempBuff[(((i*16)+k)*2)+1][1] = v4;
for(j=0;j<2;j++)
{
tempBuff[(((i*16)+k)*2)+j][4]= (float)sio;
tempBuff[(((i*16)+k)*2)+j][5]= (float)ov;
tempBuff[(((i*16)+k)*2)+j][6]= (float)((backlog * 4)/streamInfo.numChannels);
}
}
if(streamInfo.numChannels == 4)
{
tempBuff[(i*16)+k][0] = v1;
tempBuff[(i*16)+k][1] = v2;
tempBuff[(i*16)+k][2] = v3;
tempBuff[(i*16)+k][3] = v4;
tempBuff[(i*16)+k][4] = (float)sio;
tempBuff[(i*16)+k][5] = (float)ov;
tempBuff[(i*16)+k][6] = (float)((backlog * 4)/streamInfo.numChannels);
}
if(currentCount==0)
{
if(streamInfo.previousCount != 6)
{
errorcode = AI_SEQUENCE_ERROR_LJ;
}
}
else
{
if(currentCount != (streamInfo.previousCount+1))
{
errorcode = AI_SEQUENCE_ERROR_LJ;
}
}
if(bocsError)
{
if(backlog == 0)
{
errorcode = RAM_CS_ERROR_LJ;
}
else
{
//LabJack buffer overflow.
errorcode = LJ_BUFF_OVERFLOW_LJ;
}
}
if(errorcode)
{
pthread_mutex_unlock(&streamInfoMutex);
CloseAll(localID);
AIStreamClear(localID);
for(m = 0; m < 4096; m++)
{
free(tempBuff[m]);
}
free(tempBuff);
return errorcode;
}
streamInfo.previousCount = currentCount;
streamInfo.scanCount += 4;
} //for 16 scans (1 feature report)
} //end if not errorcode
else
{
pthread_mutex_unlock(&streamInfoMutex);
CloseAll(localID);
for(m = 0; m < 4096; m++)
{
free(tempBuff[m]);
}
free(tempBuff);
return errorcode;
}
Sleep(1);
//Check for timer roll-over.
if(GetTickCount() < initialTick) initialTick = GetTickCount();
//Check for timeout
if((GetTickCount()-initialTick)>((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;i<streamInfo.numScansBuff;i++)
{
voltages[i][0]=streamInfo.streamBuff[i][0];
voltages[i][1]=streamInfo.streamBuff[i][1];
voltages[i][2]=streamInfo.streamBuff[i][2];
voltages[i][3]=streamInfo.streamBuff[i][3];
stateIOout[i]=(long)streamInfo.streamBuff[i][4];
if(streamInfo.streamBuff[i][5]) *overVoltage += 1;
*ljScanBacklog=(long)streamInfo.streamBuff[i][6];
}
//Take the amount of data we need from tempBuff
j = numScans-streamInfo.numScansBuff;
for(i=0;i<j;i++)
{
voltages[i+streamInfo.numScansBuff][0]=tempBuff[i][0];
voltages[i+streamInfo.numScansBuff][1]=tempBuff[i][1];
voltages[i+streamInfo.numScansBuff][2]=tempBuff[i][2];
voltages[i+streamInfo.numScansBuff][3]=tempBuff[i][3];
stateIOout[i+streamInfo.numScansBuff]=(long)tempBuff[i][4];
if(tempBuff[i][5]) *overVoltage += 1;
*ljScanBacklog=(long)tempBuff[i][6];
}
//Put any leftover data in streamBuff
streamInfo.numScansBuff = ((numScansLJ*4)/streamInfo.numChannels) - j;
for(i=0;i<streamInfo.numScansBuff;i++)
{
streamInfo.streamBuff[i][0]=tempBuff[j+i][0];
streamInfo.streamBuff[i][1]=tempBuff[j+i][1];
streamInfo.streamBuff[i][2]=tempBuff[j+i][2];
streamInfo.streamBuff[i][3]=tempBuff[j+i][3];
streamInfo.streamBuff[i][4]=tempBuff[j+i][4];
streamInfo.streamBuff[i][5]=tempBuff[j+i][5];
streamInfo.streamBuff[i][6]=tempBuff[j+i][6];
}
} //end else retrieve scans from LabJack
//Unlock the stream info mutex
if(pthread_mutex_unlock(&streamInfoMutex) != 0)
{
errorcode = RELEASE_DEVICE_LJ;
}
for(m = 0; m < 4096; m++) {
free(tempBuff[m]);
}
free(tempBuff);
return errorcode;
}
//======================================================================
// AIStreamClear: This function stops the continuous acquisition. It
// should be called after AIStreamStart and after any
// calls to AIStreamRead.
//
// Returns: LabJack errorcodes or 0 for no error (I32).
// Inputs: localID -Send the local ID from AIStreamStart/Read (I32).
// Outputs: none
//----------------------------------------------------------------------
long AIStreamClear( long localID)
{
long errorcode=NO_ERROR_LJ;
long junk0=0,junk1=0,junk2=0,junk3=0;
if((localID<0) || (localID>255))
{
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<i; j++)
{
pthread_mutex_unlock(&labjackInfo[j].mutex);
}
return CREATE_MUTEX_LJ;
}
else
{
labjackInfo[i].isMutexInit = true;
}
}
//lock mutex
if(pthread_mutex_trylock(&labjackInfo[i].mutex) != 0)
{
//Could not lock mutex. Close previously locked mutexes.
for(j=0; j<i; j++)
{
pthread_mutex_unlock(&labjackInfo[j].mutex);
}
return CLAIM_ALL_DEVICES_LJ;
}
}
//Search all devices
devCount = LJUSB_GetDevCount(U12_PRODUCT_ID);
for(i = 0; i < devCount; i++)
{
hDevice = LJUSB_OpenDevice(i+1, 0, U12_PRODUCT_ID);
if(hDevice != NULL)
{
//new, good code
errorcode = GetU12Information(hDevice, &serialnumList[*numberFound],
&localIDList[*numberFound], &powerList[*numberFound],
calMatrix[*numberFound], fcddMaxSize,
hvcMaxSize);
if(errorcode == 0)
{
productIDList[*numberFound] = U12_PRODUCT_ID;
*numberFound = *numberFound + 1;
}
LJUSB_CloseDevice(hDevice);
}
}
//Release/unlock mutexes
for(i = 0; i < MAX_DEVICES_LJ; i++)
{
if(pthread_mutex_unlock(&labjackInfo[i].mutex) != 0)
{
errorcode = RELEASE_ALL_DEVICES_LJ;
}
}
return errorcode;
}
//======================================================================
// CloseLabJack: This function forces a device to close so it is free for
// other programs to use. Only useful if you are using
// multiple programs to access the same device at the same
// time as closing the program will close and free the device
// automatically.
//
// Returns: LabJack errorcodes or 0 for no error (I32).
// Inputs: localID -Send the local ID for the device to close (I32).
// Outputs: none
//----------------------------------------------------------------------
long CloseLabJack( long localID)
{
if((localID < 0) || (localID > 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);
}