C/C++ Developer's API usage examples

The following shows sample application framework using SP_InitAllDevices()
for sample application framework using SP_InitAllDevices_Thread() go here
 



Samples shown for Win98/WinME only
For Win2k/WinXP change only
LL_USB.DLL   to   LL_USB2k.DLL
in all prototypes and calls shown below.


Variable type syntaxing
go HERE for description of each.


Code compilation instructions:  
USE ONE OR THE OTHER
#1 Set your IDE to compile using   _stdcall calling convention and 4-byte structure alignment.
#2 Place the line:
     #pragma pack(push, 4)
at top of header, and:
     #pragma pack(pop)
at bottom of header file
Also:   important function prototype info





Function call prototypes and pointer casting from header file.
(only those used in following example shown)

typedef BOOLEAN(*P_SP_INIT_ALL_DEVICES)
          (USHORT* pDevList, BYTE* pbNumDevices_LV, DOUBLE* dblRate, BOOLEAN fShowDevList);
          P_SP_INIT_ALL_DEVICES    pSP_InitAllDevices = NULL;

typedef BOOLEAN(*P_SP_INIT_ALL_DEVICES_THREAD)
          (USHORT* pDevList, DOUBLE* dblRate, BOOLEAN fShowDevList);
          P_SP_INIT_ALL_DEVICES_THREAD    pSP_InitAllDevices_Thread = NULL;

typedef BOOLEAN(*P_SP_GET_ONE_CONVERSION)
          (USHORT usDevID, UINT* uiConvRawCount, DOUBLE* dblRate, BYTE bCurChan, BYTE* pbLastDigin);
          P_SP_GET_ONE_CONVERSION    pSP_GetOneConversion = NULL;

typedef BOOLEAN(*P_DLL_START_SCAN)
          (USHORT usDevID, PSCAN_OBJECT_DIO pScanObj_DIO, BYTE bStartMode );
          P_DLL_START_SCAN    pDLL_StartScan_DIO = NULL;

typedef BOOLEAN(*P_DLL_READ_SCAN_DATA)
          (USHORT usDevID, UINT* puiDataBuff, SHORT numPointsToRead, PSCAN_OBJECT_DIO pScanObj_DIO);
          P_DLL_READ_SCAN_DATA    pDLL_ReadScanData_DIO = NULL;

typedef BOOLEAN(*P_SP_END_SCAN)
          (USHORT usDevID);
          P_SP_END_SCAN    pSP_EndScan = NULL;

typedef BOOLEAN(*P_SP_SEND_CHAN)
          (USHORT usDevID, BYTE bCurChan, BYTE* pbLastDigin);
          P_SP_SEND_CHAN    pSP_SendChan = NULL;

typedef BOOLEAN(*P_SP_SEND_DIG_OUT)
          (USHORT usDevID, BYTE bDigOut, BYTE* pbLastDigin);
          P_SP_SEND_DIG_OUT    pSP_SendDigOut = NULL;

typedef BOOLEAN(*P_SP_SEND_DAC)
          (USHORT usDevID, DOUBLE dblVoltage, BYTE bDAC, BYTE* pbReserved);
          P_SP_SEND_DAC    pSP_SendDAC = NULL;

typedef BOOLEAN(*P_SP_SEND_RATE)
          (DOUBLE* dblRate, USHORT usDevID);
          P_SP_SEND_RATE    pSP_SendRate = NULL;








Variables declarations from header file

Initialization related
#define MAX_DEV_CNT = 32

HINSTANCE hDLL;
USHORT ausDevList[MAX_DEV_CNT];
USHORT* pausDevList = ausDevList;
DOUBLE adblRate[MAX_DEV_CNT];
DOUBLE* padblRate = adblRate;
BYTE bNumDevices, bCurChan, bLastDigin, bCurListIndex;
BOOLEAN fShowDevList;



Get one conversion
UINT uiConvRawCount;



Scan related
typedef struct _SCAN_OBJECT{      // NOTE:  Most commonly used members are underlined
BYTE SO_bScanType; // app writes (needed by DLL to start scan)
DOUBLE SO_dblDevRate; // app writes (needed by DLL to start scan)
UINT SO_uiTotalPointsReadByDrvr; // DLL writes (can be read by app)
UINT SO_uiPointsInBuffer; // DLL writes (app reads this to get num points available to be read)
UINT SO_uiStatus; // DLL writes (important scanning status information needed by app)
UINT SO_uiSizeVoltageArray; // No longer used (but must be present as placeholder)
UINT SO_uiCurHead; // DLL writes (can be read by app)
UINT SO_uiCurTail; // DLL writes (can be read by app)
BYTE SO_bDigitalInput; // DLL writes (can be read by app)
BYTE SO_bChecksum; // DLL writes (can be read by app)
BYTE SO_bDeviceDisconnect; // No longer used (but must be present as placeholder)
UINT SO_uiScanStartTime; // No longer used (app may use for convenience)
UINT SO_uiScanEndTime; // No longer used (app may use for convenience)
BYTE SO_bScanArg; // app writes (needed by DLL to start scan)
SCAN_OBJECT, *PSCAN_OBJECT;
'NOTE:  The following are possible bit settings for SO_Status shown above
#define SCAN_RUNNING    0x1 not currently used
#define SCAN_DATA_REQUEST_SUCCEEDED    0x2 not currently used
#define SCAN_ENDING    0x4 not currently used
#define SCAN_HALTED    0x8 if set, the device is no longer scanning
#define SCAN_CHECKSUM_ERROR    0x10 if set there has been a checksum error
#define SCAN_VOLTAGE_BUFFER_WRAP    0x20 indicates a wrap in the DLL's data buffer
#define SCAN_MICRO_CODE_BUFF_WRAP    0x40 indicates a wrap in the device's data buffer
#define SCAN_DEVICE_IO_ERROR    0x80 indicates I/O error
#define SCAN_DEVICE_DISCONNECTED    0x100 The device has been disconnected
#define SCAN_DEVICE_NOT_FOUND    0x200 not currently used


'NOTE:  The following are possible bit settings for SO_bScanType shown above
#define CMND_SINGLE_CHAN_SCAN    1 // single chan scan (normal)
#define CMND_SINGLE_CHAN_DIGIN_SCAN    2 // single chan with digin after every conversion
#define CMND_MULTI_CHAN_SCAN    3 // multi chan regular
#define CMND_MULTI_CHAN_CAL_SCAN    4 // multi chan with cal
#define CMND_MULTI_CHAN_DIGIN_SCAN    5 // multi chan with digin
#define CMND_MULTI_CHAN_DIGIN_CAL_SCAN    6 // multi chan with cal and digin









Function call examples

Preinitialization
BOOLEAN DoPreInitialization(void)
{
//Initialize global variables that will be used later on
memset(ausDevList, 0, sizeof(ausDevList));
memset(adblRate, 0, sizeof(adblRate));
bCurChan = 6;
bCurListIndex = 0;
if(!hDLL) LoadLibrary("LL_USB.DLL");
if((!hDLL) return FALSE;

return TRUE;
}



Initialize all devices
BOOLEAN Initialize(void)
{
bCurListIndex = 0;
ausDevList[bCurListIndex] = 199;   // your device ID here
adblRate[bCurListIndex] = 200;   // your desired rate here
fShowDevList = FALSE;

pSP_InitAllDevices = (P_SP_INIT_ALL_DEVICES)GetProcAddress(hDLL, "SP_InitAllDevices");
if(!pSP_InitAllDevices)
{ /* do critical error handling here and exit
*/    return FALSE; }

if(!pSP_InitAllDevices(pausDevList, &bNumDevices, padblRate, FALSE))
{ /* do critical error handling here and exit
*/    return FALSE; }

NOTE:
    This function does not return until it's attempted to initialize all of the devices listed in ausDevList. Each device could take up to 3 seconds. If you are using 3 or more devices, it's recommended that you use SP_InitAllDevices_Thread(), discussed elsewhere within this documentation.
    Place only those devices that you wish to initialize, in the ausDevList array, any devices already initialized will remain undisturbed.
}



GetOneConversion
BOOLEAN SP_GetOneConversion(void)
{
bCurListIndex = 0

pSP_GetOneConversion = (P_SP_GET_ONE_CONVERSION)GetProcAddress(hDLL, "SP_GetOneConversion");
if(!pSP_GetOneConversion)
{ /* do critical error handling here and exit
/*    return FALSE; }

if(!pSP_GetOneConversion(pausDevList[bCurListIndex], &uiConvRawCount, bCurChan, &bLastDigin)
{ /* do critical error handling here and exit
*/    return FALSE; }


//display +-5 volt range in a Windows message box
char szTempBuff[128];
sprintf(szTempBuff, "Voltage: \r\n\r\n%lf", ((INT)uiConvRawCount - 8388608) * 0.00000059604645);
MessageBox(GetForegroundWindow(), szTempBuff, " VOLTAGE----", 0);

NOTE:
     The SP_GetOneConversion() function returns 24-bits of valid data in a 32-bit variable. I convert it to a signed value above just so that I can more easily manipulate the result to a +-5Volt value.
     Please note that even though the current channel is passed as an argument in this call, it is not used unless the DLL experiences an error while communicating with the device, in which case it will take steps to recover from the error... one of which includes resetting the device for which it needs the channel value passed to it in this call. It is important for you to understand that you must set the channel to what you want it to be each time after initialization, ending a scan, or just when you want a different channel selected. Use SP_SendChan() shown further down in this file to do a channel change.

return TRUE;
}



Scanning -   (includes reading scan data and ending scan)

showing single chan scan (CMND_SINGLE_CHAN_SCAN)

links to other scan type examples:
          CMND_SINGLE_CHAN_DIGIN_SCAN single chan - includes digital input in separate buffer with each data point
          CMND_MULTI_CHAN_SCAN multi chan scan (normal)
          CMND_MULTI_CHAN_CAL_SCAN multi chan - includes chan 7 with each scan
          CMND_MULTI_CHAN_DIGIN_SCAN multi chan - includes digital input in separate buffer with each data point
          CMND_MULTI_CHAN_DIGIN_CAL_SCAN multi chan - includes digital input in separate buffer with each data point and chan 7 each scan

BOOLEAN DoScan(void)
{
NOTE: The following is just a simple overview of the single-channel scanning procedure.
Please see sample source code downloadable from web site for better example.

#define MAX_BUFF_SZ 10
UINT auiDataBuff[MAX_BUFF_SZ];
UINT* pauiDataBuff = auiDataBuff;
USHORT usNumPointsToRead;
bCurListIndex = 0;
SCAN_OBJECT ScanObject;
PSCAN_OBJECT pScanObject = &ScanObject;

// only members required for this type of scan are initialized.
pScanObject->SO_uiStatus = 0;
pScanObject->SO_bScanType = CMND_SINGLE_CHAN_SCAN;
pScanObject->SO_dblRate = adblRate[bCurListIndex];
pScanObject->SO_uiPointsInBuffer = 0;

// Assign the various scan related function call pointers
pDLL_StartScan_DIO = (P_DLL_START_SCAN)GetProcAddress(hDLL, "DLL_StartScan_DIO");
if(!pDLL_StartScan_DIO) { /* do critical error handling here and exit */;   return FALSE; }
pDLL_ReadScanData = (P_DLL_READ_SCAN_DATA)GetProcAddress(hDLL, "DLL_ReadScanData_DIO");
if(!pDLL_ReadScanData) { /* do critical error handling here and exit */;   return FALSE; }
pSP_EndScan = (P_SP_END_SCAN)GetProcAddress(hDLL, "SP_EndScan");
if(!pSP_EndScan) { /* do critical error handling here and exit */;   return FALSE; }

// Start the scan
if(!pDLL_StartScan_DIO(pausDevList[bCurListIndex], pScanObject, 0)
{ /* do critical error handling here and exit
*/    return FALSE; }

char szBuff [2048],    szBuff_Temp[128];
UINT SO_uiStatus_TEMP;

// Make the following anything within reason. The driver reads a minimum of 10 points with each
//    read of the device so it's recommended that you ask for an amount of points divisible by 10
//    with each read from the DLL.

USHORT usNumPointsToRead = 10;

sprintf(szBuff, "SCAN Voltages\r\n\r\n");
clock_t clkScanTestTimeout = clock() + 2000;

NOTE: This scan (since it's single channel) will scan the channel set by last call to SP_SendChan()
For this example I'll just get 10 scans and then end the scan, displaying the data in a MessageBox.
while (TRUE)
{
     //Check to see if all of our scans are ready yet.
     //Calling this with usNumPointsToRead set to 0 updates pPSCAN_OBJECT->SO_uiPointsInBuffer

     pDLL_ReadScanData(pausDevList[bCurListIndex], pauiDataBuff, 0, pPSCAN_OBJECT);
     if (pPSCAN_OBJECT->SO_uiPointsInBuffer >= usNumPointsToRead)
     {
         // Read the data
         pDLL_ReadScanData(pausDevList[bCurListIndex], pauiDataBuff, usNumPointsToRead, pPSCAN_OBJECT);
         for (BYTE bIndex = 0; bIndex < 10; bIndex++)
         {
             sprintf(szBuff_Temp, "%lf\r\n", ((INT)pauiDataBuff[bIndex] - 8388608) * 0.00000059604645);
             strcat(szBuff, szBuff_Temp);
         }
         break;
     }
     else
     {
          // Do some kind of handling of error bits that may be set in pPSCAN_OBJECT->SO_uiStatus.
          // See possible bit settings above (Scan related variables). at least test for scan HALTED.

          SO_uiStatus_TEMP = pPSCAN_OBJECT->SO_uiStatus;   // easier to bit test as a fixed variable instead of a pointer.
          if(SO_uiStatus_TEMP & SCAN_HALTED)   break;
          if(clock() > clkScanTestTimeout) { sprintf(pBuff, "\r\rScan TIMEOUT ERROR\r\n");   break; }
          Sleep(100);
     }
}

// Always end the scan when finished
if(!pSP_EndScan(pausDevList[bCurListIndex]))
{ /* do critical error handling here
*/ }

// Display the data just using a simple MessageBox
MessageBox(GetForegroundWindow(), pBuff, " SCAN DATA --------", 0);

return TRUE;
}



Channel Change
BOOLEAN SendChan(void)
{
BYTE bChanToSendLocal = 7;
bCurListIndex = 0;

NOTE: pbLastDigin remains unchanged in this call. It is included only for backward compatibility
if(!pSP_SendChan(pausDevList[bCurListIndex], bCurChan, pbLastDigin))
{ /* do critical error handling here
*/ }

// Update controls to reflect new channel and digital input value
}



Send digital output
BOOLEAN SendDigOut(void)
{
BYTE bDigOut = 170;
bCurListIndex = 0

NOTE: pbLastDigin remains unchanged in this call. It is included only for backward compatibility
if(!pSP_SendDigOut(pausDevList[bCurListIndex], bDigOut, pbLastDigin))
{ /* do critical error handling here
*/ }

// Update controls to reflect new digital output values
}



Send analog output
BOOLEAN SendAnalogOut(void)
{
// Supported by Model 302 only

BYTE bDAC = 1;
DOUBLE dblVoltage = 2.5;
bCurListIndex = 0;

if(!pSP_SendDAC(pausDevList[bCurListIndex], dlbVoltage, bDAC, bReserved))
{ /* do critical error handling here
*/ }

// Update controls to reflect new DAC settings
}



Change rate
BOOLEAN SendRate(void)
{
DOUBLE dblRate = 600;
bCurListIndex = 0;
if(!pSP_SendRate(&dlbRate, pausDevList[bCurListIndex]))
{ /* do critical error handling here
*/ }

// Update controls to reflect new rate settings
}


back to main page Table of Contents     (use browser "back" button to go back to other locations)


lawsnlab@lawsonlabs.com
last modified: 5-16-02  













































Important function call prototype info



If you do not set your IDE to use   "__stdcall"   calling convention you must preface each casting of function call pointer with the word   "CALLBACK"   like this:
typedef BOOLEAN(CALLBACK *pSP_SendDigOut)(USHORT usDevID, BYTE bDigOut, BYTE* pbLastDigin);
pSP_SendDigOut SP_SendDigOut = NULL;


otherwise you can simple do the following:
typedef BOOLEAN(*pSP_SendDigOut)(USHORT usDevID, BYTE bDigOut, BYTE* pbLastDigin);
pSP_SendDigOut SP_SendDigOut = NULL;
**Please use browser BACK button to return to where you were.











































The requested HTML is not yet ready



Please use browser BACK button to return to where you were.







lawsnlab@lawsonlabs.com
last reviewed/modified: 9-29-03 (Tim Van Dusen)