Galil Motion Control, Inc. DMCQNX - QNX Utilities and Programming Libraries Documentation CONTENTS: INTRODUCTION INSTALLATION UTILITY PROGRAMS PROGRAMMING LIBRARIES SOURCE CODE CROSS REFERENCE PROGRAMMING USING THE API ERROR CODES APPLICATION PROGRAMMING TOPICS DOWNLOADING PROGRAMS TO THE CONTROLLER INTERRUPT HANDLING DIAGNOSTICS RECEIVING LARGE AMOUNTS OF DATA FROM THE CONTROLLER BINARY COMMUNICATIONS (DMC-1800 and DMC-18x2 Only) DATA RECORD ACCESS (DMC-1800 only) INTRODUCTION The Galil QNX Utilities and Programming Libraries support the Galil DMC-1417, DMC-1800, and DMC-18x2 PCI controllers (Ethernet, serial, and ISA controllers are not supported). For those writing application programs in C/C++, the Galil QNX application programming interface (API) is nearly 100 percent compatible with the Galil Windows API. The file dmcqnx.zip includes source code and executables for utility programs (such as a terminal) and for a sample application (simppci). makefile is used to build the sample application and the api library (dmcqnx.lib) and dmcutil.mak is used to build the utility programs and their respective library (dmcutil.lib). INSTALLATION (1) Create a directory to unzip the files in: # mkdir galil # cd galil # (2) Download dmcqnx.zip from the web to this directory: http://www.galilmc.com/support/download.html#linux # ls . .. dmcqnx.zip # (3) Unzip the file: # unzip dmcqnx.zip Archive: dmcqnx.zip inflating: Qnx6PCIStartup.h inflating: bin2dmc inflating: bin2dmc.c inflating: dmca2b inflating: dmca2b.c inflating: dmcb2a.c inflating: dmcbin.c inflating: dmcbin.h inflating: dmcbootp.c inflating: dmccvs.c inflating: dmcdma.c inflating: dmcdma.h inflating: dmcdrc.h inflating: dmcdrco.h inflating: dmceth.h inflating: dmcfmw.h inflating: dmcint.c inflating: dmcint.h inflating: dmcisa.h inflating: dmcpci.c inflating: dmcpci.h inflating: dmcqnx.c inflating: dmcqnx.h inflating: dmcqnx.lib inflating: dmcreset inflating: dmcreset.c inflating: dmcser.c inflating: dmcser.h inflating: dmcsetup inflating: dmcsetup.c inflating: dmcsup.c inflating: dmcsup.h inflating: dmcterm inflating: dmcterm.c inflating: dmcutil.c inflating: dmcutil.h inflating: dmcutil.lib inflating: dmcutil.mak inflating: down2dmc inflating: down2dmc.c inflating: firm2dmc.c inflating: iomsg.h inflating: makefile inflating: readme.txt inflating: send2dmc inflating: send2dmc.c inflating: setup.dmc inflating: simpeth.c inflating: simpisa.c inflating: simppci inflating: simppci.c inflating: simpser.c inflating: stat.h inflating: stdint.h # (4) Run the terminal to verify communication # ./dmcterm Galil Terminal Program for QNX Dec 2003 Specify controller: 1 for DMC-1417 2 for DMC-1800 3 for DMC-18x2 3 CONNECTED ctrl-C quit ctrl-F send file ctrl-H display this help ctrl-L download file ctrl-P previous command ctrl-T set timeout ctrl-U upload file : :MG _BN 7871.0000 : Thank you for using Galil! # (5) Edit line 36 of simppci.c to refelct the controller you are using: # ped simppci.c controllerinfo.usModelID = MODEL_1802; //MODEL_1800 MODEL_1802 MODEL_1417 (6) Edit line 6 of makefile to reflect the location of dmcqnx.lib (the directory you created in step 1): # ped makefile LIBPATH = /root/galil/ (7) Rebuild the sample application simppci (makefile also rebuilds the library dmcqnx.lib) # make CC -c -w -Otax -g2 simppci.c -o simppci.o CC -c -w -Otax -g2 dmcqnx.c -o dmcqnx.o CC -c -w -Otax -g2 -s dmcint.c -o dmcint.o CC -c -w -Otax -g2 dmcsup.c -o dmcsup.o CC -c -w -Otax -g2 dmcpci.c -o dmcpci.o CC -c -w -Otax -g2 dmccvs.c -o dmccvs.o CC -c -w -Otax -g2 dmcdma.c -o dmcdma.o CC -c -w -Otax -g2 dmcbin.c -o dmcbin.o CC -g2 -A dmcqnx.lib dmcqnx.o dmcint.o dmcsup.o dmcpci.o dmccvs.o dmcdma.o dmcbin.o a - dmcqnx.o a - dmcint.o a - dmcsup.o a - dmcpci.o a - dmccvs.o a - dmcdma.o a - dmcbin.o CC -g2 simppci.o -l /root/galil/dmcqnx.lib -o simppci # (8) Run the sample application to verify it communicates with your controller: # ./simppci Simple pci bus communications example for Galil Motion Controllers Connected to serial number 7871.0000 : The value of the inputs is 255 The value of the X axis position is 4000 The value of the X axis position error is 4000 The interrupt status for UI0 is 240 The interrupt status for UI1 is 241 The interrupt status for UI2 is 242 The interrupt status for UI3 is 243 The interrupt status for UI4 is 244 The interrupt status for UI5 is 245 The interrupt status for UI6 is 246 The interrupt status for UI7 is 247 The interrupt status for UI8 is 248 The interrupt status for UI9 is 249 The interrupt status for UI10 is 250 The interrupt status for UI11 is 251 The interrupt status for UI12 is 252 The interrupt status for UI13 is 253 The interrupt status for UI14 is 254 The interrupt status for UI15 is 255 Done # THE FOLLOWING TWO STEPS ARE OPTIONAL IF YOU WISH TO MODIFY THE UTILITES (9) Edit line 3 of dmcutil.mak to reflect the location of dmcqnx.lib and dmcutil.lib (the directory you created in step 1): # ped dmcutil.mak LIBPATH = /root/galil/ (10) Rebuild the utility programs (dmcutil.mak also rebuilds the library dmcutil.lib) # make -f dmcutil.mak cc -c -w -Otax dmcterm.c -o dmcterm.o cc dmcterm.o -l /root/galil/dmcqnx.lib -o dmcterm cc -c -w -Otax down2dmc.c -o down2dmc.o cc -w -Otax -c -o dmcutil.o dmcutil.c cc -A dmcutil.lib dmcutil.o a - dmcutil.o cc down2dmc.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -o down2dmc cc -c -w -Otax send2dmc.c -o send2dmc.o cc send2dmc.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -o send2dmc cc -c -w -Otax dmcreset.c -o dmcreset.o cc dmcreset.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -o dmcreset cc -c -w -Otax dmcsetup.c -o dmcsetup.o cc dmcsetup.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -o dmcsetup cc -c -w -Otax bin2dmc.c -o bin2dmc.o cc bin2dmc.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -l /lib/libm.a -o bin2dmc cc -c -w -Otax dmca2b.c -o dmca2b.o cc dmca2b.o -l /root/galil/dmcqnx.lib -l /root/galil/dmcutil.lib -l /lib/libm.a -o dmca2b # UTILITY PROGRAMS All of the utility programs below accept command line options. To get a list of all the command line options for a particular utility program, simply run the utility program with the following command line option: -? For example, To get a list of all the command line options for DOWN2DMC, type: # ./down2dmc -? * DMCTERM is a terminal program which can communicate with Galil controllers interactively. * DOWN2DMC is a program used to download DMC program files to Galil controllers. Once downloaded, a program may be run on the controller without host intervention. This is also known as background execution. * SEND2DMC is a program which sends your DMC program files to Galil controllers. Sending a file means sending each program line in the file to a controller, one at a time, which the controller will execute immediately. This is also known as foreground execution. * DMCRESET is a program which either resets or master resets a Galil controller from the command prompt. * DMCSETUP is a program which records all the burnable parameters on the controller (those parameters stored in EEPROM) and stores them in a DMC program file. The DMC program file can then be used to restore those parameters at a later time. * BIN2DMC is a program which sends your DMC program files which have been converted from ASCII to binary to Galil controllers. Sending a file means sending each program line in the file to a controller, one at a time, which the controller will execute immediately. This is also known as foreground execution. The DMC-1417 does not accept commands in binary. * DMCA2B is a program which converts DMC commands from ASCII to binary. PROGRAMMING LIBRARIES * DMCQNX.LIB is a static library with a collection of application programming interface (API) routines which a are used to communicate with Galil controllers. This library was written in 'C'. * DMCUTIL.LIB is a static library containing programming routines which are used by the utility programs listed above. It is not necessary to build this library unless you are customizing or re-building one or more of the utility programs. This library is not intended to be included in a user application, but you are free to do so. This library was written in 'C'. CUSTOMIZING THE PROGRAMMING LIBRARIES As they are delivered, all of the programming libraries and utility programs have been built to support only PCI controllers. You will most likely want to customize the programming libraries when you build them for your application program. All of the options which control how they are built are contained in the 'C' language header file DMCQNX.H. To customize the Galil programming libraries, you will comment out or delete one or more lines in this header file. To enable/disable function tracing, include/delete the following line: #define DMC_DEBUG /* Enable debug trace */ To enable/disable support for PCI bus communications, include/delete the following line: #define DMC_PCIBUS /* Enable base PCI bus communications */ To enable/disable support for specific PCI bus communication features, include/delete the following lines: #define DMC_INTERRUPTS /* Enable interrupts */ To enable/disable support for specific communication features include/delete the following lines: /* For the DMC-1800 and DMC-18x2 only) */ #define DMC_BINARYCOMMANDS /* Enable binary command interface */ #define DMC_FIRMWARE /* Enable firmware updates */ /* For the DMC-1800 only */ #define DMC_DATARECORDACCESS /* Enable data record access */ SOURCE CODE CROSS REFERENCE * DMCQNX.LIB (makefile) Source Include Purpose DMCQNX.C DMCQNX.H Main API interface DMCSUP.C DMCSUP.H Support routines for API interface DMCPCI.C DMCPCI.H PCI bus interface DMCSER.C DMCSER.H Serial interface DMCINT.C DMCINT.H Bus interrupts DMCDMA.C DMCDMA.H DMC-1800 data record access DMCBIN.C DMCBIN.H DMC-1800/18x2 binary commands DMCCVS.C DMCBIN.H DMC-1200/1600/1700/1800/2000 binary command * Other Libraries and Utility Functions Object Source Include Makefile DMCUTIL.LIB DMCUTIL.C DMCUTIL.H DMCUTIL.MAK DOWN2DMC DOWN2DMC.C None SEND2DMC SEND2DMC.C None DMCRESET DMCRESET.C None DMCSETUP DMCSETUP.C None BIN2DMC BIN2DMC.C None DMCA2B DMCA2B.C None DMCB2A DMCB2A.C None PROGRAMMING USING THE API All C/C++ application programs written for use with the API will include the header file DMCQNX.H and link with the library DMCQNX.LIB. The basic model for programming is that you call the function DMCOpen to begin a communication session with the Galil controller, call the function DMCCommand to send one or more commands to the Galil controller, and then call the function DMCClose to end the communication session with the Galil controller. It is important that you eventually call DMCClose for each call made to DMCOpen. This will ensure that resources will be freed, especially controller handles. When you call the DMCOpen function, the first argument is a pointer to a structure name CONTROLLERINFO. This structure is used to describe the controller you wish to communicate with to the DMCOpen function. In your program, you should declare a variable of type CONTROLLERINFO, fill in the variable with the relevant controller properties, and pass the address of that variable in the DMCOpen function. The second argument is a pointer to a data type named HANDLEDMC. This represents a handle to a Galil controller. In your program, you should declare a variable of type HANDLEDMC (a long integer) and pass the address of that variable in the DMCOpen function. If the DMCOpen function is successful, the variable will contain the handle to the Galil controller which is required for all subsequent function calls. A VERY simple example follows. long rc; /* Return code */ HANDLEDMC hdmc; /* Handle to the controller */ CONTROLLERINFO controllerinfo; /* Controller information structure */ /* Initialize the controller information structure */ memset(&controllerinfo, '\0', sizeof(controllerinfo)); controllerinfo.cbSize = sizeof(controllerinfo); controllerinfo.usModelID = MODEL_1000; controllerinfo.fControllerType = ControllerTypeISABus; controllerinfo.ulTimeout = 1000; controllerinfo.hardwareinfo.isabusinfo.usAddress = 656; /* Connect to controller */ rc = DMCOpen(&controllerinfo, &hdmc); if (rc == DMCNOERROR) { char szBuffer[64]; /* Move the X axis 1000 counts */ rc = DMCCommand(hdmc, "PR1000;BGX;", szBuffer, sizeof(szBuffer)); /* More commands */ /* Disconnect from controller as the last action */ rc = DMCClose(hdmc); } For a complete sample application program, see the files SIMPPCI.C ERROR CODES DMCNOERROR 0 No error occurred. DMCERROR_TIMEOUT -1 A time-out occurred while waiting for a response from the Galil controller. DMCERROR_COMMAND -2 There was an error with the command sent to the Galil controller. The full message depends on the error code returned from the Galil controller. DMCERROR_CONTROLLER -3 The Galil controller could not be found or there is the CONTROLLERINFO structure is invalid. DMCERROR_FILE -4 File could not be opened. This error usually occurs when the file name is invalid or the file can not be found. DMCERROR_DRIVER -5 Device driver could not be opened, or a read or write error occurred. DMCERROR_HANDLE -6 Invalid Galil controller handle. This error will occur if you try to communicate with the Galil controller without first calling DMCOpen. DMCERROR_HMODULE -7 Not used. DMCERROR_MEMORY -8 Out of memory. DMCERROR_BUFFERFULL -9 Response from the controller was larger than the response buffer supplied. The user-supplied buffer for DMCCommand was too small to fit the complete response from the Galil controller. You can call DMCGetAdditionalResponseLen to find out how much data is left to retrieve and then call DMCGetAdditionalResponse to retrieve the additional response data. DMCERROR_RESPONSEDATA -10 Response from the controller overflowed the internal additional response buffer. The response from the Galil controller was so large that it overflowed both the user-supplied buffer and the internal additional response buffer. You must increase the size of the user-supplied buffer. DMCERROR_DMA -11 Could not communicate with DMA channel. DMCERROR_ARGUMENT -12 One or more required arguments to a DMC API function call was NULL. DMCERROR_DATARECORD -13 Could not access DMA data record. DMCERROR_DOWNLOAD -14 File download failed. The problem is most likely a file that has too many lines or one or more lines which exceed the line length restriction. DMCERROR_FIRMWARE -15 Could not update the controller's firmware. DMCERROR_CONVERSION -16 Could not convert the DMC command (ASCII to binary or binary to ASCII). DMCERROR_REGISTRY -17 Not used. DMCERROR_RESOURCE -18 Not used. All functions return an error code. If the function returned DMCNOERROR (0), the function completed successfully. An error code less than 0 is an error (see the error codes above). API REFERENCE For a detailed list of all the API functions, see the file DMCQNX.H. APPLICATION PROGRAMMING TOPICS DOWNLOADING PROGRAMS TO THE CONTROLLER Two API functions are provided to download Galil language programs to the controller: DMCDownloadFile and DMCDownloadFromBuffer. DMCDownloadFromBuffer assumes that each line of one or more commands is separated by a CR/LF, just as if your buffer was a mirror image of a text file. The program label argument can be used to download the Galil language program to a specific label or program line, or may be set to NULL to replace any existing Galil language program. You may also use the Galil "DL" command to build your own download function. If you do, make sure that you set the time-out (using the API function DMCSetTimeout) to zero as the DL command will not return an acknowledgment from the controller (except in the case of an error) until the end of file character ('\' or Cntl-Z) is sent. Remember to restore the time-out value before exiting your function. INTERRUPT HANDLING Application programs can receive notification of interrupts from the controller (PCI bus controllers only). In order to receive interrupts, you must: 1. Declare and add a function of type PFNINTERRUPTCALLBACK. This function will be your interrupt handler. 2. When you "fill-out" the CONTROLLERINFO structure before calling DMCOpen, make sure you set the hardwareinfo.isabusinfo.usInterrupt and hardwareinfo.isabusinfo.pfnInterruptCallback variables. For example: controllerinfo.hardwareinfo.isabusinfo.usInterrupt = 10; controllerinfo.hardwareinfo.isabusinfo.pfnInterruptCallback = InterruptCallback; 3. Remember to not call any C/C++ library functions which are not reentrant. DIAGNOSTICS There are two API functions DMCDiagnosticsOn and DMCDiagnosticsOff which can be used to provide a detailed trace of communications between your application and the controller. The trace output gets very large very quickly, but it does provide a lot of detail, especially when error conditions arise. To cut down on the amount of trace being output, call DMCDiagnosticsOn as close to the part of your program you wish to debug as possible. In addition, DMCDiagnosticsOn can be called with a flag to append trace output rather than replace trace output. MANAGING THE TIME-OUT VALUE The time-out value used by the API functions is often misinterpreted. The time-out value is used by API functions such as DMCCommand to control how long the function will wait before being able to send a command to the controller (controller status set to ready-to-receive) or how long to wait for a complete response (usually a ":" or "?"). Lowering the time-out value does not mean that the DMCommand or other API functions will respond faster, as most of the time the API functions return long before the time-out has expired. In fact, setting the time-out value too low will cause some functions, such as DMCDownloadFile to fail. For most Galil commands and API functions, the default value of 1000 is usually adequate. Some Galil commands such as master reset (^R^S or the API function DMCMasterReset) may take up to five seconds to complete, so the time-out value may need to be temporarily raised. If you do not care about the response from the controller and/or about time-out conditions, you can set the time-out value to zero. Using the QD command (array download) is a good time to temporarily set the time-out value to zero. The time-out value is initialized to the value passed in the CONTROLLERINFO structure when you call DMCOpen. You can get the current time-out value with the API function DMCGetTimeout. You can set the current time-out value with the API function DMCSetTimeout. RECEIVING LARGE AMOUNTS OF DATA FROM THE CONTROLLER Most Galil language commands return less than 256 characters of data. There are, however, some exceptions such as "LS" to list a program and "QU" to upload an array. Since it is inefficient to allocate a static buffer to handle the largest possible amount of data returned from the controller, how do we handle this case? Call the API function DMCCommand with your "normal" size buffer and inspect the return code. If it is DMCERROR_RESPONSEDATA, your "normal" size buffer is much too small and must be increased. The return code DMCERROR_RESPONSEDATA means that an internal buffer used to hold response data overflow has been exceeded and data has been lost. The size of the internal buffer is determined by the preprocessor variable RESPONSE_BUFFER_SIZE which is defined in DMCQNX.H. If you regularly receive this error, you should increase the value for this variable. If the return code is DMCERROR_BUFFERFULL, you can retrieve the rest of your response data by calling the API function DMCGetAdditionalResponse. The API function DMCGetAdditionalResponseLen will provide the length of buffer needed to retrieve the balance of the data from DMCCommand. For example: long rc; long lDataLength; char szBuffer[256]; rc = DMCCommand(hdmc, "QU ARRAY1[]", szBuffer, sizeof(szBuffer)); if (rc == DMCNOEROR) ; /* return success */ else if (rc == DMCERROR_BUFFERFULL) { rc = DMCGetAdditionalResponseLen(hdmc, &lDataLength); if (rc == DMCNOERROR) { char* pBuffer = (char*)malloc(lDataLength); if (pBuffer) { rc = DMCGetAdditionalResponse(hdmc, pBuffer, lDataLength); if (rc != DMCNOERROR) ; /* return an error */ free(pBuffer); } else ; /* return an error */ } } else ; /* return an error */ LOW-LEVEL I/O There are two functions available for performing low-level I/O: DMCWriteData and DMCReadData. They are ideal if you need to send data to the controller which is time critical, such as contour data or linear interpolation segments. The most important point to remember if you use DMCWriteData to send commands to the controller, is that you need to periodically call DMCReadData or DMCClear to clear the outbound FIFO or communications buffer. Failure to do so will cause communications and application programs to halt. BINARY COMMUNICATIONS (DMC-1800 and DMC-18x2 Only) All Galil controllers are communicated with in ASCII format. That is, you send commands in ASCII and the controller responds in ASCII. The Galil DMC-1800, and DMC-18x2 add a binary form of communication: you can send commands in binary format. The controller responds to binary commands the same as ASCII commands: by ASCII. The advantage of sending commands in binary is speed of execution. If the command is already in binary form, it does not need to be decoded by the controller resulting in higher throughput. Sending contour data is one area where speed is critical and may gain from sending commands in binary. Use the API function DMCBinaryCommand to send a command to the controller in binary. Use the API function DMCSendBinaryFile to send a file of binary commands to the controller. In addition, there are API functions to convert commands and files to/from ASCII/binary. Note that converting a command from ASCII to binary in-line (on-the-fly) may still result in improved throughput. An example follows of converting a command from ASCII to binary on-the-fly then sending it to the controller. LONG rc; CHAR szCommand = "PR1000,2000" CHAR szResponse[256]; BYTE BinaryCommand[32]; ULONG BinaryCommandLength; /* Convert a command from ASCII to binary */ rc = AsciiCommandToBinaryCommand(szCommand, strlen(szCommand), BinaryCommand, sizeof(BinaryCommand), &BinaryCommandLength); /* Send the binary command to the controller and get the response */ rc = BinaryCommand(BinaryCommand, BinaryCommandLength, szResponse, sizeof(szResponse)); DATA RECORD ACCESS (DMC-1800 only) The Galil DMC-1800 has a feature called Data Record Access. The controller can provide, at specified intervals, a data record containing status information for the controller in general and for each axis. The data record is sent from the controller to the PC via a secondary FIFO channel. The Galil command "DR" is used to set the Data Record refresh rate. The data record is always available, even if the primary FIFO channel is blocked because a trip-point (such as after motion) is pending. The standard data record structure is as follows: General Information unsigned short int SampleNumber unsigned char Input0 (Inputs 0 - 7) unsigned char Input1 (Inputs 8 - 15) unsigned char Input2 (Inputs 16 - 23) unsigned char Input3 (Inputs 24 - 31) unsigned char Input4 (Inputs 32 - 39) unsigned char Input5 (Inputs 40 - 47) unsigned char Input6 (Inputs 48 - 55) unsigned char Input7 (Inputs 56 - 63) unsigned char Input8 (Inputs 64 - 71) unsigned char Input9 (Inputs 72 - 79) unsigned char Output0 (Outputs 0 - 7) unsigned char Output1 (Outputs 8 - 15) unsigned char Output2 (Outputs 16 - 23) unsigned char Output3 (Outputs 24 - 31) unsigned char Output4 (Outputs 32 - 39) unsigned char Output5 (Outputs 40 - 47) unsigned char Output6 (Outputs 48 - 55) unsigned char Output7 (Outputs 56 - 63) unsigned char Output8 (Outputs 64 - 71) unsigned char Output9 (Outputs 72 - 79) unsigned char ErrorCode unsigned char Status unsigned short int SegmentCount (S) unsigned short int CoordinatedMoveStatus (S) long CoordinatedMoveDistance (S) Some firmware revisions also include information for the coordinated motion T axis, which repeats the last three items: unsigned short int SegmentCount (T) unsigned short int CoordinatedMoveStatus (T) long CoordinatedMoveDistance (T) Axis Information (Repeated for each Axis) unsigned short int Status unsigned char Switches unsigned char StopCode long ReferencePosition long MotorPosition long PositionError long AuxillaryPosition long Velocity short int Torque short int Analog Input* * Since the Analog Input data is contained in the Axis Information section, you can only retrieve data for the analog inputs up to the number of axes on your controller. This is because Analog Input 1 is with the X axis information, Analog Input 2 is with the Y axis information, and so on. Six API functions are provided to use the Data Record Access feature. DMCRefreshDataRecord gets a new copy of the data record and places it in system memory. This function must be called each time you wish to update the data record. DMCGetDataRecord and DMCGetDataRecordByItemId get a specific data record item from the copy of the data record already in memory. The header file DMCDRC.H defines several enums which list all the data record item by offsets and by Ids. DMCCopyDataRecord is used to copy the data record from system memory to a local buffer in your application program. In order to determine how large the local buffer must be, you must call DMCGetDataRecordSize. The following sample code demonstrates how to retrieve the motor position for the X, Y, and Z axes: long rc; long xPos, yPos, zPos; USHORT usDataType; /* Refresh the data record - we want comparable information (same sample period or time interval) for all three axes */ rc = DMCRefreshDataRecord(hdmc, 0); /* Note: always set the data type argument to 0 before calling DMCGetDataRecord, unless you know the data type. Acceptable data types are listed in the enum DMCDataRecordTypes in DMCDRC.H */ /* Get the X axis motor position */ usDataType = 0; rc = DMCGetDataRecord(hdmc, REV4GenOffAxis1, REV4AxisOffAxisMotorPosition, &usDataType, &xPos); /* Get the Y axis motor position */ usDataType = 0; rc = DMCGetDataRecord(hdmc, REV4GenOffAxis2, REV4AxisOffAxisMotorPosition, &usDataType, &yPos); /* Get the Z axis motor position */ usDataType = 0; rc = DMCGetDataRecord(hdmc, REV4GenOffAxis3, REV4AxisOffAxisMotorPosition, &usDataType, &zPos); You will notice that the offset constants are prefixed with a revision number. This is because the data record structure is periodically updated. In order to determine which revision of the Data Record Access feature is available on your controller, call the API function DMCGetDataRecordRevision. In order to insulate your program from changes in offset values, you could use the API function DMCGetDataRecordByItemId instead of the API function DMCGetDataRecord. Because DMCGetDataRecordByItemId uses Ids which never change over time, you will never have to modify your application program if new firmware on your controller changes the data record structure. There is a very slight performance penalty. The above example using DMCGetDataRecordByItemId is repeated below: /* Refresh the data record - we want comparable information (same sample period or time interval) for all three axes */ rc = DMCRefreshDataRecord(hdmc, 0); /* Get the X axis motor position */ rc = DMCGetDataRecordByItemId(hdmc, DRIdAxisMotorPosition, DRIdAxis1, &usDataType, &xPos); /* Get the Y axis motor position */ rc = DMCGetDataRecordByItemId(hdmc, DRIdAxisMotorPosition, DRIdAxis2, &usDataType, &xPos); /* Get the Z axis motor position */ rc = DMCGetDataRecordByItemId(hdmc, DRIdAxisMotorPosition, DRIdAxis3, &usDataType, &xPos); Data Record Access Using DMCGetDataRecordQR or DMCCopyDataRecord Some controllers such as the DMC-18x2 and the DMC-2000 do not implement the Data Record Access feature with a secondary communications channel. They do, however, support a form of Data Record Access via the QR command. This command returns, in binary format, a copy of the current data record on demand. There is no need to call the function DMCRefreshDataRecord. Use the DMCDATARECORDQR structure (defined in DMCDRC.H) to overlay the binary data returned. It can be used with the function DMCGetDataRecordQR in the following way: LONG rc; DMCDATARECORDQR MyDataRecordQR; rc = DMCGetDataRecordQR(hdmc, &MyDataRecordQR, sizeof(MyDataRecordQR)); The QR command can return a full copy of the data record or a subset depending on the arguments used with it. When you use the DMCGetDataRecordQR function, the full data record is always returned. For more information, consult the Galil Command Reference for your controller. Note: you may wish to alter the DMCDATARECORDQR structure depending on your controller's configuration. See the header file DMCDRC.H for more details. For controllers which implement the Data Record Access feature with a secondary communications channel, the function DMCCopyDataRecord can be used to retrieve a copy of the current data record (current as of the last call to the function DMCRefreshDataRecord). The structure DMCDATARECORD can be used as template for the data returned. The actual length of the data returned can be determined by using the function DMCGetDataRecordSize. You MUST allocate sufficient storage for the entire data record before calling the function DMCCopyDataRecord. An example follows: LONG rc; USHORT RecordSize; DMCDATARECORD MyDataRecord; rc = DMCGetDataRecordSize(hdmc, &RecordSize); if (sizeof(MyDataRecord) >= RecordSize) // Safe to make call rc = DMCCopyDataRecord(hdmc, (PVOID)&MyDataRecord); else // Must allocate more storage by adjusting DMCDATARECORD structure ; Note: you may wish to alter the DMCDATARECORD structure depending on your controller's configuration. See the header file DMCDRC.H for more details.