The PortIO95 Parallel Port Interface

Sample Source: readctl.c

/* ****************************************************************************
 * readctl.c - This file provides example code illustrating the use of the
 *              PortIO95 VxD. Its function is to read the ctl register
 *              (pins 1, 14, 16, 17) of the specified LPT port. The ctl
 *              register of the parallel port is read/write.  This sample
 *              script only illustrates reading the ctl port. If you hook
 *              up a series of switches and 220 ohm resistors as shown below, you
 *              should be able to affect the results reported by this program.
 *
 *        Pins on the Parallel Port D connector
 *            1  14 16 17                18
 *            |  |  |  |                 |
 *            |  |  |  |                 |      Note: \ is a dip switch
 *            \  \  \  \                 |            Z is a 220 ohm resistor
 *            |  |  |  |                 |
 *            |  |  |  |                 |      Note: Pin 1  is C0, Pin 17 is C3
 *            Z  Z  Z  Z                 |            Pin 18 is Gnd
 *            |  |  |  |                 |
 *            ----------------------------
 *
 *              As written, this program compiles cleanly under Visual C++ 4.0 
 *              using the command line compiler. It is designed to work only
 *              with the PortIO95 parallel port handler VxD
 *              
 * Note: This file is best viewed with tab stops of 4
 *
 * DISCLAIMER !!!
 * There is no warranty - you use PortIO95 entirely at your own risk.  Net 2000 Ltd. does
 * not warrant PortIO95's suitability for any purpose, does not guarantee PortIO95's
 * uninterrupted functionality, or even its functionality. Net 2000 Ltd. is not liable
 * for any damage or loss that may occur to you, your computer or the things that your
 * computer is controlling.
 *
 * NOTE: This program uses LPT1 by default. See the variable cPortToUse below to change this.
 *
 * See the PortIO95 documentation and FAQ at http://ds.dial.pipex.com/town/close/ec63 for
 * more information.
 *
 * Copyright (c) 1997 Net 2000 Ltd.
 */
 
#include 
#include 
#include 
#include 
#include "portio95.h"

/* function prototypes */
void Handle_Error(char *);

/* ##### IMPORTANT ##### Change this to the port you wish to use */
char cPortToUse='1';     /* set it for '1'=LPT1, '2'=LPT2, '3'=LPT3 */
char cOutData;           /* use this byte to get data from PortIO95 */
char cInData;            /* use this byte to get data from PortIO95 */

/* global variables */
HANDLE        hDevice;

void main(int ac, char* av[])
    {
    BOOL    retval;
    int     i;
    DWORD    err;

    /* Load the name of the vxd in here where we can pass it as a pointer
     * Note that the format is really "\\.\VXDNAME.VXD" but we have to
     * escape the back slashes with more back slashes because of the
     * special significance the backslash has in C */
    const PCHAR VxDName = "\\\\.\\PORTIO95.VXD";
    printf("\n");
    printf("Preparing to Dynamically Load VxD ->%s\n",VxDName);

    /* the VxD opens just like a regular file. Windows will look for it as follows:
     *   * if it has an .VXD extension
     *     - current directory
     *     - windows directory
     *     - on the path (the autoexec.bat one that win95 sees when it starts)
     *   * if there is no .VXD extension
     *     - in the registry under the KnownVxD's Key
     * see [HAZZAH 227]. The FILE_FLAG_DELETE_ON_CLOSE will cause the VxD to
     * be dynamically removed when the program ends. */
    hDevice = CreateFile(VxDName, 0,0,0,CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);

    /* By now the PortIO95 VxD should be loaded - lets check */
    if (hDevice == INVALID_HANDLE_VALUE)
        {
        /* Get the Last Error Value see also [PortIO95.doc, Appendix A] */
        err = GetLastError();
           printf("Could Not Load VxD, error=%08lx\n", err );

        /* There is one error we have to handle carefully. It implies that
         * the PortIO95 VxD was found ok but didn't handle the dyamic
         * loading properly. This error shouldn't happen. But if it
         * does we cope with it here. We dynamically unload the vxd
         * before we exit. NOTE there is no .VXD extension on this call
         * otherwise you really do delete the VXD file rather than just
         * forcing an unload. */
        if (err == ERROR_NOT_SUPPORTED) DeleteFile("\\\\.\\PORTIO95");
         exit(1);
        }

    /* now lets set the PortIO95 Vxd to use an LPT for its Input and output */
    retval=DeviceIoControl(hDevice, PORTIO_SETPORT, &cPortToUse, sizeof(cPortToUse), NULL, 0, NULL, NULL);
    if (!retval) Handle_Error("PORTIO_SETPORT");
    printf("PortIO95 set to use LPT%c\n",cPortToUse);

     /* In order to read from the LPT ports control register we
     * must first set the pins up for input. This is required
     * due to the design of the PC LPT port. PortIO95 offers
     * the ability to mix and match the pins in the control port
     * as input and output. - just make calls like:
     * PORTIO_SETPIN14INPUT or PORTIO_SETPIN1OUTPUT
     * If you try to write to a pin that is set as an input or
     * vice-versa an error will be returned. There are also
     * functions to set the entire register as input or output.
     * We use this in the example below. Note that setting the
     * control port up for input has the effect of causing the
     * pins to present a logical high to any equipment reading
     * pins 1, 14, 16 and 17 */
    retval=DeviceIoControl(hDevice, PORTIO_SET_PINS_1_14_16_17_AS_INPUT, NULL, 0, NULL, 0, NULL, NULL);
    if (!retval) Handle_Error("PORTIO_SET_PINS_1_14_16_17_AS_INPUT");

    /* now lets read pin 1 as input */
    retval=DeviceIoControl(hDevice, PORTIO_READPIN1, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READPIN1");
    if (cOutData == '\0') printf("Pin 1 is LOW\n");
       else printf("Pin 1 is HIGH\n");

    /* now lets read pin 14 as input */
    retval=DeviceIoControl(hDevice, PORTIO_READPIN14, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READPIN14");
    if (cOutData == '\0') printf("Pin 14 is LOW\n");
       else printf("Pin 14 is HIGH\n");
       
    /* now lets read pin 16 as input */
    retval=DeviceIoControl(hDevice, PORTIO_READPIN16, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READPIN16");
    if (cOutData == '\0') printf("Pin 16 is LOW\n");
       else printf("Pin 16 is HIGH\n");

    /* now lets read pin 17 as input */
    retval=DeviceIoControl(hDevice, PORTIO_READPIN17, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READPIN17");
    if (cOutData == '\0') printf("Pin 17 is LOW\n");
       else printf("Pin 17 is HIGH\n");

    /* now lets read the ctl register in raw mode - we get exactly what the
     * LPT port thinks it has there - the VxD does nothing but read.
     * Note that pins: 1=bit0, 14=Bit1, 16=Bit2, 17=Bit3. Bits 0,1,3 are
     * hardware NOT'ted by the port so will be the opposite to the true state */
    retval=DeviceIoControl(hDevice, PORTIO_READCREGRAW, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READCREGRAW");
    printf("The raw C Register is: 0x%X hex\n",cOutData);

    /* now lets read the ctl register in cooked mode. This call is designed
     * to provide a logical 4 bit input mechanism. Thus the values of the
     * Ctrl Register bits are  flipped (where necessary) by the PortIO95 VxD
     * so that a nice 4 bit nibble is composed and returned
     * to the calling program.
     *
     * Note that pin: 1=bit0, 14=Bit1, 16=Bit2, 17=Bit3 in the returned byte.
     * Bits  0,1,3 are logically re-NOT'ted by the VxD and so the returned
     * value will reflect the true pin state. All unused bits will be 0. */
     retval=DeviceIoControl(hDevice, PORTIO_READCREG, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READCREG");
    printf("The cooked C Register is: 0x%X hex\n",cOutData);

    /* now lets read 8 bits of input. PORTIO_READ_CS_BYTE call will take
     * the contents of the status and control registers and assemble it
     * into an 8 bit byte. This byte always compensates for any
     * hardware inversion (NOT'ting) of the pins and gives you
     * bits that reflect the true state of the pins. Basically the
     * bit to pin mapping works as follows:
     *
     * 15=bit0, 13=Bit1, 12=Bit2, 11=Bit3 1=bit4, 14=Bit5, 16=Bit6, 17=Bit7
     *
     * Basically the status register (minus pin 6 which can be used as an
     * interrupt trigger) is the low nibble and the control register
     * is the high nibble. Note: the Control Register Pins _MUST_ 
     * be set as inputs here or an error will be returned */
     retval=DeviceIoControl(hDevice, PORTIO_READ_CS_BYTE, NULL, 0, &cOutData, sizeof(cOutData), NULL, NULL);
    if (!retval) Handle_Error("PORTIO_READ_CS_BYTE");
    printf("The CS Byte is: 0x%X hex\n",(char)cOutData);

    /* unset our port, this is desireable as it resets things */
    retval=DeviceIoControl(hDevice, PORTIO_UNSETPORT, NULL, 0, NULL, 0, NULL, NULL);

    CloseHandle( hDevice );
    }

/* ********************************************************************
 * Handle_Error - a simple function to print out errors for us
 *               Saves having to put this code after every call
 *
 */
void Handle_Error(char * szErrStr)
        {
        printf("%s DeviceIoControl failed, error=%d\n", szErrStr, GetLastError() );
        exit (1);
        }


[Previous] [PortIO95 Home][PortIO95 Source Home] [Next]