How to Poll an Input to the Parallel Port

This program simply monitors the state of bit 6 of the parallel port's status register. Bit 6 is the ACK bit, which the external device (printer) controls. Provided bit 4 of the control register is set high (which enables interrupts), a hardware interrupt signal (probably IRQ 7) is generated whenever bit 6 of the control register goes high.

Software polling (especially with a busy-wait strategy) is not a good way to monitor for hardware or software conditions, using events such as interrupts is far more efficient, and often faster. The disadvantage with polling (or busy-waiting) is that it absorbs loads of CPU capacity even when the signal being monitored is not active (i.e. changing, or in a state that we are interested in). This wasted capacity could be put to use on other processes. On a monoprogramming OS such as DOS, this is almost never a problem, but on multi-programming OSes like QNX, it is nearly always a problem.

A better alternative to the busy-wait is to put the process to 'sleep' until it needs to handle a change in the monitored condition. In this case, changes can be detected by connecting them to an interrupt (for hardware signals), or by having the process poll the condition not continuously, but intermittently, with a timed sleep interval between polls.i During these sleeps, the CPU can do other things. Obviously, the sleep intervals will have to be short enough to avoid missing any events, or detecting them too late.

For more detailed information about the parallel port, and handling it in software, refer to my other web page on Parallel Port Interrupt Handling.

Note that you should slay devc-par to prevent it from trying to handle the same piece of hardware (the parallel port, of course) as your program. Having two software processes attempting to handle the same piece of hardware is not usually a good idea!

Note also that you will need to run this program as root, so that the process can get the necessary permissions to access the hardware.


#include <stdio.h>
#include <stdint.h>       /* for uintptr_t */
#include <hw/inout.h>     /* for in*() and out*() functions */
#include <sys/neutrino.h> /* for ThreadCtl() */
#include <sys/mman.h>     /* for mmap_device_io() */

/* The Neutrino IO port used here corresponds to a single register, which is
 * one byte long */
#define PORT_LENGTH 1 

/* The first parallel port usually starts at 0x378. Each parallel port is
 * three bytes wide. The first byte is the Data register, the second byte is
 * the Status register, the third byte is the Control register. */
#define CTRL_ADDRESS 0x37a
 /* bit 2 = printer initialisation (high to initialise)
  * bit 4 = hardware IRQ (high to enable) */
#define INIT_BIT 0x04
#define INTR_BIT 0x10

#define STAT_ADDRESS 0x379
/* bit 6 = acknowledge */
#define ACK_MASK 0x40  

#define ANSI_ESC8 0x9b   /* ANSI 8-bit escape code */
#define ANSI_CLS 0x0c    /* ANSI clear screen */
#define ANSI_ROW1 0x3148 /* ANSI move cursor to row 1 */

/* ______________________________________________________________________ */
int
main( )
{
   int privity_err;
   uintptr_t stat_handle;
   uintptr_t ctrl_handle;
   uint8_t stat_value;

   privity_err = ThreadCtl( _NTO_TCTL_IO, NULL );
   if ( privity_err == -1 )
   {
      printf( "Can't get root permissions\n" );
      return -1;
   }

   stat_handle = mmap_device_io( PORT_LENGTH, STAT_ADDRESS );
   ctrl_handle = mmap_device_io( PORT_LENGTH, CTRL_ADDRESS );

   /* Initialise the parallel port. */
   out8( ctrl_handle, INIT_BIT );
   
   printf( "%c\n", ANSI_CLS ); /* Clear the screen */
   for (;;)
   {
      /* Note: This loop uses a load of CPU, so don't expect Photon to
       * behave speedily while this program is running. */
      stat_value = in8( stat_handle );
      stat_value = stat_value & ACK_MASK;
      if ( stat_value == 0 )
      {
         /* Always print at top-left of screen */
         printf( "%c%cLow \n", ANSI_ESC8, ANSI_ROW1 );
      }
      else
      {
         printf( "%c%cHigh\n", ANSI_ESC8, ANSI_ROW1 );
      }
   }
   /* Press CTRL-C to terminate this program */
   return 0;
}


Home About Me
Copyright © Neil Carter

Content last updated: 2003-09-23