/************ Camera specific primitives ************/
attention()
{
	int i=0;
	unsigned char character;

	while (readserial(&character,1) && i++ <200);

	for (i=0; i<5; i++)
	{
		if (debug & 8) printf("TX>>ENQ (attention)\n");
		sendchar(0x05);
		Delay(5);
		if (readserial(&character,1) && character == 0x06) 
		{	
			if (debug & 8) printf("RX<<ACK\n");
			return(1);
		}
	}
	return(0);
}
		
senddata(unsigned char *data,char *command,int length)
{
	unsigned char bcc=0;
	int i;
	char buff[255];
	int chars_sent = 0;
	int packetlength;
	int lastpacket=0;
	int resplength=0;

	/* Send the picture */
	while (chars_sent<length && !lastpacket)
	{	
		/* prepare the size indicators in the command */
		packetlength = length - chars_sent;
		if (packetlength >512) packetlength = 512; else lastpacket=1;
		command[2] = packetlength & 0xff;
		command[3] = packetlength >> 8;			

		/* calculate checksum */
		bcc=0;
		for(i=0; i<packetlength; i++)
			bcc = bcc ^ data[i+chars_sent];
		for (i=0; i<4; i++)
			bcc =bcc ^ command[i];
		if (lastpacket) bcc = bcc ^ 0x03;
		else bcc = bcc ^ 0x17;
	
		/* send the STX */
		sendchar(0x10);
		sendchar(0x02);
	
		/* send the command */
		for (i=0; i<4; i++)
		{
			if (command[i] == 0x10) sendchar(0x10);
			sendchar(command[i]);
		}	
		printhex("Cmd > ",command,4);


		/* send the data */
		for (i=0; i<packetlength; i++)
		{
			if (data[i+chars_sent] == 0x10) sendchar(0x10);
			sendchar(data[i+chars_sent]);
		}	
		printhex("Data> ",&(data[chars_sent]),16);
	
		/* send the ETX or ETB */
		sendchar(0x10);
		if (lastpacket) sendchar(0x3); else sendchar(0x17);
		if (lastpacket) printf("ETX\n"); else printf("ETB\n");	

		/* send the BCC */
		sendchar(bcc);
	
		/* wait for the acknowledge */
		for (i=0; i<80 && readserial(buff,1)!=1; i++) Delay(5);
	
		if (i == 10)
			return( 0 * printf("!! no ACK received\n") );
	
		if(buff[0] == 0x15) 
			return( 0 * printf("RX<<NACK!\n") );
	
		if (buff[0] != 0x06)
			return( 0 * printf("RX<< %02x instead of ACK\n") );	
	
		if (buff[0]==0x6) printf("RX<<ACK\n");

		chars_sent += packetlength;
		printf("  Sent %d of %d\n",chars_sent,length);
#ifdef bongaloid
		/* receive the response */
		resplength=receivepacket(buff,4);

		printhex("Resp<  ",buff,resplength);

		/* send an ACK to the response */
		sendchar(0x06);
#endif	

	}
	Delay(50);
	flushserial(buff,100,1);
	return(1);	
}

	
sendpacket(unsigned char *message,int length)
{
	unsigned char bcc=0;
	int i;
	char buff[10];
	
	if (debug & 2)	printhex("TX>>",message,length);
	if (debug & 4)	printascii("TX>>",message,length);

	/* calculate checksum */
	for(i=0; i<length; i++)
		bcc = bcc ^ message[i];
	bcc = bcc ^ 0x03;

	/* send the STX */
	sendchar(0x10);
	sendchar(0x02);

	/* send the data */
	for (i=0; i<length; i++)
	{
		if (message[i] == 0x10) sendchar(0x10);
		sendchar(message[i]);
	}	

	/* send the ETX */
	sendchar(0x10);
	sendchar(0x03);

	/* send the BCC */
	sendchar(bcc);

	/* wait for the acknowledge */
	for (i=0; i<40 && readserial(buff,1)!=1; i++) Delay(5);

	if (i == 10)
		return( 0 * printf("!! no ACK received\n") );

	if(i!=10 && buff[0] == 0x15) 
		return( 0 * printf("RX<<NACK!\n") );

	if (i!=10 && buff[0] != 0x06)
		return( 0 * printf("RX<< %02x instead of ACK\n") );	

	if (debug & 8) printf("RX<<ACK\n");
	return(1);	
}

			

receivepacket(unsigned char *buffer, int maxlen)
{
	enum
	{	
		rxs_waitforSTX1 	=  0,	/* waiting for the escape preceeding the STX */
		rxs_waitforSTX2 	= 10,	/* waiting for STX after having received the preceeding escape */
		rxs_waitforHeader	= 12,	/* waiting for header bytes */
		rxs_waitforHCtrl	= 14,	/* waiting for a control character after escape received in header */
		rxs_waitforData 	= 20,	/* waiting for an ordinary data byte */
		rxs_waitforCtrl 	= 30,	/* waiting for a control character after escape received in data */
		rxs_waitforBCC  	= 40,	/* waiting for BCC after an ETB was recevied */
		rxs_Ready		 	= 50,	/* read all there is to read */
		rxs_waitforETB_BCC 	= 60,	/* wait for the BCC following an ETB */
		rxs_RX_Debug	 	= 1024	/* receive characters until buffer is empty */
	};

	int idlecycles = 0;			/* number of intervals since last character received */
	int timeout = 60;			/* ie 20 idlecycles */
	int cycletime = 5;			/* duration of each wait cycle */

	int state=rxs_waitforSTX1;	/* current receiving state (see enum above) */
	
	int header_chars = 0;		/* number of header chars received (there should be 4 in each camera response) */
	unsigned char headchar[4];	/* the header characters received */	

	int chars_received = 0;		/* number of characters received and accepted*/
	int chars_skipped = 0;		/* number of unexpected characters skipped */
	int packets_received=0;		/* number of good packets received */
	
	unsigned char bcc=0,bccrx;	/* the block check character (checksum of sorts) calculated and received values */

	unsigned char character;		/* the currently received character */
	int dispcount=999;			/* counter to display packet count every 20 or so */
	unsigned char a;			/* just a temporary var */
	int chars;				/* anothr one */

	while ( idlecycles < timeout && state != rxs_Ready)
	{
		if (!serchars())
		{
			idlecycles++;
			Delay(cycletime);
			if (debug & 1) printf("    Idle cycles = %03d\n",idlecycles);
		}
		else
		{
			idlecycles=0;
			if (debug & 1) printf("    From state %02d --> ",state);
			switch(state)
			{
				case rxs_waitforSTX1:
					readserial(&character,1);
					if ( character == 0x10) state = rxs_waitforSTX2;
					else chars_skipped++;
					break;
				case rxs_waitforSTX2:
					readserial(&character,1);
					if ( character == 0x02)
					{
						state = rxs_waitforHeader;
						header_chars=0;
					}
					else { chars_skipped++; state = rxs_waitforSTX1; }
					break;
				case rxs_waitforHeader:
					readserial(&character,1);
					if ( character == 0x10 ) state = rxs_waitforHCtrl;
					else
					{
						bcc = bcc ^ character;
						headchar[header_chars]=character;
						header_chars++;
						if (header_chars== 4)
						{
							if (debug & 16)	printhex("RX<< Header:",headchar,4);
							header_chars=0;
							state=rxs_waitforData;
						}
					}
					break;
				case rxs_waitforHCtrl:
					readserial( &character,1);
					switch(character)
					{
						case 0x03:
							bcc = bcc ^ character;
							state = rxs_waitforBCC;
							break;
						case 0x17:
							bcc = bcc ^ character;
							state = rxs_waitforETB_BCC;
							break;
						case 0x10:
							headchar[header_chars]=character;
							bcc = bcc ^ character;
							header_chars++;
							state = rxs_waitforHeader;
							break;
						default:
							printf("!! Character %02x received after escape in header block\n",a=character);
							return(0);
					}
					break;
				case rxs_waitforData:
					readserial( &character,1);
					if ( character == 0x10 ) state = rxs_waitforCtrl;
					else
					{
						buffer[chars_received] = character;
						chars_received++;
						if (chars_received >= maxlen) 
						{
							printf("!! Received data exceeds allocated space\n");
							return(0);
						}
						bcc = bcc ^ character;
					}
					break;
				case rxs_waitforCtrl:
					readserial( &character,1);
					switch(character)
					{
						case 0x03:
							bcc = bcc ^ character;
							state = rxs_waitforBCC;
							break;
						case 0x17:
							bcc = bcc ^ character;
							state = rxs_waitforETB_BCC;
							break;
						case 0x10:
							buffer[chars_received] = character;
							bcc = bcc ^ character;
							chars_received++;
							state = rxs_waitforData;
							break;
						default:
							printf("!! Character %02x received after escape in data block\n",a=character);
							return(0);
					}
					break;
				case rxs_waitforBCC:
					readserial( &character,1);
					bccrx=character;
					state=rxs_Ready;
					break;
				case rxs_waitforETB_BCC:
					readserial( &character,1);
					bccrx=character;
					if (bccrx!=bcc) {printf("!!calculated bcc %d instead of %d\n",bcc,bccrx); break;};
					if (debug & 8) printf("TX>>ACK\n");
                         if (dispcount ++ >18)
					{	
						dispcount=0;
						if ((debug & 64) && packets_received<1) printf("\n");
						if (debug & 64) printf("\x0b  Received %4d packets of %d \n",packets_received,maxlen/512);
					}
					packets_received++;
					sendchar(0x6);
					bcc=0;
					state=rxs_waitforSTX1;
					break;
				case rxs_RX_Debug:
					chars=readserial(buffer,MAXLEN);
					printhex(buffer,chars);
					state=rxs_RX_Debug;
					break;
			}
			if (debug & 1) printf(" state %02d by char %02x\n",state,character);	
		}
	}
	if (debug & 2)	printhex("RX<<",buffer,chars_received);
	if (debug & 4)	printascii("RX<<",buffer,chars_received);
	
	if (idlecycles>=timeout)
	{
		printf("!!Connection timed out in state %d\n",state);
		return(0);
	}

	/* check agreement of the checksum */
	if (bccrx != bcc)
	{
		printf("!!Calculated BCC is %02x instead of received value of %02x\n",bcc,bccrx);
		return(0);
	}
	else if (debug & 1) printf("    Checksum OK (%d)\n",bcc);

	
	/* Acknowledge the received packet */
	if (debug & 8) printf("TX>>ACK\n");
	sendchar(0x6);
	return(chars_received);
}
