[comp.sys.m6809] ImageWise FrameGrabber & OS-9

jimomura@lsuc.UUCP (09/12/87)

     As is usual, I don't know when I'll get around to finishing this
program, but the current version works in its simplest usage, so I'm
posting this much for now.  In fact, due to a severe re-design in the
middle of the development of this much of the code, it's about the
biggest mess I've every created from scratch.  Usually, working from
scratch leads to neater code -- at least it does for me.

     This was originally going to be a very simple capture routine.
Then later I realized that what I really wanted was a bunch of
capabilities where I hadn't provided for them.  So . . . (yuck! ;-)

     This is still only a capture routine.  You still have to write
a file processor to convert it to a displayable format for most
computers.  But it's free!

/* Icap.c
 * by Jim Omura, 2A King George's Drive, Toronto, Ontario
 * M6M 2G9, Canada,
 * Byte Information Exchange (BIX) 'jimomura'
 */

/* Version:  0.05 -- Public Domain */

/* This program is designed to capture a file sent by the Imagewise
 * digitizer.
 */

/* use: icap device [filespec] [-?hm] [-p=fullpath]
 *
 * where:
 *
 * device is the device to use, i.e. /t2
 * filespec is the a full path or filename
 *
 * Dash Swithes
 *
 *	?	Short help
 *	h	Hold after capture
 *	m	automatic Multiple files
 *	p	Full path ( ie: /dd/directory/file )
 *
 * Bugs and limits:
 *
 * Files greater than FBUFFSIZE characters will
 * cause problems without warning.
 *
 * Only basic file capture implimented.
 */

/* Manual:
 *
 *      The Imagewise digitizer sends out a picture in a stream of
 * characters using only the lower 6 bits.  Various characters using
 * the upper 2 bits are also used.  Since the files may be compressed
 * by run length encoding, one cannot be sure in advance, how long
 * the file will be.  Thus, the buffer is made to the longest possible
 * file length, but the program searches for the "end of file" char-
 * acter (0x42) to complete the frame.  The transfer looks like this:
 *
 *     Receiver Sends:     Digitizer Sends:      Explanation:
 *
 *     Resolution Byte                           Define image res.
 *     Xon                                       Start file
 *
 *                         0x40                  Start of field
 *
 *                         (various characters)  The video field
 *     Xoff/Xon                                  Flow control
 *
 *                         0x42                  End of field
 *
 *      After one field is sent, the digitizer is immediately ready
 * to send another field and awaits the next Resolution Byte/Xon
 * pair.  There is no way to abort a transmission once begun, so
 * an ongoing transmission must be discarded or "spilled" to the
 * screen or a file for diagnostic purposes.
 *
 *      Although multiple sequential file captures with automatic
 * file names is provided for, it is not practical to rely on this
 * for real-time animation because the length of time between
 * images is at the very least, seconds apart in the normal course.
 *
 *		'Icap' must be called with a serial device specified which
 * has the Imagewise attached or accessed.  There is no provision
 * to set the bit settings or baudrate after the serial device is
 * called or via the command line.  As such, be sure the baudrate
 * is correct and the driver is selected for 8 bits, 1 stop, no
 * parity.  Other driver options are selected by 'icap' and reset
 * upon exit as necessary.
 *
 *		The simplest use of 'icap' is:
 *
 *		icap /tn filename
 *
 * where /tn is the driver attached to the ImageWise or to a modem
 * which has established a connection to the ImageWise via another
 * telecom program.  'Icap' will respond with messages when the
 * capture begins ("Starting") and when it is completed ("Capture done")
 * or with error codes where applicable.  Upon completing the file
 * capture, 'icap' will exit back to the Shell or to any other
 * calling program.
 *
 *		More advanced usage require dash switches or Escape codes.
 *
 *		If no filename is given, 'icap' will request a filename
 * immediately.
 */
 
/* Local Escape Commands:
 *
 * [LESC][CR] Start New Frame with Current Filespec
 * [LESC][a]  abort
 * [LESC][e]  will exit Icap
 * [LESC][f]  filespec (new filename)
 * [LESC][l]  last frame
 * [LESC] xx  Start a series with current filespec as follows:
 *				aaaaaaxx
 *				up to 6 characters of original filespec
 *				followed by 2 digits of sequence number
 *				If filespec is "spacestation", the frames
 *				will be saved as "spaces01" etc.
 */

/* ------------------------------------------------------------ */

/* Include Files: */

#include <stdio.h>
#include <sgstat.h>

/* Standard Definitions used: */

#define C_CR		0x0d
#define C_XOFF		0x13
#define C_XON		0x11

#define FALSE		0

#define SS_OPT		0	/* GetStat values */
#define SS_RDY		1

#define STDIN		0
#define STDOUT		1
#define STDERR		2

#define TRUE		1

/* Program Specific Definitions */

#define ENDFIELD	0x42	/* End of field */
#define STARTFLD	0x40	/* Start a new field */

#define FBUFFSIZE	65782	/* Theoretical max. IW file size. */
#define HFILTER		0x7f	/* High Bit Filter Pattern */
#define HIRES		0x80	/* Imagewise 256 * 244 */
#define LESC		0x0a	/* Local Escape character ^J */
#define LORES		0x81	/* Imagewise 128 * 122 */
#define MEDRES		0x82	/* Imagewise 64 * 61 */

/* --------------------------------------------------------- */

remote char buf[FBUFFSIZE];			/* Buffer is large Array */

char *bufp;							/* Pointer to Cap. Buffer */

int capture;			/* Capture buffer flag */
char *cpntr;			/* Character pointer */
char fname[80];			/* File path spec. */
int fnflag;				/* Filename flag */
int holdflag;			/* Stay after a capture */
int mpath;				/* Modem path */
int spath;				/* Storage path */

main(argc,argv)
int argc;
char **argv;
{
/* Declare Local Variables: */

  char c;

  extern int capture;					/* Capture flag */
  extern char *cpntr;					/* Character pointer */
  int errflag;							/* Error Flag */
  extern char fname[80];				/* File path spec. */
  extern int fnflag;					/* Filename Flag */
  int frcntr;							/* sequential Frame counter */
  extern int holdflag;					/* Don't exit after field cap. */
  extern int mpath;						/* mpath is path number */
  char	outbuff[2];						/* Output buffer */
  int stopflag;							/* Xoff sent */
  extern int spath;						/* Storage path number */
  int waitcnt;							/* Characters waiting */
  struct sgbuf sgold, sgnew;			/* SCF parameters */

/* Initialize Variables: */

  bufp=&buf[0];		/* Set Buffer pointer */
  capture=FALSE;		/* Capture Buffer closed */
  fnflag=FALSE;			/* Clear Filename Flag */
  holdflag=TRUE;	/* If no name given then menu/command mode */
  stopflag=FALSE;		/* Flow open */

/* Parse for parameters first and open paths. */

  parse(argc,argv);

  if (fnflag==TRUE)
  {
    startcap(fname);
  }

/* Terminal Port Preparation */
  
  getstat(SS_OPT,STDIN,&sgold); /* save status /TERM */

/* Set STDIO path to ignore *most* special characters. */

  getstat(SS_OPT,STDIN,&sgnew); /* Get the old options again. */

  sgnew.sg_backsp=0;
  sgnew.sg_delete=0;
  sgnew.sg_echo=0;
  sgnew.sg_pause=0;
  sgnew.sg_bspch=0;
  sgnew.sg_dlnch=0;
  sgnew.sg_psch=0;
  sgnew.sg_kbich=0;
  sgnew.sg_kbach=0;
  sgnew.sg_bsech=0;

  setstat(SS_OPT,STDIN,&sgnew);	/* Set Keyboard IO */

/* Modem Path Setting */

  getstat(SS_OPT,mpath,&sgnew);	/* Get Modem port params */

  sgnew.sg_case=0;
  sgnew.sg_backsp=0;
  sgnew.sg_delete=0;
  sgnew.sg_echo=0;
  sgnew.sg_alf=0;
  sgnew.sg_nulls=0;
  sgnew.sg_pause=0;
  sgnew.sg_bspch=0;
  sgnew.sg_dlnch=0;
  sgnew.sg_eorch=0;
  sgnew.sg_eofch=0;
  sgnew.sg_rlnch=0;
  sgnew.sg_dulnch=0;
  sgnew.sg_psch=0;
  sgnew.sg_kbich=0;
  sgnew.sg_kbach=0;
  sgnew.sg_bsech=0;
  sgnew.sg_bellch=0;

  setstat(SS_OPT,mpath,&sgnew);		/* Set Modem Path */
  

  if( fnflag == 0 )			/* Get a filename */
  { /* But don't begin a capture yet */
    printf("\nFilename? ");
    gets(fname);
  }

  for(;;)
  {
	waitcnt=getstat(1,mpath);
    if((waitcnt > 0))	/* Modem character waiting? */
    {
	  if( (waitcnt > 1) )	/* Stop Flow */
	  {
		*outbuff = C_XOFF;
	  	write(mpath,outbuff,1);
	  	stopflag=TRUE;
	  }

      read(mpath,&c,1);				/* Get the character */

      if( capture )
      {
      	 *bufp++=c;
      }
      else				/* Not capturing */
      {					/* Spew it out at the screen */
      	write(STDOUT,&c,1);
      }
    if ( c==ENDFIELD )
    {
	  capdone();   	/* Close Diskfile & clear capture flag */
	  printf("File captured: \n");
	  writeln(STDOUT,fname,79);
      if ( holdflag == FALSE )
      {
      	  break;
      }
    }
    if ( c==STARTFLD )
    {
      printf("Starting\n");
    }
  }
  else	/* No Modem Character waiting */
  {
  	if ( stopflag )
   	{
		*outbuff=C_XON;
   		write(mpath,outbuff,1);
   		stopflag=FALSE;
   	}
  }

  if((getstat(1,STDIN) > 0))
  {
      read(STDIN,&c,1);
      c &= HFILTER;					/* Filter High bit */
      if(c==LESC)					/* If local ESCape */
      {
        read(STDIN,&c,1);			/* Get next character */
        c &= HFILTER;

        if(c==C_CR && argc)			/* Begin new capture */
        {
        	startcap();
        }

        if(c=='a')				/* Keyboard Abort */
        {
          capture=0;
          write(spath,&buf[0],bufp-&buf[0]);
          close(spath);
          continue;
        }

        if(c=='e')				/* Exit from icap */
        {
        	break;
        }

      }

      write(mpath,&c,1);
	  write(STDOUT,&c,1);	/* Local Echo */
    }
  }
  close(mpath);		/* Don't need to restore modem params */
  setstat(0,0,&sgold);
  exit(0);
} /* End of Main */

/* ---------------------------------------------------- */

capdone()
{
  extern char *bufp;
  extern int capture;
  extern int spath;

  capture=0;
  write(spath,&buf[0],bufp-&buf[0]);
  close(spath);
} /* End of capdone() */

/* ------------------------------------------- */

int startcap(filespec)
char	*filespec;
{
	char		outbuff[2];	/* Output Buffer */
	extern int capture;		/* Capture flag */
	extern int mpath;		/* Modem path */
	extern int spath;		/* Storage path */

    spath=(create(filespec,3,3));
    if (spath==-1)
    {
      printf("Icap:  Cannot open diskfile ");
      writeln(STDOUT,filespec,79);
      printf("\n");
    }
    else
    {
      capture=TRUE;
    }
    outbuff[0]=HIRES;
	outbuff[1]=C_XON;
	write(mpath,outbuff,2);
} /* End of startcap() */

/* ----------------------------------------- */

getname()
{
	/* To be Written */
} /* End of getname() */

/* ----------------------------------------- */

parse(argc,argv)
int argc;
char **argv;
{
  extern char *cpntr;
  int errflag;
  extern char fname[80];
  extern int fnflag;
  extern int holdflag;
  int opthlpflag;

  errflag=0;
  opthlpflag=FALSE;
  
  --argc;		/* Dec. Arg. counter */
  ++argv;		/* move pointer to first character of next arg */

  for(;(argc > 0);)
  {
    if (**argv=='-')		/* Dash parameter handler */
    {
      for(;;)					/* Copy the filename to a buffer */
      {
        if (**argv == 'h')
        {
          opthlpflag=TRUE;
        }

		if (**argv == '\0')
		{
			break;
		}						/* Endif end of pathname */

		++*argv;

      }			/* End of filename copy loop */
      continue;
    }						/* Endif dash handler */

	if (**argv=='/')
	{
      mpath=open(*argv,3);
      if (mpath == -1)
      {
        printf("Icap:  modem port failure");
        writeln(STDOUT,*argv,79);
        printf("\n" );
      }						/* Endif modpath error */
    }					/* Endif slash parameter */
    else				/* Disk Path parameter */
    {
      strcpy(fname,*argv);
      holdflag = 0;	/* Exit after 1 field */
      fnflag=1;	/* Set Filename Flag */
    }			/* End of Argument handling */
    --argc;		/* Dec. Arg. counter */
    ++argv;		/* move pointer to first character of next arg */
  }				/* End of for loop */
}
/* End of parse() */

/* End of icap.c */
-- 
Jim Omura, 2A King George's Drive, Toronto, (416) 652-3880
ihnp4!utzoo!lsuc!jimomura
Byte Information eXchange: jimomura