/* Vision VV6300 CMOS camera frame routines implementation
 * fileName: vcamFrame.c
 * author: Jesse Pepper <peppe-jj@ee.uwa.edu.au>
 */

#include "vcamFrame.h"
#include "pc_io.h"
#include "vcamInit.h"
#include <stdio.h>
#include <sys/io.h>
#include <errno.h>
#include <asm/io.h>

BYTE vcamData[60000];
int frameFlag=0;
int pixel=0;

/**********************************************************/

int getVisibleFrame ( BYTE* visible )
	{
	int missedLine=0;
	int i=0;
	int lines=0; 
	int line=12;
	int lastLine=12;
	BYTE packedLine[2];
	BYTE b=0;
	int j=0;
	int k=0;

	while (FST_read () == 0)
		; /* wait for FST pulse */
	while (FST_read () == 1)
		; /* wait for FST pulse */
	while (FST_read () == 0)
		; /* wait for FST pulse */

#if QCK_SLOW
	while (i < 30000)
		{
		while ((inb ( PAR_SR ) & 0x40))
			j++; /* wait for QCK to go low */
		vcamData[i++] = inb ( PAR_DATA );
		while (!(inb ( PAR_SR ) & 0x40))
			k++; /* wait for QCK to go high */
		vcamData[i++] = inb ( PAR_DATA );
		}
#else
	for (i=0; i<30000; i++)
		{
		while ((inb ( PAR_SR ) & 0x40))
			j++; /* wait for QCK to go low */
		vcamData[i] = inb ( PAR_DATA );
		while (!(inb ( PAR_SR ) & 0x40))
			k++; /* wait for QCK to go high */
		}
#endif

#if 1
	/* DEBUG */
		{
		static int firstTime=2;
		if (firstTime)
			{
			FILE* outFile = fopen ( "raw.hex", "wb" );
			fprintf ( stderr, "Writing raw.hex...  ");
			fwrite ( vcamData, 1, 60000, outFile );
			fprintf ( stderr, "...done\n");
			firstTime--;
			}
		}
#endif
	
	do
		{
		while ( getPixel () != 0x00 )
			;
		
		if ( getPixel () != 0xb6 )
			continue;
		else
			{
			/* get line number pixels */
			packedLine[0] = getPixel ();
			packedLine[1] = getPixel ();
			lastLine = line;
			line = ((packedLine[0]&0x7e)<<5) + ((packedLine[1]&0x7e)>>1);

			if (lastLine != line-1)
				{
				fprintf ( stderr, "line = %d, lastLine = %d, ", line, lastLine );
				fprintf ( stderr, "code = %x:%x\n", packedLine[0], packedLine[1]);
				continue;
				}

			b = getPixel ();
			while ( b < 0x10 )
				b = getPixel(); /* wait for >= 0x10 pixels */

			for (i=0; i<160; i++)
				{
				if ( i!=0 )
					b = getPixel ();

				if (b <= 0x10)
					{
					fprintf ( stderr, "### code = %x:%x, b = %x\n", packedLine[0], packedLine[1], b );
					break;
					}
				visible[lines*160 + i] = b;
				}
			}
			lines++;
		} while (lines < 120);

		frameFlag = 1;
		if ( line != 132 )
			fprintf ( stderr, "insufficient line = %d\n", line );
		printf ( "got frame\n" );
		
		return (0);
	}

/**********************************************************/

BYTE getPixel ( void )
	{
	if (frameFlag == 1)
		{
		frameFlag = 0;
		pixel = 0;
		}

	if (pixel>=30000)
		{
		fprintf ( stderr, "D" );
		pixel = 0;
		}

	return vcamData[pixel++];
	}

/**********************************************************/

int visibleToRGB ( BYTE* visible, BYTE* rgbImage )
	{
	int i,j;
	int rgbPixel=0;
	BYTE temp;
	/* for debug */
	static int frame=0;
	char fileName[] = "test0000.ppm";
	FILE* outFile;


#if 0
	for (i=0; i<IMAGE_Y; i++)
		{
		if (i%2 == 0)
			{
			for (j=0; j<IMAGE_X; j++)
				{
				if (j%2 == 0)
					{
					rgbImage[rgbPixel++] = visible[(i*IMAGE_X) + j];
					rgbImage[rgbPixel++] = 0;
					rgbImage[rgbPixel++] = 0;
					}
				else
					{
					rgbImage[rgbPixel++] = 0;
					rgbImage[rgbPixel++] = visible[(i*IMAGE_X) + j]>>1;
					rgbImage[rgbPixel++] = 0;
					}
				}
			}
		else
			{
			for (j=0; j<IMAGE_X; j++)
				{
				if (j%2 == 0)
					{
					rgbImage[rgbPixel++] = 0;
					rgbImage[rgbPixel++] = visible[(i*IMAGE_X) + j]>>1;
					rgbImage[rgbPixel++] = 0;
					}
				else
					{
					rgbImage[rgbPixel++] = 0;
					rgbImage[rgbPixel++] = 0;
					rgbImage[rgbPixel++] = visible[(i*IMAGE_X) + j];
					}
				}
			}
		}

	for (i=0; i<19200; i++)
		{
		rgbImage[(3*i)+0] = visible[i];
		rgbImage[(3*i)+1] = visible[i];
		rgbImage[(3*i)+2] = visible[i];
		}
#endif

	for (i=0; i<IMAGE_Y; i+= 2)
		{
		for (j=0; j<IMAGE_X; j+= 2)
			{
			/* FIXME the documentation is sort of wrong, it's RGGB, not GRBG */
			/*temp = visible[i*IMAGE_X + j + 1]; /* red */
			temp = visible[i*IMAGE_X + j]; /* red */
			rgbImage[3*(i*IMAGE_X + j)]         = temp;
			rgbImage[3*(i*IMAGE_X + j + 1)]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j)]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j + 1)] = temp;

			/*temp = (visible[i*IMAGE_X + j] + visible[(i+1)*IMAGE_X + j + 1]) >> 1; /* green */
			temp = (visible[i*IMAGE_X + j + 1] + visible[(i+1)*IMAGE_X + j]) >> 1; /* green */
			rgbImage[3*(i*IMAGE_X + j) + 1]         = temp;
			rgbImage[3*(i*IMAGE_X + j + 1) + 1]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j) + 1]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j + 1) + 1] = temp;
			
			/*temp = visible[(i+1)*IMAGE_X + j]; /* blue */
			temp = visible[(i+1)*IMAGE_X + j + 1]; /* blue */
			rgbImage[3*(i*IMAGE_X + j) + 2]         = temp;
			rgbImage[3*(i*IMAGE_X + j + 1) + 2]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j) + 2]     = temp;
			rgbImage[3*((i+1)*IMAGE_X + j + 1) + 2] = temp;
			}
		}

#if WRITE_FILE
	/* debug, output ppm's of each image */
	fileName[4] = (frame%10000)/1000 + 48;
	fileName[5] = (frame%1000)/100 + 48;
	fileName[6] = (frame%100)/10 + 48;
	fileName[7] = (frame%10)/1 + 48;
	frame++;
	outFile = fopen ( fileName, "wb" );
	if (outFile == NULL)
		fprintf ( stderr, "Couldn't open file %s for writing, errno: %d\n", fileName, errno );
	else
		fprintf ( stderr, "got this far\n" );
	
	fprintf ( outFile, "P6\n" );
	fprintf ( outFile, "# OUTPUT BUFFER IN PPM FORMAT\n" );
	fprintf ( outFile, "# TESTING IMAGE OUTPUT\n" );
	fprintf ( outFile, "160 120\n" );
	fprintf ( outFile, "255\n" );
	fwrite ( rgbImage, 1, 57600, outFile );
	fclose ( outFile );
#endif

	return (0);
	}

/**********************************************************/

int FST_read ( void )
	{
	BYTE b;

	b = OSReadParSR () & FST;
	return (b>0);
	}

/**********************************************************/

int QCK_read ( void )
	{
	BYTE b;

	b = OSReadParSR () & QCK;
	return (b>0);
	}

/**********************************************************/

int testForQCK ( void )
	{
	int i, j;

	for (i=0; i<QCK_WAITS; i++)
		wait ();

	for (i=0; i<QCK_WAITS; i++)
		{
		if (QCK_read () == 0)
			break; /* wait for QCK to go low */
		}

	for (j=0; j<QCK_WAITS; j++)
		{
		if (QCK_read () == 1)
			break; /* wait for QCK to go high */
		}

	if (i < QCK_WAITS && j < QCK_WAITS)
		return (QCK_FOUND);
	else
		return (NO_QCK_FOUND);
	}

/**********************************************************/

