The custom driver in this example takes over the open, close, read, and write responsibility. The example illustrates the form of a driver and the necessary initialization, registration, and mechanism of the driver. The coding of user- specific functionality is not represented.
Assume that you chose MYDRIVER as the driver name and that you added this name to the onpload database with ipload. The plcstdrv.c file is as follows:
#include "plcstdrv.h" int DrConfig(); (*pl_get_user_method(driver, method)) () char *driver; int method; { if (strcmp(driver, "customdrv") == 0) { if (method == PL_MTH_CONFIGURE) return (DrConfig); } return (0); }
The following driver code supports MYDRIVER:
#include <plcstdrv.h> #include <sys/types.h> #include <unistd.h> #include <sys/fcntl.h> extern char *malloc(); extern errno; static int DrOpen(); static int DrRead(); static int DrWrite(); static int DrClose(); #define CTRLDELIM 0x01 /* fake delimiter (CTRL-A) */ #define REALDELIM 0x7c /* real delimiter (|) */ #define ESCAPSIGN 0x5c /* escape sign (\) */ #define ENDRECORD 0x0a /* end of record (\n) */ int fd; /*--------------------------------------------------------------------- * DrConfig() * * Input : (char *) driver name * (void *) method table * * Return : PL_RTN_OK * * Schema : Fills in the driver table *-------------------------------------------------------------------*/ int DrConfig(driver,methodtable) char *driver; void *methodtable; { pl_inherit_methods("Delimited", methodtable); pl_set_method_function(methodtable, PL_MTH_OPEN, DrOpen); pl_set_method_function(methodtable, PL_MTH_RAWREAD, DrRead); pl_set_method_function(methodtable, PL_MTH_RAWWRITE, DrWrite); pl_set_method_function(methodtable, PL_MTH_CLOSE, DrClose); pl_lock_globals(); return PL_RTN_OK; }
/*-------------------------------------------------------------------- * DrOpen() * * Input : (devicearray *) dev device array structure * * Return : PL_RTN_FAIL error * PL_RTN_OK open succeeded * * Schema : Open the specific file for that driver thread * Note that the custom driver thread is bound to its * own CPU VP, therefore it is safe to have globals like fd *------------------------------------------------------------------*/ static int DrOpen(dev) devicearray *dev; { fd = open(dev->filename, O_RDONLY); if (fd < 0) { return PL_RTN_FAIL; } return PL_RTN_OK; } /*-------------------------------------------------------------------- * DrRead() * * Input : (char *) bf output buffer to write record to * (int) size size of output buffer * (int *) count number of bytes written to output buffer * * Return : PL_RTN_FAIL error * PL_RTN_OK returning buffer * PL_RTN_EOF returning the last buffer, no more data * * * Schema : Reads from input and fill up data buffer provided by the * caller. Here, the caller expect a record where the delimiter * is |. Our custom driver changes all CTRL-A into | and * escapes the already existing | from input. *------------------------------------------------------------------*/ static int DrRead(bf, size, count) char *bf; int size; int *count; { int rtn; /* return value */ int n; /* bytes read in */ static char *bftemp = 0; /* temp buffer */ char *p; /* pointer to temp buff */ char *start; /* start of output buffer */ static off_t currseek = 0; /* current seek in input */ int escaped = 0; /* did we escape last character */
start = bf; if (bftemp == 0) { if ( (bftemp = malloc(size)) == 0 ) { return PL_RTN_FAIL; } } /* * read data in */ errno = 0; do { n = read(fd, bftemp, size); } while (n == -1 && errno == 4); rtn = (n < 0) ? PL_RTN_FAIL : (n == size) ? PL_RTN_OK : PL_RTN_EOF; currseek += n; p = bftemp; /* * format output buffer */ while (size) { if (*p == REALDELIM) { *bf = ESCAPSIGN; escaped = 1; } else if (*p == CTRLDELIM) { *bf = REALDELIM; } else { *bf = *p; } size--; bf++; if (escaped && size) { *bf++ = *p; escaped = 0; size--; } p++; if ((int) (p - bftemp) == n) break; } if (escaped) { p--; rtn = PL_RTN_OK; } if ((int) (p - bftemp) != n) { currseek -= (off_t) (n - (p - bftemp)); lseek(fd, currseek, SEEK_SET); } if (rtn == PL_RTN_EOF) { *bf = 0; } *count = (int) (bf - start); return rtn; } static int DrWrite(bf, size) char *bf; int size; { return PL_RTN_OK; } static int DrClose(device) devicearray *device; { close(fd); return PL_RTN_OK; }Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]