Two-Axis Real-Time Camera Control 
by Cort Dougan


Listing One
int init_module(void)
{
   if (rtl_register_dev("/dev/lpt0", &rtl_par_fops) )
   {
       printk("Unable to install driver\n");
       return - EIO;
   }
   return 0;
}
void cleanup module(void)
{
   rtl_unregister_dev("/dev/lpt0");
}


Listing Two
static int rtl_par_open(struct rtl_file *filp)
{
   return 0;
}
static int rtl_par_release(struct rtl_file *filp)
{
   return 0;
}


Listing Three
#define PORT 0x378
char out_byte;
static ssize_t rtl_par_read(struct rtl_file *filp, char *buf, size_t count, off_t* ppos)
{
   if ( count < sizeof(char) )
      return - 1;
   buf[0] = inb( PORT );
   return 0;
}
static ssize_t rtl_par_write(struct rtl_file *filp, const char *buf,  size_t count, off_t* ppos)
{
   int i;
   for ( i = 0; i < count; i++ )
   {
      out_byte = buf[i];
      outb( out_byte, PORT );
   }
   return 0;
}


Listing Four
static int rtl_par_ioctl(struct rtl_file *filp, unsigned int request, unsigned long l)
{
   switch ( request )
   {
   case RTL_PAR_SETBIT:
      out_byte | = 1<<l;
      break;
   case RTL_PAR_CLEARBIT:
      out_byte &= ~(1<<l);
      break;
   default:
      return - EINVAL;
   }
   outb( out_byte, PORT );
   return 0;
}


Listing Five
include /opt/rtldk-1.1/rtlinuxpro/include/rtl.mk
all: rtl_parallel.o
clean:
   rm - f *.o


Listing Six
define SERVO_FIFO 16
pthread_t thread[2];
int fd[2], fd_par;
int init_module(void)
{
   int i;
   char file[256];
   /* open the fifo's */
   for ( i = 0; i < 2; i++ )
   {
      sprintf( file, "/dev/rtf%d", SERVO_FIFO+i );
      if ( (fd[i] = open(file, O_RDONLY | O_CREAT | O_NONBLOCK) ) < 0 )
      {
         rtl_printf("Could not open %s\n", file);
         return -1;
      }
   }
   /* create FIFO handlers */
   for ( i = 0; i < 2; i++ )
      rtf_create_handler(SERVO FIFO+i, fifo_handler);
   /* open the parallel port device */
   if ( (fd_par = open("/dev/lpt0", O_NONBLOCK)) < 0 )
   {
      rtl_printf("Could not open /dev/lpt0\n");
      return -1;
   }
   /* create the tasks */
   for ( i = 0; i < 2 ; i++ )
      {
      if ( pthread_create( &thread[i], NULL, thread_code, (void *)i ) )
         rtl_printf("thread %d failed create\n", i);
      }
   return 0;
}


Listing Seven
void cleanup_module(void)
{
   int i;
   for ( i = 0 ; i < NUM MOTORS ; i++ )
   {
      pthread_cancel( thread[i] );
   close(fd[i]);
   }
   close(fd par);
}


Listing Eight
unsigned long pulse_length[2];
int fifo_handler(unsigned int fifo)
{
   int position = -1, err;
   char msg[16];
   char *junk;
   /* read "position" from 0-180 degrees */
   while ( (err = read(fd[fifo - SERVO FIFO], msg, sizeof(msg) )) != 0 )
      position = simple_strtoul(msg, &junk, 10);
   /* stay within the range of the motor */
   if ( (position < 0) | | (position > 180) )
   return -1;
   /* compute pulse width */
   pulse_length[fifo - SERVO FIFO] = 1000000 /* 1ms */
                                     + ((1000000 * position)/180);
   return 0;
}


Listing Nine
unsigned long frame length = 20000000;
void *thread_code(void *t)
{
   int num = (int)t;
   clock_gettime( CLOCK REALTIME, &next );
   for (;;)
   {
      /* turn on the pulse */
      ioctl(fd_par, RTL_PAR_SETBIT, num);
      /* setup for the idle part of the duty cycle */
      timespec_add_ns( &next, pulse_length[num] );
      clock_nanosleep( CLOCK_REALTIME,TIMER_ABSTIME, &next, NULL);
      /* turn off the pulse */
      ioctl(fd_par, RTL_PAR_CLEARBIT, num);
      /* setup for the next pulse */
      timespec_add_ns( &next,frame_length - pulse_length[num] );
      clock_nanosleep( CLOCK_REALTIME,TIMER_ABSTIME, &next, NULL);
   }
}


Listing Ten
<HTML>
<HEAD><TITLE>RtlCam</TITLE>
</HEAD>
<FRAMESET COLS="*,60">
<FRAMESET ROWS="*,40">
<FRAME SRC="image.html" NAME="image">
<FRAME SRC="pan.html" NAME="pan">
</FRAMESET>
<FRAME SRC="tilt.html" NAME="tilt">
</FRAMESET>
</BODY>
</NOFRAME></FRAMESET>
</HTML>


Listing Eleven
Camera Position, relative to center:
<a href="/cgi-bin/pan.sh?0">-90</a>
<a href="/cgi-bin/pan.sh?15">-75</a>
<a href="/cgi-bin/pan.sh?30">-60</a>
<a href="/cgi-bin/pan.sh?60">-30</a>
<a href="/cgi-bin/pan.sh?75">-15</a>
<a href="/cgi-bin/pan.sh?90">center</a>
<a href="/cgi-bin/pan.sh?105">+15</a>
<a href="/cgi-bin/pan.sh?120">+30</a>
<a href="/cgi-bin/pan.sh?135">+45</a>
<a href="/cgi-bin/pan.sh?150">+60</a>
<a href="/cgi-bin/pan.sh?165">+75</a>
<a href="/cgi-bin/pan.sh?180">+90</a>


Listing Twelve
Tilt:
<a href="/cgi-bin/tilt.sh?180">+90</a><br>
<a href="/cgi-bin/tilt.sh?165">+75</a><br>
<a href="/cgi-bin/tilt.sh?150">+60</a><br>
<a href="/cgi-bin/tilt.sh?135">+45</a><br>
<a href="/cgi-bin/tilt.sh?120">+30</a><br>
<a href="/cgi-bin/tilt.sh?105">+15</a><br>
<a href="/cgi-bin/tilt.sh?90">center</a><br>
<a href="/cgi-bin/tilt.sh?75">-15</a><br>
<a href="/cgi-bin/tilt.sh?60">-30</a><br>
<a href="/cgi-bin/tilt.sh?45">-45</a><br>
<a href="/cgi-bin/tilt.sh?30">-60</a><br>
<a href="/cgi-bin/tilt.sh?15">-75</a><br>
<a href="/cgi-bin/tilt.sh?0">-90</a><br>


