/*

  File:		ProGrabr.c
  Author:	Nicholas Redgrave
  Date:		20th September 1998
  Description:	Program to grab video frames using the FG24/ProGrab24RT
  Requirements:	FG24/ProGrab24RT, prograb.library, ixemul.library
  Environment:	GNU C compiler, WorkBench 3.1

  Contact:	baron@bologrew.demon.co.uk


  AREXX code based on SnoopDOS source.




*/


#include <exec/types.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/memory.h>

#include <libraries/gadtools.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>
#include <intuition/sghooks.h>
#include <libraries/asl.h>
#include <graphics/displayinfo.h>
#include <resources/misc.h>
#include <graphics/gfxbase.h>


#include <clib/asl_protos.h>
#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/misc_protos.h>
#include <clib/icon_protos.h>
#include <clib/rexxsyslib_protos.h>


#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <rexx/errors.h>


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "prograba.h"
#include "prograbi.h"



/* Prototypes */

int main( int argc, char *argv[]);
void MainLoop(void);
int  InitRexxPort(void);
void HandleRexxMsgs(void);
void CleanupRexxPort(void);
int  ProcessRexxMsgs(char *);
long InitStuff( void );
void CleanStuff( void );




#define PORT_NAME  "PROGRAB"
#define REXX_OKAY 0
#define REXX_UNKNOWN 1





struct Library *ProGrabBase = NULL;
struct Library *GfxBase = NULL;
struct Library *DOSBase = NULL;
struct Library *IntuitionBase = NULL;
struct Library *RexxSysBase;

struct MsgPort *SnoopPort;	/* ARexx message port */
ULONG  RexxPortMask;		/* Sig mask for Rexx msgs	*/
int    QuitFlag;		/* If true, user said quit	*/



UBYTE *pmem;
struct EVDigi vdigi;


/* Default Image resolution */
int iGrabFormat = EVDIGI_MODE_LORES;

long lWidth, lHeight;

/*
Header for P6 PPM file "P6,LF,320,LF,256,LF,255"
                       "P6,LF,Width,LF,Height,LF,255"
*/

char cPPMheader[15] = {80,54,10,51,50,48,10,50,53,54,10,50,53,53,10};
char cTmp[4];



FILE *fp;

#ifdef DEBUG
FILE *fp2;
#endif




int main( int argc, char *argv[] )
{
  char *param;
  int i;


#ifdef DEBUG
  fp2=fopen("tmp.tmp","wt");
  if(!fp2) return 30;
#endif


/* Was a command line parameter specified? */
  if( argc <= 1 )
  {
    iGrabFormat = EVDIGI_MODE_LORES;
  }
  else
  {
    param = argv[1];

    if(*param == '0') iGrabFormat = EVDIGI_MODE_LORES;
    if(*param == '1') iGrabFormat = EVDIGI_MODE_LORES_OSCAN;
    if(*param == '2') iGrabFormat = EVDIGI_MODE_HIRES;
    if(*param == '3') iGrabFormat = EVDIGI_MODE_HIRES_OSCAN;
    if(*param == '4') iGrabFormat = EVDIGI_MODE_HIRESLACE;
    if(*param == '5') iGrabFormat = EVDIGI_MODE_HIRESLACE_OSCAN;
    if(*param == '?')
    {
      printf("Usage: prograbr <resolution number>\n");
      printf("0: 320x256 (default)\n");
      printf("1: 368x256\n");
      printf("2: 640x256\n");
      printf("3: 736x283\n");
      printf("4: 640x512\n");
      printf("5: 736x512\n");
      exit(0);
    }
  }




/* Select resolution paramters (change if using NTSC) */


  switch(iGrabFormat)
  {
    case EVDIGI_MODE_LORES:
      lWidth  = 320L;
      lHeight = 256L;
    break;
    case EVDIGI_MODE_LORES_OSCAN:
      lWidth  = 368L;
      lHeight = 283L;
    break;
    case EVDIGI_MODE_HIRES:
      lWidth  = 640L;
      lHeight = 256L;
    break;
    case EVDIGI_MODE_HIRES_OSCAN:
      lWidth  = 736L;
      lHeight = 283L;
    break;
    case EVDIGI_MODE_HIRESLACE:
      lWidth  = 640L;
      lHeight = 512L;
    break;
    case EVDIGI_MODE_HIRESLACE_OSCAN:
      lWidth  = 736L;
      lHeight = 512L;
    break;
  }

/* Patch PPM header */
  sprintf(cTmp,"%ld",lWidth);
  memcpy(&cPPMheader[3],cTmp,3);
  sprintf(cTmp,"%ld",lHeight);
  memcpy(&cPPMheader[7],cTmp,3);


/* Allocate memory for the required resolution */
     pmem = AllocMem( lWidth * lHeight * 3, MEMF_ANY|MEMF_CLEAR);
     if(!pmem)
     {
#ifdef DEBUG
       fclose(fp2);
#endif
       return 30;
     }


     if( InitStuff() == 0 )
     {
        InitRexxPort();


        /* Initialize private structure of the "prograb.library" */
        vdigi.GfxBase = (struct Library *)GfxBase;
        vdigi.DOSBase = (struct Library *)DOSBase;
        vdigi.IntuitionBase = (struct Library *)IntuitionBase;



        /* EVDIGI_Init() will automatically detect the PCMCIA interface. */

        EVDIGI_Init(&vdigi);


        /* Check if there is any video signal connected */
        if(! EVDIGI_CheckVideoSignal() )
        {
          printf("No video signal detected\n");
          FreeMem( pmem, lWidth * lHeight * 3 );
          EVDIGI_Cleanup();
          CleanStuff();
          return 10;
        }



        /* Now we can change default values for: */
        EVDIGI_SetBrightness(10);     /* default is 0  */
        EVDIGI_SetSaturation(15);     /* default is 10 */
        EVDIGI_SetContrast(11);       /* default is 10 */






/* wait for commands here */
        MainLoop();

        CleanupRexxPort();

     }

     FreeMem( pmem, lWidth * lHeight * 3 );


     EVDIGI_Cleanup();
     CleanStuff();


#ifdef DEBUG
     fclose(fp2);
#endif

}


/*
 *	MainLoop()
 *
 *	Processes all incoming events
 */
void MainLoop(void)
{


        QuitFlag = 0;

	while (!QuitFlag)
        {
		ULONG mask;

		mask = Wait(	RexxPortMask | SIGBREAKF_CTRL_C);


		if (mask & RexxPortMask)
                {
#ifdef DEBUG
                  fprintf(fp2,"REXX message received\n");
#endif
                  HandleRexxMsgs();
                }
		if (mask & SIGBREAKF_CTRL_C)
                {
#ifdef DEBUG
                  fprintf(fp2,"CTRL-C received\n");
#endif
                  QuitFlag = 1;
                }
	}

}



/*
 *		InitRexxPort
 *
 *		Attempts to create SnoopDos's public port and initialise SnoopPort
 *		and RexxPortMask accordingly. If the port already exists, still
 *		returns TRUE but SnoopPort will be NULL.
 *
 *		If we can't create the port for some reason, returns FALSE.
 */
int InitRexxPort(void)
{
	struct MsgPort *port;

	Forbid();
	port = FindPort(PORT_NAME);
	if (!port)
        {
		SnoopPort = CreateMsgPort();
		if (!SnoopPort)
                {
			Permit();
			return (FALSE);
		}
		SnoopPort->mp_Node.ln_Name = PORT_NAME;
		SnoopPort->mp_Node.ln_Pri  = 1;	/* Speed up searches */
		AddPort(SnoopPort);
		RexxPortMask = 1 << SnoopPort->mp_SigBit;
	}
	Permit();
	return (TRUE);
}



/*
 *		CleanupRexxPort()
 *
 *		Cleans up our SnoopDos port -- removes it from the public port
 *		list, and then replies to any messages it has outstanding. Call
 *		before exiting.
 */
void CleanupRexxPort(void)
{
	if (SnoopPort) {
		struct RexxMsg *msg;

		Forbid();
		RemPort(SnoopPort);
		while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL)
                {
			msg->rm_Result1 = RC_FATAL;
			msg->rm_Result2 = NULL;
			ReplyMsg(msg);
		}
		Permit();
		DeleteMsgPort(SnoopPort);
		SnoopPort = NULL;
	}
}


/*
 *		HandleRexxMsgs()
 *
 *		Handles any new messages at our Rexx port
 */

void HandleRexxMsgs(void)
{
  struct RexxMsg *msg;
  int iret;

  while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL)
  {
    msg->rm_Result1 = RC_OK;
    msg->rm_Result2 = NULL;

    if ((msg->rm_Action & RXCODEMASK) == RXCOMM)
    {

/*
 *  Got a valid ARexx message, now process it
 */
      iret = ProcessRexxMsgs(msg->rm_Args[0]);


      if(iret == REXX_OKAY)
      {
        msg->rm_Result1 = RC_OK;
      }
      else
      {
        msg->rm_Result1 = 30;
      }


    }

    ReplyMsg(msg);
  }


}


/*
 *
 * 	ProcessRexxMsgs
 *
 *
 */

int ProcessRexxMsgs(char *cmdline)
{
  long i;


  if(strcmp("QUIT",cmdline) == 0)
  {
#ifdef DEBUG
    fprintf(fp2,"QUIT received\n");
#endif
    QuitFlag = 1;
    return REXX_OKAY;
  }


  if(strcmp("GRAB",cmdline) == 0)
  {
#ifdef DEBUG
    fprintf(fp2,"GRAB received\n");
#endif



/* Now grab an image in required resolution.
   RGB data will be saved from the "pmem" address. */
    if( EVDIGI_CheckVideoSignal() )
    {
      EVDIGI_GrabImage(&vdigi, iGrabFormat, pmem);


/* Write image data to disk */
      fp = fopen("ram:tmp.ppm","wb");
      if(fp != NULL)
      {
        fwrite(cPPMheader,1,15,fp);


/* Amount of data to copy depends on resolution used
   e.g. EVDIGI_MODE_LORES           320 x 256 x 3 bytes = 245760
        EVDIGI_MODE_HIRESLACE_OSCAN 736 x 512 x 3 bytes = 1130496
*/

        for(i=0L; i<(lWidth * lHeight * 3); i++)
        {
          fwrite(pmem+i,1,1,fp);
        }
      }
      fclose(fp);
    }

    return REXX_OKAY;
  }


  return REXX_UNKNOWN;

}

long InitStuff( void )
{
    DOSBase = OpenLibrary( "dos.library", 37L );
    if( DOSBase == NULL )
        return( 1l );

    IntuitionBase = OpenLibrary("intuition.library", 37L );
    if( IntuitionBase == NULL )
        return( 2l );

    GfxBase = OpenLibrary( "graphics.library", 37L );
    if( GfxBase == NULL )
        return( 1l );


    RexxSysBase = OpenLibrary("rexxsyslib.library",  0);
    if( RexxSysBase == NULL )
        return( 1l );


    ProGrabBase = (struct Library *)OpenLibrary("prograb.library", 0L );
    if( ProGrabBase == NULL )
        return( 3l );


     return 0L;
}

void CleanStuff( void )
{



  if( ProGrabBase )
     CloseLibrary( ProGrabBase );

  if (RexxSysBase)
     CloseLibrary( (struct Library *)RexxSysBase);

  if( GfxBase )
      CloseLibrary( (struct Library *)GfxBase );

  if( IntuitionBase )
      CloseLibrary( ( struct Library *)IntuitionBase );

  if( DOSBase )
      CloseLibrary( ( struct Library *)DOSBase );

}

