IOdevice(7)

NAME
IOdevice -- RCI I/O device and driver interface.

INTERFACE
The driver interface to an RCI I/O device is summarized below:

#include <IOdevice.h>

read(dev, buffer, size)
   IO_DEVICE *dev;
   char *buffer;
   int size;

testRead(dev)
   IO_DEVICE *dev;

write(dev, buffer, size)
   IO_DEVICE *dev;
   char *buffer;
   int size;

testWrite(dev)
   IO_DEVICE *dev;

probe(dev)
   IO_DEVICE *dev;

attach(dev)
   IO_DEVICE *dev;

detach(dev)
   IO_DEVICE *dev;

signal(dev, signo)
   IO_DEVICE *dev;
   int signo;

ioctl(dev, com, data)
   IO_DEVICE *dev;
   int com;
   void *data;

ARGUMENTS

dev --
    Pointer to device structure.

buffer --
    Buffer for sending or receiving information.

size --
    Amount of information to send, or maximum amount of information that can be received.

signo --
    Signal number.

DESCRIPTION
An RCI I/O device consists of, physically, some computer interface device like a parallel port or serial line connect that is used to communicate with an outside peripheral (like a robot).

In terms of software, an I/O device consists of an instantiated IO_DEVICE structure (described below), and a collection of driver routines that conform to the interface specified above. Pointers to the driver routines are contained in the IO_DEVICE structure.

read() receives a data packet from the device, and should return the number of bytes received.

testRead() returns true when the device is ready to be read from, and false otherwise. This function can be used as a task wakeup function. In particular, it is typically used to implement the robot ready function (see ROBOT_READY()).

write() sends a packet of data to the device, and should return the number of bytes sent.

testWrite() returns true when the device is ready to be written to, and false otherwise.

NOTE: testWrite() is on its way out. It is not used presently by any RCI software at the time of this writing. Moreover, it is not implemented by the sim driver which is used whenever RCI is run in simulator mode.

signal() sends a notification signal to the device. In particular, the routine is used by the existing robot interface functions to send wakeup and release signals to the robot controller (see ROBOT_WAKEUP()).

probe() checks for the existence of the device, and is responsible for setting the size and location fields of the device structure. The probe() routine should return -1 if the device does not exist or appears to be malfunctioning.

attach() initiates a control session with a device; it should return -1 if it cannot do this.

detach() disconnects the device and puts it into a "known state".

ioctl() is used to set various options and modes associated with the device. A few I/O control codes are predefined in <IOdevice.h>:

IOC_SIGINTER_ENABLE --
    Enables interrupts on the device.

IOC_SIGINTER_DISABLE --
    Disables device interrupts.

IOC_TIMEOUT --
    Sets the timeout field in the device structure to the integer value pointed to by data. This number is used internally by the driver routines to control their timeout tolerance.

IOC_SET_BLOCKTIME --
    Sets the maximum blocking time associated with read or write operations, in milliseconds, to the integer value pointed to by data. The number is also written into the blocktime field in the device structure.

IOC_GET_BLOCKTIME --
    Returns the maximum blocking time permitted for a read or write operation, in milliseconds, into an integer pointed to by data.

All of the above routines should return -1 in the event of an error (see DIAGNOSTICS, below).

The device structure contains pointers to all of the driver functions, as well as several data fields for use by the functions. These fields are:

 char *name;             /* name of the device               */
 int unit;               /* unit number of the driver        */
 int address;            /* bus address of interface         */
 char *addrStr;          /* supplemental address information */
 int args[MAX_DEVARGS];  /* program supplied arguments       */
 unsigned char *location;/* memory address of interface      */
 int size;               /* size of the interface (in bytes) */
 unsigned long timeout;  /* a spin-loop timeout parameter    */
 int blocktime;          /* max. time read or write can block */
 int byteCount;          /* byte count for I/O operations    */

name --
    Assigned by RCI. A copy of the string name of the device.

unit --
    Assigned by RCI. A unique unit number (small integer) is assigned by RCI to each device of a given type used by a program; this can be used by the driver as an index into an array of per-device data structures. The unit number depends only on the order that devices are defined in the program, not on the actual location of the device itself.

address --
    Assigned when the device is created (either from config file information or a call to rciAllocDevice()). This identifies the physical location of the device; typically this is its bus address.

addrStr --
    Addtional address information, in string form, that can be assigned when the device is created with rciAllocDevice().

WARNING: This field is valid for applications which are running on the arbiter CPU only. It is actually just a kludge around to provide a way to pass TCP addressing information to the simulation device sim.

args --
    Optional arguments supplied when the device is allocated (either from config file information or a call to rciAllocDevice()). These arguments may supply any extra per-device information needed by the driver, including extra addressing information.

location --
    Set by the probe() routine. This is a pointer to the memory location where the device can be found; assumably, this will lie somewhere in the I/O space memory map that RCI provides to the tasks. The location is computed directly from the address information.

size --
    Set by the probe() routine. This is the size of the device, in bytes (the amount of space the device takes up in the I/O space memory map).

timeout --
    Generally set by either the probe() routine or the predefined I/O control IOC_TIMEOUT. This is a parameter from which the I/O routines decide how long to wait before issuing a timeout error.

blocktime --
    Generally set by either the probe() routine or the predefined I/O control IOC_SET_BLOCKTIME. This is a parameter which determines how long I/O routines which are supposed to block should block before issuing a timeout error. It is different from the timeout parameter in that blocking may be acceptable, and may also be a large number. The timeout parameter, on the other hand, generally controls interactions that are assumed to be immediate.

byteCount --
    Set by the read function (and possibly the write function) to indicate to the calling routine the number of bytes transferred during I/O.

INSTALLATION
The easiest way to write an I/O driver is to clone an existing one. At the time of this writing, there exists an I/O driver in the file priDriver.c; this controls a DEC DRV11 Q-bus parallel port. Driver specific definitions and function declarations should be placed in a separate .h file.

Once the driver is written, it may be installed in the RCI libraries by editing the table IOdrivers in the file IOdriverTable.c. The entry should consist of (1) a string by which the driver will be referenced, and (2) the function pointers for the driver itself, in the order that they are described above. It will be necessary to declare the functions before the table; this can be done by including the driver's .h file.

After the file has been prepared, in must be compiled and installed into the RCI system. Driver modules are normally kept in the directory drivers. New modules must be incorporated into this directory's Imakefile. If this is done properly, then the command make libs should compile the file and load it into the RCI libraries.

DIAGNOSTICS
All driver functions should return -1 in the event of error. Error codes can be returned on the error stack (q.v.). The following error codes, defined in <errorCode.h>, are used by the existing device drivers:

EDevTimeout --
    No response from the device.

ETransmit --
    Data corruption was detected during transmission.

ECount --
    A bad data count (too large or negative) was either received or specified for transmission.

ENoDev --
    Device does not exist (can be returned by probe(), for instance).

ESync --
    Data transfer protocol error.

EConnect --
    Device is not ready; can't connect to it.

EBadIoctl --
    Invalid or unsupported ioctl command.

The file drivers/driErrorMsgs.c contains string messages associated with these error codes.

SEE ALSO
rciAllocDevice(3), rciScheduling(3), ROBOT_WAKEUP(3), ROBOT_READY(3), errorStack(3).