
27-Jan-97

The Oregon Micro Systems PC3X8 motor controller device driver allows the
programmer to use Windows NT 3.51 and NT4.0 file system functions to
communicate with OMS PC38 and equivalent motor controller boards.  This
version of the driver allows the
programmer:
- To install separate copies of the driver for up to four controllers.
- To specify each controller's base address, IRQ level and Dual Port Ram
  segment address.
- Access to a single controller board from multiple execution threads. 
  

DRIVER INSTALLATION

To install the OMS motor controller driver:

 - If you have one PC3X controller installed copy omsntdrv.sys from the
   installation disk to the windows\system32\drivers subdirectory as
   omsnt_1.sys.  This will provide the driver for device OMS1.
   For each additional PC3X8 controller repeat the above proceedure except copy
   omsntdrv.sys to omsnt_2.sys ... 
   
 - If this is the first PC3X use the INSTOMS1 utility to install the driver.
   Use a command of the form:
   instoms1  <base address> <IRQ>
   For example entering the command:
   instoms1 300 5  
   would install a copy of the driver and :
   - Assign this controller the device name PC58_1.
   - Tell the driver that the controller's base address is 0x300.
   - Tell the driver that the controller's IRQ level is 5.
   Repeat the above proceedure for additional PC3X controllers except use the
   INSTOMS2... utilities.  

Note:
   valid values for the instoms parameters are:  
   -  0x200 <= base address <= 0x3fc 
   -  3 <= IRQ level <= 15
   
Once installed the driver will be loaded and started each time your NT
system is booted.

The driver can be uninstalled via the remoms utility i.e.

   remoms 1

Note:
   valid values for the remoms parameters are:  
   - 1 <= controller id <= 4


USING THE DRIVER

See the testdrv.c program for an example of a single thread program that
illustrates the use of the driver's I/O control functions.
See the task8.c program for an example of multi-thread use of the driver.

Access to the driver's I/O functions require a device handle.  The following
code fragment illustrates how to obtain a device handle to OMS1:
  
 char     completeDeviceName[64] = "\\\\.\\OMS1";
 
 HANDLE   hDevice;        //Device driver handle for the CreateFile function
    ...
    ...
 //Get a device handle to the motor controller driver OMS1
 hDevice = CreateFile (completeDeviceName,
                       GENERIC_READ | GENERIC_WRITE,
                       0,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       NULL
                       );

 if (hDevice == ((HANDLE)-1))
 {
    printf ("Can't get a handle to OMS1\n");
    exit(1);        
 }
 else
 {
    printf ("CreateFile SUCCESS\n");
 }
    

The Windows NT SDK function DeviceIoControl is used to communicate
with the device driver via several special I/O control codes.  The
I/O Control codes are described below:


 - IOCTL_OMS_COMMAND -
 
   The IOCTL_OMS_COMMAND I/O control function code is used to send a null
   terminated ASCII command string to the controller.  Control is returned
   to the application program as soon as the driver has sent the last
   character of the command string to the controller.  The number of command
   characters sent to the controller will be returned to the application.
   Note if the driver does not complete sending the command string within two
   seconds the I/O request will time out and a charater count of zero will
   returned to the application.  Therefore the program should check this count
   and if it is zero handle the error condition.
                       
 The follwing code fragments illustate the use of the IOCTL_OMS_COMMAND
 function:
 
 #include <windows.h>
 #include <winioctl.h>
 ...
 ... 
 //Define the OMS NT driver I/O control codes
 #include "NTIOCTL.H"
 ...
 ...                                              
 //Define a move command string
 char Command[128] = "aa mr1000,1000,1000,1000,1000,1000,1000,1000;gd id";
 
 HANDLE   hDevice;        //Device driver handle from the CreateFile function
 BOOLEAN  Status;
 DWORD    BytesReturned;
 UCHAR    CommandCharsSent;
 
...
...
 //Send a move command string to the controller.
 Status = DeviceIoControl(
                          hDevice,                  //Device handle
                          (DWORD)IOCTL_OMS_COMMAND, //IOCTL code
                          (LPVOID)Command,          //Command string
                          (DWORD)128,               //Max length of string
                          &CommandCharsSent,        //Returns count of
                                                    // command chars sent
                          (DWORD)1,                 //...
                          &BytesReturned,           //Not used but required
                           NULL);                   //Synchronous Operations
                           
 if(CommandCharSent == 0)
 {
  //Handle command send error here...
 
 }                          

 - IOCTL_OMS_QUERY -
 
   The IOCTL_OMS_QUERY I/O control function code is used to send a null
   terminated ASCII command string to the controller and then return the
   controller's ASCII response to the application program.  Control will be
   returned to the application when:
   -  The controller has completed sending it's ASCII response to the 
      host computer.  Carriage returns and line feeds will be stripped from
      the response and all text up to the second line feed will be returned
      to the application program, as a null terminated string.  Any characters
      following the second line feed will be discarded.  Therefore each query
      command string, sent to the controller, must not contain more than one
      controller command that requests a response.
   -  If the controller does not send response text within two seconds
      the I/O request will time out and a null string will be returned to
      the application program.  Therefore the programmer should check
      for null response strings and if one is detected they should determine
      if:
      - The command string sent actually contains a controller command that
        requests a response.
      - Determine if a string containing an invalid command was sent.
      - Determine if one of the axis command queues has become full and the
        controller is having to wait, for axis command queue space to become
        available, before it can finish decoding a command.
                          
   The follwing code fragments illustate the use of the IOCTL_OMS_QUERY
   function:
 
   #include <windows.h>
   #include <winioctl.h>
   ...
   ... 
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
   ...
   ...                                              
   //  Define an axes position request command string
   char Command[128] = "aa rp";
   //Alocate a buffer to receive the controller's ASCII response
   char Response[128];
 
   HANDLE   hDevice;        //Device driver handle from the CreateFile function
   BOOLEAN  Status;
   DWORD    BytesReturned;
   ...
   ...
   //  Send an axes position request command string to the controller and collect
   //  the controller's response.
   Status = DeviceIoControl(
                            hDevice,                //Device handle
                            (DWORD)IOCTL_OMS_QUERY, //IOCTL code
                            (LPVOID)Command,        //Command string
                            (DWORD)128,             //Max length of cmd string
                            (LPVOID)Response        //Response goes here
                            (DWORD)128,             //Maximum response size
                            &BytesReturned,         //Actual length of the 
                                                    //response, including the null
                             NULL);                 //Synchronous Operations

   if(Response[0] != (UCHAR)NULL)
      printf("Axes positions are %s \n", Response);
   else
      printf("Controller did not send a response with in 2 seconds. \n");   


    
 - IOCTL_OMS_READ_STATUS -
 
   Each time the driver's interrupt service routine responds to a controller
   interrupt request the controller's status register is read.  If the
   controller has set any of the following status flags:
    - Bit 0 = A command error has been detected
    - Bit 1 = The controller is initializing
    - Bit 2 = An encoder slip error has been detected
    - Bit 3 = An axis over travel has been detected.
   they will be added to the driver's copy of the flags via a logical OR.
   The IOCTL_OMS_READ_STATUS I/O control function code is used to read
   this copy of the controller's status flags.  Note once the application
   has processed this status data the flag bits must be cleared.  See the
   IOCTL_OMS_CLR_STATUS function described below.
    
 The follwing code fragments illustate the use of the IOCTL_OMS_READ_STATUS
 function:
 
 #include <windows.h>
 #include <winioctl.h>
 ...
 ... 
 //Define the OMS NT driver I/O control codes
 #include "NTIOCTL.H"
 ...
 ...
 HANDLE   hDevice;        //Device driver handle from the CreateFile function
 BOOLEAN  Status;
 DWORD    BytesReturned;
 UCHAR    StatusFlags;
                                               
 //Read the driver's copy of the status flags                         
 Status = DeviceIoControl(
                           hDevice,
                          (DWORD)IOCTL_OMS_READ_STATUS, //Read status flags
                          (LPVOID)NULL,                 //String not sent
                          (DWORD) 0,                    //...
                          &StatusFlags,                 //Status flags go here
                          (DWORD)1,                     //Return one byte
                          &BytesReturned,               //Actual bytes returned
                           NULL);                       //Synchronous operations
 printf("Controller status = %0x \n", StatusFlags);
    
    
 - OMS_CLR_STATUS -
 
   After the status flag information has been processed by the
   application program it must be cleared.  The IOCTL_OMS_CLR_STATUS I/O
   control function code is used to clear selected bits in the driver's
   copy of the controller's status flags.
    
   The follwing code fragments illustate the use of the IOCTL_OMS_CLR_STATUS
   function:
   
   #include <windows.h>
   #include <winioctl.h>
   ...
   ... 
   
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
   ...
   ...
   HANDLE   hDevice;        //Device driver handle from the CreateFile function
   BOOLEAN  Status;
   DWORD    BytesReturned;
   UCHAR    ClearMask;
                              
   //Clear status bits 0, 1, 2 & 3                           
   ClearMask = 0x0f;
   Status = DeviceIoControl(
                            hDevice,
                           (DWORD)IOCTL_OMS_CLR_STATUS, //Clear status flags
                           &ClearMask,                  //Flags selected by ones
                           (DWORD) 1,                   //Mask is one byte
                           (LPVOID)NULL,                //No response expected
                           (DWORD) 0,                   //...
                           &BytesReturned,              //Not used but required
                            NULL);                      //Synchronous Operations


    
 - IOCTL_OMS_READ_DONE -
 
   Each time the driver's interrupt service routine responds to a controller
   interrupt request the controller's status register is read.  If the
   controller has set the done status flag then the controller's done register
   will be read and this information will be added to the controller's copy
   of the done flags, via a logical OR.  The IOCTL_OMS_READ_DONE I/O control
   function code is used to read this copy of the axes done flags.  Note once
   the application has read and processed the done flags, for a  specific set
   of axes, they must be cleared.  See the IOCTL_OMS_CLR_DONE function
   described below.
    
   The following code fragments illustate the use of the IOCTL_OMS_READ_DONE
   function:
 
   #include <windows.h>
   #include <winioctl.h>
   ...
   ... 
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
                                              
   HANDLE   hDevice;        //Device driver handle from the CreateFile function
   BOOLEAN  Status;
   DWORD    BytesReturned;
   UCHAR    DoneFlags;
                                               
   //Read the driver's copy of the done flags                         
   Status = DeviceIoControl(
                            hDevice,
                            (DWORD)IOCTL_OMS_READ_DONE, //Read done flags
                            (LPVOID)NULL,                 //String not sent
                            (DWORD) 0,                    //...
                            &DoneFlags,                   //Status flags go here
                            (DWORD)1,                     //Return one byte
                            &BytesReturned,               //Actual bytes returned
                             NULL);                       //Synchronous operations
   printf("Controller done flags = %0x \n", DoneFlags);
 
    
    
 - IOCTL_OMS_CLR_DONE -

   After axis done flag information has been processed by the
   application program, it must be cleared.  The IOCTL_OMS_CLR_DONE I/O
   control function code is used to clear selected bits in the driver's
   copy of the controller's done flags.
    
   The follwing code fragments illustate the use of the IOCTL_OMS_CLR_DONE
   function:
 
 
   #include <windows.h>
   #include <winioctl.h>
   ...
   ... 
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
   ...
   ...
   HANDLE   hDevice;        //Device driver handle from the CreateFile function
   BOOLEAN  Status;
   DWORD    BytesReturned;
   UCHAR    ClearMask;
                              
   //Clear only the X and Z axis done flags                           
   ClearMask = 0x05;
   Status = DeviceIoControl(
                            hDevice,
                           (DWORD)IOCTL_OMS_CLR_DONE,  //Clear done flags
                           &ClearMask,                 //Flags selected by ones
                           (DWORD) 1,                  //Mask is one byte
                           (LPVOID)NULL,               //No response expected
                           (DWORD) 0,                  //...
                           &BytesReturned,             //Not used but required
    
    
 - IOCTL_OMS_RESET -

   Send a reset, "RS", command to the controller and wait until initialization
   is complete.  The controller will execute a hardware reset and will set
   all of its parameters to their power up state.  If the controller was
   successfully reset with in 5 seconds ResetOk will be set TRUE.
    
   The follwing code fragments illustate the use of the IOCTL_OMS_RESET
   function:
 
 
   #include <windows.h>
   #include <winioctl.h>
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
   ...
   ...
   DWORD cbBytesReturned;
   BOOLEAN  Status;
   BOOLEAN ResetOk;
   ...
   ...
   //Send reset to controller and reinitialize driver variables
   Status =  DeviceIoControl(hDevice, 
                             (DWORD)IOCTL_OMS_RESET,
                             (LPVOID)NULL,
                             0,
                             &ResetOk,
                             1,
                             &cbBytesReturned,
                             NULL
                            );
                            
  if(ResetOk)
    //Controller was sucessfully restet..                            
    
    
 - IOCTL_OMS_GET_VERSION -

   Get the device driver's version string.
    
   The follwing code fragments illustate the use of the IOCTL_OMS_GET_VERSION
   function:
 
 
   #include <windows.h>
   #include <winioctl.h>
   //Define the OMS NT driver I/O control codes
   #include "NTIOCTL.H"
   ...
   ...
   DWORD cbBytesReturned;
   BOOLEAN  Status;
   char VersionString[128];
   ...
   ...
   //Request the driver's version string
   Status =  DeviceIoControl(hDevice, 
                             (DWORD)IOCTL_OMS_GET_VERSION,
                             (LPVOID)NULL,
                             0,
                             &VersionString,
                             128,
                             &cbBytesReturned,
                             NULL
                            );
                            
  printf("Driver version = %s\n", VersionString);

 

